@simplysm/orm-common 13.0.29 → 13.0.30
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/README.md +210 -3
- package/docs/queries.md +89 -5
- package/docs/schema.md +12 -20
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -38,8 +38,8 @@ See [docs/schema.md](docs/schema.md) for full documentation.
|
|
|
38
38
|
|
|
39
39
|
See [docs/queries.md](docs/queries.md) for full documentation.
|
|
40
40
|
|
|
41
|
-
- **[Connection & Transactions](docs/queries.md#connection-and-transactions)** - `db.connect()`, `db.connectWithoutTransaction()`
|
|
42
|
-
- **[SELECT Queries](docs/queries.md#select-queries)** - `.where()`, `.select()`, `.single()`, `.first()`, `.result()`, `.count()`, `.exists()`
|
|
41
|
+
- **[Connection & Transactions](docs/queries.md#connection-and-transactions)** - `db.connect()`, `db.connectWithoutTransaction()`, `db.trans()`
|
|
42
|
+
- **[SELECT Queries](docs/queries.md#select-queries)** - `.where()`, `.select()`, `.distinct()`, `.orderBy()`, `.single()`, `.first()`, `.result()`, `.count()`, `.exists()`
|
|
43
43
|
- **[JOIN Queries](docs/queries.md#join-queries)** - `.join()`, `.joinSingle()`, `.include()`
|
|
44
44
|
- **[Grouping & Aggregation](docs/queries.md#grouping-and-aggregation)** - `.groupBy()`, `.having()`
|
|
45
45
|
- **[Pagination](docs/queries.md#pagination)** - `.top()`, `.limit()`
|
|
@@ -67,7 +67,7 @@ See [docs/expressions.md](docs/expressions.md) for full documentation.
|
|
|
67
67
|
- **[Date Expressions](docs/expressions.md#date-expressions)** - `expr.year()`, `expr.month()`, `expr.day()`, `expr.dateDiff()`, `expr.dateAdd()`, `expr.formatDate()`
|
|
68
68
|
- **[Conditional Expressions](docs/expressions.md#conditional-expressions)** - `expr.ifNull()`, `expr.nullIf()`, `expr.if()`, `expr.switch()`
|
|
69
69
|
- **[Aggregate Expressions](docs/expressions.md#aggregate-expressions)** - `expr.count()`, `expr.sum()`, `expr.avg()`, `expr.max()`, `expr.min()`, `expr.greatest()`, `expr.least()`
|
|
70
|
-
- **[Window Functions](docs/expressions.md#window-functions)** - `expr.rowNumber()`, `expr.rank()`, `expr.denseRank()`, `expr.lag()`, `expr.lead()`, `expr.sumOver()`, `expr.avgOver()`
|
|
70
|
+
- **[Window Functions](docs/expressions.md#window-functions)** - `expr.rowNumber()`, `expr.rank()`, `expr.denseRank()`, `expr.ntile()`, `expr.lag()`, `expr.lead()`, `expr.firstValue()`, `expr.lastValue()`, `expr.sumOver()`, `expr.avgOver()`, `expr.countOver()`, `expr.minOver()`, `expr.maxOver()`
|
|
71
71
|
- **[Other Expressions](docs/expressions.md#other-expressions)** - `expr.val()`, `expr.raw()`, `expr.cast()`, `expr.subquery()`, `expr.random()`
|
|
72
72
|
|
|
73
73
|
## DbContext API
|
|
@@ -109,6 +109,32 @@ await db.connect(async () => {
|
|
|
109
109
|
});
|
|
110
110
|
```
|
|
111
111
|
|
|
112
|
+
#### `defineDbContext(config)`
|
|
113
|
+
|
|
114
|
+
Creates a `DbContextDef` schema blueprint without any runtime state.
|
|
115
|
+
|
|
116
|
+
| Parameter | Type | Description |
|
|
117
|
+
|-----------|------|-------------|
|
|
118
|
+
| `config.tables` | `Record<string, TableBuilder>` | Table builders |
|
|
119
|
+
| `config.views` | `Record<string, ViewBuilder>` | View builders |
|
|
120
|
+
| `config.procedures` | `Record<string, ProcedureBuilder>` | Procedure builders |
|
|
121
|
+
| `config.migrations` | `Migration[]` | Migration list |
|
|
122
|
+
|
|
123
|
+
Returns `DbContextDef<TTables, TViews, TProcedures>`.
|
|
124
|
+
|
|
125
|
+
#### `createDbContext(def, executor, opt)`
|
|
126
|
+
|
|
127
|
+
Creates a fully functional `DbContextInstance` from a `DbContextDef`.
|
|
128
|
+
|
|
129
|
+
| Parameter | Type | Description |
|
|
130
|
+
|-----------|------|-------------|
|
|
131
|
+
| `def` | `DbContextDef` | Schema definition from `defineDbContext()` |
|
|
132
|
+
| `executor` | `DbContextExecutor` | Query executor (from `orm-node` or service client) |
|
|
133
|
+
| `opt.database` | `string` | Default database name |
|
|
134
|
+
| `opt.schema` | `string?` | Default schema name (MSSQL: `dbo`, PostgreSQL: `public`) |
|
|
135
|
+
|
|
136
|
+
Returns `DbContextInstance<TDef>`.
|
|
137
|
+
|
|
112
138
|
#### Type Definitions
|
|
113
139
|
|
|
114
140
|
| Type | Description |
|
|
@@ -116,6 +142,9 @@ await db.connect(async () => {
|
|
|
116
142
|
| `DbContextDef<TTables, TViews, TProcedures>` | DbContext definition (schema blueprint) |
|
|
117
143
|
| `DbContextInstance<TDef>` | Full DbContext instance with queryable accessors and DDL methods |
|
|
118
144
|
| `DbContextBase` | Core interface used internally (status, executeDefs, etc.) |
|
|
145
|
+
| `DbContextConnectionMethods` | Interface for connection/transaction methods (`connect`, `connectWithoutTransaction`, `trans`) |
|
|
146
|
+
| `DbContextDdlMethods` | Interface for all DDL methods and QueryDef generator methods |
|
|
147
|
+
| `DbContextStatus` | `"ready" \| "connect" \| "transact"` — current connection status |
|
|
119
148
|
|
|
120
149
|
### Class-based API (Removed)
|
|
121
150
|
|
|
@@ -193,6 +222,184 @@ async function doSomething(db: MyDb) {
|
|
|
193
222
|
}
|
|
194
223
|
```
|
|
195
224
|
|
|
225
|
+
## Low-Level Utilities
|
|
226
|
+
|
|
227
|
+
### `queryable(db, tableOrView, as?)`
|
|
228
|
+
|
|
229
|
+
Factory function that returns a `() => Queryable` accessor. Used internally by `createDbContext` to attach table/view accessors, but can also be used directly when building custom db context wrappers.
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
import { queryable } from "@simplysm/orm-common";
|
|
233
|
+
|
|
234
|
+
const getUserQueryable = queryable(db, User);
|
|
235
|
+
const users = await getUserQueryable().where((u) => [expr.eq(u.isActive, true)]).result();
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### `executable(db, procedureBuilder)`
|
|
239
|
+
|
|
240
|
+
Factory function that returns a `() => Executable` accessor. Used internally by `createDbContext`.
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
import { executable } from "@simplysm/orm-common";
|
|
244
|
+
|
|
245
|
+
const getUser = executable(db, GetUserById);
|
|
246
|
+
const result = await getUser().execute({ userId: 1 });
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### `parseQueryResult(rawResults, meta)`
|
|
250
|
+
|
|
251
|
+
Parses raw DB query results into typed TypeScript objects. Handles type coercion and JOIN result grouping/nesting.
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
import { parseQueryResult } from "@simplysm/orm-common";
|
|
255
|
+
|
|
256
|
+
const meta = {
|
|
257
|
+
columns: { id: "number", name: "string", createdAt: "DateTime" },
|
|
258
|
+
joins: {},
|
|
259
|
+
};
|
|
260
|
+
const result = await parseQueryResult(rawResults, meta);
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### `parseSearchQuery(searchText)`
|
|
264
|
+
|
|
265
|
+
Parses a search query string into SQL LIKE patterns for use with `.search()`.
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
import { parseSearchQuery } from "@simplysm/orm-common";
|
|
269
|
+
|
|
270
|
+
const parsed = parseSearchQuery('apple "exact phrase" +required -excluded');
|
|
271
|
+
// { or: ["%apple%"], must: ["%exact phrase%", "%required%"], not: ["%excluded%"] }
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Returns `ParsedSearchQuery`:
|
|
275
|
+
|
|
276
|
+
| Property | Type | Description |
|
|
277
|
+
|----------|------|-------------|
|
|
278
|
+
| `or` | `string[]` | OR conditions (LIKE patterns) |
|
|
279
|
+
| `must` | `string[]` | Required AND conditions (LIKE patterns) |
|
|
280
|
+
| `not` | `string[]` | NOT conditions (LIKE patterns) |
|
|
281
|
+
|
|
282
|
+
### `createQueryBuilder(dialect)`
|
|
283
|
+
|
|
284
|
+
Creates a dialect-specific `QueryBuilderBase` instance for converting `QueryDef` JSON AST to SQL strings.
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
import { createQueryBuilder } from "@simplysm/orm-common";
|
|
288
|
+
|
|
289
|
+
const builder = createQueryBuilder("mysql"); // "mysql" | "mssql" | "postgresql"
|
|
290
|
+
const { sql } = builder.build(queryDef);
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### `createColumnFactory()`
|
|
294
|
+
|
|
295
|
+
Creates a column type factory used in `TableBuilder.columns()` and `ProcedureBuilder.params()/returns()`. Can also be used standalone for DDL migrations.
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
import { createColumnFactory } from "@simplysm/orm-common";
|
|
299
|
+
|
|
300
|
+
const c = createColumnFactory();
|
|
301
|
+
await db.addColumn({ database: "mydb", name: "User" }, "status", c.varchar(20).nullable());
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Expression Types
|
|
305
|
+
|
|
306
|
+
### `ExprUnit<TPrimitive>`
|
|
307
|
+
|
|
308
|
+
Type-safe expression wrapper. All `expr.*` methods return `ExprUnit`. The generic parameter tracks the TypeScript return type of the expression.
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
import { ExprUnit } from "@simplysm/orm-common";
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
| Member | Type | Description |
|
|
315
|
+
|--------|------|-------------|
|
|
316
|
+
| `dataType` | `ColumnPrimitiveStr` | Runtime type name |
|
|
317
|
+
| `expr` | `Expr` | Raw JSON AST |
|
|
318
|
+
| `n` | `ExprUnit<NonNullable<TPrimitive>>` | Non-nullable accessor (strips `undefined`) |
|
|
319
|
+
|
|
320
|
+
### `WhereExprUnit`
|
|
321
|
+
|
|
322
|
+
Wrapper for WHERE condition expressions. All comparison and logical `expr.*` methods return `WhereExprUnit`.
|
|
323
|
+
|
|
324
|
+
### `ExprInput<TPrimitive>`
|
|
325
|
+
|
|
326
|
+
Union type that accepts either an `ExprUnit<TPrimitive>` or a plain literal value. Most `expr.*` parameters accept `ExprInput` so you can pass raw values without wrapping in `expr.val()`.
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
type ExprInput<TPrimitive> = ExprUnit<TPrimitive> | TPrimitive;
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### `QueryableRecord<TData>`
|
|
333
|
+
|
|
334
|
+
Maps a data record type to its expression counterpart. Each primitive field becomes `ExprUnit`, each array field becomes `QueryableRecord[]`, and each nested object becomes `QueryableRecord`.
|
|
335
|
+
|
|
336
|
+
### `SwitchExprBuilder<TPrimitive>`
|
|
337
|
+
|
|
338
|
+
Builder interface returned by `expr.switch()`:
|
|
339
|
+
|
|
340
|
+
| Method | Description |
|
|
341
|
+
|--------|-------------|
|
|
342
|
+
| `.case(condition, then)` | Add WHEN ... THEN branch |
|
|
343
|
+
| `.default(value)` | Add ELSE and finalize to `ExprUnit` |
|
|
344
|
+
|
|
345
|
+
### `toExpr(value)`
|
|
346
|
+
|
|
347
|
+
Converts an `ExprInput` to a raw `Expr` JSON AST. Used internally; exposed for custom QueryBuilder extensions.
|
|
348
|
+
|
|
349
|
+
## Type Reference
|
|
350
|
+
|
|
351
|
+
### Column Types
|
|
352
|
+
|
|
353
|
+
| Type | Description |
|
|
354
|
+
|------|-------------|
|
|
355
|
+
| `ColumnPrimitive` | Union of all column-storable TypeScript types (`string \| number \| boolean \| DateTime \| DateOnly \| Time \| Uuid \| Bytes \| undefined`) |
|
|
356
|
+
| `ColumnPrimitiveStr` | String key of `ColumnPrimitiveMap` — `"string" \| "number" \| "boolean" \| "DateTime" \| "DateOnly" \| "Time" \| "Uuid" \| "Bytes"` |
|
|
357
|
+
| `ColumnPrimitiveMap` | Mapping from `ColumnPrimitiveStr` → TypeScript type |
|
|
358
|
+
| `DataType` | SQL data type discriminated union (`{ type: "int" }`, `{ type: "varchar"; length: number }`, etc.) |
|
|
359
|
+
| `ColumnMeta` | Column metadata stored inside `ColumnBuilder` |
|
|
360
|
+
| `InferColumnPrimitiveFromDataType<T>` | TypeScript type from a `DataType` |
|
|
361
|
+
| `dataTypeStrToColumnPrimitiveStr` | Constant object mapping SQL type name → `ColumnPrimitiveStr` |
|
|
362
|
+
| `inferColumnPrimitiveStr(value)` | Runtime function: infer `ColumnPrimitiveStr` from a value |
|
|
363
|
+
|
|
364
|
+
#### SQL Type to TypeScript Type Mapping
|
|
365
|
+
|
|
366
|
+
| SQL Type | TypeScript Type | Notes |
|
|
367
|
+
|----------|----------------|-------|
|
|
368
|
+
| `int`, `bigint`, `float`, `double`, `decimal` | `number` | `bigint` means SQL BIGINT (8 bytes), not JS `BigInt` |
|
|
369
|
+
| `varchar`, `char`, `text` | `string` | |
|
|
370
|
+
| `boolean` | `boolean` | MySQL: TINYINT(1), MSSQL: BIT |
|
|
371
|
+
| `datetime` | `DateTime` | From `@simplysm/core-common` |
|
|
372
|
+
| `date` | `DateOnly` | From `@simplysm/core-common` |
|
|
373
|
+
| `time` | `Time` | From `@simplysm/core-common` |
|
|
374
|
+
| `uuid` | `Uuid` | From `@simplysm/core-common` |
|
|
375
|
+
| `binary` | `Bytes` | `Uint8Array` |
|
|
376
|
+
|
|
377
|
+
### Database Types
|
|
378
|
+
|
|
379
|
+
| Type/Const | Description |
|
|
380
|
+
|------------|-------------|
|
|
381
|
+
| `Dialect` | `"mysql" \| "mssql" \| "postgresql"` |
|
|
382
|
+
| `dialects` | `Dialect[]` constant — all supported dialects |
|
|
383
|
+
| `IsolationLevel` | `"READ_UNCOMMITTED" \| "READ_COMMITTED" \| "REPEATABLE_READ" \| "SERIALIZABLE"` |
|
|
384
|
+
| `DataRecord` | Recursive query result type: `{ [key: string]: ColumnPrimitive \| DataRecord \| DataRecord[] }` |
|
|
385
|
+
| `DbContextExecutor` | Interface that actual DB connectors implement |
|
|
386
|
+
| `ResultMeta` | Metadata for converting raw query results (`{ columns, joins }`) |
|
|
387
|
+
| `Migration` | `{ name: string; up: (db) => Promise<void> }` |
|
|
388
|
+
| `QueryBuildResult` | `{ sql: string; resultSetIndex?: number; resultSetStride?: number }` |
|
|
389
|
+
|
|
390
|
+
### Schema Builder Types
|
|
391
|
+
|
|
392
|
+
| Type | Description |
|
|
393
|
+
|------|-------------|
|
|
394
|
+
| `ColumnBuilderRecord` | `Record<string, ColumnBuilder<...>>` |
|
|
395
|
+
| `RelationBuilderRecord` | Union record of all relation builder types |
|
|
396
|
+
| `InferColumns<T>` | Infer column value types from a `ColumnBuilderRecord` |
|
|
397
|
+
| `InferInsertColumns<T>` | INSERT type (required + optional fields) |
|
|
398
|
+
| `InferUpdateColumns<T>` | UPDATE type (all optional) |
|
|
399
|
+
| `InferColumnExprs<T>` | Expression input type from a `ColumnBuilderRecord` |
|
|
400
|
+
| `InferDeepRelations<T>` | Infer relation types (all optional) |
|
|
401
|
+
| `PathProxy<TObject>` | Type-safe path proxy for `.include()` navigation |
|
|
402
|
+
|
|
196
403
|
## Security Notes
|
|
197
404
|
|
|
198
405
|
orm-common uses **enhanced string escaping** instead of parameter binding due to its dynamic query nature.
|
package/docs/queries.md
CHANGED
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
## Connection and Transactions
|
|
4
4
|
|
|
5
5
|
```typescript
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
import { defineDbContext, createDbContext } from "@simplysm/orm-common";
|
|
7
|
+
|
|
8
|
+
const MyDbDef = defineDbContext({ tables: { user: User } });
|
|
9
|
+
const db = createDbContext(MyDbDef, executor, { database: "mydb" });
|
|
8
10
|
|
|
9
11
|
// Execute within transaction (auto commit/rollback)
|
|
10
12
|
const users = await db.connect(async () => {
|
|
@@ -13,17 +15,33 @@ const users = await db.connect(async () => {
|
|
|
13
15
|
return result;
|
|
14
16
|
});
|
|
15
17
|
|
|
16
|
-
// Connect without transaction (for DDL operations)
|
|
18
|
+
// Connect without transaction (for DDL operations or read-only queries)
|
|
17
19
|
await db.connectWithoutTransaction(async () => {
|
|
18
20
|
await db.initialize(); // Code First initialization
|
|
19
21
|
});
|
|
20
22
|
|
|
23
|
+
// Partial transaction within connectWithoutTransaction
|
|
24
|
+
await db.connectWithoutTransaction(async () => {
|
|
25
|
+
const report = await db.report().result(); // read without transaction
|
|
26
|
+
await db.trans(async () => {
|
|
27
|
+
await db.log().insert([{ message: "accessed" }]); // write with transaction
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
21
31
|
// Specify isolation level
|
|
22
32
|
await db.connect(async () => {
|
|
23
33
|
// ...
|
|
24
34
|
}, "SERIALIZABLE");
|
|
25
35
|
```
|
|
26
36
|
|
|
37
|
+
### Connection Methods
|
|
38
|
+
|
|
39
|
+
| Method | Description |
|
|
40
|
+
|--------|-------------|
|
|
41
|
+
| `db.connect(fn, isolationLevel?)` | Open connection, begin transaction, run fn, commit. Auto-rollback on error. |
|
|
42
|
+
| `db.connectWithoutTransaction(fn)` | Open connection without transaction, run fn, close. |
|
|
43
|
+
| `db.trans(fn, isolationLevel?)` | Begin transaction on an already-connected db. Must be called inside `connectWithoutTransaction`. |
|
|
44
|
+
|
|
27
45
|
## SELECT Queries
|
|
28
46
|
|
|
29
47
|
```typescript
|
|
@@ -41,6 +59,12 @@ const names = await db.user()
|
|
|
41
59
|
}))
|
|
42
60
|
.result();
|
|
43
61
|
|
|
62
|
+
// Distinct rows
|
|
63
|
+
const uniqueNames = await db.user()
|
|
64
|
+
.select((u) => ({ name: u.name }))
|
|
65
|
+
.distinct()
|
|
66
|
+
.result();
|
|
67
|
+
|
|
44
68
|
// Single result (error if 2 or more)
|
|
45
69
|
const user = await db.user()
|
|
46
70
|
.where((u) => [expr.eq(u.id, 1)])
|
|
@@ -62,6 +86,22 @@ const hasAdmin = await db.user()
|
|
|
62
86
|
.exists();
|
|
63
87
|
```
|
|
64
88
|
|
|
89
|
+
### Queryable Method Reference
|
|
90
|
+
|
|
91
|
+
| Method | Description |
|
|
92
|
+
|--------|-------------|
|
|
93
|
+
| `.select(fn)` | Map columns to a new shape |
|
|
94
|
+
| `.distinct()` | Remove duplicate rows |
|
|
95
|
+
| `.where(fn)` | Add WHERE condition (multiple calls = AND) |
|
|
96
|
+
| `.orderBy(fn, dir?)` | Add ORDER BY (`"ASC"` or `"DESC"`, default `"ASC"`) |
|
|
97
|
+
| `.top(n)` | Return at most n rows |
|
|
98
|
+
| `.limit(skip, take)` | Paginate (requires `orderBy` first) |
|
|
99
|
+
| `.result()` | Execute and return all rows |
|
|
100
|
+
| `.single()` | Execute, return first row, error if > 1 row |
|
|
101
|
+
| `.first()` | Execute, return first row only |
|
|
102
|
+
| `.count(fn?)` | Execute COUNT query |
|
|
103
|
+
| `.exists()` | Return true if any row matches |
|
|
104
|
+
|
|
65
105
|
## JOIN Queries
|
|
66
106
|
|
|
67
107
|
```typescript
|
|
@@ -277,7 +317,7 @@ await db.connect(async () => {
|
|
|
277
317
|
|
|
278
318
|
## DDL Operations
|
|
279
319
|
|
|
280
|
-
`
|
|
320
|
+
`DbContextInstance` supports Code First DDL operations.
|
|
281
321
|
|
|
282
322
|
```typescript
|
|
283
323
|
await db.connectWithoutTransaction(async () => {
|
|
@@ -296,9 +336,43 @@ await db.connectWithoutTransaction(async () => {
|
|
|
296
336
|
|
|
297
337
|
await db.renameTable({ database: "mydb", name: "User" }, "Member");
|
|
298
338
|
await db.truncate({ database: "mydb", name: "User" });
|
|
339
|
+
|
|
340
|
+
// Table existence / schema check
|
|
341
|
+
const exists = await db.schemaExists("mydb");
|
|
342
|
+
|
|
343
|
+
// FK management
|
|
344
|
+
await db.switchFk({ database: "mydb", name: "User" }, "off");
|
|
345
|
+
await db.switchFk({ database: "mydb", name: "User" }, "on");
|
|
299
346
|
});
|
|
300
347
|
```
|
|
301
348
|
|
|
349
|
+
### DDL Method Reference
|
|
350
|
+
|
|
351
|
+
| Method | Description |
|
|
352
|
+
|--------|-------------|
|
|
353
|
+
| `db.initialize(opts?)` | Create all tables, views, procedures, FKs, indexes per schema. `opts.force` drops before recreating. |
|
|
354
|
+
| `db.createTable(table)` | CREATE TABLE |
|
|
355
|
+
| `db.dropTable(name)` | DROP TABLE |
|
|
356
|
+
| `db.renameTable(name, newName)` | Rename table |
|
|
357
|
+
| `db.createView(view)` | CREATE VIEW |
|
|
358
|
+
| `db.dropView(name)` | DROP VIEW |
|
|
359
|
+
| `db.createProc(proc)` | CREATE PROCEDURE |
|
|
360
|
+
| `db.dropProc(name)` | DROP PROCEDURE |
|
|
361
|
+
| `db.addColumn(table, col, builder)` | ALTER TABLE ADD COLUMN |
|
|
362
|
+
| `db.dropColumn(table, col)` | ALTER TABLE DROP COLUMN |
|
|
363
|
+
| `db.modifyColumn(table, col, builder)` | ALTER TABLE MODIFY COLUMN |
|
|
364
|
+
| `db.renameColumn(table, col, newName)` | Rename column |
|
|
365
|
+
| `db.addPk(table, cols)` | Add primary key constraint |
|
|
366
|
+
| `db.dropPk(table)` | Drop primary key constraint |
|
|
367
|
+
| `db.addFk(table, relName, fkBuilder)` | Add foreign key constraint |
|
|
368
|
+
| `db.dropFk(table, relName)` | Drop foreign key constraint |
|
|
369
|
+
| `db.addIdx(table, idxBuilder)` | Add index |
|
|
370
|
+
| `db.dropIdx(table, cols)` | Drop index |
|
|
371
|
+
| `db.clearSchema(params)` | Drop all objects in schema |
|
|
372
|
+
| `db.schemaExists(database, schema?)` | Check if schema exists |
|
|
373
|
+
| `db.truncate(table)` | TRUNCATE TABLE |
|
|
374
|
+
| `db.switchFk(table, "on"\|"off")` | Enable/disable FK constraints |
|
|
375
|
+
|
|
302
376
|
## Query Builder (SQL Generation)
|
|
303
377
|
|
|
304
378
|
Converts `QueryDef` JSON AST to DBMS-specific SQL strings.
|
|
@@ -318,6 +392,16 @@ const queryDef = db.user()
|
|
|
318
392
|
const { sql } = mysqlBuilder.build(queryDef);
|
|
319
393
|
```
|
|
320
394
|
|
|
395
|
+
`QueryBuilderBase.build(def)` accepts any `QueryDef` and returns `QueryBuildResult`:
|
|
396
|
+
|
|
397
|
+
```typescript
|
|
398
|
+
interface QueryBuildResult {
|
|
399
|
+
sql: string;
|
|
400
|
+
resultSetIndex?: number; // which result set index to use (for multi-result queries)
|
|
401
|
+
resultSetStride?: number; // stride for multi-result queries (MySQL INSERT with OUTPUT)
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
321
405
|
## Error Handling
|
|
322
406
|
|
|
323
407
|
```typescript
|
|
@@ -345,7 +429,7 @@ try {
|
|
|
345
429
|
|
|
346
430
|
| Code | Description |
|
|
347
431
|
|------|------|
|
|
348
|
-
| `NO_ACTIVE_TRANSACTION` | No active transaction |
|
|
432
|
+
| `NO_ACTIVE_TRANSACTION` | No active transaction (e.g. rollback with no transaction open) |
|
|
349
433
|
| `TRANSACTION_ALREADY_STARTED` | Transaction already started |
|
|
350
434
|
| `DEADLOCK` | Deadlock occurred |
|
|
351
435
|
| `LOCK_TIMEOUT` | Lock timeout |
|
package/docs/schema.md
CHANGED
|
@@ -139,32 +139,24 @@ await db.connect(async () => {
|
|
|
139
139
|
});
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
-
###
|
|
142
|
+
### Low-level Utilities (Advanced)
|
|
143
|
+
|
|
144
|
+
`queryable()` and `executable()` are the underlying factory functions used internally by `createDbContext()`. They can be used directly when implementing a custom `DbContextBase`.
|
|
143
145
|
|
|
144
146
|
```typescript
|
|
145
|
-
import {
|
|
147
|
+
import { queryable, executable, type DbContextBase } from "@simplysm/orm-common";
|
|
146
148
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
readonly getUserById = executable(this, GetUserById);
|
|
149
|
+
// queryable(db, tableOrView, as?) - creates a () => Queryable factory
|
|
150
|
+
const getUserQueryable = queryable(db, User);
|
|
151
|
+
const userQueryable = getUserQueryable(); // returns Queryable<UserData, typeof User>
|
|
151
152
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
up: async (db: MyDb) => {
|
|
156
|
-
const c = createColumnFactory();
|
|
157
|
-
await db.addColumn(
|
|
158
|
-
{ database: "mydb", name: "User" },
|
|
159
|
-
"status",
|
|
160
|
-
c.varchar(20).nullable(),
|
|
161
|
-
);
|
|
162
|
-
},
|
|
163
|
-
},
|
|
164
|
-
];
|
|
165
|
-
}
|
|
153
|
+
// executable(db, procedure) - creates a () => Executable factory
|
|
154
|
+
const getByIdExecutable = executable(db, GetUserById);
|
|
155
|
+
const exec = getByIdExecutable(); // returns Executable<Params, Returns>
|
|
166
156
|
```
|
|
167
157
|
|
|
158
|
+
> For most use cases, `createDbContext()` is preferred and manages `queryable`/`executable` automatically.
|
|
159
|
+
|
|
168
160
|
## View Definition
|
|
169
161
|
|
|
170
162
|
```typescript
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplysm/orm-common",
|
|
3
|
-
"version": "13.0.
|
|
3
|
+
"version": "13.0.30",
|
|
4
4
|
"description": "심플리즘 패키지 - ORM 모듈 (common)",
|
|
5
5
|
"author": "김석래",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -19,6 +19,6 @@
|
|
|
19
19
|
],
|
|
20
20
|
"sideEffects": false,
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@simplysm/core-common": "13.0.
|
|
22
|
+
"@simplysm/core-common": "13.0.30"
|
|
23
23
|
}
|
|
24
24
|
}
|