turbine-orm 0.4.0 → 0.7.0
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 +243 -26
- package/dist/cjs/cli/config.js +151 -0
- package/dist/cjs/cli/index.js +1176 -0
- package/dist/cjs/cli/migrate.js +446 -0
- package/dist/cjs/cli/ui.js +233 -0
- package/dist/cjs/client.js +512 -0
- package/dist/cjs/errors.js +293 -0
- package/dist/cjs/generate.js +321 -0
- package/dist/cjs/index.js +94 -0
- package/dist/cjs/introspect.js +287 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/pipeline.js +78 -0
- package/dist/cjs/query.js +1891 -0
- package/dist/cjs/schema-builder.js +238 -0
- package/dist/cjs/schema-sql.js +509 -0
- package/dist/cjs/schema.js +140 -0
- package/dist/cjs/serverless.js +110 -0
- package/dist/cli/config.js +6 -16
- package/dist/cli/index.js +256 -49
- package/dist/cli/migrate.d.ts +35 -6
- package/dist/cli/migrate.js +124 -76
- package/dist/cli/ui.js +5 -9
- package/dist/client.d.ts +87 -3
- package/dist/client.js +122 -46
- package/dist/errors.d.ts +138 -0
- package/dist/errors.js +278 -0
- package/dist/generate.js +37 -11
- package/dist/index.d.ts +10 -8
- package/dist/index.js +15 -11
- package/dist/introspect.js +3 -5
- package/dist/pipeline.js +8 -1
- package/dist/query.d.ts +310 -45
- package/dist/query.js +565 -237
- package/dist/schema-builder.js +91 -23
- package/dist/schema-sql.d.ts +6 -2
- package/dist/schema-sql.js +180 -26
- package/dist/schema.js +4 -1
- package/dist/serverless.d.ts +91 -139
- package/dist/serverless.js +86 -173
- package/package.json +44 -21
- package/dist/cli/config.d.ts.map +0 -1
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/migrate.d.ts.map +0 -1
- package/dist/cli/ui.d.ts.map +0 -1
- package/dist/client.d.ts.map +0 -1
- package/dist/generate.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/introspect.d.ts.map +0 -1
- package/dist/pipeline.d.ts.map +0 -1
- package/dist/query.d.ts.map +0 -1
- package/dist/schema-builder.d.ts.map +0 -1
- package/dist/schema-sql.d.ts.map +0 -1
- package/dist/schema.d.ts.map +0 -1
- package/dist/serverless.d.ts.map +0 -1
- package/dist/types.d.ts +0 -93
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -126
package/dist/generate.js
CHANGED
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Output goes to the specified directory (default: ./generated/turbine/).
|
|
10
10
|
*/
|
|
11
|
-
import {
|
|
12
|
-
import { join } from 'node:path';
|
|
13
|
-
import {
|
|
11
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
12
|
+
import { join, relative, resolve } from 'node:path';
|
|
13
|
+
import { singularize, snakeToPascal } from './schema.js';
|
|
14
14
|
/** Get the TypeScript type name for a table (singularized PascalCase) */
|
|
15
15
|
function entityName(tableName) {
|
|
16
16
|
return snakeToPascal(singularize(tableName));
|
|
@@ -24,6 +24,12 @@ function escSQ(value) {
|
|
|
24
24
|
// ---------------------------------------------------------------------------
|
|
25
25
|
export function generate(options) {
|
|
26
26
|
const outDir = options.outDir ?? './generated/turbine';
|
|
27
|
+
// Path traversal protection — ensure output stays within project root
|
|
28
|
+
const resolved = resolve(outDir);
|
|
29
|
+
const rel = relative(process.cwd(), resolved);
|
|
30
|
+
if (rel.startsWith('..') || resolve(rel) !== resolved) {
|
|
31
|
+
throw new Error(`Output directory must be within the project root. Got: ${outDir}`);
|
|
32
|
+
}
|
|
27
33
|
mkdirSync(outDir, { recursive: true });
|
|
28
34
|
const files = [];
|
|
29
35
|
// Generate types.ts
|
|
@@ -49,15 +55,13 @@ function generatedFileHeader() {
|
|
|
49
55
|
' * Auto-generated by turbine-orm — DO NOT EDIT',
|
|
50
56
|
' *',
|
|
51
57
|
` * Generated at: ${new Date().toISOString()}`,
|
|
52
|
-
' * @see https://
|
|
58
|
+
' * @see https://turbineorm.dev',
|
|
53
59
|
' */',
|
|
54
60
|
'',
|
|
55
61
|
];
|
|
56
62
|
}
|
|
57
63
|
function generateTypes(schema) {
|
|
58
|
-
const lines = [
|
|
59
|
-
...generatedFileHeader(),
|
|
60
|
-
];
|
|
64
|
+
const lines = [...generatedFileHeader()];
|
|
61
65
|
// Generate enum types
|
|
62
66
|
for (const [enumName, labels] of Object.entries(schema.enums)) {
|
|
63
67
|
const typeName = snakeToPascal(enumName);
|
|
@@ -107,9 +111,23 @@ function generateTypes(schema) {
|
|
|
107
111
|
}
|
|
108
112
|
lines.push('};');
|
|
109
113
|
lines.push('');
|
|
110
|
-
// ---
|
|
114
|
+
// --- Relations map (for type-safe `with` clauses) ---
|
|
111
115
|
const hasRelations = Object.keys(table.relations).length > 0;
|
|
112
116
|
if (hasRelations) {
|
|
117
|
+
lines.push(`/** Available relations for the \`${table.name}\` table */`);
|
|
118
|
+
lines.push(`export interface ${typeName}Relations {`);
|
|
119
|
+
for (const [relName, rel] of Object.entries(table.relations)) {
|
|
120
|
+
const targetType = entityName(rel.to);
|
|
121
|
+
if (rel.type === 'hasMany') {
|
|
122
|
+
lines.push(` ${relName}: ${targetType}[];`);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
lines.push(` ${relName}: ${targetType} | null;`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
lines.push('}');
|
|
129
|
+
lines.push('');
|
|
130
|
+
// --- Legacy per-relation interfaces (kept for backward compatibility) ---
|
|
113
131
|
for (const [relName, rel] of Object.entries(table.relations)) {
|
|
114
132
|
const targetType = entityName(rel.to);
|
|
115
133
|
if (rel.type === 'hasMany') {
|
|
@@ -213,8 +231,14 @@ function generateIndex(schema) {
|
|
|
213
231
|
"import type { TurbineConfig } from 'turbine-orm';",
|
|
214
232
|
"import { SCHEMA } from './metadata.js';",
|
|
215
233
|
];
|
|
216
|
-
// Import all entity types
|
|
217
|
-
const typeImports =
|
|
234
|
+
// Import all entity types and relations maps
|
|
235
|
+
const typeImports = [];
|
|
236
|
+
for (const t of tableEntries) {
|
|
237
|
+
typeImports.push(entityName(t.name));
|
|
238
|
+
if (Object.keys(t.relations).length > 0) {
|
|
239
|
+
typeImports.push(`${entityName(t.name)}Relations`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
218
242
|
lines.push(`import type { ${typeImports.join(', ')} } from './types.js';`);
|
|
219
243
|
lines.push('');
|
|
220
244
|
// Generate the client class with JSDoc
|
|
@@ -240,8 +264,10 @@ function generateIndex(schema) {
|
|
|
240
264
|
for (const table of tableEntries) {
|
|
241
265
|
const typeName = entityName(table.name);
|
|
242
266
|
const accessor = snakeToCamelStr(table.name);
|
|
267
|
+
const hasRelations = Object.keys(table.relations).length > 0;
|
|
268
|
+
const genericArgs = hasRelations ? `${typeName}, ${typeName}Relations` : typeName;
|
|
243
269
|
lines.push(` /** Query interface for the \`${table.name}\` table */`);
|
|
244
|
-
lines.push(` declare readonly ${accessor}: QueryInterface<${
|
|
270
|
+
lines.push(` declare readonly ${accessor}: QueryInterface<${genericArgs}>;`);
|
|
245
271
|
}
|
|
246
272
|
lines.push('');
|
|
247
273
|
lines.push(' constructor(config?: TurbineConfig) {');
|
package/dist/index.d.ts
CHANGED
|
@@ -32,13 +32,15 @@
|
|
|
32
32
|
* await db.disconnect();
|
|
33
33
|
* ```
|
|
34
34
|
*/
|
|
35
|
-
export {
|
|
36
|
-
export {
|
|
35
|
+
export { type Middleware, type MiddlewareNext, type MiddlewareParams, type PgCompatPool, type PgCompatPoolClient, type PgCompatQueryResult, TransactionClient, type TransactionOptions, TurbineClient, type TurbineConfig, } from './client.js';
|
|
36
|
+
export { CheckConstraintError, CircularRelationError, ConnectionError, ForeignKeyError, MigrationError, NotFoundError, NotNullViolationError, RelationError, TimeoutError, TurbineError, TurbineErrorCode, UniqueConstraintError, ValidationError, wrapPgError, } from './errors.js';
|
|
37
|
+
export { type GenerateOptions, generate } from './generate.js';
|
|
38
|
+
export { type IntrospectOptions, introspect } from './introspect.js';
|
|
37
39
|
export { executePipeline, type PipelineResults } from './pipeline.js';
|
|
38
|
-
export type
|
|
39
|
-
export {
|
|
40
|
-
export {
|
|
41
|
-
export {
|
|
42
|
-
export {
|
|
43
|
-
export {
|
|
40
|
+
export { type AggregateArgs, type AggregateResult, type ArrayFilter, type CountArgs, type CreateArgs, type CreateManyArgs, type DeferredQuery, type DeleteArgs, type DeleteManyArgs, type FindManyArgs, type FindManyStreamArgs, type FindUniqueArgs, type GroupByArgs, type JsonFilter, type OrderDirection, QueryInterface, type RelationFilter, type TypedWithClause, type UpdateArgs, type UpdateInput, type UpdateManyArgs, type UpdateOperatorInput, type UpsertArgs, type WithClause, type WithOptions, type WithResult, } from './query.js';
|
|
41
|
+
export type { ColumnMetadata, IndexMetadata, RelationDef, SchemaMetadata, TableMetadata, } from './schema.js';
|
|
42
|
+
export { camelToSnake, isDateType, pgArrayType, pgTypeToTs, singularize, snakeToCamel, snakeToPascal, } from './schema.js';
|
|
43
|
+
export { ColumnBuilder, type ColumnConfig, type ColumnDef, type ColumnType, type ColumnTypeName, column, defineSchema, type SchemaDef, type TableDef, table, } from './schema-builder.js';
|
|
44
|
+
export { type AlterColumnDef, type AlterDef, type DiffResult, type PushResult, schemaDiff, schemaPush, schemaToSQL, schemaToSQLString, } from './schema-sql.js';
|
|
45
|
+
export { type TurbineHttpOptions, turbineHttp } from './serverless.js';
|
|
44
46
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -33,21 +33,25 @@
|
|
|
33
33
|
* ```
|
|
34
34
|
*/
|
|
35
35
|
// Client
|
|
36
|
-
export {
|
|
37
|
-
//
|
|
38
|
-
export {
|
|
36
|
+
export { TransactionClient, TurbineClient, } from './client.js';
|
|
37
|
+
// Error types
|
|
38
|
+
export { CheckConstraintError, CircularRelationError, ConnectionError, ForeignKeyError, MigrationError, NotFoundError, NotNullViolationError, RelationError, TimeoutError, TurbineError, TurbineErrorCode, UniqueConstraintError, ValidationError, wrapPgError, } from './errors.js';
|
|
39
|
+
// Code generation
|
|
40
|
+
export { generate } from './generate.js';
|
|
41
|
+
// Introspection
|
|
42
|
+
export { introspect } from './introspect.js';
|
|
39
43
|
// Pipeline
|
|
40
44
|
export { executePipeline } from './pipeline.js';
|
|
45
|
+
// Query builder
|
|
46
|
+
export { QueryInterface, } from './query.js';
|
|
41
47
|
// Schema utilities
|
|
42
|
-
export {
|
|
43
|
-
// Introspection
|
|
44
|
-
export { introspect } from './introspect.js';
|
|
45
|
-
// Code generation
|
|
46
|
-
export { generate } from './generate.js';
|
|
48
|
+
export { camelToSnake, isDateType, pgArrayType, pgTypeToTs, singularize, snakeToCamel, snakeToPascal, } from './schema.js';
|
|
47
49
|
// Schema builder — define schemas in TypeScript
|
|
48
|
-
export { defineSchema,
|
|
50
|
+
export { ColumnBuilder, column, defineSchema,
|
|
49
51
|
// Legacy compat (deprecated — use object format with defineSchema)
|
|
50
|
-
table,
|
|
52
|
+
table, } from './schema-builder.js';
|
|
51
53
|
// Schema SQL — generate DDL, diff, and push
|
|
52
|
-
export {
|
|
54
|
+
export { schemaDiff, schemaPush, schemaToSQL, schemaToSQLString, } from './schema-sql.js';
|
|
55
|
+
// Serverless / edge factory
|
|
56
|
+
export { turbineHttp } from './serverless.js';
|
|
53
57
|
//# sourceMappingURL=index.js.map
|
package/dist/introspect.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* This is the foundation of `npx turbine generate`.
|
|
9
9
|
*/
|
|
10
10
|
import pg from 'pg';
|
|
11
|
-
import {
|
|
11
|
+
import { isDateType, pgArrayType, pgTypeToTs, singularize, snakeToCamel, } from './schema.js';
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
13
|
// SQL queries (all parameterized, no interpolation)
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
@@ -99,7 +99,7 @@ export async function introspect(options) {
|
|
|
99
99
|
});
|
|
100
100
|
try {
|
|
101
101
|
// Run all information_schema queries in parallel
|
|
102
|
-
const [tablesResult, columnsResult, pkResult, fkResult, uniqueResult, indexResult, enumResult
|
|
102
|
+
const [tablesResult, columnsResult, pkResult, fkResult, uniqueResult, indexResult, enumResult] = await Promise.all([
|
|
103
103
|
pool.query(SQL_TABLES, [schema]),
|
|
104
104
|
pool.query(SQL_COLUMNS, [schema]),
|
|
105
105
|
pool.query(SQL_PRIMARY_KEYS, [schema]),
|
|
@@ -172,9 +172,7 @@ export async function introspect(options) {
|
|
|
172
172
|
const isUnique = row.indexdef.includes('UNIQUE');
|
|
173
173
|
// Extract column names from indexdef (e.g. "CREATE INDEX idx ON tbl USING btree (col1, col2)")
|
|
174
174
|
const colMatch = row.indexdef.match(/\((.+)\)/);
|
|
175
|
-
const columns = colMatch
|
|
176
|
-
? colMatch[1].split(',').map((c) => c.trim().replace(/ (ASC|DESC)/i, ''))
|
|
177
|
-
: [];
|
|
175
|
+
const columns = colMatch ? colMatch[1].split(',').map((c) => c.trim().replace(/ (ASC|DESC)/i, '')) : [];
|
|
178
176
|
indexesByTable.get(row.tablename).push({
|
|
179
177
|
name: row.indexname,
|
|
180
178
|
columns,
|
package/dist/pipeline.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* we simulate it by running queries concurrently on a single connection or via
|
|
16
16
|
* a multi-statement batch.
|
|
17
17
|
*/
|
|
18
|
+
import { wrapPgError } from './errors.js';
|
|
18
19
|
// ---------------------------------------------------------------------------
|
|
19
20
|
// Pipeline executor
|
|
20
21
|
// ---------------------------------------------------------------------------
|
|
@@ -52,7 +53,13 @@ export async function executePipeline(pool, queries) {
|
|
|
52
53
|
// Future: use actual Postgres pipeline protocol for true pipelining.
|
|
53
54
|
const results = [];
|
|
54
55
|
for (const q of queries) {
|
|
55
|
-
|
|
56
|
+
let raw;
|
|
57
|
+
try {
|
|
58
|
+
raw = await client.query(q.sql, q.params);
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
throw wrapPgError(err);
|
|
62
|
+
}
|
|
56
63
|
results.push(q.transform(raw));
|
|
57
64
|
}
|
|
58
65
|
await client.query('COMMIT');
|