Skip to content

Commit 701c00e

Browse files
committed
refactor!: externalize soft delete sqlite builder
1 parent 17f7cc3 commit 701c00e

File tree

8 files changed

+261
-268
lines changed

8 files changed

+261
-268
lines changed

README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,10 @@ await db.syncDB(useSchema(DBSchema, { logger: false }))
7878
await db.syncDB(useMigrator(new FileMigrationProvider('./migrations'), {/* options */}))
7979
```
8080

81-
sync options type:
81+
Schema sync options type:
8282

8383
```ts
84-
export type SyncOptions<T extends Schema> = {
84+
export type SchemaSyncOptions<T extends Schema> = {
8585
/**
8686
* Whether to enable debug logger
8787
*/
@@ -245,21 +245,21 @@ const softDeleteTable = defineTable({
245245
const softDeleteSchema = {
246246
testSoftDelete: softDeleteTable,
247247
}
248-
const { executor, whereExists, whereDeleted } = createSoftDeleteExecutor()
249248

250-
const db = new SqliteBuilder<InferDatabase<typeof softDeleteSchema>>({
249+
const db = new SoftDeleteSqliteBuilder<InferDatabase<typeof softDeleteSchema>>({
251250
dialect: new SqliteDialect({
252251
database: new Database(':memory:'),
253252
}),
254-
// use soft delete executor
255-
executor,
256253
})
257254

258255
await db.deleteFrom('testSoftDelete').where('id', '=', 1).execute()
259256
// update "testSoftDelete" set "isDeleted" = 1 where "id" = 1
260257

261-
// If you are using original kysely instance:
262-
await db.kysely.selectFrom('testSoftDelete').selectAll().$call(whereExists).execute()
258+
// if you are using original kysely instance:
259+
await db.kysely.selectFrom('testSoftDelete').selectAll().$call(db.whereExists).execute()
260+
261+
// fix `DeleteResult` runtime type
262+
db.toDeleteResult(await db.deleteFrom('testSoftDelete').where('id', '=', 1).execute())
263263
```
264264

265265
### Page Query

src/builder.ts renamed to src/builder/base.ts

Lines changed: 15 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,26 @@
11
import type { Promisable } from '@subframe7536/type-utils'
22
import type {
33
CompiledQuery,
4-
DeleteQueryBuilder,
5-
DeleteResult,
64
Dialect,
5+
JoinType,
76
KyselyPlugin,
87
QueryResult,
98
RawBuilder,
109
Transaction,
1110
} from 'kysely'
12-
import type {
13-
ExtractTableAlias,
14-
From,
15-
FromTables,
16-
TableReference,
17-
} from 'kysely/dist/cjs/parser/table-parser'
1811
import { Kysely } from 'kysely'
1912
import { BaseSerializePlugin } from 'kysely-plugin-serialize'
20-
import { baseExecutor, type Executor, type JoinFnName } from './executor'
21-
import { createKyselyLogger, type LoggerOptions } from './logger'
22-
import { checkIntegrity as runCheckIntegrity } from './pragma'
23-
import { savePoint } from './savepoint'
24-
import { defaultDeserializer, defaultSerializer } from './serialize'
13+
import { createKyselyLogger, type LoggerOptions } from '../logger'
14+
import { checkIntegrity as runCheckIntegrity } from '../pragma'
15+
import { savePoint } from '../savepoint'
16+
import { defaultDeserializer, defaultSerializer } from '../serialize'
2517
import {
2618
type DBLogger,
2719
IntegrityError,
2820
type SchemaUpdater,
2921
type StatusResult,
30-
} from './types'
31-
import { executeSQL } from './utils'
22+
} from '../types'
23+
import { executeSQL } from '../utils'
3224

3325
export type SqliteBuilderOptions = {
3426
/**
@@ -52,22 +44,6 @@ export type SqliteBuilderOptions = {
5244
* DB logger
5345
*/
5446
logger?: DBLogger
55-
/**
56-
* Custom executor
57-
* @example
58-
* import { SqliteBuilder, createSoftDeleteExecutor } from 'kysely-sqlite-builder'
59-
*
60-
* const { executor, whereExists } = createSoftDeleteExecutor()
61-
*
62-
* const db = new SqliteBuilder<DB>({
63-
* dialect: new SqliteDialect({
64-
* database: new Database(':memory:'),
65-
* }),
66-
* // use soft delete executor
67-
* executor,
68-
* })
69-
*/
70-
executor?: Executor
7147
}
7248

7349
interface TransactionOptions<T> {
@@ -82,12 +58,18 @@ interface TransactionOptions<T> {
8258
onRollback?: (err: unknown) => Promisable<void>
8359
}
8460

85-
export class SqliteBuilder<DB extends Record<string, any>> {
61+
type CamelCase<S extends string> = S extends `${infer First}${infer Rest}`
62+
? First extends Uppercase<First>
63+
? `${Lowercase<First>}${Rest}`
64+
: S
65+
: S
66+
export type JoinFnName = CamelCase<JoinType>
67+
68+
export class BaseSqliteBuilder<DB extends Record<string, any>> {
8669
public trxCount = 0
8770
private ky: Kysely<DB>
8871
private trx?: Transaction<DB>
8972
private log?: DBLogger
90-
private e: Executor
9173

9274
/**
9375
* Current kysely / transaction instance
@@ -96,136 +78,12 @@ export class SqliteBuilder<DB extends Record<string, any>> {
9678
return this.trx || this.ky
9779
}
9880

99-
public insertInto: Kysely<DB>['insertInto'] = tb => this.e.insertInto(this.kysely, tb)
100-
public replaceInto: Kysely<DB>['replaceInto'] = tb => this.e.replaceInto(this.kysely, tb)
101-
public selectFrom: Kysely<DB>['selectFrom'] = (tb: any) => this.e.selectFrom(this.kysely, tb)
102-
public updateTable: Kysely<DB>['updateTable'] = (tb: any) => this.e.updateTable(this.kysely, tb)
103-
/**
104-
* Creates a delete query.
105-
*
106-
* See the {@link DeleteQueryBuilder.where} method for examples on how to specify
107-
* a where clause for the delete operation.
108-
*
109-
* The return value of the query is an instance of {@link DeleteResult}.
110-
*
111-
* ### Examples
112-
*
113-
* <!-- siteExample("delete", "Single row", 10) -->
114-
*
115-
* Delete a single row:
116-
*
117-
* ```ts
118-
* const result = await db
119-
* .deleteFrom('person')
120-
* .where('person.id', '=', '1')
121-
* .executeTakeFirst()
122-
*
123-
* console.log(result.numDeletedRows)
124-
* ```
125-
*
126-
* The generated SQL (PostgreSQL):
127-
*
128-
* ```sql
129-
* delete from "person" where "person"."id" = $1
130-
* ```
131-
*/
132-
public deleteFrom: {
133-
<TR extends keyof DB & string>(from: TR): Omit<
134-
DeleteQueryBuilder<DB, ExtractTableAlias<DB, TR>, DeleteResult>,
135-
JoinFnName
136-
>
137-
<TR extends TableReference<DB>>(table: TR): Omit<
138-
DeleteQueryBuilder<From<DB, TR>, FromTables<DB, never, TR>, DeleteResult>,
139-
JoinFnName
140-
>
141-
} = (tb: any) => this.e.deleteFrom(this.kysely, tb) as any
142-
143-
/**
144-
* SQLite builder. All methods will run in current transaction
145-
* @param options options
146-
* @example
147-
* ### Definition
148-
*
149-
* ```ts
150-
* import { FileMigrationProvider, SqliteDialect, createSoftDeleteExecutor } from 'kysely'
151-
* import { SqliteBuilder } from 'kysely-sqlite-builder'
152-
* import { useMigrator } from 'kysely-sqlite-builder/migrator'
153-
* import Database from 'better-sqlite3'
154-
* import type { InferDatabase } from 'kysely-sqlite-builder/schema'
155-
* import { DataType, column, defineTable } from 'kysely-sqlite-builder/schema'
156-
*
157-
* const testTable = defineTable({
158-
* columns: {
159-
* id: column.increments(),
160-
* person: column.object({ defaultTo: { name: 'test' } }),
161-
* gender: column.boolean({ notNull: true }),
162-
* // or just object
163-
* manual: { type: DataType.boolean },
164-
* array: column.object().$cast<string[]>(),
165-
* literal: column.string().$cast<'l1' | 'l2'>(),
166-
* score: column.float(),
167-
* birth: column.date(),
168-
* buffer: column.blob(),
169-
* },
170-
* primary: 'id', // optional
171-
* index: ['person', ['id', 'gender']],
172-
* timeTrigger: { create: true, update: true },
173-
* })
174-
*
175-
* const DBSchema = {
176-
* test: testTable,
177-
* }
178-
*
179-
* // create soft delete executor
180-
* const { executor, whereExists } = createSoftDeleteExecutor()
181-
*
182-
* const db = new SqliteBuilder<InferDatabase<typeof DBSchema>>({
183-
* dialect: new SqliteDialect({
184-
* database: new Database(':memory:'),
185-
* }),
186-
* logger: console,
187-
* onQuery: true,
188-
* executor, // use soft delete executor
189-
* })
190-
*
191-
* // update table using schema
192-
* await db.syncDB(useSchema(DBSchema, { logger: false }))
193-
*
194-
* // update table using migrator
195-
* await db.syncDB(useMigrator(new FileMigrationProvider('./migrations'), { options}))
196-
*
197-
* // usage: insertInto / selectFrom / updateTable / deleteFrom
198-
* await db.insertInto('test').values({ person: { name: 'test' }, gender: true }).execute()
199-
*
200-
* db.transaction(async (trx) => {
201-
* // auto load transaction
202-
* await db.insertInto('test').values({ gender: true }).execute()
203-
* // or
204-
* await trx.insertInto('test').values({ person: { name: 'test' }, gender: true }).execute()
205-
* db.transaction(async () => {
206-
* // nest transaction, use savepoint
207-
* await db.selectFrom('test').where('gender', '=', true).execute()
208-
* })
209-
* })
210-
*
211-
* // use origin instance: Kysely or Transaction
212-
* await db.kysely.insertInto('test').values({ gender: false }).execute()
213-
*
214-
* // run raw sql
215-
* await db.execute(sql`PRAGMA user_version = ${2}`)
216-
* await db.execute('PRAGMA user_version = ?', [2])
217-
*
218-
* // destroy
219-
* await db.destroy()
220-
* ```
221-
*/
22281
public constructor(options: SqliteBuilderOptions) {
22382
const {
22483
dialect,
22584
logger,
22685
onQuery,
22786
plugins = [],
228-
executor = baseExecutor,
22987
} = options
23088
this.log = logger
23189
plugins.push(new BaseSerializePlugin({
@@ -245,7 +103,6 @@ export class SqliteBuilder<DB extends Record<string, any>> {
245103
}
246104

247105
this.ky = new Kysely<DB>({ dialect, log, plugins })
248-
this.e = executor
249106
}
250107

251108
/**

src/builder/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from './base'
2+
export * from './normal'
3+
export * from './softDelete'

0 commit comments

Comments
 (0)