@simplysm/orm-common 13.0.81 → 13.0.83
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 +106 -0
- package/docs/db-context.md +238 -0
- package/docs/expressions.md +413 -0
- package/docs/query-builder.md +198 -0
- package/docs/queryable.md +420 -0
- package/docs/schema-builders.md +216 -0
- package/docs/types-and-utilities.md +353 -0
- package/package.json +4 -3
package/README.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# @simplysm/orm-common
|
|
2
|
+
|
|
3
|
+
> Simplysm Package - ORM Module (common)
|
|
4
|
+
|
|
5
|
+
A dialect-independent ORM framework for TypeScript that supports MySQL, MSSQL, and PostgreSQL. Provides type-safe schema definitions, fluent query building, expression AST generation, and automatic DDL/migration management -- all without writing raw SQL.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @simplysm/orm-common
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Key Concepts
|
|
14
|
+
|
|
15
|
+
- **Schema Builders** -- Define tables, views, and procedures with a fluent API (`Table`, `View`, `Procedure`)
|
|
16
|
+
- **DbContext** -- Central entry point that combines schema definitions with a database executor for connection/transaction management
|
|
17
|
+
- **Queryable** -- Chainable query builder for SELECT, INSERT, UPDATE, DELETE, JOIN, GROUP BY, UNION, and recursive CTE
|
|
18
|
+
- **Expression Builder (`expr`)** -- Dialect-independent expression AST generator for WHERE conditions, SELECT projections, aggregations, window functions, and more
|
|
19
|
+
- **Query Builder** -- Converts expression ASTs into dialect-specific SQL (MySQL, MSSQL, PostgreSQL)
|
|
20
|
+
- **Search Parser** -- Parses user search strings into structured SQL LIKE patterns
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import {
|
|
26
|
+
Table, View, Procedure,
|
|
27
|
+
defineDbContext, createDbContext,
|
|
28
|
+
expr,
|
|
29
|
+
} from "@simplysm/orm-common";
|
|
30
|
+
|
|
31
|
+
// 1. Define tables
|
|
32
|
+
const User = Table("User")
|
|
33
|
+
.columns((c) => ({
|
|
34
|
+
id: c.bigint().autoIncrement(),
|
|
35
|
+
name: c.varchar(100),
|
|
36
|
+
email: c.varchar(200).nullable(),
|
|
37
|
+
status: c.varchar(20).default("active"),
|
|
38
|
+
}))
|
|
39
|
+
.primaryKey("id")
|
|
40
|
+
.indexes((i) => [i.index("email").unique()]);
|
|
41
|
+
|
|
42
|
+
const Post = Table("Post")
|
|
43
|
+
.columns((c) => ({
|
|
44
|
+
id: c.bigint().autoIncrement(),
|
|
45
|
+
authorId: c.bigint(),
|
|
46
|
+
title: c.varchar(200),
|
|
47
|
+
content: c.text(),
|
|
48
|
+
}))
|
|
49
|
+
.primaryKey("id")
|
|
50
|
+
.relations((r) => ({
|
|
51
|
+
author: r.foreignKey(["authorId"], () => User),
|
|
52
|
+
}));
|
|
53
|
+
|
|
54
|
+
// 2. Define DbContext
|
|
55
|
+
const MyDb = defineDbContext({
|
|
56
|
+
tables: { user: User, post: Post },
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// 3. Create instance with executor
|
|
60
|
+
const db = createDbContext(MyDb, executor, { database: "mydb" });
|
|
61
|
+
|
|
62
|
+
// 4. Query
|
|
63
|
+
await db.connect(async () => {
|
|
64
|
+
// SELECT with WHERE
|
|
65
|
+
const activeUsers = await db.user()
|
|
66
|
+
.where((u) => [expr.eq(u.status, "active")])
|
|
67
|
+
.execute();
|
|
68
|
+
|
|
69
|
+
// JOIN
|
|
70
|
+
const postsWithAuthor = await db.post()
|
|
71
|
+
.include((p) => p.author)
|
|
72
|
+
.execute();
|
|
73
|
+
|
|
74
|
+
// INSERT
|
|
75
|
+
await db.user().insert([{ name: "Alice" }]);
|
|
76
|
+
|
|
77
|
+
// UPDATE
|
|
78
|
+
await db.user()
|
|
79
|
+
.where((u) => [expr.eq(u.id, 1)])
|
|
80
|
+
.update(() => ({ name: expr.val("string", "Bob") }));
|
|
81
|
+
|
|
82
|
+
// DELETE
|
|
83
|
+
await db.user()
|
|
84
|
+
.where((u) => [expr.eq(u.id, 1)])
|
|
85
|
+
.delete();
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Documentation
|
|
90
|
+
|
|
91
|
+
| Category | Description | File |
|
|
92
|
+
|----------|-------------|------|
|
|
93
|
+
| Schema Builders | Table, View, Procedure definitions and column/index/relation factories | [docs/schema-builders.md](docs/schema-builders.md) |
|
|
94
|
+
| DbContext | defineDbContext, createDbContext, connection/transaction management, DDL methods | [docs/db-context.md](docs/db-context.md) |
|
|
95
|
+
| Queryable | Chainable query builder for SELECT, INSERT, UPDATE, DELETE, JOIN, GROUP BY, etc. | [docs/queryable.md](docs/queryable.md) |
|
|
96
|
+
| Expression Builder | Dialect-independent expression AST (`expr.*`) for conditions, projections, aggregations | [docs/expressions.md](docs/expressions.md) |
|
|
97
|
+
| Query Builder | QueryDef to SQL rendering for MySQL, MSSQL, PostgreSQL | [docs/query-builder.md](docs/query-builder.md) |
|
|
98
|
+
| Types and Utilities | Column types, database types, error handling, search parsing, result parsing | [docs/types-and-utilities.md](docs/types-and-utilities.md) |
|
|
99
|
+
|
|
100
|
+
## Supported Dialects
|
|
101
|
+
|
|
102
|
+
| Dialect | Version | Notes |
|
|
103
|
+
|---------|---------|-------|
|
|
104
|
+
| MySQL | 8.0.14+ | `database.name` namespace |
|
|
105
|
+
| MSSQL | 2012+ | `database.schema.name` namespace (default schema: `dbo`) |
|
|
106
|
+
| PostgreSQL | 9.0+ | `schema.name` namespace (default schema: `public`) |
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# DbContext
|
|
2
|
+
|
|
3
|
+
Central entry point for database operations. Combines schema definitions with an executor for connection management, transaction handling, DDL operations, and schema initialization.
|
|
4
|
+
|
|
5
|
+
## API Reference
|
|
6
|
+
|
|
7
|
+
### `defineDbContext(config)`
|
|
8
|
+
|
|
9
|
+
Creates a `DbContextDef` (blueprint) containing schema metadata but no runtime state.
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
function defineDbContext<TTables, TViews, TProcedures>(config: {
|
|
13
|
+
tables?: TTables;
|
|
14
|
+
views?: TViews;
|
|
15
|
+
procedures?: TProcedures;
|
|
16
|
+
migrations?: Migration[];
|
|
17
|
+
}): DbContextDef<TTables & { _migration: typeof _Migration }, TViews, TProcedures>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
A `_migration` system table is automatically added to track applied migrations.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
### `createDbContext(def, executor, opt)`
|
|
25
|
+
|
|
26
|
+
Creates a complete `DbContextInstance` from a definition and executor.
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
function createDbContext<TDef extends DbContextDef<any, any, any>>(
|
|
30
|
+
def: TDef,
|
|
31
|
+
executor: DbContextExecutor,
|
|
32
|
+
opt: { database: string; schema?: string },
|
|
33
|
+
): DbContextInstance<TDef>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Parameters:**
|
|
37
|
+
- `def` -- Definition created by `defineDbContext()`
|
|
38
|
+
- `executor` -- Query executor implementation (e.g., `NodeDbContextExecutor`, `ServiceDbContextExecutor`)
|
|
39
|
+
- `opt.database` -- Database name
|
|
40
|
+
- `opt.schema` -- Schema name (MSSQL: `dbo`, PostgreSQL: `public`)
|
|
41
|
+
|
|
42
|
+
The returned instance automatically maps:
|
|
43
|
+
- Each table key to a `() => Queryable` accessor
|
|
44
|
+
- Each view key to a `() => Queryable` accessor
|
|
45
|
+
- Each procedure key to a `() => Executable` accessor
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
### Connection Management
|
|
50
|
+
|
|
51
|
+
#### `db.connect(fn, isolationLevel?)`
|
|
52
|
+
|
|
53
|
+
Execute callback within a managed connection and transaction. Automatically commits on success or rolls back on error.
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
connect<TResult>(
|
|
57
|
+
fn: () => Promise<TResult>,
|
|
58
|
+
isolationLevel?: IsolationLevel
|
|
59
|
+
): Promise<TResult>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### `db.connectWithoutTransaction(fn)`
|
|
63
|
+
|
|
64
|
+
Connect without a transaction. Used for DDL operations or read-only operations.
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
connectWithoutTransaction<TResult>(
|
|
68
|
+
fn: () => Promise<TResult>
|
|
69
|
+
): Promise<TResult>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
#### `db.transaction(fn, isolationLevel?)`
|
|
73
|
+
|
|
74
|
+
Start a nested transaction within an already connected state (`connectWithoutTransaction`).
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
transaction<TResult>(
|
|
78
|
+
fn: () => Promise<TResult>,
|
|
79
|
+
isolationLevel?: IsolationLevel
|
|
80
|
+
): Promise<TResult>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**IsolationLevel values:** `"READ_UNCOMMITTED"` | `"READ_COMMITTED"` | `"REPEATABLE_READ"` | `"SERIALIZABLE"`
|
|
84
|
+
|
|
85
|
+
**DbContextStatus lifecycle:** `"ready"` -> `"connect"` -> `"transact"` -> `"connect"` -> `"ready"`
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
### DDL Methods
|
|
90
|
+
|
|
91
|
+
All DDL methods are available on the `DbContextInstance`. They cannot be executed inside a transaction.
|
|
92
|
+
|
|
93
|
+
#### Table Operations
|
|
94
|
+
|
|
95
|
+
| Method | Description |
|
|
96
|
+
|--------|-------------|
|
|
97
|
+
| `createTable(table)` | CREATE TABLE from a TableBuilder |
|
|
98
|
+
| `dropTable(table)` | DROP TABLE |
|
|
99
|
+
| `renameTable(table, newName)` | RENAME TABLE |
|
|
100
|
+
| `createView(view)` | CREATE VIEW from a ViewBuilder |
|
|
101
|
+
| `dropView(view)` | DROP VIEW |
|
|
102
|
+
| `createProc(procedure)` | CREATE PROCEDURE from a ProcedureBuilder |
|
|
103
|
+
| `dropProc(procedure)` | DROP PROCEDURE |
|
|
104
|
+
|
|
105
|
+
#### Column Operations
|
|
106
|
+
|
|
107
|
+
| Method | Description |
|
|
108
|
+
|--------|-------------|
|
|
109
|
+
| `addColumn(table, name, column)` | ADD COLUMN |
|
|
110
|
+
| `dropColumn(table, column)` | DROP COLUMN |
|
|
111
|
+
| `modifyColumn(table, name, column)` | MODIFY COLUMN (type/properties) |
|
|
112
|
+
| `renameColumn(table, column, newName)` | RENAME COLUMN |
|
|
113
|
+
|
|
114
|
+
#### Constraint Operations
|
|
115
|
+
|
|
116
|
+
| Method | Description |
|
|
117
|
+
|--------|-------------|
|
|
118
|
+
| `addPrimaryKey(table, columns)` | ADD PRIMARY KEY |
|
|
119
|
+
| `dropPrimaryKey(table)` | DROP PRIMARY KEY |
|
|
120
|
+
| `addForeignKey(table, name, fkBuilder)` | ADD FOREIGN KEY |
|
|
121
|
+
| `dropForeignKey(table, name)` | DROP FOREIGN KEY |
|
|
122
|
+
| `addIndex(table, indexBuilder)` | CREATE INDEX |
|
|
123
|
+
| `dropIndex(table, columns)` | DROP INDEX |
|
|
124
|
+
|
|
125
|
+
#### Schema Operations
|
|
126
|
+
|
|
127
|
+
| Method | Description |
|
|
128
|
+
|--------|-------------|
|
|
129
|
+
| `clearSchema(params)` | Drop all objects in a schema |
|
|
130
|
+
| `schemaExists(database, schema?)` | Check if schema/database exists |
|
|
131
|
+
| `truncate(table)` | TRUNCATE TABLE |
|
|
132
|
+
| `switchFk(table, enabled)` | Enable/disable FK constraints |
|
|
133
|
+
|
|
134
|
+
Each DDL method also has a corresponding `get*QueryDef()` method that returns the raw `QueryDef` without executing it.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
### `db.initialize(options?)`
|
|
139
|
+
|
|
140
|
+
Run all pending migrations and create missing tables/views/procedures.
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
initialize(options?: {
|
|
144
|
+
dbs?: string[]; // Limit to specific databases
|
|
145
|
+
force?: boolean; // Force re-create (drop and recreate)
|
|
146
|
+
}): Promise<void>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
### DbContextExecutor Interface
|
|
152
|
+
|
|
153
|
+
Implement this interface to connect the ORM to a specific database driver.
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
interface DbContextExecutor {
|
|
157
|
+
connect(): Promise<void>;
|
|
158
|
+
close(): Promise<void>;
|
|
159
|
+
beginTransaction(isolationLevel?: IsolationLevel): Promise<void>;
|
|
160
|
+
commitTransaction(): Promise<void>;
|
|
161
|
+
rollbackTransaction(): Promise<void>;
|
|
162
|
+
executeDefs<T = DataRecord>(
|
|
163
|
+
defs: QueryDef[],
|
|
164
|
+
resultMetas?: (ResultMeta | undefined)[],
|
|
165
|
+
): Promise<T[][]>;
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
### Migration
|
|
172
|
+
|
|
173
|
+
Define schema migrations for version control.
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
interface Migration {
|
|
177
|
+
name: string;
|
|
178
|
+
up: (db: DbContextBase & DbContextDdlMethods) => Promise<void>;
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Usage Examples
|
|
185
|
+
|
|
186
|
+
### Basic Setup and Query
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
const MyDb = defineDbContext({
|
|
190
|
+
tables: { user: User, post: Post },
|
|
191
|
+
views: { activeUsers: ActiveUsers },
|
|
192
|
+
procedures: { getUserById: GetUserById },
|
|
193
|
+
migrations: [
|
|
194
|
+
{
|
|
195
|
+
name: "20260101_001_add_status_column",
|
|
196
|
+
up: async (db) => {
|
|
197
|
+
await db.addColumn(
|
|
198
|
+
{ database: "mydb", name: "User" },
|
|
199
|
+
"status",
|
|
200
|
+
createColumnFactory().varchar(20).default("active"),
|
|
201
|
+
);
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
const db = createDbContext(MyDb, executor, { database: "mydb" });
|
|
208
|
+
|
|
209
|
+
// Transactional query
|
|
210
|
+
await db.connect(async () => {
|
|
211
|
+
const users = await db.user().execute();
|
|
212
|
+
const activeUsers = await db.activeUsers().execute();
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// DDL operations (no transaction)
|
|
216
|
+
await db.connectWithoutTransaction(async () => {
|
|
217
|
+
await db.initialize();
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Execute procedure
|
|
221
|
+
await db.connect(async () => {
|
|
222
|
+
const result = await db.getUserById().execute({ userId: 1n });
|
|
223
|
+
});
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Nested Transaction
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
await db.connectWithoutTransaction(async () => {
|
|
230
|
+
// DDL first (no transaction needed)
|
|
231
|
+
await db.createTable(NewTable);
|
|
232
|
+
|
|
233
|
+
// Then transactional DML
|
|
234
|
+
await db.transaction(async () => {
|
|
235
|
+
await db.user().insert([{ name: "Alice" }]);
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
```
|