DB Storage Re-engineering #1
@ -20,6 +20,7 @@ import { commands } from "./commands"
|
|||||||
import { DBCall } from "./utilties/storage/entities/DBCall"
|
import { DBCall } from "./utilties/storage/entities/DBCall"
|
||||||
import { DBCallTranscriptions } from "./utilties/storage/entities/DBCallTranscriptions"
|
import { DBCallTranscriptions } from "./utilties/storage/entities/DBCallTranscriptions"
|
||||||
import { DBCallUsers } from "./utilties/storage/entities/DBCallUsers"
|
import { DBCallUsers } from "./utilties/storage/entities/DBCallUsers"
|
||||||
|
import { DBMessageRegex } from "./utilties/storage/entities/DBMessageRegex"
|
||||||
|
|
||||||
console.log(__dirname + path.sep + "utilities" + path.sep + "storage" + path.sep + "entities" + path.sep + "*.ts")
|
console.log(__dirname + path.sep + "utilities" + path.sep + "storage" + path.sep + "entities" + path.sep + "*.ts")
|
||||||
|
|
||||||
@ -36,7 +37,8 @@ export const dataSource = new DataSource({
|
|||||||
DBMessageAttachments,
|
DBMessageAttachments,
|
||||||
DBCall,
|
DBCall,
|
||||||
DBCallTranscriptions,
|
DBCallTranscriptions,
|
||||||
DBCallUsers
|
DBCallUsers,
|
||||||
|
DBMessageRegex
|
||||||
],
|
],
|
||||||
synchronize: true,
|
synchronize: true,
|
||||||
logging: true
|
logging: true
|
||||||
|
|||||||
@ -1,55 +0,0 @@
|
|||||||
import { CommandInteraction, SlashCommandBuilder } from "discord.js";
|
|
||||||
|
|
||||||
export const enabled: boolean = true
|
|
||||||
|
|
||||||
export const data = new SlashCommandBuilder()
|
|
||||||
.setName("breadalert")
|
|
||||||
.setDescription("Controls event alerting using the Bread Alert subsystem")
|
|
||||||
.addSubcommand((subcommand) =>
|
|
||||||
subcommand
|
|
||||||
.setName("list")
|
|
||||||
.setDescription("List the current Bread Alert active alerts")
|
|
||||||
.addIntegerOption(option =>
|
|
||||||
option
|
|
||||||
.setName("count")
|
|
||||||
.setDescription("The number of future alerts to return, default 5")
|
|
||||||
.setRequired(false)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.addSubcommand(subcommand =>
|
|
||||||
subcommand
|
|
||||||
.setName("add")
|
|
||||||
.setDescription("Add a new Bread Alert")
|
|
||||||
.addStringOption(option =>
|
|
||||||
option
|
|
||||||
.setName("name")
|
|
||||||
.setDescription("The name of the event, must be unique")
|
|
||||||
.setRequired(true)
|
|
||||||
)
|
|
||||||
.addStringOption(option =>
|
|
||||||
option
|
|
||||||
.setName("date")
|
|
||||||
.setDescription("The date and time of the event in YYYY-MM-DD HH:MM:SS format")
|
|
||||||
.setRequired(true)
|
|
||||||
)
|
|
||||||
.addStringOption(option =>
|
|
||||||
option
|
|
||||||
.setName("notifications")
|
|
||||||
.setDescription("A comma separated list of time offsets that determine when to alert prior to the event")
|
|
||||||
.setRequired(false)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.addSubcommand(subcommand =>
|
|
||||||
subcommand
|
|
||||||
.setName("delete")
|
|
||||||
.setDescription("Delete a Bread Alert")
|
|
||||||
.addStringOption(option =>
|
|
||||||
option
|
|
||||||
.setName("name")
|
|
||||||
.setDescription("The name of the event to remove")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
export async function execute(interaction: CommandInteraction) {
|
|
||||||
return interaction.reply("NOT IMPLEMENTED!")
|
|
||||||
}
|
|
||||||
@ -1,7 +1,5 @@
|
|||||||
import * as ping from "./ping";
|
import * as ping from "./ping";
|
||||||
import * as breadalert from "./breadalert"
|
|
||||||
|
|
||||||
export const commands = {
|
export const commands = {
|
||||||
ping,
|
ping
|
||||||
breadalert
|
|
||||||
}
|
}
|
||||||
@ -1,57 +0,0 @@
|
|||||||
import { timeShorthandToSeconds } from "../time/conversions";
|
|
||||||
import { SQLCommon } from "../storage/interfaces";
|
|
||||||
import { Client } from "discord.js";
|
|
||||||
|
|
||||||
export async function breadthreadLockExists(db: SQLCommon, channelId: string) : Promise<boolean> {
|
|
||||||
const queryResult: Object[] = await db.getAllParameterized(
|
|
||||||
"SELECT * FROM breadthread_autolock WHERE channel_snowflake = ?",
|
|
||||||
[channelId]
|
|
||||||
)
|
|
||||||
|
|
||||||
return queryResult.length != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function breadthreadEnsureAutoLock(db: SQLCommon, channelId: string, inactiveTimeUntilLocked: string) {
|
|
||||||
const timeUntilLocked = timeShorthandToSeconds(inactiveTimeUntilLocked)
|
|
||||||
|
|
||||||
if(await breadthreadLockExists(db, channelId)) {
|
|
||||||
await db.runParameterized(
|
|
||||||
"UPDATE breadthread_autolock SET inactivity_seconds = ? WHERE channel_snowflake = ?",
|
|
||||||
[timeUntilLocked, channelId]
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
await db.runParameterized(
|
|
||||||
"INSERT INTO breadthread_autolock (channel_snowflake, inactivity_seconds, locked) VALUES (?, ?, ?)",
|
|
||||||
[channelId, timeUntilLocked, 0]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function breadthreadRemoveAutoLock(db: SQLCommon, channelId: string) {
|
|
||||||
await db.runParameterized(
|
|
||||||
"DELETE FROM breadthread_autolock WHERE channel_snowflake = ?",
|
|
||||||
[channelId]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function breadthreadProcessLocks(db: SQLCommon, client: Client) {
|
|
||||||
const currentTimeSeconds = Math.round((new Date()).getTime() / 1000);
|
|
||||||
(await db.getAll("SELECT * FROM breadthread_autolock WHERE locked = 0")).forEach(async (row : any) => {
|
|
||||||
const channel = client.channels.cache.find(row.channel_snowflake)
|
|
||||||
|
|
||||||
if(channel?.isThread()) {
|
|
||||||
const lastMessageTime: number = Math.round(
|
|
||||||
channel.lastMessage?.createdAt.getTime() ?? 0 / 1000
|
|
||||||
)
|
|
||||||
|
|
||||||
if(lastMessageTime != 0 && currentTimeSeconds - lastMessageTime >= row.inactivity_seconds) {
|
|
||||||
await channel.setLocked(true, "Breadbot is locking this thread because the inactivity timeout was exceeded!")
|
|
||||||
|
|
||||||
await db.runParameterized(
|
|
||||||
"UPDATE breadthread_autolock SET locked = 1 WHERE locked = 0 AND channel_snowflake = ?",
|
|
||||||
[channel.id]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@ -1,16 +1,18 @@
|
|||||||
import { Guild } from "discord.js";
|
import { Guild } from "discord.js";
|
||||||
import { SQLCommon } from "../storage/interfaces";
|
import { DBMessageRegex } from "../storage/entities/DBMessageRegex";
|
||||||
|
import { Repository } from "typeorm";
|
||||||
|
import { DBServer } from "../storage/entities/DBServer";
|
||||||
|
|
||||||
export async function getRegexesForGuild(db: SQLCommon, guild: Guild): Promise<any[]> {
|
export async function getRegexesForGuild(db: Repository<DBServer>, guild: Guild): Promise<DBMessageRegex[] | null | undefined> {
|
||||||
return db.getAllParameterized(
|
return (await db.findOne({
|
||||||
"SELECT * FROM message_regexes WHERE server_snowflake = ?",
|
select: {
|
||||||
[guild.id]
|
regexes: true
|
||||||
)
|
},
|
||||||
|
relations: {
|
||||||
|
regexes: true
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
server_snowflake: guild.id
|
||||||
}
|
}
|
||||||
|
}))?.regexes
|
||||||
export async function getRoleExclusionSnowflakesForGuild(db: SQLCommon, guild: Guild): Promise<string[]> {
|
|
||||||
return (await db.getAllParameterized(
|
|
||||||
"SELECT role_snowflake FROM message_regex_no_role_check WHERE server_snowflake = ?",
|
|
||||||
[guild.id]
|
|
||||||
)).map((o) => (o as any).role_snowflake)
|
|
||||||
}
|
}
|
||||||
@ -1,20 +1,21 @@
|
|||||||
import { Guild, VoiceBasedChannel } from "discord.js";
|
import { VoiceBasedChannel } from "discord.js";
|
||||||
import { SQLCommon } from "../storage/interfaces";
|
import { IsNull, Repository } from "typeorm";
|
||||||
|
import { DBCall } from "../storage/entities/DBCall";
|
||||||
|
|
||||||
export async function breadbotInCall(db: SQLCommon, channel: VoiceBasedChannel) : Promise<boolean> {
|
export async function breadbotInCall(db: Repository<DBCall>, channel: VoiceBasedChannel) : Promise<boolean> {
|
||||||
const queryResult: Object[] = await db.getAllParameterized(
|
return (await db.findOne({
|
||||||
"SELECT * FROM calls WHERE channel_snowflake = ? AND call_end_time IS NULL",
|
where: {
|
||||||
[channel.id]
|
channel: {channel_snowflake: channel.id},
|
||||||
)
|
call_end_time: IsNull()
|
||||||
|
}
|
||||||
return queryResult.length != 0
|
})) != null
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getExistingCallID(db: SQLCommon, channel: VoiceBasedChannel) : Promise<Number> {
|
export async function getExistingCallID(db: Repository<DBCall>, channel: VoiceBasedChannel) : Promise<Number | undefined> {
|
||||||
const queryResult: any[] = await db.getAllParameterized(
|
return (await db.findOne({
|
||||||
"SELECT * FROM calls WHERE channel_snowflake = ? AND call_end_time IS NULL",
|
where: {
|
||||||
[channel.id]
|
channel: {channel_snowflake: channel.id},
|
||||||
)
|
call_end_time: IsNull()
|
||||||
|
}
|
||||||
return queryResult.length != 0 ? queryResult[0].call_id : -1
|
}))?.call_id
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import { Client, Events, VoiceState } from "discord.js"
|
import { Client, Events, VoiceState } from "discord.js"
|
||||||
import { SQLCommon } from "../storage/interfaces";
|
import { Repository } from "typeorm"
|
||||||
|
import { DBCall } from "../storage/entities/DBCall"
|
||||||
|
|
||||||
export function setupVoice(client: Client, db: SQLCommon) {
|
export function setupVoice(client: Client, db: Repository<DBCall>) {
|
||||||
client.on(Events.VoiceStateUpdate, (oldState: VoiceState, newState: VoiceState) => {
|
client.on(Events.VoiceStateUpdate, (oldState: VoiceState, newState: VoiceState) => {
|
||||||
if(oldState.channel == null && newState.channel != null) {
|
if(oldState.channel == null && newState.channel != null) {
|
||||||
// TODO Null Type Safety Risk?
|
// TODO Null Type Safety Risk?
|
||||||
@ -14,6 +15,6 @@ export function setupVoice(client: Client, db: SQLCommon) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function processCallJoin(db: SQLCommon, voiceState: VoiceState) {
|
async function processCallJoin(db: Repository<DBCall>, voiceState: VoiceState) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,21 +1,15 @@
|
|||||||
import * as commands from "./discord/commands"
|
import * as commands from "./discord/commands"
|
||||||
import * as sqlite from "./storage/sqlite"
|
|
||||||
import * as tables from "./storage/tables"
|
|
||||||
import * as guilds from "./discord/guilds"
|
import * as guilds from "./discord/guilds"
|
||||||
import * as channels from "./discord/channels"
|
import * as channels from "./discord/channels"
|
||||||
import * as users from "./discord/users"
|
import * as users from "./discord/users"
|
||||||
import * as breadthread from "./breadbot/breadthread"
|
|
||||||
import * as roles from "./discord/roles"
|
import * as roles from "./discord/roles"
|
||||||
import { events } from "./events"
|
import { events } from "./events"
|
||||||
|
|
||||||
export const utilities = {
|
export const utilities = {
|
||||||
commands,
|
commands,
|
||||||
sqlite,
|
|
||||||
tables,
|
|
||||||
guilds,
|
guilds,
|
||||||
channels,
|
channels,
|
||||||
users,
|
users,
|
||||||
events,
|
events,
|
||||||
breadthread,
|
|
||||||
roles
|
roles
|
||||||
}
|
}
|
||||||
@ -1,8 +1,9 @@
|
|||||||
import { Column, Entity, ManyToOne, OneToMany, PrimaryColumn } from "typeorm";
|
import { Column, Entity, ManyToOne, OneToMany, OneToOne, PrimaryColumn } from "typeorm";
|
||||||
import { DBChannel } from "./DBChannel";
|
import { DBChannel } from "./DBChannel";
|
||||||
import { DBUser } from "./DBUser";
|
import { DBUser } from "./DBUser";
|
||||||
import { DBMessageContentChanges } from "./DBMessageContentChanges";
|
import { DBMessageContentChanges } from "./DBMessageContentChanges";
|
||||||
import { DBMessageAttachments } from "./DBMessageAttachment";
|
import { DBMessageAttachments } from "./DBMessageAttachment";
|
||||||
|
import { DBMessageRegexMatches } from "./DBMessageRegexMatches";
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class DBMessage {
|
export class DBMessage {
|
||||||
@ -29,4 +30,7 @@ export class DBMessage {
|
|||||||
|
|
||||||
@OneToMany(() => DBMessageAttachments, (ma: DBMessageAttachments) => ma.attachment_snowflake, {nullable: true})
|
@OneToMany(() => DBMessageAttachments, (ma: DBMessageAttachments) => ma.attachment_snowflake, {nullable: true})
|
||||||
attachments: DBMessageAttachments[] | null
|
attachments: DBMessageAttachments[] | null
|
||||||
|
|
||||||
|
@OneToOne(() => DBMessageRegexMatches, (mrm: DBMessageRegexMatches) => mrm.message, {nullable: true})
|
||||||
|
violation_regex: DBMessageRegexMatches | null
|
||||||
}
|
}
|
||||||
18
src/utilties/storage/entities/DBMessageRegex.ts
Normal file
18
src/utilties/storage/entities/DBMessageRegex.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn } from "typeorm";
|
||||||
|
import { DBServer } from "./DBServer";
|
||||||
|
import { DBMessageRegexMatches } from "./DBMessageRegexMatches";
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
export class DBMessageRegex {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
message_regex_id: number
|
||||||
|
|
||||||
|
@ManyToOne(() => DBServer, (server: DBServer) => server.regexes)
|
||||||
|
server: DBServer
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
regex: string
|
||||||
|
|
||||||
|
@OneToMany(() => DBMessageRegexMatches, (mrm: DBMessageRegexMatches) => mrm.regex, {nullable: true})
|
||||||
|
matches: DBMessageRegexMatches[] | null
|
||||||
|
}
|
||||||
15
src/utilties/storage/entities/DBMessageRegexMatches.ts
Normal file
15
src/utilties/storage/entities/DBMessageRegexMatches.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { Entity, ManyToOne, OneToOne, PrimaryGeneratedColumn } from "typeorm";
|
||||||
|
import { DBMessage } from "./DBMessage";
|
||||||
|
import { DBMessageRegex } from "./DBMessageRegex";
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
export class DBMessageRegexMatches {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
message_regex_match_id: number
|
||||||
|
|
||||||
|
@OneToOne(() => DBMessage, (message: DBMessage) => message.violation_regex)
|
||||||
|
message: DBMessage
|
||||||
|
|
||||||
|
@ManyToOne(() => DBMessageRegex, (regex: DBMessageRegex) => regex.matches)
|
||||||
|
regex: DBMessageRegex
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
import { Column, Entity, OneToMany, PrimaryColumn } from "typeorm";
|
import { Column, Entity, OneToMany, PrimaryColumn } from "typeorm";
|
||||||
import { DBChannel } from "./DBChannel";
|
import { DBChannel } from "./DBChannel";
|
||||||
import { DBRole } from "./DBRole";
|
import { DBRole } from "./DBRole";
|
||||||
|
import { DBMessageRegex } from "./DBMessageRegex";
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class DBServer {
|
export class DBServer {
|
||||||
@ -18,4 +19,7 @@ export class DBServer {
|
|||||||
|
|
||||||
@OneToMany(() => DBRole, (role: DBRole) => role.server)
|
@OneToMany(() => DBRole, (role: DBRole) => role.server)
|
||||||
roles: DBRole[]
|
roles: DBRole[]
|
||||||
|
|
||||||
|
@OneToMany(() => DBMessageRegex, (regex: DBMessageRegex) => regex.server, {nullable: true})
|
||||||
|
regexes: DBMessageRegex[] | null
|
||||||
}
|
}
|
||||||
@ -1,7 +0,0 @@
|
|||||||
export enum SQLResult {
|
|
||||||
CREATED,
|
|
||||||
UPDATED,
|
|
||||||
DELETED,
|
|
||||||
ALREADYEXISTS,
|
|
||||||
FAILED
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
export interface SQLCommon {
|
|
||||||
run(query: string) : Promise<number>
|
|
||||||
runParameterized(query: string, parameters: any[]): Promise<number>
|
|
||||||
getAll(query: string) : Promise<Object[]>
|
|
||||||
getAllParameterized(query: string, parameters: any[]) : Promise<Object[]>
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,68 +0,0 @@
|
|||||||
import * as sqlite3 from 'sqlite3'
|
|
||||||
|
|
||||||
import { SQLCommon } from "./interfaces"
|
|
||||||
|
|
||||||
export class SqliteDB implements SQLCommon {
|
|
||||||
private db : sqlite3.Database;
|
|
||||||
|
|
||||||
public constructor(private readonly dbName: string) {
|
|
||||||
this.db = new sqlite3.Database(this.dbName);
|
|
||||||
}
|
|
||||||
|
|
||||||
async run(query: string): Promise<number> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.db.run(query, function (this : sqlite3.RunResult, err: Error) {
|
|
||||||
if (err) {
|
|
||||||
// TODO Winston should handle this
|
|
||||||
console.log(err)
|
|
||||||
reject(err)
|
|
||||||
} else {
|
|
||||||
resolve(this.changes)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async runParameterized(query: string, parameters: any[]): Promise<number> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.db.run(query, parameters, function (this : sqlite3.RunResult, err: Error) {
|
|
||||||
if (err) {
|
|
||||||
// TODO Winston should handle this
|
|
||||||
console.log(err)
|
|
||||||
reject(err)
|
|
||||||
} else {
|
|
||||||
resolve(this.changes)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAll(query: string): Promise<Object[]> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.db.all(query, (err: Error, rows: Object[]) => {
|
|
||||||
if (err) {
|
|
||||||
// TODO Winston should handle this
|
|
||||||
console.log(err)
|
|
||||||
reject(err)
|
|
||||||
} else {
|
|
||||||
resolve(rows)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
getAllParameterized(query: string, parameters: any[]): Promise<Object[]> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.db.all(query, parameters, (err: Error, rows: Object[]) => {
|
|
||||||
if (err) {
|
|
||||||
// TODO Winston should handle this
|
|
||||||
console.log(err)
|
|
||||||
reject(err)
|
|
||||||
} else {
|
|
||||||
resolve(rows)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
import { SQLCommon } from "./interfaces";
|
|
||||||
|
|
||||||
const tables: string[] = [
|
|
||||||
"CREATE TABLE IF NOT EXISTS message_scan_regex_matches (message_scan_regex_matches_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,message_snowflake bigint NOT NULL,message_regexes_id bigint NOT NULL);",
|
|
||||||
"CREATE TABLE IF NOT EXISTS message_regex_no_role_check (message_regex_no_role_check_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,server_snowflake bigint NOT NULL,role_snowflake bigint NOT NULL);",
|
|
||||||
"CREATE TABLE IF NOT EXISTS message_regexes (message_regexes_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,server_snowflake bigint NOT NULL,regex text NOT NULL,priority int NOT NULL,severity int NOT NULL);",
|
|
||||||
"CREATE TABLE IF NOT EXISTS message_regex_words (message_regex_words_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,message_regexes_id bigint,word text NOT NULL);",
|
|
||||||
"CREATE TABLE IF NOT EXISTS calls (call_id bigint NOT NULL PRIMARY KEY AUTOINCREMENT, channel_snowflake bigint NOT NULL, call_start_time datetime NOT NULL, call_end_time datetime DEFAULT NULL, call_consolidated INTEGER DEFAULT 0 CHECK(call_consolidated IN (0, 1)), call_transcribed INTEGER DEFAULT 0 CHECK(call_transcribed IN (0, 1)), call_data_cleaned_up INTEGER DEFAULT 0 CHECK(call_data_cleaned_up IN (0, 1)));",
|
|
||||||
"CREATE TABLE IF NOT EXISTS call_transcriptions (transcription_id bitint NOT NULL PRIMARY KEY AUTOINCREMENT, call_id bigint NOT NULL, user_snowflake bigint NOT NULL, speaking_start_time datetime NOT NULL, text TEXT NOT NULL);",
|
|
||||||
"CREATE TABLE IF NOT EXISTS call_users (call_users_id bigint NOT NULL PRIMARY KEY AUTOINCREMENT, call_id bigint NOT NULL, user_snowflake bigint NOT NULL, call_join_time datetime NOT NULL, call_leave_time datetime DEFAULT NULL);"
|
|
||||||
]
|
|
||||||
|
|
||||||
const constraints: string[] = [
|
|
||||||
"ALTER TABLE channels ADD CONSTRAINT channels_server_snowflake_fk FOREIGN KEY (server_snowflake) REFERENCES servers (server_snowflake);"
|
|
||||||
]
|
|
||||||
|
|
||||||
export async function makeTables(db: SQLCommon): Promise<number[]> {
|
|
||||||
return Promise.all(tables.map((statement) => db.run(statement)))
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function makeConstraints(db: SQLCommon): Promise<number[]> {
|
|
||||||
return Promise.all(constraints.map((statement) => db.run(statement)))
|
|
||||||
}
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user