diff --git a/package.json b/package.json index e22969db..64a2625b 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "dep": "yakumo upgrade", "pub": "yakumo publish", "lint": "eslint packages --ext=ts --cache", - "test": "yakumo mocha -r esbuild-register -t 10000", + "test": "yakumo mocha -r esbuild-register -r yml-register -t 10000", "test:text": "shx rm -rf coverage && c8 -r text yarn test", "test:json": "shx rm -rf coverage && c8 -r json yarn test", "test:html": "shx rm -rf coverage && c8 -r html yarn test" @@ -36,6 +36,7 @@ "yakumo": "^1.0.0-beta.6", "yakumo-esbuild": "^1.0.0-beta.2", "yakumo-mocha": "^1.0.0-beta.2", - "yakumo-tsc": "^1.0.0-beta.3" + "yakumo-tsc": "^1.0.0-beta.3", + "yml-register": "^1.1.0" } } diff --git a/packages/core/package.json b/packages/core/package.json index 1ce80782..95a464f5 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -42,7 +42,7 @@ "postgres" ], "dependencies": { - "cordis": "^3.8.5", + "cordis": "^3.9.0", "cosmokit": "^1.5.2" } } diff --git a/packages/core/src/database.ts b/packages/core/src/database.ts index 02ef9ee5..0a85021d 100644 --- a/packages/core/src/database.ts +++ b/packages/core/src/database.ts @@ -46,7 +46,7 @@ export class Database extends Service { private stashed = new Set() - constructor(ctx = new Context()) { + constructor(ctx?: Context) { super(ctx, 'model', true) } diff --git a/packages/core/src/driver.ts b/packages/core/src/driver.ts index 6912a4dc..ae512e81 100644 --- a/packages/core/src/driver.ts +++ b/packages/core/src/driver.ts @@ -58,7 +58,7 @@ export abstract class Driver { constructor(public ctx: Context, public config: C) { this.database = ctx.model - this.logger = ctx.logger(this['contructor'].name) + this.logger = ctx.logger(this.constructor.name) ctx.on('ready', async () => { await this.start() diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index e3f84452..d6f57c41 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -22,4 +22,6 @@ declare module 'cordis' { export interface Tables {} +export { Logger, Schema, Schema as z } from 'cordis' + export default Database diff --git a/packages/mongo/src/index.ts b/packages/mongo/src/index.ts index d3e91cc2..9e2c0d7e 100644 --- a/packages/mongo/src/index.ts +++ b/packages/mongo/src/index.ts @@ -1,33 +1,11 @@ import { BSONType, ClientSession, Collection, Db, IndexDescription, MongoClient, MongoClientOptions, MongoError } from 'mongodb' import { Dict, isNullable, makeArray, mapValues, noop, omit, pick } from 'cosmokit' -import { Driver, Eval, executeUpdate, Query, RuntimeError, Selection } from 'minato' +import { Driver, Eval, executeUpdate, Query, RuntimeError, Selection, z } from 'minato' import { URLSearchParams } from 'url' import { Transformer } from './utils' const tempKey = '__temp_minato_mongo__' -export namespace MongoDriver { - export interface Config extends MongoClientOptions { - username?: string - password?: string - protocol?: string - host?: string - port?: number - /** database name */ - database?: string - /** default auth database */ - authDatabase?: string - connectOptions?: ConstructorParameters[0] - /** connection string (will overwrite all configs except 'name') */ - uri?: string - /** - * store single primary key in `_id` field to enhance index performance - * @default false - */ - optimizeIndex?: boolean - } -} - export class MongoDriver extends Driver { static name = 'mongo' @@ -491,4 +469,47 @@ See https://www.mongodb.com/docs/manual/tutorial/convert-standalone-to-replica-s } } +export namespace MongoDriver { + export interface Config extends MongoClientOptions { + username?: string + password?: string + protocol?: string + host?: string + port?: number + /** database name */ + database?: string + /** default auth database */ + authDatabase?: string + connectOptions?: ConstructorParameters[0] + /** connection string (will overwrite all configs except 'name') */ + uri?: string + /** + * store single primary key in `_id` field to enhance index performance + * @default false + */ + optimizeIndex?: boolean + } + + export const Config: z = z.object({ + protocol: z.string().default('mongodb'), + host: z.string().default('localhost'), + port: z.natural().max(65535), + username: z.string(), + password: z.string().role('secret'), + database: z.string().default('koishi'), + writeConcern: z.object({ + w: z.union([ + z.const(undefined), + z.number().required(), + z.const('majority').required(), + ]), + wtimeoutMS: z.number(), + journal: z.boolean(), + }), + }).i18n({ + 'en-US': require('./locales/en-US'), + 'zh-CN': require('./locales/zh-CN'), + }) +} + export default MongoDriver diff --git a/packages/mongo/src/locales/en-US.yml b/packages/mongo/src/locales/en-US.yml new file mode 100644 index 00000000..9dab87fc --- /dev/null +++ b/packages/mongo/src/locales/en-US.yml @@ -0,0 +1,16 @@ +protocol: The protocol to use. +host: The host to connect to. +port: The port number to be connected. +username: The username used for authentication. +password: The password used for authentication. +database: The name of the database we want to use. +writeConcern: + $description: Write Concern + w: + $description: The write concern. + $value: + - Default + - Custom + - Majority + wtimeoutMS: The write concern timeout. + journal: The journal write concern. diff --git a/packages/mongo/src/locales/zh-CN.yml b/packages/mongo/src/locales/zh-CN.yml new file mode 100644 index 00000000..4d125b97 --- /dev/null +++ b/packages/mongo/src/locales/zh-CN.yml @@ -0,0 +1,16 @@ +protocol: 要使用的协议名。 +host: 要连接到的主机名。 +port: 要连接到的端口号。 +username: 要使用的用户名。 +password: 要使用的密码。 +database: 要访问的数据库名。 +writeConcern: + $description: Write Concern + w: + $description: The write concern. + $value: + - Default + - Custom + - Majority + wtimeoutMS: The write concern timeout. + journal: The journal write concern. diff --git a/packages/mysql/src/index.ts b/packages/mysql/src/index.ts index 242b0d3c..f680b574 100644 --- a/packages/mysql/src/index.ts +++ b/packages/mysql/src/index.ts @@ -1,7 +1,7 @@ import { createPool, format } from '@vlasky/mysql' import type { OkPacket, Pool, PoolConfig, PoolConnection } from 'mysql' import { Dict, difference, makeArray, pick, Time } from 'cosmokit' -import { Driver, Eval, executeUpdate, Field, isEvalExpr, Model, randomId, RuntimeError, Selection } from 'minato' +import { Driver, Eval, executeUpdate, Field, isEvalExpr, Model, randomId, RuntimeError, Selection, z } from 'minato' import { Builder, escapeId, isBracketed } from '@minatojs/sql-utils' declare module 'mysql' { @@ -255,10 +255,6 @@ class MySQLBuilder extends Builder { } } -export namespace MySQLDriver { - export interface Config extends PoolConfig {} -} - export class MySQLDriver extends Driver { static name = 'mysql' @@ -680,4 +676,49 @@ INSERT INTO mtt VALUES(json_extract(j, concat('$[', i, ']'))); SET i=i+1; END WH } } +export namespace MySQLDriver { + export interface Config extends PoolConfig {} + + export const Config: z = z.intersect([ + z.object({ + host: z.string().default('localhost'), + port: z.natural().max(65535).default(3306), + user: z.string().default('root'), + password: z.string().role('secret'), + database: z.string().default('koishi'), + }), + z.object({ + ssl: z.union([ + z.const(undefined), + z.object({ + ca: z.string(), + cert: z.string(), + sigalgs: z.string(), + ciphers: z.string(), + clientCertEngine: z.string(), + crl: z.string(), + dhparam: z.string(), + ecdhCurve: z.string(), + honorCipherOrder: z.boolean(), + key: z.string(), + privateKeyEngine: z.string(), + privateKeyIdentifier: z.string(), + maxVersion: z.string(), + minVersion: z.string(), + passphrase: z.string(), + pfx: z.string(), + rejectUnauthorized: z.boolean(), + secureOptions: z.natural(), + secureProtocol: z.string(), + sessionIdContext: z.string(), + sessionTimeout: z.number(), + }), + ]) as any, + }), + ]).i18n({ + 'en-US': require('./locales/en-US'), + 'zh-CN': require('./locales/zh-CN'), + }) +} + export default MySQLDriver diff --git a/packages/mysql/src/locales/en-US.yml b/packages/mysql/src/locales/en-US.yml new file mode 100644 index 00000000..6b951df3 --- /dev/null +++ b/packages/mysql/src/locales/en-US.yml @@ -0,0 +1,12 @@ +host: The hostname of the database you are connecting to. +port: The port number to connect to. +user: The MySQL user to authenticate as. +password: The password of that MySQL user. +database: Name of the database to use for this connection. + +ssl: + $description: SSL options. + $value: + - Default + - $description: Custom + rejectUnauthorized: Reject clients with invalid certificates. diff --git a/packages/mysql/src/locales/zh-CN.yml b/packages/mysql/src/locales/zh-CN.yml new file mode 100644 index 00000000..8a79dc6f --- /dev/null +++ b/packages/mysql/src/locales/zh-CN.yml @@ -0,0 +1,12 @@ +host: 要连接到的主机名。 +port: 要连接到的端口号。 +user: 要使用的用户名。 +password: 要使用的密码。 +database: 要访问的数据库名。 + +ssl: + $description: SSL 高级选项。 + $value: + - 默认值 + - $description: 自定义 + rejectUnauthorized: 拒绝使用无效证书的客户端。 diff --git a/packages/postgres/src/index.ts b/packages/postgres/src/index.ts index 779ea7c3..67f58928 100644 --- a/packages/postgres/src/index.ts +++ b/packages/postgres/src/index.ts @@ -1,6 +1,6 @@ import postgres from 'postgres' import { Dict, difference, isNullable, makeArray, pick, Time } from 'cosmokit' -import { Driver, Eval, executeUpdate, Field, isEvalExpr, Model, randomId, Selection } from 'minato' +import { Driver, Eval, executeUpdate, Field, isEvalExpr, Model, randomId, Selection, z } from 'minato' import { Builder, isBracketed } from '@minatojs/sql-utils' const timeRegex = /(\d+):(\d+):(\d+)/ @@ -440,16 +440,6 @@ class PostgresBuilder extends Builder { } } -export namespace PostgresDriver { - export interface Config = {}> extends postgres.Options { - host: string - port: number - username: string - password: string - database: string - } -} - export class PostgresDriver extends Driver { static name = 'postgres' @@ -463,7 +453,7 @@ export class PostgresDriver extends Driver { async start() { this.postgres = postgres({ onnotice: () => { }, - debug(_, query, parameters) { + debug: (_, query, parameters) => { this.logger.debug(`> %s` + (parameters.length ? `\nparameters: %o` : ``), query, parameters.length ? parameters : '') }, transform: { @@ -785,4 +775,25 @@ export class PostgresDriver extends Driver { } } +export namespace PostgresDriver { + export interface Config = {}> extends postgres.Options { + host: string + port: number + user: string + password: string + database: string + } + + export const Config: z = z.object({ + host: z.string().default('localhost'), + port: z.natural().max(65535).default(5432), + user: z.string().default('root'), + password: z.string().role('secret'), + database: z.string().default('koishi'), + }).i18n({ + 'en-US': require('./locales/en-US'), + 'zh-CN': require('./locales/zh-CN'), + }) +} + export default PostgresDriver diff --git a/packages/postgres/src/locales/en-US.yml b/packages/postgres/src/locales/en-US.yml new file mode 100644 index 00000000..6b373cbe --- /dev/null +++ b/packages/postgres/src/locales/en-US.yml @@ -0,0 +1,5 @@ +host: The hostname of the database you are connecting to. +port: The port number to connect to. +user: The MySQL user to authenticate as. +password: The password of that MySQL user. +database: Name of the database to use for this connection. diff --git a/packages/postgres/src/locales/zh-CN.yml b/packages/postgres/src/locales/zh-CN.yml new file mode 100644 index 00000000..353924bd --- /dev/null +++ b/packages/postgres/src/locales/zh-CN.yml @@ -0,0 +1,5 @@ +host: 要连接到的主机名。 +port: 要连接到的端口号。 +username: 要使用的用户名。 +password: 要使用的密码。 +database: 要访问的数据库名。 diff --git a/packages/postgres/tests/index.spec.ts b/packages/postgres/tests/index.spec.ts index f83bd8a3..3646ce68 100644 --- a/packages/postgres/tests/index.spec.ts +++ b/packages/postgres/tests/index.spec.ts @@ -13,7 +13,7 @@ describe('@minatojs/driver-postgres', () => { await database.connect(PostgresDriver, { host: 'localhost', port: 5432, - username: 'koishi', + user: 'koishi', password: 'koishi@114514', database: 'test' }) diff --git a/packages/sqlite/src/index.ts b/packages/sqlite/src/index.ts index ac23e2b8..d6ac81e4 100644 --- a/packages/sqlite/src/index.ts +++ b/packages/sqlite/src/index.ts @@ -1,8 +1,10 @@ import { clone, deepEqual, Dict, difference, isNullable, makeArray } from 'cosmokit' -import { Driver, Eval, executeUpdate, Field, Model, randomId, Selection } from 'minato' +import { Driver, Eval, executeUpdate, Field, Model, randomId, Selection, z } from 'minato' import { Builder, escapeId } from '@minatojs/sql-utils' import { promises as fs } from 'fs' import init from '@minatojs/sql.js' +import { dirname, join } from 'path' +import { mkdir, rename, stat } from 'fs/promises' function getTypeDef({ type }: Field) { switch (type) { @@ -33,12 +35,6 @@ export interface SQLiteFieldInfo { pk: boolean } -export namespace SQLiteDriver { - export interface Config { - path: string - } -} - class SQLiteBuilder extends Builder { protected escapeMap = { "'": "''", @@ -252,6 +248,15 @@ export class SQLiteDriver extends Driver { } async start() { + if (this.config.path !== ':memory:') { + this.config.path = join(this.ctx.baseDir, this.config.path) + const oldPath = join(this.ctx.baseDir, '.koishi.db') + if (await stat(oldPath).catch(() => null)) { + this.logger.info('migrating to data directory') + await mkdir(dirname(this.config.path), { recursive: true }) + await rename(oldPath, this.config.path) + } + } const isBrowser = process.env.KOISHI_ENV === 'browser' const sqlite = await init({ locateFile: (file: string) => process.env.KOISHI_BASE @@ -261,6 +266,7 @@ export class SQLiteDriver extends Driver { : require.resolve('@minatojs/sql.js/dist/' + file), }) if (!isBrowser || this.config.path === ':memory:') { + console.log(this.config.path) this.db = new sqlite.Database(this.config.path) } else { const buffer = await fs.readFile(this.config.path).catch(() => null) @@ -457,4 +463,16 @@ export class SQLiteDriver extends Driver { } } +export namespace SQLiteDriver { + export interface Config { + path: string + } + + export const Config: z = z.object({ + path: z.string().role('path').default('data/koishi.db'), + }).i18n({ + // 'zh-CN': zhCN, + }) +} + export default SQLiteDriver diff --git a/packages/sqlite/src/locales/en-US.yml b/packages/sqlite/src/locales/en-US.yml new file mode 100644 index 00000000..4728d564 --- /dev/null +++ b/packages/sqlite/src/locales/en-US.yml @@ -0,0 +1 @@ +path: Database path. diff --git a/packages/sqlite/src/locales/zh-CN.yml b/packages/sqlite/src/locales/zh-CN.yml new file mode 100644 index 00000000..b09c9d6b --- /dev/null +++ b/packages/sqlite/src/locales/zh-CN.yml @@ -0,0 +1 @@ +path: 数据库路径。