@starbemtech/star-db-query-builder 1.3.1 → 1.4.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/.claude/skills/star-db-query-builder/SKILL.md +104 -0
- package/CHANGELOG.md +107 -55
- package/LICENSE +21 -0
- package/README.md +92 -1391
- package/bin/install-skill.js +53 -0
- package/dist/src/core/repository.d.ts +125 -10
- package/dist/src/core/repository.js +336 -43
- package/dist/src/core/repository.js.map +1 -1
- package/dist/src/core/types.d.ts +29 -6
- package/dist/src/core/utils.d.ts +119 -0
- package/dist/src/core/utils.js +353 -82
- package/dist/src/core/utils.js.map +1 -1
- package/dist/src/db/IDatabaseClient.d.ts +14 -4
- package/dist/src/db/initDb.d.ts +60 -50
- package/dist/src/db/initDb.js +96 -64
- package/dist/src/db/initDb.js.map +1 -1
- package/dist/src/db/mysqlClient.d.ts +3 -8
- package/dist/src/db/mysqlClient.js +10 -11
- package/dist/src/db/mysqlClient.js.map +1 -1
- package/dist/src/db/pgClient.js +1 -2
- package/dist/src/db/pgClient.js.map +1 -1
- package/dist/src/monitor/monitor.js +7 -0
- package/dist/src/monitor/monitor.js.map +1 -1
- package/package.json +32 -24
- package/.github/workflows/publish.yml +0 -118
- package/.prettierignore +0 -3
- package/.prettierrc +0 -5
- package/ARCHITECTURE.md +0 -313
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -131
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -131
- package/coverage/lcov-report/mysqlClient.ts.html +0 -685
- package/coverage/lcov-report/pgClient.ts.html +0 -823
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -210
- package/coverage/lcov.info +0 -533
- package/coverage/mysqlClient.ts.html +0 -685
- package/coverage/pgClient.ts.html +0 -823
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -210
- package/dist/src/setupTests.d.ts +0 -26
- package/dist/src/setupTests.js +0 -43
- package/dist/src/setupTests.js.map +0 -1
- package/docs/INDEX.md +0 -145
- package/docs/methods/findFirst.md +0 -394
- package/docs/methods/findMany.md +0 -587
- package/docs/methods/insert.md +0 -536
- package/docs/methods/insertMany.md +0 -627
- package/docs/methods/joins.md +0 -781
- package/docs/methods/rawQuery.md +0 -284
- package/docs/methods/transactions.md +0 -737
- package/eslint.config.mjs +0 -77
- package/index.ts +0 -16
- package/jest.config.ts +0 -194
- package/scripts/release.sh +0 -123
- package/src/core/repository.ts +0 -865
- package/src/core/types.ts +0 -97
- package/src/core/utils.ts +0 -357
- package/src/db/IDatabaseClient.ts +0 -16
- package/src/db/__tests__/mysqlClient.test.ts +0 -262
- package/src/db/__tests__/pgClient.test.ts +0 -260
- package/src/db/initDb.ts +0 -181
- package/src/db/mysqlClient.ts +0 -200
- package/src/db/pgClient.ts +0 -246
- package/src/monitor/monitor.ts +0 -16
- package/src/setupTests.ts +0 -45
- package/tsconfig.test.json +0 -21
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Copies this package's bundled Claude Code skill into the consuming repo's
|
|
4
|
+
// .claude/skills/ so agents get correct star-db-query-builder usage guidance
|
|
5
|
+
// without a manual copy-paste. Run from the consuming repo's root:
|
|
6
|
+
//
|
|
7
|
+
// npx star-db-query-builder-install-skill
|
|
8
|
+
//
|
|
9
|
+
// Safe to re-run after upgrading the package — it always overwrites with the
|
|
10
|
+
// version bundled in the currently installed package.
|
|
11
|
+
|
|
12
|
+
const fs = require('fs')
|
|
13
|
+
const path = require('path')
|
|
14
|
+
|
|
15
|
+
const SKILL_NAME = 'star-db-query-builder'
|
|
16
|
+
const SOURCE = path.join(__dirname, '..', '.claude', 'skills', SKILL_NAME, 'SKILL.md')
|
|
17
|
+
const TARGET_DIR = path.join(process.cwd(), '.claude', 'skills', SKILL_NAME)
|
|
18
|
+
const TARGET = path.join(TARGET_DIR, 'SKILL.md')
|
|
19
|
+
|
|
20
|
+
function main() {
|
|
21
|
+
if (!fs.existsSync(SOURCE)) {
|
|
22
|
+
console.error(
|
|
23
|
+
`[star-db-query-builder] Could not find bundled skill at ${SOURCE}. ` +
|
|
24
|
+
'Is @starbemtech/star-db-query-builder installed correctly?'
|
|
25
|
+
)
|
|
26
|
+
process.exitCode = 1
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const alreadyExists = fs.existsSync(TARGET)
|
|
31
|
+
const previous = alreadyExists ? fs.readFileSync(TARGET, 'utf8') : null
|
|
32
|
+
const next = fs.readFileSync(SOURCE, 'utf8')
|
|
33
|
+
|
|
34
|
+
if (previous === next) {
|
|
35
|
+
console.log(`[star-db-query-builder] Skill already up to date at ${path.relative(process.cwd(), TARGET)}`)
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
fs.mkdirSync(TARGET_DIR, { recursive: true })
|
|
40
|
+
fs.writeFileSync(TARGET, next)
|
|
41
|
+
|
|
42
|
+
console.log(
|
|
43
|
+
`[star-db-query-builder] ${alreadyExists ? 'Updated' : 'Installed'} skill at ${path.relative(
|
|
44
|
+
process.cwd(),
|
|
45
|
+
TARGET
|
|
46
|
+
)}`
|
|
47
|
+
)
|
|
48
|
+
if (!alreadyExists) {
|
|
49
|
+
console.log('[star-db-query-builder] Commit this file so the rest of the team gets it too.')
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
main()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { QueryParams, RawQueryParams } from './types';
|
|
2
|
-
import { ITransactionClient } from '../db/IDatabaseClient';
|
|
1
|
+
import { QueryParams, RawQueryParams, CursorPageResult, Conditions } from './types';
|
|
2
|
+
import { IDatabaseClient, ITransactionClient } from '../db/IDatabaseClient';
|
|
3
3
|
/**
|
|
4
4
|
* Finds the first record in the specified table
|
|
5
5
|
*
|
|
@@ -18,7 +18,7 @@ import { ITransactionClient } from '../db/IDatabaseClient';
|
|
|
18
18
|
* tableName: 'users',
|
|
19
19
|
* dbClient: dbClient,
|
|
20
20
|
* select: ['id', 'name', 'email'],
|
|
21
|
-
* where: { status: 'active' },
|
|
21
|
+
* where: { status: { operator: '=', value: 'active' } },
|
|
22
22
|
* groupBy: ['status'],
|
|
23
23
|
* orderBy: [{ field: 'created_at', direction: 'DESC' }],
|
|
24
24
|
* })
|
|
@@ -28,7 +28,7 @@ import { ITransactionClient } from '../db/IDatabaseClient';
|
|
|
28
28
|
* tableName: 'users',
|
|
29
29
|
* dbClient: dbClient,
|
|
30
30
|
* select: ['id', 'name', 'email'],
|
|
31
|
-
* where: { status: 'active' },
|
|
31
|
+
* where: { status: { operator: '=', value: 'active' } },
|
|
32
32
|
* groupBy: ['status'],
|
|
33
33
|
* orderBy: [{ field: 'created_at', direction: 'DESC' }],
|
|
34
34
|
* })
|
|
@@ -52,7 +52,7 @@ export declare const findFirst: <T>({ tableName, dbClient, select, where, groupB
|
|
|
52
52
|
* tableName: 'users',
|
|
53
53
|
* dbClient: dbClient,
|
|
54
54
|
* select: ['id', 'name', 'email'],
|
|
55
|
-
* where: { status: 'active' },
|
|
55
|
+
* where: { status: { operator: '=', value: 'active' } },
|
|
56
56
|
* groupBy: ['status'],
|
|
57
57
|
* orderBy: [{ field: 'created_at', direction: 'DESC' }],
|
|
58
58
|
* limit: 10,
|
|
@@ -61,6 +61,51 @@ export declare const findFirst: <T>({ tableName, dbClient, select, where, groupB
|
|
|
61
61
|
* })
|
|
62
62
|
*/
|
|
63
63
|
export declare const findMany: <T>({ tableName, dbClient, select, where, groupBy, orderBy, limit, offset, unaccent, }: QueryParams<T>) => Promise<T[]>;
|
|
64
|
+
/**
|
|
65
|
+
* Finds multiple records in the specified table using keyset (cursor)
|
|
66
|
+
* pagination instead of offset/limit
|
|
67
|
+
*
|
|
68
|
+
* Unlike offset-based pagination, keyset pagination stays O(1) regardless of
|
|
69
|
+
* how deep the page is (no `OFFSET N` row-skipping) and does not skip/repeat
|
|
70
|
+
* rows when the underlying data changes between pages. It requires
|
|
71
|
+
* `cursorField` to be a strictly ordered, indexed column — `id` (if
|
|
72
|
+
* sequential) or `created_at` are typical choices; a plain UUID `id` works
|
|
73
|
+
* for uniqueness but its ordering is arbitrary, so prefer a monotonically
|
|
74
|
+
* increasing column when the page order matters to callers.
|
|
75
|
+
*
|
|
76
|
+
* @template T - The type of the records to be returned
|
|
77
|
+
* @param params - Query parameters including table name, database client, select fields, where conditions, cursor field, cursor value, direction, page size and unaccent
|
|
78
|
+
* @returns Promise<CursorPageResult<T>> - The page of records plus the cursor to request the next page (`null` when there is no next page)
|
|
79
|
+
*
|
|
80
|
+
* @throws {Error} When table name is not provided
|
|
81
|
+
* @throws {Error} When database client is not provided
|
|
82
|
+
* @throws {Error} When direction is not ASC or DESC
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* // First page
|
|
86
|
+
* const page1 = await findManyCursor({
|
|
87
|
+
* tableName: 'users',
|
|
88
|
+
* dbClient: dbClient,
|
|
89
|
+
* where: { status: { operator: '=', value: 'active' } },
|
|
90
|
+
* cursorField: 'created_at',
|
|
91
|
+
* limit: 20,
|
|
92
|
+
* })
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* // Next page
|
|
96
|
+
* const page2 = await findManyCursor({
|
|
97
|
+
* tableName: 'users',
|
|
98
|
+
* dbClient: dbClient,
|
|
99
|
+
* cursorField: 'created_at',
|
|
100
|
+
* cursor: page1.nextCursor,
|
|
101
|
+
* limit: 20,
|
|
102
|
+
* })
|
|
103
|
+
*/
|
|
104
|
+
export declare const findManyCursor: <T>({ tableName, dbClient, select, where, cursorField, cursor, direction, limit, unaccent, }: QueryParams<T> & {
|
|
105
|
+
cursorField?: string;
|
|
106
|
+
cursor?: string | number;
|
|
107
|
+
direction?: "ASC" | "DESC";
|
|
108
|
+
}) => Promise<CursorPageResult<T>>;
|
|
64
109
|
/**
|
|
65
110
|
* Inserts a new record into the specified table
|
|
66
111
|
*
|
|
@@ -115,6 +160,44 @@ export declare const insertMany: <P, R>({ tableName, dbClient, data, returning,
|
|
|
115
160
|
data: P[];
|
|
116
161
|
returning?: string[];
|
|
117
162
|
}) => Promise<R[]>;
|
|
163
|
+
/**
|
|
164
|
+
* Inserts a record, or updates it in place if it collides with an existing
|
|
165
|
+
* unique/primary key
|
|
166
|
+
*
|
|
167
|
+
* Builds `INSERT ... ON CONFLICT (...) DO UPDATE SET ...` for pg and
|
|
168
|
+
* `INSERT ... ON DUPLICATE KEY UPDATE ...` for mysql. `conflictFields` must
|
|
169
|
+
* name columns actually covered by a unique or primary key constraint on
|
|
170
|
+
* `tableName` — this function does not create or verify that constraint, it
|
|
171
|
+
* only builds SQL that assumes it exists. For mysql, `conflictFields` is not
|
|
172
|
+
* part of the generated SQL (`ON DUPLICATE KEY UPDATE` relies on the table's
|
|
173
|
+
* own constraint) — it is used only to re-select the row afterwards, since
|
|
174
|
+
* mysql has no `RETURNING`.
|
|
175
|
+
*
|
|
176
|
+
* @template P - The type of the data to be upserted
|
|
177
|
+
* @template R - The type of the record to be returned
|
|
178
|
+
* @param params - Query parameters including table name, database client, data, conflict target fields, optional fields to update on conflict (defaults to every field in data), and optional returning fields
|
|
179
|
+
* @returns Promise<R> - The inserted or updated record
|
|
180
|
+
*
|
|
181
|
+
* @throws {Error} When table name is not provided
|
|
182
|
+
* @throws {Error} When database client is not provided
|
|
183
|
+
* @throws {Error} When data object is not provided
|
|
184
|
+
* @throws {Error} When conflictFields is not provided or empty
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* const record = await upsert({
|
|
188
|
+
* tableName: 'users',
|
|
189
|
+
* dbClient: dbClient,
|
|
190
|
+
* data: { email: 'john.doe@example.com', name: 'John Doe' },
|
|
191
|
+
* conflictFields: ['email'],
|
|
192
|
+
* returning: ['id', 'name', 'email'],
|
|
193
|
+
* })
|
|
194
|
+
*/
|
|
195
|
+
export declare const upsert: <P, R>({ tableName, dbClient, data, conflictFields, updateFields, returning, }: QueryParams<R> & {
|
|
196
|
+
data: P;
|
|
197
|
+
conflictFields: string[];
|
|
198
|
+
updateFields?: string[];
|
|
199
|
+
returning?: string[];
|
|
200
|
+
}) => Promise<R>;
|
|
118
201
|
/**
|
|
119
202
|
* Updates a record in the specified table
|
|
120
203
|
*
|
|
@@ -164,7 +247,7 @@ export declare const update: <P, R>({ tableName, dbClient, id, data, returning,
|
|
|
164
247
|
* tableName: 'users',
|
|
165
248
|
* dbClient: dbClient,
|
|
166
249
|
* data: { name: 'John Doe', email: 'john.doe@example.com' },
|
|
167
|
-
* where: { status: 'active' },
|
|
250
|
+
* where: { status: { operator: '=', value: 'active' } },
|
|
168
251
|
* returning: ['id', 'name', 'email'],
|
|
169
252
|
* })
|
|
170
253
|
*/
|
|
@@ -247,7 +330,7 @@ export declare const deleteMany: <T>({ tableName, dbClient, ids, field, permanen
|
|
|
247
330
|
* dbClient: dbClient,
|
|
248
331
|
* select: ['id', 'name', 'email'],
|
|
249
332
|
* joins: [{ type: 'INNER', table: 'orders', on: 'users.id = orders.user_id' }],
|
|
250
|
-
* where: { status: 'active' },
|
|
333
|
+
* where: { status: { operator: '=', value: 'active' } },
|
|
251
334
|
* groupBy: ['status'],
|
|
252
335
|
* orderBy: [{ field: 'created_at', direction: 'DESC' }],
|
|
253
336
|
* limit: 10,
|
|
@@ -255,7 +338,39 @@ export declare const deleteMany: <T>({ tableName, dbClient, ids, field, permanen
|
|
|
255
338
|
* unaccent: true,
|
|
256
339
|
* })
|
|
257
340
|
*/
|
|
258
|
-
export declare const joins: <T>({ tableName, dbClient, select, joins, where, groupBy, orderBy, limit, offset, unaccent, }: QueryParams<T>
|
|
341
|
+
export declare const joins: <T, W = T>({ tableName, dbClient, select, joins, where, groupBy, orderBy, limit, offset, unaccent, }: Omit<QueryParams<T>, "where"> & {
|
|
342
|
+
/**
|
|
343
|
+
* `W` (defaults to `T`) is a separate generic from the result row type `T`:
|
|
344
|
+
* a join's `where` routinely qualifies columns from joined tables (e.g.
|
|
345
|
+
* `'orders.total'`), which are never keys of `T`. `Conditions<T | W>`'s
|
|
346
|
+
* `OR`/`AND`/`JOINS` already accept a dotted qualified-column key
|
|
347
|
+
* structurally (see `QualifiedCondition` in `./types`), so this only
|
|
348
|
+
* matters when `T` is passed explicitly and a qualified column is needed
|
|
349
|
+
* at the top level of `where` (not inside `AND`/`OR`/`JOINS`) — pass `W`
|
|
350
|
+
* explicitly too in that case:
|
|
351
|
+
* `joins<Row, Row & { 'orders.total'?: unknown }>(...)`.
|
|
352
|
+
*/
|
|
353
|
+
where?: Conditions<W>;
|
|
354
|
+
}) => Promise<T[]>;
|
|
355
|
+
/**
|
|
356
|
+
* Error thrown by `rawQuery` when the underlying driver query fails.
|
|
357
|
+
*
|
|
358
|
+
* Carries over the original driver error as `cause` plus the common
|
|
359
|
+
* cross-driver fields consumers actually branch on (e.g. Postgres'
|
|
360
|
+
* `code: '23505'` for a unique violation, `detail`, `constraint`; mysql2's
|
|
361
|
+
* `errno`/`sqlState`) — `rawQuery` used to wrap failures in a plain `Error`
|
|
362
|
+
* built from just `error.message`, which discarded all of this and left
|
|
363
|
+
* callers with no way to distinguish a conflict from a syntax error.
|
|
364
|
+
*/
|
|
365
|
+
export declare class RawQueryError extends Error {
|
|
366
|
+
cause?: unknown;
|
|
367
|
+
code?: string;
|
|
368
|
+
detail?: string;
|
|
369
|
+
constraint?: string;
|
|
370
|
+
errno?: number;
|
|
371
|
+
sqlState?: string;
|
|
372
|
+
constructor(message: string, cause: unknown);
|
|
373
|
+
}
|
|
259
374
|
/**
|
|
260
375
|
* Executa uma query SQL raw diretamente no banco de dados
|
|
261
376
|
* @param params - Parâmetros da query raw
|
|
@@ -341,7 +456,7 @@ export declare const rawQuery: <T = any>({ dbClient, sql, params, }: RawQueryPar
|
|
|
341
456
|
* console.error('Transaction failed:', error)
|
|
342
457
|
* }
|
|
343
458
|
*/
|
|
344
|
-
export declare const withTransaction: <T>(dbClient:
|
|
459
|
+
export declare const withTransaction: <T>(dbClient: IDatabaseClient, transactionFn: (tx: ITransactionClient) => Promise<T>) => Promise<T>;
|
|
345
460
|
/**
|
|
346
461
|
* Creates a transaction client for manual transaction management
|
|
347
462
|
* @param dbClient - Database client instance
|
|
@@ -371,4 +486,4 @@ export declare const withTransaction: <T>(dbClient: any, transactionFn: (tx: ITr
|
|
|
371
486
|
* throw error
|
|
372
487
|
* }
|
|
373
488
|
*/
|
|
374
|
-
export declare const beginTransaction: (dbClient:
|
|
489
|
+
export declare const beginTransaction: (dbClient: IDatabaseClient) => Promise<ITransactionClient>;
|