Skip to content

Commit f474ff9

Browse files
committed
feat(builder): add skip same version option
1 parent 8980a7e commit f474ff9

File tree

4 files changed

+101
-69
lines changed

4 files changed

+101
-69
lines changed

packages/sqlite-builder/src/sync/core.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { type Kysely, sql } from 'kysely'
22
import type { DBLogger } from '../types'
3+
import { getOrSetDBVersion } from '../utils'
34
import type { Columns, Schema, Table } from './types'
45
import {
56
parseColumnType,
@@ -16,6 +17,16 @@ export type SyncOptions<T extends Schema> = {
1617
* whether to enable debug logger
1718
*/
1819
log?: boolean
20+
version?: {
21+
/**
22+
* current version
23+
*/
24+
current: number
25+
/**
26+
* whether to skip sync when the db's `user_version` is same with `version.current`
27+
*/
28+
skipSyncWhenSame?: boolean
29+
}
1930
/**
2031
* exclude table prefix list, append with `%`
2132
*
@@ -38,7 +49,19 @@ export async function syncTables<T extends Schema>(
3849
options: SyncOptions<T> = {},
3950
logger?: DBLogger,
4051
): Promise<void> {
41-
const { reserveOldData, truncateIfExists = [], log, excludeTablePrefix } = options
52+
const {
53+
reserveOldData,
54+
truncateIfExists = [],
55+
log,
56+
version: { current, skipSyncWhenSame } = {},
57+
excludeTablePrefix,
58+
} = options
59+
60+
if (skipSyncWhenSame && current === await getOrSetDBVersion(db)) {
61+
return
62+
}
63+
await getOrSetDBVersion(db, current)
64+
4265
const debug = (e: any) => log && logger?.debug(e)
4366
const { existTables, indexList, triggerList } = await parseExistDB(db, excludeTablePrefix)
4467
debug('====== sync tables start ======')

packages/sqlite-builder/src/sync/define.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,20 @@ export const TGR = '__TIME_TRIGGER__'
1414
* define table function
1515
*
1616
* if you want to explicitly declare column type,
17-
* use {@link defineColumn}
17+
* use {@link defineObject} or {@link defineLiteral}
18+
* @example
19+
* const testTable = defineTable({
20+
* id: { type: 'increments' },
21+
* person: { type: 'object', defaultTo: { name: 'test' } },
22+
* gender: { type: 'boolean', notNull: true },
23+
* array: defineObject<string[]>(),
24+
* literal: defineLiteral<'l1' | 'l2'>(),
25+
* buffer: { type: 'blob' },
26+
* }, {
27+
* primary: 'id',
28+
* index: ['person', ['id', 'gender']],
29+
* timeTrigger: { create: true, update: true },
30+
* })
1831
*/
1932
export function defineTable<
2033
T extends Columns,
Lines changed: 9 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,23 @@
1-
import type { Generated, Kysely } from 'kysely'
2-
import type { IsNotNull } from '@subframe7536/type-utils'
1+
import type { Kysely } from 'kysely'
32
import type { DBLogger, SyncTableFn } from '../types'
4-
import type { ColumnProperty, Columns, Schema, TimeTriggerOptions } from './types'
3+
import type { Schema } from './types'
54
import type { SyncOptions } from './core'
65
import { syncTables } from './core'
76

87
export * from './types'
98
export { defineTable, defineLiteral, defineObject } from './define'
109

10+
/**
11+
* create sync schema function
12+
* @param schema table schema, see {@link defineTable}
13+
* @param options sync options
14+
*/
1115
export function createAutoSyncSchemaFn<T extends Schema>(
12-
tables: T,
16+
schema: T,
1317
options: SyncOptions<T> = {},
1418
): SyncTableFn {
1519
const { log } = options
1620
return async (db: Kysely<any>, logger?: DBLogger) => {
17-
await syncTables(db, tables, options, log ? logger : undefined)
21+
await syncTables(db, schema, options, log ? logger : undefined)
1822
}
1923
}
20-
21-
type Prettify<T> = {
22-
[K in keyof T]: T[K]
23-
} & {}
24-
25-
type ERROR_INFO = 'HAVE_TYPE_ERROR_AT_DEFINITION'
26-
27-
type TriggerKey<A, B> =
28-
| (A extends true ? 'createAt' : A extends string ? A : never)
29-
| (B extends true ? 'updateAt' : B extends string ? B : never)
30-
31-
type ParseTableWithTrigger<
32-
T extends Columns,
33-
P extends TimeTriggerOptions<any, any> | undefined,
34-
> = P extends TimeTriggerOptions<infer A, infer B>
35-
? Omit<T, TriggerKey<A, B>> & (
36-
{ [K in TriggerKey<A, B>]: {
37-
type: 'increments' // #hack to ensure Generated
38-
defaultTo: Generated<Date> | null
39-
notNull: null
40-
} }
41-
)
42-
: never
43-
44-
/**
45-
* util type for infering type of table
46-
*/
47-
export type InferTable<
48-
T extends {
49-
columns: Columns
50-
timeTrigger?: TimeTriggerOptions<any, any>
51-
},
52-
P = ParseTableWithTrigger<T['columns'], T['timeTrigger']>,
53-
> = Prettify<{
54-
[K in keyof P]: P[K] extends ColumnProperty
55-
? IsNotNull<P[K]['notNull']> extends true // if not null
56-
? Exclude<P[K]['defaultTo'], null> // return required defaultTo
57-
: P[K]['type'] extends 'increments' // if type is "increments"
58-
? Exclude<P[K]['defaultTo'], null> // return "Generated<...>"
59-
: IsNotNull<P[K]['defaultTo']> extends true // if defaultTo is required
60-
? Generated<Exclude<P[K]['defaultTo'], null>> // return Generated
61-
: P[K]['defaultTo'] | null // return optional
62-
: ERROR_INFO // return error info
63-
}>
64-
65-
/**
66-
* util type for infering type of database
67-
*
68-
* if infered type contains `"HAVE_DEFAULT_VALUE_TYPE_ERROR"`,
69-
* there is some error in target table's default value type
70-
*
71-
* use {@link InferTable} to check details
72-
*/
73-
export type InferDatabase<T extends Schema> = Prettify<{
74-
[K in keyof T]: T[K] extends {
75-
columns: Columns
76-
timeTrigger?: TimeTriggerOptions<any, any>
77-
}
78-
? InferTable<T[K]>
79-
: ERROR_INFO
80-
}>

packages/sqlite-builder/src/sync/types.ts

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Generated, RawBuilder } from 'kysely'
2-
import type { Arrayable } from '@subframe7536/type-utils'
2+
import type { Arrayable, IsNotNull, Prettify } from '@subframe7536/type-utils'
33

44
export type ColumnType =
55
| 'string'
@@ -97,3 +97,56 @@ export type FilterGenerated<
9797
? Table[K]
9898
: InferGenereated<Table[K]>
9999
}
100+
101+
type ERROR_INFO = 'HAVE_TYPE_ERROR_AT_DEFINITION'
102+
103+
type TriggerKey<A, B> =
104+
| (A extends true ? 'createAt' : A extends string ? A : never)
105+
| (B extends true ? 'updateAt' : B extends string ? B : never)
106+
107+
type ParseTableWithTrigger<
108+
T extends Columns,
109+
P extends TimeTriggerOptions<any, any> | undefined,
110+
> = P extends TimeTriggerOptions<infer A, infer B> ? Omit<T, TriggerKey<A, B>> & ({
111+
[K in TriggerKey<A, B>]: {
112+
type: 'increments' // #hack to ensure Generated
113+
defaultTo: Generated<Date> | null
114+
notNull: null
115+
}
116+
}) : never
117+
118+
/**
119+
* util type for infering type of table
120+
*/
121+
export type InferTable<
122+
T extends {
123+
columns: Columns
124+
timeTrigger?: TimeTriggerOptions<any, any>
125+
},
126+
P = ParseTableWithTrigger<T['columns'], T['timeTrigger']>,
127+
> = Prettify<{
128+
[K in keyof P]: P[K] extends ColumnProperty ? IsNotNull<P[K]['notNull']> extends true // if not null
129+
? Exclude<P[K]['defaultTo'], null> // return required defaultTo
130+
: P[K]['type'] extends 'increments' // if type is "increments"
131+
? Exclude<P[K]['defaultTo'], null> // return "Generated<...>"
132+
: IsNotNull<P[K]['defaultTo']> extends true // if defaultTo is required
133+
? Generated<Exclude<P[K]['defaultTo'], null>> // return Generated
134+
: P[K]['defaultTo'] | null // return optional
135+
: ERROR_INFO // return error info
136+
137+
}>
138+
139+
/**
140+
* util type for infering type of database
141+
*
142+
* if infered type contains `"HAVE_DEFAULT_VALUE_TYPE_ERROR"`,
143+
* there is some error in target table's default value type
144+
*
145+
* use {@link InferTable} to check details
146+
*/
147+
export type InferDatabase<T extends Schema> = Prettify<{
148+
[K in keyof T]: T[K] extends {
149+
columns: Columns
150+
timeTrigger?: TimeTriggerOptions<any, any>
151+
} ? InferTable<T[K]> : ERROR_INFO
152+
}>

0 commit comments

Comments
 (0)