Skip to content

Commit

Permalink
stage
Browse files Browse the repository at this point in the history
  • Loading branch information
Hieuzest committed Oct 31, 2024
1 parent ab0ee82 commit 0df3030
Show file tree
Hide file tree
Showing 19 changed files with 68 additions and 66 deletions.
4 changes: 2 additions & 2 deletions packages/core/src/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -603,13 +603,13 @@ export class Database<S = {}, N = {}, C extends Context = Context> extends Servi
async drop<K extends Keys<S>>(table: K) {
if (this[Database.transact]) throw new Error('cannot drop table in transaction')
const driver = this.getDriver(table)
if (driver.config.readOnly) throw new Error('cannot drop table in read-only mode')
if (driver.config.readonly) throw new Error('cannot drop table in read-only mode')
await driver.drop(table)
}

async dropAll() {
if (this[Database.transact]) throw new Error('cannot drop table in transaction')
await Promise.all(Object.values(this.drivers).filter(driver => !driver.config.readOnly).map(driver => driver.dropAll()))
await Promise.all(Object.values(this.drivers).filter(driver => !driver.config.readonly).map(driver => driver.dropAll()))
}

async stats() {
Expand Down
17 changes: 12 additions & 5 deletions packages/core/src/driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { Field, Model, Relation } from './model.ts'
import { Database } from './database.ts'
import { Type } from './type.ts'
import { FlatKeys, Keys, Values } from './utils.ts'
import enUS from './locales/en-US.yml'
import zhCN from './locales/zh-CN.yml'

export namespace Driver {
export interface Stats {
Expand Down Expand Up @@ -165,14 +167,14 @@ export abstract class Driver<T extends Driver.Config = Driver.Config, C extends
async _ensureSession() {}

async prepareIndexes(table: string) {
const { immutable, indexes } = this.model(table)
if (immutable || this.config.readOnly) return
const { indexes } = this.model(table)
if (this.config.migrateStrategy == 'never' || this.config.readonly) return

Check failure on line 171 in packages/core/src/driver.ts

View workflow job for this annotation

GitHub Actions / lint

Expected '===' and instead saw '=='
const oldIndexes = await this.getIndexes(table)
for (const index of indexes) {
const oldIndex = oldIndexes.find(info => info.name === index.name)
if (!oldIndex) {
await this.createIndex(table, index)
} else if (!deepEqual(oldIndex, index)) {
} else if (this.config.migrateStrategy === 'auto' && !deepEqual(oldIndex, index)) {
await this.dropIndex(table, index.name!)
await this.createIndex(table, index)
}
Expand All @@ -182,11 +184,16 @@ export abstract class Driver<T extends Driver.Config = Driver.Config, C extends

export namespace Driver {
export interface Config {
readOnly?: boolean
readonly?: boolean
migrateStrategy?: 'auto' | 'create' | 'never'
}

export const Config: z<Config> = z.object({
readOnly: z.boolean().default(false),
readonly: z.boolean().default(false),
migrateStrategy: z.union([z.const('auto'), z.const('create'), z.const('never')]).default('auto'),
}).i18n({
'en-US': enUS,
'zh-CN': zhCN,
})
}

Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/locales/en-US.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
$description: Access settings
readonly: Connect in read-only mode.
migrateStrategy: Table migration strategy.
3 changes: 3 additions & 0 deletions packages/core/src/locales/zh-CN.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
$description: 访问设置
readonly: 以只读模式连接。
migrateStrategy: 表迁移策略。
5 changes: 1 addition & 4 deletions packages/core/src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,6 @@ export namespace Model {
export interface Config<K extends string = string> {
callback?: Migration
autoInc: boolean
immutable: boolean
primary: MaybeArray<K>
unique: MaybeArray<K>[]
indexes: (MaybeArray<K> | Driver.IndexDef<K>)[]
Expand All @@ -267,7 +266,6 @@ export class Model<S = any> {

constructor(public name: string) {
this.autoInc = false
this.immutable = false
this.primary = 'id' as never
this.unique = []
this.indexes = []
Expand All @@ -276,11 +274,10 @@ export class Model<S = any> {

extend(fields: Field.Extension<S>, config?: Partial<Model.Config>): void
extend(fields = {}, config: Partial<Model.Config> = {}) {
const { primary, autoInc, immutable, unique = [], indexes = [], foreign, callback } = config
const { primary, autoInc, unique = [], indexes = [], foreign, callback } = config

this.primary = primary || this.primary
this.autoInc = autoInc || this.autoInc
this.immutable = immutable || this.immutable
unique.forEach(key => this.unique.includes(key) || this.unique.push(key))
indexes.map(x => this.parseIndex(x)).forEach(index => (this.indexes.some(ind => deepEqual(ind, index))) || this.indexes.push(index))
Object.assign(this.foreign, foreign)
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ class Executable<S = any, T = any> {
}

async execute(): Promise<T> {
if (this.driver.config.readOnly && !['get', 'eval'].includes(this.type)) {
if (this.driver.config.readonly && !['get', 'eval'].includes(this.type)) {
throw new Error(`database is in read-only mode`)
}

Check warning on line 151 in packages/core/src/selection.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/selection.ts#L150-L151

Added lines #L150 - L151 were not covered by tests
await this.driver.database.prepared()
Expand Down
16 changes: 7 additions & 9 deletions packages/mongo/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,10 +229,8 @@ export class MongoDriver extends Driver<MongoDriver.Config> {

/** synchronize table schema */
async prepare(table: string) {
const { immutable } = this.model(table)

if (immutable || this.config.readOnly) {
if (immutable && this.shouldEnsurePrimary(table)) {
if (this.config.migrateStrategy === 'never' || this.config.readonly) {
if (this.config.migrateStrategy === 'never' && this.shouldEnsurePrimary(table)) {
throw new Error(`immutable table ${table} cannot be autoInc`)
}
return
Expand Down Expand Up @@ -566,7 +564,6 @@ export namespace MongoDriver {
}

export const Config: z<Config> = z.intersect([
Driver.Config,
z.object({
protocol: z.string().default('mongodb'),
host: z.string().default('localhost'),
Expand All @@ -584,11 +581,12 @@ export namespace MongoDriver {
wtimeoutMS: z.number(),
journal: z.boolean(),
}) as any,
}).i18n({
'en-US': enUS,
'zh-CN': zhCN,
}),
]).i18n({
'en-US': enUS,
'zh-CN': zhCN,
})
Driver.Config,
])
}

export default MongoDriver
1 change: 0 additions & 1 deletion packages/mongo/src/locales/en-US.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,3 @@ writeConcern:
- Majority
wtimeoutMS: The write concern timeout.
journal: The journal write concern.
readOnly: Connect in read-only mode.
1 change: 0 additions & 1 deletion packages/mongo/src/locales/zh-CN.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,3 @@ writeConcern:
- Majority
wtimeoutMS: The write concern timeout.
journal: The journal write concern.
readOnly: 以只读模式连接。
28 changes: 14 additions & 14 deletions packages/mysql/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,6 @@ export class MySQLDriver extends Driver<MySQLDriver.Config> {

const table = this.model(name)
const { primary, foreign, autoInc } = table
const immutable = table.immutable || this.config.readOnly
const fields = table.avaiableFields()
const unique = [...table.unique]
const create: string[] = []
Expand Down Expand Up @@ -233,18 +232,21 @@ export class MySQLDriver extends Driver<MySQLDriver.Config> {
}
}

if (immutable) {
if (!columns.length) {
if (this.config.readonly || this.config.migrateStrategy === 'never') {
throw new Error(`immutable table ${name} cannot be created`)
}

Check warning on line 238 in packages/mysql/src/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/mysql/src/index.ts#L237-L238

Added lines #L237 - L238 were not covered by tests
this.logger.info('auto creating table %c', name)
return this.query(`CREATE TABLE ${escapeId(name)} (${create.join(', ')}) COLLATE = ${this.sql.escape(this.config.charset ?? 'utf8mb4_general_ci')}`)
}

if (this.config.readonly || this.config.migrateStrategy !== 'auto') {
if (create.length || update.length) {
throw new Error(`immutable table ${name} cannot be migrated`)
}
return

Check warning on line 247 in packages/mysql/src/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/mysql/src/index.ts#L247

Added line #L247 was not covered by tests
}

if (!columns.length) {
this.logger.info('auto creating table %c', name)
return this.query(`CREATE TABLE ${escapeId(name)} (${create.join(', ')}) COLLATE = ${this.sql.escape(this.config.charset ?? 'utf8mb4_general_ci')}`)
}

const operations = [
...create.map(def => 'ADD ' + def),
...update,
Expand Down Expand Up @@ -604,15 +606,12 @@ export namespace MySQLDriver {
export interface Config extends Driver.Config, PoolConfig {}

export const Config: z<Config> = z.intersect([
Driver.Config,
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().required(),
}),
z.object({
ssl: z.union([
z.const(undefined),
z.object({
Expand All @@ -639,11 +638,12 @@ export namespace MySQLDriver {
sessionTimeout: z.number(),
}),
]) as any,
}).i18n({
'en-US': enUS,
'zh-CN': zhCN,
}),
]).i18n({
'en-US': enUS,
'zh-CN': zhCN,
})
Driver.Config,
])
}

export default MySQLDriver
1 change: 0 additions & 1 deletion packages/mysql/src/locales/en-US.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,3 @@ ssl:
- Default
- $description: Custom
rejectUnauthorized: Reject clients with invalid certificates.
readOnly: Connect in read-only mode.
1 change: 0 additions & 1 deletion packages/mysql/src/locales/zh-CN.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,3 @@ ssl:
- 默认值
- $description: 自定义
rejectUnauthorized: 拒绝使用无效证书的客户端。
readOnly: 以只读模式连接。
26 changes: 14 additions & 12 deletions packages/postgres/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,6 @@ export class PostgresDriver extends Driver<PostgresDriver.Config> {

const table = this.model(name)
const { primary, foreign } = table
const immutable = table.immutable || this.config.readOnly
const fields = { ...table.avaiableFields() }
const unique = [...table.unique]
const create: string[] = []
Expand Down Expand Up @@ -237,18 +236,21 @@ export class PostgresDriver extends Driver<PostgresDriver.Config> {
}
}

if (immutable) {
if (!columns.length) {
if (this.config.readonly || this.config.migrateStrategy === 'never') {
throw new Error(`immutable table ${name} cannot be created`)
}

Check warning on line 242 in packages/postgres/src/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/postgres/src/index.ts#L241-L242

Added lines #L241 - L242 were not covered by tests
this.logger.info('auto creating table %c', name)
return this.query<any>(`CREATE TABLE ${escapeId(name)} (${create.join(', ')}, _pg_mtime BIGINT)`)
}

if (this.config.readonly || this.config.migrateStrategy !== 'auto') {
if (create.length || update.length) {
throw new Error(`immutable table ${name} cannot be migrated`)
}
return

Check warning on line 251 in packages/postgres/src/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/postgres/src/index.ts#L251

Added line #L251 was not covered by tests
}

if (!columns.length) {
this.logger.info('auto creating table %c', name)
return this.query<any>(`CREATE TABLE ${escapeId(name)} (${create.join(', ')}, _pg_mtime BIGINT)`)
}

const operations = [
...create.map(def => 'ADD ' + def),
...update,
Expand Down Expand Up @@ -539,18 +541,18 @@ export namespace PostgresDriver {
}

export const Config: z<Config> = z.intersect([
Driver.Config,
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().required(),
}).i18n({
'en-US': enUS,
'zh-CN': zhCN,
}),
]).i18n({
'en-US': enUS,
'zh-CN': zhCN,
})
Driver.Config,
])
}

export default PostgresDriver
1 change: 0 additions & 1 deletion packages/postgres/src/locales/en-US.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@ 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.
readOnly: Connect in read-only mode.
1 change: 0 additions & 1 deletion packages/postgres/src/locales/zh-CN.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@ port: 要连接到的端口号。
username: 要使用的用户名。
password: 要使用的密码。
database: 要访问的数据库名。
readOnly: 以只读模式连接。
15 changes: 8 additions & 7 deletions packages/sqlite/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ export class SQLiteDriver extends Driver<SQLiteDriver.Config> {
async prepare(table: string, dropKeys?: string[]) {
const columns = this._all(`PRAGMA table_info(${escapeId(table)})`) as SQLiteFieldInfo[]
const model = this.model(table)
const immutable = model.immutable || this.config.readOnly
const columnDefs: string[] = []
const indexDefs: string[] = []
const alter: string[] = []
Expand Down Expand Up @@ -113,7 +112,7 @@ export class SQLiteDriver extends Driver<SQLiteDriver.Config> {
}))
}

if (immutable) {
if (this.config.readonly || this.config.migrateStrategy === 'never') {
if (!columns.length || shouldMigrate || alter.length) {
throw new Error(`immutable table ${table} cannot be migrated`)
}
Expand All @@ -123,6 +122,8 @@ export class SQLiteDriver extends Driver<SQLiteDriver.Config> {
if (!columns.length) {
this.logger.info('auto creating table %c', table)
this._run(`CREATE TABLE ${escapeId(table)} (${[...columnDefs, ...indexDefs].join(', ')})`)
} else if (this.config.migrateStrategy === 'create') {
throw new Error(`immutable table ${table} cannot be migrated`)

Check warning on line 126 in packages/sqlite/src/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/sqlite/src/index.ts#L126

Added line #L126 was not covered by tests
} else if (shouldMigrate) {
// preserve old columns
for (const { name, type, notnull, pk, dflt_value: value } of columns) {
Expand Down Expand Up @@ -495,14 +496,14 @@ export namespace SQLiteDriver {
}

export const Config: z<Config> = z.intersect([
Driver.Config,
z.object({
path: z.string().role('path').required(),
}).i18n({
'en-US': enUS,
'zh-CN': zhCN,
}),
]).i18n({
'en-US': enUS,
'zh-CN': zhCN,
})
Driver.Config,
])
}

export default SQLiteDriver
1 change: 0 additions & 1 deletion packages/sqlite/src/locales/en-US.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
path: Database path.
readOnly: Connect in read-only mode.
1 change: 0 additions & 1 deletion packages/sqlite/src/locales/zh-CN.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
path: 数据库路径。
readOnly: 以只读模式连接。
7 changes: 3 additions & 4 deletions packages/tests/src/migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ function MigrationTests(database: Database<Tables>, options: MigrationOptions =
}))).to.not.be.undefined
})

definition && it('model.immutable', async () => {
definition && it('immutable model', async () => {
Reflect.deleteProperty(database.tables, 'qux')

database.extend('qux', {
Expand All @@ -299,12 +299,10 @@ function MigrationTests(database: Database<Tables>, options: MigrationOptions =
])

Reflect.deleteProperty(database.tables, 'qux')

Object.values(database.drivers)[0].config.migrateStrategy = 'never'
database.extend('qux', {
id: 'unsigned',
text: 'integer' as any,
}, {
immutable: true,
})

await expect(database.upsert('qux', [
Expand All @@ -314,6 +312,7 @@ function MigrationTests(database: Database<Tables>, options: MigrationOptions =

Reflect.deleteProperty(database.tables, 'qux')
Reflect.deleteProperty(database['prepareTasks'], 'qux')
Object.values(database.drivers)[0].config.migrateStrategy = 'auto'
})
}

Expand Down

0 comments on commit 0df3030

Please sign in to comment.