@koishijs/plugin-database-mysql 4.0.0-beta.0 → 4.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts CHANGED
@@ -41,10 +41,15 @@ declare class MysqlDatabase extends Database {
41
41
  stop(): void;
42
42
  }
43
43
  declare namespace MysqlDatabase {
44
- export const name = "database-mysql";
45
- export const schema: Schema<Config>;
46
44
  export interface Config extends PoolConfig {
47
45
  }
46
+ export const Config: Schema<{
47
+ host?: string;
48
+ port?: number;
49
+ user?: string;
50
+ password?: string;
51
+ database?: string;
52
+ }>;
48
53
  type Declarations = {
49
54
  [T in TableType]?: {
50
55
  [K in keyof Tables[T]]?: string | (() => string) | Domain<Tables[T][K]>;
package/lib/index.js CHANGED
@@ -23,9 +23,6 @@ var __spreadValues = (a, b) => {
23
23
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
24
24
  var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
25
25
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
26
- var __require = typeof require !== "undefined" ? require : (x) => {
27
- throw new Error('Dynamic require of "' + x + '" is not supported');
28
- };
29
26
  var __export = (target, all) => {
30
27
  __markAsModule(target);
31
28
  for (var name in all)
@@ -289,8 +286,7 @@ __name(MysqlDatabase, "MysqlDatabase");
289
286
  MysqlDatabase.prototype.escape = escape;
290
287
  MysqlDatabase.prototype.escapeId = import_mysql.escapeId;
291
288
  (function(MysqlDatabase2) {
292
- MysqlDatabase2.name = "database-mysql";
293
- MysqlDatabase2.schema = import_koishi.Schema.object({
289
+ MysqlDatabase2.Config = import_koishi.Schema.object({
294
290
  host: import_koishi.Schema.string("要连接到的主机名。").default("localhost"),
295
291
  port: import_koishi.Schema.number("要连接到的端口号。").default(3306),
296
292
  user: import_koishi.Schema.string("要使用的用户名。").default("root"),
package/lib/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["import { createPool, Pool, PoolConfig, escape as mysqlEscape, escapeId, format, TypeCast } from 'mysql'\nimport { Context, Database, difference, Logger, makeArray, Schema, Query } from 'koishi'\nimport { SQLBuilder } from '@koishijs/sql-utils'\nimport * as Koishi from 'koishi'\nimport { types } from 'util'\nimport { OkPacket } from 'mysql'\n\ndeclare module 'mysql' {\n interface UntypedFieldInfo {\n packet: UntypedFieldInfo\n }\n}\n\ndeclare module 'koishi' {\n interface Database {\n mysql: MysqlDatabase\n }\n\n interface Modules {\n 'database-mysql': typeof import('.')\n }\n}\n\nconst logger = new Logger('mysql')\n\nexport type TableType = keyof Tables\n\nexport interface Tables extends Koishi.Tables {}\n\nfunction stringify(value: any, table?: string, field?: string) {\n const type = MysqlDatabase.tables[table]?.[field]\n if (typeof type === 'object') return type.stringify(value)\n\n const meta = Koishi.Tables.config[table]?.fields[field]\n if (meta?.type === 'json') {\n return JSON.stringify(value)\n } else if (meta?.type === 'list') {\n return value.join(',')\n }\n\n return value\n}\n\nfunction escape(value: any, table?: string, field?: string) {\n return mysqlEscape(stringify(value, table, field))\n}\n\nfunction getIntegerType(length = 11) {\n if (length <= 4) return 'tinyint'\n if (length <= 6) return 'smallint'\n if (length <= 9) return 'mediumint'\n if (length <= 11) return 'int'\n return 'bigint'\n}\n\nfunction getTypeDefinition({ type, length, precision, scale }: Koishi.Tables.Field) {\n switch (type) {\n case 'float':\n case 'double':\n case 'date':\n case 'time':\n case 'timestamp': return type\n case 'integer': return getIntegerType(length)\n case 'unsigned': return `${getIntegerType(length)} unsigned`\n case 'decimal': return `decimal(${precision}, ${scale}) unsigned`\n case 'char': return `char(${length || 255})`\n case 'string': return `char(${length || 255})`\n case 'text': return `text(${length || 65535})`\n case 'list': return `text(${length || 65535})`\n case 'json': return `text(${length || 65535})`\n }\n}\n\nfunction createIndex(keys: string | string[]) {\n return makeArray(keys).map(key => escapeId(key)).join(', ')\n}\n\nclass MysqlDatabase extends Database {\n public pool: Pool\n public config: MysqlDatabase.Config\n\n mysql = this\n sql: SQLBuilder\n\n escape: (value: any, table?: TableType, field?: string) => string\n escapeId: (value: string) => string\n\n inferFields<T extends TableType>(table: T, keys: readonly string[]) {\n if (!keys) return\n const types = MysqlDatabase.tables[table] || {}\n return keys.map((key) => {\n const type = types[key]\n return typeof type === 'function' ? `${type()} AS ${key}` : key\n }) as (keyof Tables[T])[]\n }\n\n constructor(public ctx: Context, config?: MysqlDatabase.Config) {\n super(ctx)\n this.config = {\n host: 'localhost',\n port: 3306,\n user: 'root',\n database: 'koishi',\n charset: 'utf8mb4_general_ci',\n multipleStatements: true,\n typeCast: (field, next) => {\n const { orgName, orgTable } = field.packet\n const type = MysqlDatabase.tables[orgTable]?.[orgName]\n if (typeof type === 'object') return type.parse(field)\n\n const meta = Koishi.Tables.config[orgTable]?.fields[orgName]\n if (meta?.type === 'string') {\n return field.string()\n } else if (meta?.type === 'json') {\n return JSON.parse(field.string()) || meta.initial\n } else if (meta?.type === 'list') {\n const source = field.string()\n return source ? source.split(',') : []\n }\n\n if (field.type === 'BIT') {\n return Boolean(field.buffer()?.readUInt8(0))\n } else {\n return next()\n }\n },\n ...config,\n }\n\n this.sql = new class extends SQLBuilder {\n escape = escape\n escapeId = escapeId\n }()\n }\n\n private columns: Record<string, string[]> = {}\n\n private getColDefs(name: string, cols: string[] = []) {\n const table = Koishi.Tables.config[name]\n const { primary, foreign, autoInc } = table\n const fields = { ...table.fields }\n const unique = [...table.unique]\n const keys = this.columns[name] || []\n\n // create platform rows\n if (name === 'user') {\n const platforms = new Set<string>(this.ctx.bots.map(bot => bot.platform))\n for (const name of platforms) {\n fields[name] = { type: 'string', length: 63 }\n unique.push(name)\n }\n }\n\n // mysql definitions (FIXME: remove in v4)\n for (const key in MysqlDatabase.tables[name]) {\n const value = MysqlDatabase.tables[name][key]\n if (keys.includes(key) || typeof value === 'function') continue\n cols.push(`${escapeId(key)} ${MysqlDatabase.Domain.definition(value)}`)\n }\n\n // orm definitions\n for (const key in fields) {\n if (keys.includes(key)) continue\n const { initial, nullable = initial === undefined || initial === null } = fields[key]\n let def = escapeId(key)\n if (key === primary && autoInc) {\n def += ' int unsigned not null auto_increment'\n } else {\n const typedef = getTypeDefinition(fields[key])\n def += ' ' + typedef + (nullable ? ' ' : ' not ') + 'null'\n // blob, text, geometry or json columns cannot have default values\n if (initial && !typedef.startsWith('text')) {\n def += ' default ' + escape(initial, name, key)\n }\n }\n cols.push(def)\n }\n\n if (!keys.length) {\n cols.push(`primary key (${createIndex(primary)})`)\n for (const key of unique) {\n cols.push(`unique index (${createIndex(key)})`)\n }\n for (const key in foreign) {\n const [table, key2] = foreign[key]\n cols.push(`foreign key (${escapeId(key)}) references ${escapeId(table)} (${escapeId(key2)})`)\n }\n }\n\n return cols\n }\n\n async start() {\n this.pool = createPool(this.config)\n const data = await this.query<any[]>('SELECT TABLE_NAME, COLUMN_NAME from information_schema.columns WHERE TABLE_SCHEMA = ?', [this.config.database])\n for (const { TABLE_NAME, COLUMN_NAME } of data) {\n (this.columns[TABLE_NAME] ||= []).push(COLUMN_NAME)\n }\n\n for (const name in Koishi.Tables.config) {\n const cols = this.getColDefs(name)\n if (!this.columns[name]) {\n logger.info('auto creating table %c', name)\n await this.query(`CREATE TABLE ?? (${cols.join(',')}) COLLATE = ?`, [name, this.config.charset])\n } else if (cols.length) {\n logger.info('auto updating table %c', name)\n await this.query(`ALTER TABLE ?? ${cols.map(def => 'ADD ' + def).join(',')}`, [name])\n }\n }\n }\n\n joinKeys = (keys: readonly string[]) => {\n return keys ? keys.map(key => key.includes('`') ? key : `\\`${key}\\``).join(',') : '*'\n }\n\n $in = (table: TableType, key: string, values: readonly any[]) => {\n return `${this.escapeId(key)} IN (${values.map(val => this.escape(val, table, key)).join(', ')})`\n }\n\n formatValues = (table: string, data: object, keys: readonly string[]) => {\n return keys.map((key) => {\n if (typeof data[key] !== 'object' || types.isDate(data[key])) return data[key]\n return stringify(data[key], table as never, key)\n })\n }\n\n query<T extends {}>(source: string, values?: any): Promise<T>\n query<T extends {}>(source: string[], values?: any): Promise<T>\n async query<T extends {}>(source: string | string[], values?: any): Promise<T> {\n if (Array.isArray(source)) {\n if (this.config.multipleStatements) {\n return this.query(source.join(';'), values)\n } else {\n const result: any = []\n for (const sql of source) {\n result.push(await this.query(sql, values))\n }\n return result\n }\n }\n\n const error = new Error()\n return new Promise((resolve, reject) => {\n const sql = format(source, values)\n logger.debug('[sql]', sql)\n this.pool.query(sql, (err, results) => {\n if (!err) return resolve(results)\n logger.warn(sql)\n err.stack = err.message + error.stack.slice(7)\n if (err.code === 'ER_DUP_ENTRY') {\n err[Symbol.for('koishi.error-type')] = 'duplicate-entry'\n }\n reject(err)\n })\n })\n }\n\n select<T extends {}>(table: string, fields: readonly (string & keyof T)[], conditional?: string, values?: readonly any[]): Promise<T[]>\n select(table: string, fields: string[], conditional?: string, values: readonly any[] = []) {\n logger.debug(`[select] ${table}: ${fields ? fields.join(', ') : '*'}`)\n const sql = 'SELECT '\n + this.joinKeys(fields)\n + (table.includes('.') ? `FROM ${table}` : ' FROM `' + table + `\\` _${table}`)\n + (conditional ? ' WHERE ' + conditional : '')\n return this.query(sql, values)\n }\n\n async count<K extends TableType>(table: K, conditional?: string) {\n const [{ 'COUNT(*)': count }] = await this.query(`SELECT COUNT(*) FROM ?? ${conditional ? 'WHERE ' + conditional : ''}`, [table])\n return count as number\n }\n\n stop() {\n this.pool.end()\n }\n}\n\nMysqlDatabase.prototype.escape = escape\nMysqlDatabase.prototype.escapeId = escapeId\n\nnamespace MysqlDatabase {\n export const name = 'database-mysql'\n\n export const schema: Schema<Config> = Schema.object({\n host: Schema.string('要连接到的主机名。').default('localhost'),\n port: Schema.number('要连接到的端口号。').default(3306),\n user: Schema.string('要使用的用户名。').default('root'),\n password: Schema.string('要使用的密码。'),\n database: Schema.string('要访问的数据库名。').default('koishi'),\n }, true)\n\n export interface Config extends PoolConfig {}\n\n type Declarations = {\n [T in TableType]?: {\n [K in keyof Tables[T]]?: string | (() => string) | Domain<Tables[T][K]>\n }\n }\n\n /**\n * @deprecated use `import('koishi').Field` instead\n */\n export const tables: Declarations = {\n user: {},\n channel: {},\n }\n\n type FieldInfo = Parameters<Exclude<TypeCast, boolean>>[0]\n\n export interface Domain<T = any> {\n definition: string\n parse(source: FieldInfo): T\n stringify(value: T): string\n }\n\n /**\n * @deprecated use `import('koishi').Field` instead\n */\n export namespace Domain {\n export function definition(domain: string | Domain) {\n return typeof domain === 'string' ? domain : domain.definition\n }\n\n export class String implements Domain<string> {\n constructor(public definition = 'TEXT') {}\n\n parse(field: FieldInfo) {\n return field.string()\n }\n\n stringify(value: any) {\n return value\n }\n }\n\n export class Array implements Domain<string[]> {\n constructor(public definition = 'TEXT') {}\n\n parse(field: FieldInfo) {\n const source = field.string()\n return source ? source.split(',') : []\n }\n\n stringify(value: string[]) {\n return value.join(',')\n }\n }\n\n export class Json implements Domain {\n // mysql does not support text column with default value\n constructor(public definition = 'text', private defaultValue?: any) {}\n\n parse(field: FieldInfo) {\n return JSON.parse(field.string()) || this.defaultValue\n }\n\n stringify(value: any) {\n return JSON.stringify(value)\n }\n }\n }\n}\n\nDatabase.extend(MysqlDatabase, {\n async drop(name) {\n if (name) {\n await this.query(`DROP TABLE ${this.escapeId(name)}`)\n } else {\n const data = await this.select('information_schema.tables', ['TABLE_NAME'], 'TABLE_SCHEMA = ?', [this.config.database])\n if (!data.length) return\n await this.query(data.map(({ TABLE_NAME }) => `DROP TABLE ${this.escapeId(TABLE_NAME)}`).join('; '))\n }\n },\n\n async get(name, query, modifier) {\n const filter = this.sql.parseQuery(Query.resolve(name, query))\n if (filter === '0') return []\n const { fields, limit, offset } = Query.resolveModifier(modifier)\n const keys = this.joinKeys(this.inferFields(name, fields))\n let sql = `SELECT ${keys} FROM ${name} _${name} WHERE ${filter}`\n if (limit) sql += ' LIMIT ' + limit\n if (offset) sql += ' OFFSET ' + offset\n return this.query(sql)\n },\n\n async set(name, query, data) {\n const filter = this.sql.parseQuery(Query.resolve(name, query))\n if (filter === '0') return\n const keys = Object.keys(data)\n const update = keys.map((key) => {\n return `${this.escapeId(key)} = ${this.escape(data[key], name, key)}`\n }).join(', ')\n await this.query(`UPDATE ${name} SET ${update} WHERE ${filter}`)\n },\n\n async remove(name, query) {\n const filter = this.sql.parseQuery(Query.resolve(name, query))\n if (filter === '0') return\n await this.query('DELETE FROM ?? WHERE ' + filter, [name])\n },\n\n async create(name, data) {\n data = { ...Koishi.Tables.create(name), ...data }\n const keys = Object.keys(data)\n const header = await this.query<OkPacket>(\n `INSERT INTO ?? (${this.joinKeys(keys)}) VALUES (${keys.map(() => '?').join(', ')})`,\n [name, ...this.formatValues(name, data, keys)],\n )\n return { ...data, id: header.insertId } as any\n },\n\n async upsert(name, data, keys: string | string[]) {\n if (!data.length) return\n const { fields, primary } = Koishi.Tables.config[name]\n const fallback = Koishi.Tables.create(name)\n const initKeys = Object.keys(fields)\n const updateKeys = Object.keys(data[0])\n data = data.map(item => ({ ...fallback, ...item }))\n keys = makeArray(keys || primary)\n const placeholder = `(${initKeys.map(() => '?').join(', ')})`\n const update = difference(updateKeys, keys).map((key) => {\n key = this.escapeId(key)\n return `${key} = VALUES(${key})`\n }).join(', ')\n await this.query(\n `INSERT INTO ${this.escapeId(name)} (${this.joinKeys(initKeys)}) VALUES ${data.map(() => placeholder).join(', ')}\n ON DUPLICATE KEY UPDATE ${update}`,\n [].concat(...data.map(data => this.formatValues(name, data, initKeys))),\n )\n },\n\n async aggregate(name, fields, query) {\n const keys = Object.keys(fields)\n if (!keys.length) return {}\n\n const filter = this.sql.parseQuery(Query.resolve(name, query))\n const exprs = keys.map(key => `${this.sql.parseEval(fields[key])} AS ${this.escapeId(key)}`).join(', ')\n const [data] = await this.query(`SELECT ${exprs} FROM ${name} WHERE ${filter}`)\n return data\n },\n})\n\nexport default MysqlDatabase\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { createPool, Pool, PoolConfig, escape as mysqlEscape, escapeId, format, TypeCast } from 'mysql'\nimport { Context, Database, difference, Logger, makeArray, Schema, Query } from 'koishi'\nimport { SQLBuilder } from '@koishijs/sql-utils'\nimport * as Koishi from 'koishi'\nimport { types } from 'util'\nimport { OkPacket } from 'mysql'\n\ndeclare module 'mysql' {\n interface UntypedFieldInfo {\n packet: UntypedFieldInfo\n }\n}\n\ndeclare module 'koishi' {\n interface Database {\n mysql: MysqlDatabase\n }\n\n interface Modules {\n 'database-mysql': typeof import('.')\n }\n}\n\nconst logger = new Logger('mysql')\n\nexport type TableType = keyof Tables\n\nexport interface Tables extends Koishi.Tables {}\n\nfunction stringify(value: any, table?: string, field?: string) {\n const type = MysqlDatabase.tables[table]?.[field]\n if (typeof type === 'object') return type.stringify(value)\n\n const meta = Koishi.Tables.config[table]?.fields[field]\n if (meta?.type === 'json') {\n return JSON.stringify(value)\n } else if (meta?.type === 'list') {\n return value.join(',')\n }\n\n return value\n}\n\nfunction escape(value: any, table?: string, field?: string) {\n return mysqlEscape(stringify(value, table, field))\n}\n\nfunction getIntegerType(length = 11) {\n if (length <= 4) return 'tinyint'\n if (length <= 6) return 'smallint'\n if (length <= 9) return 'mediumint'\n if (length <= 11) return 'int'\n return 'bigint'\n}\n\nfunction getTypeDefinition({ type, length, precision, scale }: Koishi.Tables.Field) {\n switch (type) {\n case 'float':\n case 'double':\n case 'date':\n case 'time':\n case 'timestamp': return type\n case 'integer': return getIntegerType(length)\n case 'unsigned': return `${getIntegerType(length)} unsigned`\n case 'decimal': return `decimal(${precision}, ${scale}) unsigned`\n case 'char': return `char(${length || 255})`\n case 'string': return `char(${length || 255})`\n case 'text': return `text(${length || 65535})`\n case 'list': return `text(${length || 65535})`\n case 'json': return `text(${length || 65535})`\n }\n}\n\nfunction createIndex(keys: string | string[]) {\n return makeArray(keys).map(key => escapeId(key)).join(', ')\n}\n\nclass MysqlDatabase extends Database {\n public pool: Pool\n public config: MysqlDatabase.Config\n\n mysql = this\n sql: SQLBuilder\n\n escape: (value: any, table?: TableType, field?: string) => string\n escapeId: (value: string) => string\n\n inferFields<T extends TableType>(table: T, keys: readonly string[]) {\n if (!keys) return\n const types = MysqlDatabase.tables[table] || {}\n return keys.map((key) => {\n const type = types[key]\n return typeof type === 'function' ? `${type()} AS ${key}` : key\n }) as (keyof Tables[T])[]\n }\n\n constructor(public ctx: Context, config?: MysqlDatabase.Config) {\n super(ctx)\n this.config = {\n host: 'localhost',\n port: 3306,\n user: 'root',\n database: 'koishi',\n charset: 'utf8mb4_general_ci',\n multipleStatements: true,\n typeCast: (field, next) => {\n const { orgName, orgTable } = field.packet\n const type = MysqlDatabase.tables[orgTable]?.[orgName]\n if (typeof type === 'object') return type.parse(field)\n\n const meta = Koishi.Tables.config[orgTable]?.fields[orgName]\n if (meta?.type === 'string') {\n return field.string()\n } else if (meta?.type === 'json') {\n return JSON.parse(field.string()) || meta.initial\n } else if (meta?.type === 'list') {\n const source = field.string()\n return source ? source.split(',') : []\n }\n\n if (field.type === 'BIT') {\n return Boolean(field.buffer()?.readUInt8(0))\n } else {\n return next()\n }\n },\n ...config,\n }\n\n this.sql = new class extends SQLBuilder {\n escape = escape\n escapeId = escapeId\n }()\n }\n\n private columns: Record<string, string[]> = {}\n\n private getColDefs(name: string, cols: string[] = []) {\n const table = Koishi.Tables.config[name]\n const { primary, foreign, autoInc } = table\n const fields = { ...table.fields }\n const unique = [...table.unique]\n const keys = this.columns[name] || []\n\n // create platform rows\n if (name === 'user') {\n const platforms = new Set<string>(this.ctx.bots.map(bot => bot.platform))\n for (const name of platforms) {\n fields[name] = { type: 'string', length: 63 }\n unique.push(name)\n }\n }\n\n // mysql definitions (FIXME: remove in v4)\n for (const key in MysqlDatabase.tables[name]) {\n const value = MysqlDatabase.tables[name][key]\n if (keys.includes(key) || typeof value === 'function') continue\n cols.push(`${escapeId(key)} ${MysqlDatabase.Domain.definition(value)}`)\n }\n\n // orm definitions\n for (const key in fields) {\n if (keys.includes(key)) continue\n const { initial, nullable = initial === undefined || initial === null } = fields[key]\n let def = escapeId(key)\n if (key === primary && autoInc) {\n def += ' int unsigned not null auto_increment'\n } else {\n const typedef = getTypeDefinition(fields[key])\n def += ' ' + typedef + (nullable ? ' ' : ' not ') + 'null'\n // blob, text, geometry or json columns cannot have default values\n if (initial && !typedef.startsWith('text')) {\n def += ' default ' + escape(initial, name, key)\n }\n }\n cols.push(def)\n }\n\n if (!keys.length) {\n cols.push(`primary key (${createIndex(primary)})`)\n for (const key of unique) {\n cols.push(`unique index (${createIndex(key)})`)\n }\n for (const key in foreign) {\n const [table, key2] = foreign[key]\n cols.push(`foreign key (${escapeId(key)}) references ${escapeId(table)} (${escapeId(key2)})`)\n }\n }\n\n return cols\n }\n\n async start() {\n this.pool = createPool(this.config)\n const data = await this.query<any[]>('SELECT TABLE_NAME, COLUMN_NAME from information_schema.columns WHERE TABLE_SCHEMA = ?', [this.config.database])\n for (const { TABLE_NAME, COLUMN_NAME } of data) {\n (this.columns[TABLE_NAME] ||= []).push(COLUMN_NAME)\n }\n\n for (const name in Koishi.Tables.config) {\n const cols = this.getColDefs(name)\n if (!this.columns[name]) {\n logger.info('auto creating table %c', name)\n await this.query(`CREATE TABLE ?? (${cols.join(',')}) COLLATE = ?`, [name, this.config.charset])\n } else if (cols.length) {\n logger.info('auto updating table %c', name)\n await this.query(`ALTER TABLE ?? ${cols.map(def => 'ADD ' + def).join(',')}`, [name])\n }\n }\n }\n\n joinKeys = (keys: readonly string[]) => {\n return keys ? keys.map(key => key.includes('`') ? key : `\\`${key}\\``).join(',') : '*'\n }\n\n $in = (table: TableType, key: string, values: readonly any[]) => {\n return `${this.escapeId(key)} IN (${values.map(val => this.escape(val, table, key)).join(', ')})`\n }\n\n formatValues = (table: string, data: object, keys: readonly string[]) => {\n return keys.map((key) => {\n if (typeof data[key] !== 'object' || types.isDate(data[key])) return data[key]\n return stringify(data[key], table as never, key)\n })\n }\n\n query<T extends {}>(source: string, values?: any): Promise<T>\n query<T extends {}>(source: string[], values?: any): Promise<T>\n async query<T extends {}>(source: string | string[], values?: any): Promise<T> {\n if (Array.isArray(source)) {\n if (this.config.multipleStatements) {\n return this.query(source.join(';'), values)\n } else {\n const result: any = []\n for (const sql of source) {\n result.push(await this.query(sql, values))\n }\n return result\n }\n }\n\n const error = new Error()\n return new Promise((resolve, reject) => {\n const sql = format(source, values)\n logger.debug('[sql]', sql)\n this.pool.query(sql, (err, results) => {\n if (!err) return resolve(results)\n logger.warn(sql)\n err.stack = err.message + error.stack.slice(7)\n if (err.code === 'ER_DUP_ENTRY') {\n err[Symbol.for('koishi.error-type')] = 'duplicate-entry'\n }\n reject(err)\n })\n })\n }\n\n select<T extends {}>(table: string, fields: readonly (string & keyof T)[], conditional?: string, values?: readonly any[]): Promise<T[]>\n select(table: string, fields: string[], conditional?: string, values: readonly any[] = []) {\n logger.debug(`[select] ${table}: ${fields ? fields.join(', ') : '*'}`)\n const sql = 'SELECT '\n + this.joinKeys(fields)\n + (table.includes('.') ? `FROM ${table}` : ' FROM `' + table + `\\` _${table}`)\n + (conditional ? ' WHERE ' + conditional : '')\n return this.query(sql, values)\n }\n\n async count<K extends TableType>(table: K, conditional?: string) {\n const [{ 'COUNT(*)': count }] = await this.query(`SELECT COUNT(*) FROM ?? ${conditional ? 'WHERE ' + conditional : ''}`, [table])\n return count as number\n }\n\n stop() {\n this.pool.end()\n }\n}\n\nMysqlDatabase.prototype.escape = escape\nMysqlDatabase.prototype.escapeId = escapeId\n\nnamespace MysqlDatabase {\n export interface Config extends PoolConfig {}\n\n export const Config = Schema.object({\n host: Schema.string('要连接到的主机名。').default('localhost'),\n port: Schema.number('要连接到的端口号。').default(3306),\n user: Schema.string('要使用的用户名。').default('root'),\n password: Schema.string('要使用的密码。'),\n database: Schema.string('要访问的数据库名。').default('koishi'),\n }, true)\n\n type Declarations = {\n [T in TableType]?: {\n [K in keyof Tables[T]]?: string | (() => string) | Domain<Tables[T][K]>\n }\n }\n\n /**\n * @deprecated use `import('koishi').Field` instead\n */\n export const tables: Declarations = {\n user: {},\n channel: {},\n }\n\n type FieldInfo = Parameters<Exclude<TypeCast, boolean>>[0]\n\n export interface Domain<T = any> {\n definition: string\n parse(source: FieldInfo): T\n stringify(value: T): string\n }\n\n /**\n * @deprecated use `import('koishi').Field` instead\n */\n export namespace Domain {\n export function definition(domain: string | Domain) {\n return typeof domain === 'string' ? domain : domain.definition\n }\n\n export class String implements Domain<string> {\n constructor(public definition = 'TEXT') {}\n\n parse(field: FieldInfo) {\n return field.string()\n }\n\n stringify(value: any) {\n return value\n }\n }\n\n export class Array implements Domain<string[]> {\n constructor(public definition = 'TEXT') {}\n\n parse(field: FieldInfo) {\n const source = field.string()\n return source ? source.split(',') : []\n }\n\n stringify(value: string[]) {\n return value.join(',')\n }\n }\n\n export class Json implements Domain {\n // mysql does not support text column with default value\n constructor(public definition = 'text', private defaultValue?: any) {}\n\n parse(field: FieldInfo) {\n return JSON.parse(field.string()) || this.defaultValue\n }\n\n stringify(value: any) {\n return JSON.stringify(value)\n }\n }\n }\n}\n\nDatabase.extend(MysqlDatabase, {\n async drop(name) {\n if (name) {\n await this.query(`DROP TABLE ${this.escapeId(name)}`)\n } else {\n const data = await this.select('information_schema.tables', ['TABLE_NAME'], 'TABLE_SCHEMA = ?', [this.config.database])\n if (!data.length) return\n await this.query(data.map(({ TABLE_NAME }) => `DROP TABLE ${this.escapeId(TABLE_NAME)}`).join('; '))\n }\n },\n\n async get(name, query, modifier) {\n const filter = this.sql.parseQuery(Query.resolve(name, query))\n if (filter === '0') return []\n const { fields, limit, offset } = Query.resolveModifier(modifier)\n const keys = this.joinKeys(this.inferFields(name, fields))\n let sql = `SELECT ${keys} FROM ${name} _${name} WHERE ${filter}`\n if (limit) sql += ' LIMIT ' + limit\n if (offset) sql += ' OFFSET ' + offset\n return this.query(sql)\n },\n\n async set(name, query, data) {\n const filter = this.sql.parseQuery(Query.resolve(name, query))\n if (filter === '0') return\n const keys = Object.keys(data)\n const update = keys.map((key) => {\n return `${this.escapeId(key)} = ${this.escape(data[key], name, key)}`\n }).join(', ')\n await this.query(`UPDATE ${name} SET ${update} WHERE ${filter}`)\n },\n\n async remove(name, query) {\n const filter = this.sql.parseQuery(Query.resolve(name, query))\n if (filter === '0') return\n await this.query('DELETE FROM ?? WHERE ' + filter, [name])\n },\n\n async create(name, data) {\n data = { ...Koishi.Tables.create(name), ...data }\n const keys = Object.keys(data)\n const header = await this.query<OkPacket>(\n `INSERT INTO ?? (${this.joinKeys(keys)}) VALUES (${keys.map(() => '?').join(', ')})`,\n [name, ...this.formatValues(name, data, keys)],\n )\n return { ...data, id: header.insertId } as any\n },\n\n async upsert(name, data, keys: string | string[]) {\n if (!data.length) return\n const { fields, primary } = Koishi.Tables.config[name]\n const fallback = Koishi.Tables.create(name)\n const initKeys = Object.keys(fields)\n const updateKeys = Object.keys(data[0])\n data = data.map(item => ({ ...fallback, ...item }))\n keys = makeArray(keys || primary)\n const placeholder = `(${initKeys.map(() => '?').join(', ')})`\n const update = difference(updateKeys, keys).map((key) => {\n key = this.escapeId(key)\n return `${key} = VALUES(${key})`\n }).join(', ')\n await this.query(\n `INSERT INTO ${this.escapeId(name)} (${this.joinKeys(initKeys)}) VALUES ${data.map(() => placeholder).join(', ')}\n ON DUPLICATE KEY UPDATE ${update}`,\n [].concat(...data.map(data => this.formatValues(name, data, initKeys))),\n )\n },\n\n async aggregate(name, fields, query) {\n const keys = Object.keys(fields)\n if (!keys.length) return {}\n\n const filter = this.sql.parseQuery(Query.resolve(name, query))\n const exprs = keys.map(key => `${this.sql.parseEval(fields[key])} AS ${this.escapeId(key)}`).join(', ')\n const [data] = await this.query(`SELECT ${exprs} FROM ${name} WHERE ${filter}`)\n return data\n },\n})\n\nexport default MysqlDatabase\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@koishijs/plugin-database-mysql",
3
3
  "description": "MySQL support for Koishi",
4
- "version": "4.0.0-beta.0",
4
+ "version": "4.0.0-beta.1",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -31,10 +31,10 @@
31
31
  "mysql"
32
32
  ],
33
33
  "peerDependencies": {
34
- "koishi": "^4.0.0-beta.0"
34
+ "koishi": "^4.0.0-beta.2"
35
35
  },
36
36
  "dependencies": {
37
- "@koishijs/sql-utils": "^1.0.0-beta.0",
37
+ "@koishijs/sql-utils": "^1.0.0-beta.1",
38
38
  "@types/mysql": "^2.15.19",
39
39
  "mysql": "^2.18.1"
40
40
  }