@b9g/zen 0.1.1 → 0.1.3
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/CHANGELOG.md +39 -0
- package/README.md +240 -125
- package/package.json +12 -3
- package/{chunk-W7JTNEM4.js → src/_chunks/chunk-2C6KOX4F.js} +1 -1
- package/{chunk-CHF7L5PC.js → src/_chunks/chunk-2R6FDKLS.js} +1 -1
- package/{chunk-XHXMCOSW.js → src/_chunks/chunk-DKLSJISE.js} +40 -0
- package/{ddl-2A2UFUR3.js → src/_chunks/ddl-32B7E53E.js} +2 -2
- package/src/bun.js +4 -4
- package/src/impl/builtins.d.ts +52 -0
- package/src/impl/database.d.ts +495 -0
- package/src/impl/ddl.d.ts +34 -0
- package/src/impl/errors.d.ts +195 -0
- package/src/impl/query.d.ts +249 -0
- package/src/impl/sql.d.ts +47 -0
- package/src/impl/table.d.ts +961 -0
- package/src/impl/template.d.ts +75 -0
- package/src/mysql.js +3 -3
- package/src/postgres.js +3 -3
- package/src/sqlite.js +3 -3
- package/src/zen.d.ts +6 -7
- package/src/zen.js +5 -2
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured error types for database operations.
|
|
3
|
+
*
|
|
4
|
+
* All database errors extend DatabaseError, which includes an error code
|
|
5
|
+
* for programmatic error handling.
|
|
6
|
+
*/
|
|
7
|
+
export type DatabaseErrorCode = "VALIDATION_ERROR" | "TABLE_DEFINITION_ERROR" | "MIGRATION_ERROR" | "MIGRATION_LOCK_ERROR" | "QUERY_ERROR" | "NOT_FOUND" | "ALREADY_EXISTS" | "CONSTRAINT_VIOLATION" | "CONNECTION_ERROR" | "TRANSACTION_ERROR" | "ENSURE_ERROR" | "SCHEMA_DRIFT_ERROR" | "CONSTRAINT_PREFLIGHT_ERROR";
|
|
8
|
+
/**
|
|
9
|
+
* Base error class for all database errors.
|
|
10
|
+
*
|
|
11
|
+
* Includes an error code for programmatic handling.
|
|
12
|
+
*/
|
|
13
|
+
export declare class DatabaseError extends Error {
|
|
14
|
+
readonly code: DatabaseErrorCode;
|
|
15
|
+
constructor(code: DatabaseErrorCode, message: string, options?: ErrorOptions);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Thrown when Zod validation fails during insert/update.
|
|
19
|
+
*/
|
|
20
|
+
export declare class ValidationError extends DatabaseError {
|
|
21
|
+
readonly fieldErrors: Record<string, string[]>;
|
|
22
|
+
constructor(message: string, fieldErrors?: Record<string, string[]>, options?: ErrorOptions);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Thrown when table definition is invalid (e.g., dots in names).
|
|
26
|
+
*/
|
|
27
|
+
export declare class TableDefinitionError extends DatabaseError {
|
|
28
|
+
readonly tableName?: string;
|
|
29
|
+
readonly fieldName?: string;
|
|
30
|
+
constructor(message: string, tableName?: string, fieldName?: string, options?: ErrorOptions);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Thrown when migration fails.
|
|
34
|
+
*/
|
|
35
|
+
export declare class MigrationError extends DatabaseError {
|
|
36
|
+
readonly fromVersion: number;
|
|
37
|
+
readonly toVersion: number;
|
|
38
|
+
constructor(message: string, fromVersion: number, toVersion: number, options?: ErrorOptions);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Thrown when migration lock cannot be acquired.
|
|
42
|
+
*/
|
|
43
|
+
export declare class MigrationLockError extends DatabaseError {
|
|
44
|
+
constructor(message: string, options?: ErrorOptions);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Thrown when a query fails.
|
|
48
|
+
*/
|
|
49
|
+
export declare class QueryError extends DatabaseError {
|
|
50
|
+
readonly sql?: string;
|
|
51
|
+
constructor(message: string, sql?: string, options?: ErrorOptions);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Thrown when an expected entity is not found.
|
|
55
|
+
*/
|
|
56
|
+
export declare class NotFoundError extends DatabaseError {
|
|
57
|
+
readonly tableName: string;
|
|
58
|
+
readonly id?: unknown;
|
|
59
|
+
constructor(tableName: string, id?: unknown, options?: ErrorOptions);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Thrown when trying to create an entity that already exists.
|
|
63
|
+
*/
|
|
64
|
+
export declare class AlreadyExistsError extends DatabaseError {
|
|
65
|
+
readonly tableName: string;
|
|
66
|
+
readonly field?: string;
|
|
67
|
+
readonly value?: unknown;
|
|
68
|
+
constructor(tableName: string, field?: string, value?: unknown, options?: ErrorOptions);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Thrown when a database constraint is violated.
|
|
72
|
+
*
|
|
73
|
+
* Constraint violations are detected at the database level and converted
|
|
74
|
+
* from driver-specific errors into this normalized format.
|
|
75
|
+
*
|
|
76
|
+
* **Stable fields**: All fields are always present with defined types.
|
|
77
|
+
* Best-effort extraction from driver errors means some may be undefined.
|
|
78
|
+
*
|
|
79
|
+
* **Transaction behavior**: This error is thrown immediately and does NOT
|
|
80
|
+
* auto-rollback. The caller or driver transaction wrapper handles rollback.
|
|
81
|
+
*/
|
|
82
|
+
export declare class ConstraintViolationError extends DatabaseError {
|
|
83
|
+
/**
|
|
84
|
+
* Type of constraint that was violated.
|
|
85
|
+
* "unknown" if the specific type couldn't be determined from the error.
|
|
86
|
+
*/
|
|
87
|
+
readonly kind: "unique" | "foreign_key" | "check" | "not_null" | "unknown";
|
|
88
|
+
/**
|
|
89
|
+
* Name of the constraint (e.g., "users_email_unique", "users.email").
|
|
90
|
+
* May be undefined if the database error didn't include it.
|
|
91
|
+
*/
|
|
92
|
+
readonly constraint?: string;
|
|
93
|
+
/**
|
|
94
|
+
* Table name where the violation occurred.
|
|
95
|
+
* May be undefined if not extractable from the error.
|
|
96
|
+
*/
|
|
97
|
+
readonly table?: string;
|
|
98
|
+
/**
|
|
99
|
+
* Column name involved in the violation.
|
|
100
|
+
* May be undefined if not extractable from the error.
|
|
101
|
+
*/
|
|
102
|
+
readonly column?: string;
|
|
103
|
+
constructor(message: string, details: {
|
|
104
|
+
kind: "unique" | "foreign_key" | "check" | "not_null" | "unknown";
|
|
105
|
+
constraint?: string;
|
|
106
|
+
table?: string;
|
|
107
|
+
column?: string;
|
|
108
|
+
}, options?: ErrorOptions);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Thrown when database connection fails.
|
|
112
|
+
*/
|
|
113
|
+
export declare class ConnectionError extends DatabaseError {
|
|
114
|
+
constructor(message: string, options?: ErrorOptions);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Thrown when a transaction fails.
|
|
118
|
+
*/
|
|
119
|
+
export declare class TransactionError extends DatabaseError {
|
|
120
|
+
constructor(message: string, options?: ErrorOptions);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Operation type for ensure operations.
|
|
124
|
+
*/
|
|
125
|
+
export type EnsureOperation = "ensureTable" | "ensureConstraints" | "copyColumn";
|
|
126
|
+
/**
|
|
127
|
+
* Thrown when an ensure operation fails.
|
|
128
|
+
*
|
|
129
|
+
* Includes step information for diagnosing partial failures,
|
|
130
|
+
* since DDL is not reliably transactional on all databases (especially MySQL).
|
|
131
|
+
*/
|
|
132
|
+
export declare class EnsureError extends DatabaseError {
|
|
133
|
+
/** The operation that failed */
|
|
134
|
+
readonly operation: EnsureOperation;
|
|
135
|
+
/** The table being operated on */
|
|
136
|
+
readonly table: string;
|
|
137
|
+
/** The step index where failure occurred (0-based) */
|
|
138
|
+
readonly step: number;
|
|
139
|
+
constructor(message: string, details: {
|
|
140
|
+
operation: EnsureOperation;
|
|
141
|
+
table: string;
|
|
142
|
+
step: number;
|
|
143
|
+
}, options?: ErrorOptions);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Thrown when schema drift is detected.
|
|
147
|
+
*
|
|
148
|
+
* Schema drift occurs when an existing database object doesn't match
|
|
149
|
+
* the expected schema definition. For example, a column exists but
|
|
150
|
+
* has a different type, or an index covers different columns.
|
|
151
|
+
*/
|
|
152
|
+
export declare class SchemaDriftError extends DatabaseError {
|
|
153
|
+
/** The table where drift was detected */
|
|
154
|
+
readonly table: string;
|
|
155
|
+
/** Description of what drifted */
|
|
156
|
+
readonly drift: string;
|
|
157
|
+
/** Suggested action to resolve */
|
|
158
|
+
readonly suggestion?: string;
|
|
159
|
+
constructor(message: string, details: {
|
|
160
|
+
table: string;
|
|
161
|
+
drift: string;
|
|
162
|
+
suggestion?: string;
|
|
163
|
+
}, options?: ErrorOptions);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Thrown when a constraint preflight check finds violations.
|
|
167
|
+
*
|
|
168
|
+
* Before adding a UNIQUE constraint or foreign key to existing data,
|
|
169
|
+
* a preflight check verifies data integrity. This error is thrown
|
|
170
|
+
* when violations are found, including the query used to detect them.
|
|
171
|
+
*/
|
|
172
|
+
export declare class ConstraintPreflightError extends DatabaseError {
|
|
173
|
+
/** The table being constrained */
|
|
174
|
+
readonly table: string;
|
|
175
|
+
/** The constraint being added (e.g., "unique:email" or "fk:authorId") */
|
|
176
|
+
readonly constraint: string;
|
|
177
|
+
/** Number of violating rows */
|
|
178
|
+
readonly violationCount: number;
|
|
179
|
+
/** The SQL query that found the violations - run it to see details */
|
|
180
|
+
readonly query: string;
|
|
181
|
+
constructor(message: string, details: {
|
|
182
|
+
table: string;
|
|
183
|
+
constraint: string;
|
|
184
|
+
violationCount: number;
|
|
185
|
+
query: string;
|
|
186
|
+
}, options?: ErrorOptions);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Check if an error is a DatabaseError.
|
|
190
|
+
*/
|
|
191
|
+
export declare function isDatabaseError(error: unknown): error is DatabaseError;
|
|
192
|
+
/**
|
|
193
|
+
* Check if an error has a specific error code.
|
|
194
|
+
*/
|
|
195
|
+
export declare function hasErrorCode(error: unknown, code: DatabaseErrorCode): error is DatabaseError;
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query layer - tagged template SQL with parameterized queries.
|
|
3
|
+
*
|
|
4
|
+
* Generates SELECT statements with prefixed column aliases for entity normalization.
|
|
5
|
+
*/
|
|
6
|
+
import { type Table, type DriverDecoder } from "./table.js";
|
|
7
|
+
import { type SQLTemplate } from "./template.js";
|
|
8
|
+
import { type SQLDialect } from "./sql.js";
|
|
9
|
+
export type { SQLDialect } from "./sql.js";
|
|
10
|
+
export interface QueryOptions {
|
|
11
|
+
dialect?: SQLDialect;
|
|
12
|
+
}
|
|
13
|
+
export interface ParsedQuery {
|
|
14
|
+
sql: string;
|
|
15
|
+
params: unknown[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Render a SQL template to {sql, params} format.
|
|
19
|
+
* Useful for testing and debugging template output.
|
|
20
|
+
*
|
|
21
|
+
* @param template - SQLTemplate tuple [strings, ...values]
|
|
22
|
+
* @param dialect - SQL dialect for identifier quoting (default: sqlite)
|
|
23
|
+
* @returns {sql, params} for the rendered template
|
|
24
|
+
*/
|
|
25
|
+
export declare function renderFragment(template: SQLTemplate, dialect?: SQLDialect): {
|
|
26
|
+
sql: string;
|
|
27
|
+
params: unknown[];
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Build SELECT clause as a template with ident markers.
|
|
31
|
+
*
|
|
32
|
+
* Returns a template tuple that can be rendered with renderSQL().
|
|
33
|
+
* All identifiers use ident() markers instead of dialect-specific quoting.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* const {strings, values} = buildSelectColumnsTemplate([posts, users]);
|
|
37
|
+
* // values contains ident markers: [ident("posts"), ident("id"), ident("posts.id"), ...]
|
|
38
|
+
*/
|
|
39
|
+
export declare function buildSelectColumnsTemplate(tables: Table<any>[]): {
|
|
40
|
+
strings: TemplateStringsArray;
|
|
41
|
+
values: unknown[];
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Build SELECT clause with prefixed column aliases.
|
|
45
|
+
*
|
|
46
|
+
* For derived tables (created via Table.derive()), this function:
|
|
47
|
+
* - Skips derived fields when outputting regular columns
|
|
48
|
+
* - Appends derived SQL expressions with auto-generated aliases
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* buildSelectColumns([posts, users], "sqlite")
|
|
52
|
+
* // { sql: '"posts"."id" AS "posts.id", ...', params: [] }
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* // With derived table
|
|
56
|
+
* const PostsWithCount = Posts.derive('likeCount', z.number())`COUNT(*)`;
|
|
57
|
+
* buildSelectColumns([PostsWithCount], "sqlite")
|
|
58
|
+
* // { sql: '"posts"."id" AS "posts.id", ..., COUNT(*) AS "posts.likeCount"', params: [] }
|
|
59
|
+
*/
|
|
60
|
+
export declare function buildSelectColumns(tables: Table<any>[], dialect?: SQLDialect): {
|
|
61
|
+
sql: string;
|
|
62
|
+
params: unknown[];
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Expand a template by flattening nested fragments and converting tables to ident markers.
|
|
66
|
+
*
|
|
67
|
+
* This produces a flat template tuple with:
|
|
68
|
+
* - SQLTemplate tuples merged in
|
|
69
|
+
* - Table objects converted to ident() markers
|
|
70
|
+
* - Regular values passed through
|
|
71
|
+
*
|
|
72
|
+
* The result can be rendered with renderSQL() for final SQL output.
|
|
73
|
+
*
|
|
74
|
+
* @param strings - Template strings
|
|
75
|
+
* @param values - Template values
|
|
76
|
+
* @returns Flat template tuple {strings, values}
|
|
77
|
+
*/
|
|
78
|
+
export declare function expandTemplate(strings: TemplateStringsArray, values: unknown[]): {
|
|
79
|
+
strings: TemplateStringsArray;
|
|
80
|
+
values: unknown[];
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Parse a tagged template into SQL string and params array.
|
|
84
|
+
*
|
|
85
|
+
* Supports:
|
|
86
|
+
* - SQL templates/fragments: merged and parameterized
|
|
87
|
+
* - Table objects: interpolated as quoted table names
|
|
88
|
+
* - Other values: become parameterized placeholders
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* parseTemplate`WHERE id = ${userId} AND active = ${true}`
|
|
92
|
+
* // { sql: "WHERE id = ? AND active = ?", params: ["user-123", true] }
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* parseTemplate`WHERE ${where(Users, { role: "admin" })}`
|
|
96
|
+
* // { sql: "WHERE role = ?", params: ["admin"] }
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* parseTemplate`FROM ${Posts} JOIN ${Users} ON ...`
|
|
100
|
+
* // { sql: 'FROM "posts" JOIN "users" ON ...', params: [] }
|
|
101
|
+
*/
|
|
102
|
+
export declare function parseTemplate(strings: TemplateStringsArray, values: unknown[], dialect?: SQLDialect): ParsedQuery;
|
|
103
|
+
/**
|
|
104
|
+
* Build a full SELECT query as a template with ident markers.
|
|
105
|
+
*
|
|
106
|
+
* Returns a template tuple that can be rendered with renderSQL().
|
|
107
|
+
* The userClauses string is appended as-is (it should already contain placeholders).
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* const {strings, values} = buildQueryTemplate([posts, users], "WHERE published = ?");
|
|
111
|
+
* // values contains ident markers plus any params from derived expressions
|
|
112
|
+
*/
|
|
113
|
+
/**
|
|
114
|
+
* @internal
|
|
115
|
+
* Build a query template from tables and raw SQL clauses.
|
|
116
|
+
*
|
|
117
|
+
* WARNING: userClauses is appended verbatim as raw SQL. Do not pass untrusted input.
|
|
118
|
+
* For parameterized queries, use Database methods or tagged templates instead.
|
|
119
|
+
*/
|
|
120
|
+
export declare function buildQueryTemplate(tables: Table<any>[], userClauses?: string): {
|
|
121
|
+
strings: TemplateStringsArray;
|
|
122
|
+
values: unknown[];
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* @internal
|
|
126
|
+
* Build a full SELECT query for tables with user-provided clauses.
|
|
127
|
+
*
|
|
128
|
+
* WARNING: userClauses is appended verbatim as raw SQL. Do not pass untrusted input.
|
|
129
|
+
* For parameterized queries, use Database methods or tagged templates instead.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* buildQuery([posts, users], "JOIN users ON users.id = posts.author_id WHERE published = ?", "sqlite")
|
|
133
|
+
*/
|
|
134
|
+
export declare function buildQuery(tables: Table<any>[], userClauses: string, dialect?: SQLDialect): {
|
|
135
|
+
sql: string;
|
|
136
|
+
params: unknown[];
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* Create a tagged template function for querying tables.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* const query = createQuery([posts, users], "sqlite");
|
|
143
|
+
* const { sql, params } = query`
|
|
144
|
+
* JOIN users ON users.id = posts.author_id
|
|
145
|
+
* WHERE published = ${true}
|
|
146
|
+
* `;
|
|
147
|
+
*/
|
|
148
|
+
export declare function createQuery(tables: Table<any>[], dialect?: SQLDialect): (strings: TemplateStringsArray, ...values: unknown[]) => ParsedQuery;
|
|
149
|
+
/**
|
|
150
|
+
* Parse a raw SQL template (no table-based SELECT generation).
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* const { sql, params } = rawQuery`SELECT COUNT(*) FROM posts WHERE author_id = ${userId}`;
|
|
154
|
+
*/
|
|
155
|
+
export declare function rawQuery(strings: TemplateStringsArray, ...values: unknown[]): ParsedQuery;
|
|
156
|
+
/**
|
|
157
|
+
* Create a raw query function for a specific dialect.
|
|
158
|
+
*/
|
|
159
|
+
export declare function createRawQuery(dialect: SQLDialect): (strings: TemplateStringsArray, ...values: unknown[]) => ParsedQuery;
|
|
160
|
+
/**
|
|
161
|
+
* Entity normalization - Apollo-style entity deduplication with reference resolution.
|
|
162
|
+
*
|
|
163
|
+
* Takes raw SQL results with prefixed columns and returns normalized entities
|
|
164
|
+
* with references resolved to actual object instances.
|
|
165
|
+
*/
|
|
166
|
+
/**
|
|
167
|
+
* Raw row from SQL query with prefixed column names.
|
|
168
|
+
* @example { "posts.id": "p1", "posts.authorId": "u1", "users.id": "u1", "users.name": "Alice" }
|
|
169
|
+
*/
|
|
170
|
+
export type RawRow = Record<string, unknown>;
|
|
171
|
+
/**
|
|
172
|
+
* Entity map keyed by "table:primaryKey"
|
|
173
|
+
*/
|
|
174
|
+
export type EntityMap = Map<string, Record<string, unknown>>;
|
|
175
|
+
/**
|
|
176
|
+
* Table map by table name for lookup
|
|
177
|
+
*/
|
|
178
|
+
export type TableMap = Map<string, Table<any>>;
|
|
179
|
+
/**
|
|
180
|
+
* Extract entity data from a raw row for a specific table.
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* extractEntityData({ "posts.id": "p1", "users.id": "u1" }, "posts")
|
|
184
|
+
* // { id: "p1" }
|
|
185
|
+
*/
|
|
186
|
+
export declare function extractEntityData(row: RawRow, tableName: string): Record<string, unknown> | null;
|
|
187
|
+
/**
|
|
188
|
+
* Get the primary key value for an entity.
|
|
189
|
+
*/
|
|
190
|
+
export declare function getPrimaryKeyValue(entity: Record<string, unknown>, table: Table<any>): string | null;
|
|
191
|
+
/**
|
|
192
|
+
* Create entity key for the entity map.
|
|
193
|
+
*/
|
|
194
|
+
export declare function entityKey(tableName: string, primaryKey: string): string;
|
|
195
|
+
/**
|
|
196
|
+
* Build an entity map from raw rows.
|
|
197
|
+
*
|
|
198
|
+
* Entities are deduplicated - same primary key = same object instance.
|
|
199
|
+
* Each entity is parsed through its table's schema for type coercion
|
|
200
|
+
* (e.g., z.coerce.date() converts date strings to Date objects).
|
|
201
|
+
*/
|
|
202
|
+
export declare function buildEntityMap(rows: RawRow[], tables: Table<any>[], driver?: DriverDecoder): EntityMap;
|
|
203
|
+
/**
|
|
204
|
+
* Resolve references for all entities in the map.
|
|
205
|
+
*
|
|
206
|
+
* Resolves both forward references (belongs-to) and reverse references (has-many).
|
|
207
|
+
*
|
|
208
|
+
* **Forward references** (`as`): Populates referenced entity as a single object.
|
|
209
|
+
* **Reverse references** (`reverseAs`): Populates array of referencing entities.
|
|
210
|
+
*
|
|
211
|
+
* **Performance**: Uses indexing to avoid O(n²) scans - builds index once per table,
|
|
212
|
+
* then attaches in O(n).
|
|
213
|
+
*
|
|
214
|
+
* **Ordering**: Reverse relationship arrays follow query result order, which is
|
|
215
|
+
* database-dependent unless you specify ORDER BY in your SQL.
|
|
216
|
+
*/
|
|
217
|
+
export declare function resolveReferences(entities: EntityMap, tables: Table<any>[]): void;
|
|
218
|
+
/**
|
|
219
|
+
* Apply derived properties to entities.
|
|
220
|
+
*
|
|
221
|
+
* Derived properties are non-enumerable lazy getters that transform already-fetched data.
|
|
222
|
+
* They must be pure functions (no I/O, no side effects).
|
|
223
|
+
*/
|
|
224
|
+
export declare function applyDerivedProperties(entities: EntityMap, tables: Table<any>[]): void;
|
|
225
|
+
/**
|
|
226
|
+
* Extract main table entities from the entity map in row order.
|
|
227
|
+
*
|
|
228
|
+
* Maintains the order from the original query results.
|
|
229
|
+
*/
|
|
230
|
+
export declare function extractMainEntities<T>(rows: RawRow[], mainTable: Table<any>, entities: EntityMap): T[];
|
|
231
|
+
/**
|
|
232
|
+
* Normalize raw SQL rows into deduplicated entities with resolved references.
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* const rows = [
|
|
236
|
+
* { "posts.id": "p1", "posts.authorId": "u1", "users.id": "u1", "users.name": "Alice" },
|
|
237
|
+
* { "posts.id": "p2", "posts.authorId": "u1", "users.id": "u1", "users.name": "Alice" },
|
|
238
|
+
* ];
|
|
239
|
+
*
|
|
240
|
+
* const posts = normalize(rows, [posts, users]);
|
|
241
|
+
* // posts[0].author === posts[1].author // Same instance!
|
|
242
|
+
*/
|
|
243
|
+
export declare function normalize<T>(rows: RawRow[], tables: Table<any>[], driver?: DriverDecoder): T[];
|
|
244
|
+
/**
|
|
245
|
+
* Normalize a single row into an entity.
|
|
246
|
+
*
|
|
247
|
+
* Returns null if the main table has no data (e.g., no match).
|
|
248
|
+
*/
|
|
249
|
+
export declare function normalizeOne<T>(row: RawRow | null, tables: Table<any>[], driver?: DriverDecoder): T | null;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQL rendering utilities for all dialects.
|
|
3
|
+
*
|
|
4
|
+
* This is the single source of truth for dialect-specific SQL rendering:
|
|
5
|
+
* - Identifier quoting
|
|
6
|
+
* - Placeholder syntax
|
|
7
|
+
* - SQL builtin resolution
|
|
8
|
+
* - Template rendering (for DDL and queries)
|
|
9
|
+
*/
|
|
10
|
+
export type SQLDialect = "sqlite" | "postgresql" | "mysql";
|
|
11
|
+
/**
|
|
12
|
+
* Quote an identifier based on dialect.
|
|
13
|
+
* MySQL uses backticks, PostgreSQL/SQLite use double quotes.
|
|
14
|
+
*/
|
|
15
|
+
export declare function quoteIdent(name: string, dialect: SQLDialect): string;
|
|
16
|
+
/**
|
|
17
|
+
* Get placeholder syntax based on dialect.
|
|
18
|
+
* PostgreSQL uses $1, $2, etc. MySQL/SQLite use ?.
|
|
19
|
+
*/
|
|
20
|
+
export declare function placeholder(index: number, dialect: SQLDialect): string;
|
|
21
|
+
export { resolveSQLBuiltin } from "./builtins.js";
|
|
22
|
+
/**
|
|
23
|
+
* Render a template to SQL string with parameters.
|
|
24
|
+
* Handles SQLIdentifier markers and regular values.
|
|
25
|
+
*/
|
|
26
|
+
export declare function renderSQL(strings: TemplateStringsArray, values: readonly unknown[], dialect: SQLDialect): {
|
|
27
|
+
sql: string;
|
|
28
|
+
params: unknown[];
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Render a DDL template to SQL string.
|
|
32
|
+
* Handles identifiers (quoted), SQL builtins (resolved), and literal values (escaped/inlined).
|
|
33
|
+
* Used for CREATE TABLE, CREATE VIEW, etc.
|
|
34
|
+
*/
|
|
35
|
+
export declare function renderDDL(strings: TemplateStringsArray, values: readonly unknown[], dialect: SQLDialect): string;
|
|
36
|
+
/**
|
|
37
|
+
* Build SQL from template parts with parameter placeholders.
|
|
38
|
+
*
|
|
39
|
+
* This is the shared implementation used by all Node drivers (MySQL, PostgreSQL, SQLite).
|
|
40
|
+
* Handles SQLBuiltin symbols, SQLIdentifiers, and regular parameter values.
|
|
41
|
+
*
|
|
42
|
+
* SQL builtins and identifiers are inlined directly; other values use placeholders.
|
|
43
|
+
*/
|
|
44
|
+
export declare function buildSQL(strings: TemplateStringsArray, values: unknown[], dialect: SQLDialect): {
|
|
45
|
+
sql: string;
|
|
46
|
+
params: unknown[];
|
|
47
|
+
};
|