@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 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
+ ```