alepha 0.10.6 → 0.11.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/api/files.d.ts +336 -175
- package/api/jobs.d.ts +139 -195
- package/api/notifications.cjs +8 -0
- package/api/notifications.d.ts +264 -0
- package/api/notifications.js +1 -0
- package/api/users.d.ts +790 -261
- package/api/verifications.cjs +8 -0
- package/api/verifications.d.ts +1 -0
- package/api/verifications.js +1 -0
- package/batch.d.ts +1 -1
- package/bucket.d.ts +1 -195
- package/cache.d.ts +1 -1
- package/core.d.ts +301 -189
- package/datetime.d.ts +41 -10
- package/email.d.ts +41 -225
- package/logger.d.ts +19 -10
- package/package.json +70 -62
- package/postgres.d.ts +624 -1284
- package/react/auth.d.ts +1 -1
- package/react/form.d.ts +19 -8
- package/react/i18n.d.ts +8 -5
- package/react.d.ts +30 -10
- package/scheduler.d.ts +12 -2
- package/server/cache.d.ts +86 -11
- package/server/health.d.ts +31 -8
- package/server/multipart.d.ts +2 -2
- package/server/swagger.d.ts +6 -1
- package/server.d.ts +43 -29
- package/ui.cjs +8 -0
- package/ui.d.ts +619 -0
- package/ui.js +1 -0
- package/vite.d.ts +12 -5
package/postgres.d.ts
CHANGED
|
@@ -1,80 +1,23 @@
|
|
|
1
1
|
import * as _alepha_core1 from "alepha";
|
|
2
|
-
import { Alepha, AlephaError, Descriptor,
|
|
3
|
-
import * as drizzle_orm6 from "drizzle-orm";
|
|
4
|
-
import { BuildColumns, BuildExtraConfigColumns, SQL, SQLWrapper, TableConfig, sql } from "drizzle-orm";
|
|
5
|
-
import * as pg$1 from "drizzle-orm/pg-core";
|
|
6
|
-
import { AnyPgColumn, AnyPgTable, LockConfig, LockStrength, PgColumn, PgColumnBuilderBase, PgDatabase, PgInsertValue, PgSequenceOptions, PgTableExtraConfigValue, PgTableWithColumns, PgTransaction, PgTransactionConfig, SelectedFields, TableConfig as TableConfig$1, UpdateDeleteAction } from "drizzle-orm/pg-core";
|
|
2
|
+
import { Alepha, AlephaError, Descriptor, DescriptorArgs, KIND, Static, StaticEncode, TArray, TBigInt, TBoolean, TInteger, TNull, TNumber, TNumberOptions, TObject, TObjectOptions, TOptional, TOptionalAdd, TRecord, TSchema, TString, TStringOptions, TUnion, TUnsafe } from "alepha";
|
|
7
3
|
import { DateTime, DateTimeProvider } from "alepha/datetime";
|
|
8
|
-
import * as
|
|
4
|
+
import * as _alepha_logger0 from "alepha/logger";
|
|
9
5
|
import * as _alepha_lock0 from "alepha/lock";
|
|
10
|
-
import { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
11
|
-
import postgres from "postgres";
|
|
12
6
|
import * as _alepha_retry0 from "alepha/retry";
|
|
13
|
-
import * as
|
|
7
|
+
import * as drizzle_orm0 from "drizzle-orm";
|
|
8
|
+
import { BuildExtraConfigColumns, SQL, SQLWrapper, sql } from "drizzle-orm";
|
|
9
|
+
import * as drizzle_orm_pg_core0 from "drizzle-orm/pg-core";
|
|
10
|
+
import { LockConfig, LockStrength, PgColumn, PgColumnBuilderBase, PgDatabase, PgInsertValue, PgSchema, PgSelectBase, PgSequenceOptions, PgTableExtraConfigValue, PgTableWithColumns, PgTransaction, PgTransactionConfig, UpdateDeleteAction } from "drizzle-orm/pg-core";
|
|
11
|
+
import * as typebox9 from "typebox";
|
|
14
12
|
import { PgTransactionConfig as PgTransactionConfig$1 } from "drizzle-orm/pg-core/session";
|
|
15
13
|
import * as DrizzleKit from "drizzle-kit/api";
|
|
16
14
|
import { MigrationConfig } from "drizzle-orm/migrator";
|
|
15
|
+
import { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
16
|
+
import postgres from "postgres";
|
|
17
|
+
import * as dayjs0 from "dayjs";
|
|
17
18
|
import { UpdateDeleteAction as UpdateDeleteAction$1 } from "drizzle-orm/pg-core/foreign-keys";
|
|
18
19
|
export * from "drizzle-orm/pg-core";
|
|
19
20
|
|
|
20
|
-
//#region src/constants/PG_SCHEMA.d.ts
|
|
21
|
-
declare const PG_SCHEMA: unique symbol;
|
|
22
|
-
//#endregion
|
|
23
|
-
//#region src/constants/PG_SYMBOLS.d.ts
|
|
24
|
-
declare const PG_DEFAULT: unique symbol;
|
|
25
|
-
declare const PG_PRIMARY_KEY: unique symbol;
|
|
26
|
-
declare const PG_CREATED_AT: unique symbol;
|
|
27
|
-
declare const PG_UPDATED_AT: unique symbol;
|
|
28
|
-
declare const PG_DELETED_AT: unique symbol;
|
|
29
|
-
declare const PG_VERSION: unique symbol;
|
|
30
|
-
declare const PG_IDENTITY: unique symbol;
|
|
31
|
-
declare const PG_MANY: unique symbol;
|
|
32
|
-
declare const PG_ONE: unique symbol;
|
|
33
|
-
declare const PG_REF: unique symbol;
|
|
34
|
-
/**
|
|
35
|
-
* @deprecated Use `PG_IDENTITY` instead.
|
|
36
|
-
*/
|
|
37
|
-
declare const PG_SERIAL: unique symbol;
|
|
38
|
-
type PgDefault = typeof PG_DEFAULT;
|
|
39
|
-
type PgMany = typeof PG_MANY;
|
|
40
|
-
type PgOne = typeof PG_ONE;
|
|
41
|
-
type PgRef = typeof PG_REF;
|
|
42
|
-
type PgPrimaryKey = typeof PG_PRIMARY_KEY;
|
|
43
|
-
type PgSymbols = {
|
|
44
|
-
[PG_DEFAULT]: {};
|
|
45
|
-
[PG_PRIMARY_KEY]: {};
|
|
46
|
-
[PG_CREATED_AT]: {};
|
|
47
|
-
[PG_UPDATED_AT]: {};
|
|
48
|
-
[PG_DELETED_AT]: {};
|
|
49
|
-
[PG_VERSION]: {};
|
|
50
|
-
[PG_IDENTITY]: PgIdentityOptions;
|
|
51
|
-
[PG_MANY]: PgManyOptions;
|
|
52
|
-
[PG_ONE]: PgManyOptions;
|
|
53
|
-
[PG_REF]: PgRefOptions;
|
|
54
|
-
/**
|
|
55
|
-
* @deprecated Use `PG_IDENTITY` instead.
|
|
56
|
-
*/
|
|
57
|
-
[PG_SERIAL]: {};
|
|
58
|
-
};
|
|
59
|
-
type PgSymbolKeys = keyof PgSymbols;
|
|
60
|
-
type PgIdentityOptions = {
|
|
61
|
-
mode: "always" | "byDefault";
|
|
62
|
-
} & PgSequenceOptions & {
|
|
63
|
-
name?: string;
|
|
64
|
-
};
|
|
65
|
-
interface PgManyOptions {
|
|
66
|
-
table: AnyPgTable;
|
|
67
|
-
schema: TObject;
|
|
68
|
-
foreignKey: string;
|
|
69
|
-
}
|
|
70
|
-
interface PgRefOptions {
|
|
71
|
-
ref: () => AnyPgColumn;
|
|
72
|
-
actions?: {
|
|
73
|
-
onUpdate?: UpdateDeleteAction;
|
|
74
|
-
onDelete?: UpdateDeleteAction;
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
//#endregion
|
|
78
21
|
//#region src/schemas/insertSchema.d.ts
|
|
79
22
|
/**
|
|
80
23
|
* Transforms a TObject schema for insert operations.
|
|
@@ -104,484 +47,41 @@ declare const insertSchema: <T extends TObject>(obj: T) => TObjectInsert<T>;
|
|
|
104
47
|
type TObjectUpdate<T extends TObject> = TObject<{ [K in keyof T["properties"]]: T["properties"][K] extends TOptional<infer U> ? TOptional<TUnion<[U, TNull]>> : T["properties"][K] }>;
|
|
105
48
|
declare const updateSchema: <T extends TObject>(schema: T) => TObjectUpdate<T>;
|
|
106
49
|
//#endregion
|
|
107
|
-
//#region src/helpers/schemaToPgColumns.d.ts
|
|
108
|
-
/**
|
|
109
|
-
* Convert a Typebox Schema to Drizzle ORM Postgres columns
|
|
110
|
-
*/
|
|
111
|
-
declare const schemaToPgColumns: <T extends TObject>(schema: T) => FromSchema<T>;
|
|
112
|
-
/**
|
|
113
|
-
* Map a Typebox field to a PG column.
|
|
114
|
-
*
|
|
115
|
-
* @param name The key of the field.
|
|
116
|
-
* @param value The value of the field.
|
|
117
|
-
* @returns The PG column.
|
|
118
|
-
*/
|
|
119
|
-
declare const mapFieldToColumn: (name: string, value: TSchema$1) => pg$1.PgSerialBuilderInitial<string> | pg$1.PgIntegerBuilderInitial<string> | drizzle_orm6.IsIdentity<pg$1.PgBigInt64BuilderInitial<"">, "byDefault"> | drizzle_orm6.IsIdentity<pg$1.PgBigInt64BuilderInitial<"">, "always"> | pg$1.PgBigInt53BuilderInitial<string> | pg$1.PgNumericBuilderInitial<string> | pg$1.PgDateStringBuilderInitial<string> | pg$1.PgUUIDBuilderInitial<string> | pg$1.PgCustomColumnBuilder<{
|
|
120
|
-
name: string;
|
|
121
|
-
dataType: "custom";
|
|
122
|
-
columnType: "PgCustomColumn";
|
|
123
|
-
data: Buffer<ArrayBufferLike>;
|
|
124
|
-
driverParam: unknown;
|
|
125
|
-
enumValues: undefined;
|
|
126
|
-
}> | pg$1.PgTimestampStringBuilderInitial<string> | pg$1.PgTextBuilderInitial<string, [string, ...string[]]> | pg$1.PgBooleanBuilderInitial<string> | drizzle_orm6.$Type<pg$1.PgCustomColumnBuilder<{
|
|
127
|
-
name: string;
|
|
128
|
-
dataType: "custom";
|
|
129
|
-
columnType: "PgCustomColumn";
|
|
130
|
-
data: {
|
|
131
|
-
[x: string]: unknown;
|
|
132
|
-
[x: number]: unknown;
|
|
133
|
-
[x: symbol]: unknown;
|
|
134
|
-
};
|
|
135
|
-
driverParam: string;
|
|
136
|
-
enumValues: undefined;
|
|
137
|
-
}>, {
|
|
138
|
-
[x: string]: unknown;
|
|
139
|
-
[x: number]: unknown;
|
|
140
|
-
[x: symbol]: unknown;
|
|
141
|
-
}> | drizzle_orm6.$Type<pg$1.PgCustomColumnBuilder<{
|
|
142
|
-
name: string;
|
|
143
|
-
dataType: "custom";
|
|
144
|
-
columnType: "PgCustomColumn";
|
|
145
|
-
data: Record<string, unknown>;
|
|
146
|
-
driverParam: string;
|
|
147
|
-
enumValues: undefined;
|
|
148
|
-
}>, Record<string, unknown>> | drizzle_orm6.$Type<pg$1.PgCustomColumnBuilder<{
|
|
149
|
-
name: string;
|
|
150
|
-
dataType: "custom";
|
|
151
|
-
columnType: "PgCustomColumn";
|
|
152
|
-
data: unknown[];
|
|
153
|
-
driverParam: string;
|
|
154
|
-
enumValues: undefined;
|
|
155
|
-
}>, unknown[]> | pg$1.PgArrayBuilder<{
|
|
156
|
-
name: string;
|
|
157
|
-
dataType: "array";
|
|
158
|
-
columnType: "PgArray";
|
|
159
|
-
data: string[];
|
|
160
|
-
driverParam: string | string[];
|
|
161
|
-
enumValues: [string, ...string[]];
|
|
162
|
-
size: undefined;
|
|
163
|
-
baseBuilder: {
|
|
164
|
-
name: string;
|
|
165
|
-
dataType: "string";
|
|
166
|
-
columnType: "PgText";
|
|
167
|
-
data: string;
|
|
168
|
-
enumValues: [string, ...string[]];
|
|
169
|
-
driverParam: string;
|
|
170
|
-
};
|
|
171
|
-
}, {
|
|
172
|
-
name: string;
|
|
173
|
-
dataType: "string";
|
|
174
|
-
columnType: "PgText";
|
|
175
|
-
data: string;
|
|
176
|
-
enumValues: [string, ...string[]];
|
|
177
|
-
driverParam: string;
|
|
178
|
-
}> | pg$1.PgArrayBuilder<{
|
|
179
|
-
name: string;
|
|
180
|
-
dataType: "array";
|
|
181
|
-
columnType: "PgArray";
|
|
182
|
-
data: number[];
|
|
183
|
-
driverParam: string | (string | number)[];
|
|
184
|
-
enumValues: undefined;
|
|
185
|
-
size: undefined;
|
|
186
|
-
baseBuilder: {
|
|
187
|
-
name: string;
|
|
188
|
-
dataType: "number";
|
|
189
|
-
columnType: "PgInteger";
|
|
190
|
-
data: number;
|
|
191
|
-
driverParam: number | string;
|
|
192
|
-
enumValues: undefined;
|
|
193
|
-
};
|
|
194
|
-
}, {
|
|
195
|
-
name: string;
|
|
196
|
-
dataType: "number";
|
|
197
|
-
columnType: "PgInteger";
|
|
198
|
-
data: number;
|
|
199
|
-
driverParam: number | string;
|
|
200
|
-
enumValues: undefined;
|
|
201
|
-
}> | pg$1.PgArrayBuilder<{
|
|
202
|
-
name: string;
|
|
203
|
-
dataType: "array";
|
|
204
|
-
columnType: "PgArray";
|
|
205
|
-
data: string[];
|
|
206
|
-
driverParam: string | string[];
|
|
207
|
-
enumValues: undefined;
|
|
208
|
-
size: undefined;
|
|
209
|
-
baseBuilder: {
|
|
210
|
-
name: string;
|
|
211
|
-
dataType: "string";
|
|
212
|
-
columnType: "PgNumeric";
|
|
213
|
-
data: string;
|
|
214
|
-
driverParam: string;
|
|
215
|
-
enumValues: undefined;
|
|
216
|
-
};
|
|
217
|
-
}, {
|
|
218
|
-
name: string;
|
|
219
|
-
dataType: "string";
|
|
220
|
-
columnType: "PgNumeric";
|
|
221
|
-
data: string;
|
|
222
|
-
driverParam: string;
|
|
223
|
-
enumValues: undefined;
|
|
224
|
-
}> | pg$1.PgArrayBuilder<{
|
|
225
|
-
name: string;
|
|
226
|
-
dataType: "array";
|
|
227
|
-
columnType: "PgArray";
|
|
228
|
-
data: boolean[];
|
|
229
|
-
driverParam: string | boolean[];
|
|
230
|
-
enumValues: undefined;
|
|
231
|
-
size: undefined;
|
|
232
|
-
baseBuilder: {
|
|
233
|
-
name: string;
|
|
234
|
-
dataType: "boolean";
|
|
235
|
-
columnType: "PgBoolean";
|
|
236
|
-
data: boolean;
|
|
237
|
-
driverParam: boolean;
|
|
238
|
-
enumValues: undefined;
|
|
239
|
-
};
|
|
240
|
-
}, {
|
|
241
|
-
name: string;
|
|
242
|
-
dataType: "boolean";
|
|
243
|
-
columnType: "PgBoolean";
|
|
244
|
-
data: boolean;
|
|
245
|
-
driverParam: boolean;
|
|
246
|
-
enumValues: undefined;
|
|
247
|
-
}>;
|
|
248
|
-
/**
|
|
249
|
-
* Map a string to a PG column.
|
|
250
|
-
*
|
|
251
|
-
* @param key The key of the field.
|
|
252
|
-
* @param value The value of the field.
|
|
253
|
-
*/
|
|
254
|
-
declare const mapStringToColumn: (key: string, value: TSchema$1) => pg$1.PgDateStringBuilderInitial<string> | pg$1.PgUUIDBuilderInitial<string> | pg$1.PgCustomColumnBuilder<{
|
|
255
|
-
name: string;
|
|
256
|
-
dataType: "custom";
|
|
257
|
-
columnType: "PgCustomColumn";
|
|
258
|
-
data: Buffer<ArrayBufferLike>;
|
|
259
|
-
driverParam: unknown;
|
|
260
|
-
enumValues: undefined;
|
|
261
|
-
}> | pg$1.PgTimestampStringBuilderInitial<string> | pg$1.PgTextBuilderInitial<string, [string, ...string[]]>;
|
|
262
|
-
declare const camelToSnakeCase: (str: string) => string;
|
|
263
|
-
/**
|
|
264
|
-
* Convert a schema to columns.
|
|
265
|
-
*/
|
|
266
|
-
type FromSchema<T extends TObject> = { [key in keyof T["properties"]]: PgColumnBuilderBase };
|
|
267
|
-
/**
|
|
268
|
-
* A table with columns and schema.
|
|
269
|
-
*/
|
|
270
|
-
type PgTableWithColumnsAndSchema<T extends TableConfig, R extends TObject> = PgTableWithColumns<T> & {
|
|
271
|
-
get $table(): PgTableWithColumns<T>;
|
|
272
|
-
get $schema(): R;
|
|
273
|
-
get $insertSchema(): TObjectInsert<R>;
|
|
274
|
-
get $updateSchema(): TObjectUpdate<R>;
|
|
275
|
-
};
|
|
276
|
-
//#endregion
|
|
277
50
|
//#region src/descriptors/$entity.d.ts
|
|
278
51
|
/**
|
|
279
52
|
* Creates a database entity descriptor that defines table structure using TypeBox schemas.
|
|
280
53
|
*
|
|
281
|
-
* This descriptor provides a type-safe way to define database tables using JSON Schema
|
|
282
|
-
* syntax while generating the necessary database metadata for migrations and operations.
|
|
283
|
-
* It integrates with Drizzle ORM under the hood and works seamlessly with the $repository
|
|
284
|
-
* descriptor for complete database functionality.
|
|
285
|
-
*
|
|
286
|
-
* **Key Features**
|
|
287
|
-
*
|
|
288
|
-
* - **Type-Safe Schema Definition**: Uses TypeBox for full TypeScript type inference
|
|
289
|
-
* - **Automatic Table Generation**: Creates Drizzle ORM table structures automatically
|
|
290
|
-
* - **Index Management**: Supports single-column, multi-column, and unique indexes
|
|
291
|
-
* - **Constraint Support**: Foreign keys, unique constraints, and check constraints
|
|
292
|
-
* - **Audit Fields**: Built-in support for created_at, updated_at, deleted_at, and version fields
|
|
293
|
-
* - **Schema Validation**: Automatic insert/update schema generation with validation
|
|
294
|
-
*
|
|
295
|
-
* **Important Note**:
|
|
296
|
-
* This descriptor only defines the table structure - it does not create the physical
|
|
297
|
-
* database table. Use it with $repository to perform actual database operations,
|
|
298
|
-
* and run migrations to create the tables in your database.
|
|
299
|
-
*
|
|
300
|
-
* **Use Cases**
|
|
301
|
-
*
|
|
302
|
-
* Essential for defining database schema in type-safe applications:
|
|
303
|
-
* - User management and authentication tables
|
|
304
|
-
* - Business domain entities (products, orders, customers)
|
|
305
|
-
* - Audit and logging tables
|
|
306
|
-
* - Junction tables for many-to-many relationships
|
|
307
|
-
* - Configuration and settings tables
|
|
308
|
-
*
|
|
309
54
|
* @example
|
|
310
|
-
* **Basic entity with indexes:**
|
|
311
55
|
* ```ts
|
|
56
|
+
* import { t } from "alepha";
|
|
312
57
|
* import { $entity } from "alepha/postgres";
|
|
313
|
-
* import { pg, t } from "alepha";
|
|
314
58
|
*
|
|
315
|
-
* const
|
|
59
|
+
* const userEntity = $entity({
|
|
316
60
|
* name: "users",
|
|
317
61
|
* schema: t.object({
|
|
318
|
-
* id: pg.primaryKey(
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
* firstName: t.text(),
|
|
322
|
-
* lastName: t.text(),
|
|
323
|
-
* isActive: t.boolean({ default: true }),
|
|
324
|
-
* createdAt: pg.createdAt(),
|
|
325
|
-
* updatedAt: pg.updatedAt(),
|
|
326
|
-
* deletedAt: pg.deletedAt()
|
|
327
|
-
* }),
|
|
328
|
-
* indexes: [
|
|
329
|
-
* "email", // Simple index on email
|
|
330
|
-
* "username", // Simple index on username
|
|
331
|
-
* { column: "email", unique: true }, // Unique constraint on email
|
|
332
|
-
* { columns: ["firstName", "lastName"] } // Composite index
|
|
333
|
-
* ]
|
|
334
|
-
* });
|
|
335
|
-
* ```
|
|
336
|
-
*
|
|
337
|
-
* @example
|
|
338
|
-
* **E-commerce product entity with relationships:**
|
|
339
|
-
* ```ts
|
|
340
|
-
* const Product = $entity({
|
|
341
|
-
* name: "products",
|
|
342
|
-
* schema: t.object({
|
|
343
|
-
* id: pg.primaryKey(t.uuid()),
|
|
344
|
-
* sku: t.text({ minLength: 3 }),
|
|
345
|
-
* name: t.text({ minLength: 1, maxLength: 200 }),
|
|
346
|
-
* description: t.optional(t.text()),
|
|
347
|
-
* price: t.number({ minimum: 0 }),
|
|
348
|
-
* categoryId: t.text({ format: "uuid" }),
|
|
349
|
-
* inStock: t.boolean({ default: true }),
|
|
350
|
-
* stockQuantity: t.integer({ minimum: 0, default: 0 }),
|
|
351
|
-
* tags: t.optional(t.array(t.text())), // PostgreSQL array column
|
|
352
|
-
* metadata: t.optional(t.record(t.text(), t.any())), // JSONB column
|
|
353
|
-
* version: pg.version(),
|
|
354
|
-
* createdAt: pg.createdAt(),
|
|
355
|
-
* updatedAt: pg.updatedAt()
|
|
356
|
-
* }),
|
|
357
|
-
* indexes: [
|
|
358
|
-
* { column: "sku", unique: true }, // Unique SKU
|
|
359
|
-
* "categoryId", // Foreign key index
|
|
360
|
-
* "inStock", // Filter frequently by stock status
|
|
361
|
-
* { columns: ["categoryId", "inStock"] }, // Composite for category + stock queries
|
|
362
|
-
* "createdAt" // For date-based queries
|
|
363
|
-
* ],
|
|
364
|
-
* foreignKeys: [
|
|
365
|
-
* {
|
|
366
|
-
* name: "fk_product_category",
|
|
367
|
-
* columns: ["categoryId"],
|
|
368
|
-
* foreignColumns: [Category.id] // Reference to Category entity
|
|
369
|
-
* }
|
|
370
|
-
* ]
|
|
371
|
-
* });
|
|
372
|
-
* ```
|
|
373
|
-
*
|
|
374
|
-
* @example
|
|
375
|
-
* **Audit log entity with constraints:**
|
|
376
|
-
* ```ts
|
|
377
|
-
* const AuditLog = $entity({
|
|
378
|
-
* name: "audit_logs",
|
|
379
|
-
* schema: t.object({
|
|
380
|
-
* id: pg.primaryKey(t.uuid()),
|
|
381
|
-
* tableName: t.text(),
|
|
382
|
-
* recordId: t.text(),
|
|
383
|
-
* action: t.enum(["CREATE", "UPDATE", "DELETE"]),
|
|
384
|
-
* userId: t.optional(t.text({ format: "uuid" })),
|
|
385
|
-
* oldValues: t.optional(t.record(t.text(), t.any())),
|
|
386
|
-
* newValues: t.optional(t.record(t.text(), t.any())),
|
|
387
|
-
* timestamp: pg.createdAt(),
|
|
388
|
-
* ipAddress: t.optional(t.text()),
|
|
389
|
-
* userAgent: t.optional(t.text())
|
|
390
|
-
* }),
|
|
391
|
-
* indexes: [
|
|
392
|
-
* "tableName",
|
|
393
|
-
* "recordId",
|
|
394
|
-
* "userId",
|
|
395
|
-
* "action",
|
|
396
|
-
* { columns: ["tableName", "recordId"] }, // Find all changes to a record
|
|
397
|
-
* { columns: ["userId", "timestamp"] }, // User activity timeline
|
|
398
|
-
* "timestamp" // Time-based queries
|
|
399
|
-
* ],
|
|
400
|
-
* constraints: [
|
|
401
|
-
* {
|
|
402
|
-
* name: "valid_action_values",
|
|
403
|
-
* columns: ["action"],
|
|
404
|
-
* check: sql`action IN ('CREATE', 'UPDATE', 'DELETE')`
|
|
405
|
-
* }
|
|
406
|
-
* ]
|
|
407
|
-
* });
|
|
408
|
-
* ```
|
|
409
|
-
*
|
|
410
|
-
* @example
|
|
411
|
-
* **Many-to-many junction table:**
|
|
412
|
-
* ```ts
|
|
413
|
-
* const UserRole = $entity({
|
|
414
|
-
* name: "user_roles",
|
|
415
|
-
* schema: t.object({
|
|
416
|
-
* id: pg.primaryKey(t.uuid()),
|
|
417
|
-
* userId: t.text({ format: "uuid" }),
|
|
418
|
-
* roleId: t.text({ format: "uuid" }),
|
|
419
|
-
* assignedBy: t.text({ format: "uuid" }),
|
|
420
|
-
* assignedAt: pg.createdAt(),
|
|
421
|
-
* expiresAt: t.optional(t.datetime())
|
|
422
|
-
* }),
|
|
423
|
-
* indexes: [
|
|
424
|
-
* "userId",
|
|
425
|
-
* "roleId",
|
|
426
|
-
* "assignedBy",
|
|
427
|
-
* { columns: ["userId", "roleId"], unique: true }, // Prevent duplicate assignments
|
|
428
|
-
* "expiresAt" // For cleanup of expired roles
|
|
429
|
-
* ],
|
|
430
|
-
* foreignKeys: [
|
|
431
|
-
* {
|
|
432
|
-
* columns: ["userId"],
|
|
433
|
-
* foreignColumns: [User.id]
|
|
434
|
-
* },
|
|
435
|
-
* {
|
|
436
|
-
* columns: ["roleId"],
|
|
437
|
-
* foreignColumns: [Role.id]
|
|
438
|
-
* },
|
|
439
|
-
* {
|
|
440
|
-
* columns: ["assignedBy"],
|
|
441
|
-
* foreignColumns: [User.id]
|
|
442
|
-
* }
|
|
443
|
-
* ]
|
|
444
|
-
* });
|
|
445
|
-
* ```
|
|
446
|
-
*
|
|
447
|
-
* @example
|
|
448
|
-
* **Entity with custom Drizzle configuration:**
|
|
449
|
-
* ```ts
|
|
450
|
-
* const Order = $entity({
|
|
451
|
-
* name: "orders",
|
|
452
|
-
* schema: t.object({
|
|
453
|
-
* id: pg.primaryKey(t.uuid()),
|
|
454
|
-
* orderNumber: t.text(),
|
|
455
|
-
* customerId: t.text({ format: "uuid" }),
|
|
456
|
-
* status: t.enum(["pending", "processing", "shipped", "delivered"]),
|
|
457
|
-
* totalAmount: t.number({ minimum: 0 }),
|
|
458
|
-
* currency: t.text({ default: "USD" }),
|
|
459
|
-
* notes: t.optional(t.text()),
|
|
460
|
-
* createdAt: pg.createdAt(),
|
|
461
|
-
* updatedAt: pg.updatedAt(),
|
|
462
|
-
* version: pg.version()
|
|
62
|
+
* id: pg.primaryKey(),
|
|
63
|
+
* name: t.text(),
|
|
64
|
+
* email: t.email(),
|
|
463
65
|
* }),
|
|
464
|
-
* indexes: [
|
|
465
|
-
* { column: "orderNumber", unique: true },
|
|
466
|
-
* "customerId",
|
|
467
|
-
* "status",
|
|
468
|
-
* "createdAt",
|
|
469
|
-
* { columns: ["customerId", "status"] }
|
|
470
|
-
* ],
|
|
471
|
-
* // Advanced Drizzle ORM configuration
|
|
472
|
-
* config: (table) => [
|
|
473
|
-
* // Custom index with specific options
|
|
474
|
-
* index("idx_orders_amount_status")
|
|
475
|
-
* .on(table.totalAmount, table.status)
|
|
476
|
-
* .where(sql`status != 'cancelled'`), // Partial index
|
|
477
|
-
*
|
|
478
|
-
* // Full-text search index (PostgreSQL specific)
|
|
479
|
-
* index("idx_orders_search")
|
|
480
|
-
* .using("gin", table.notes)
|
|
481
|
-
* ]
|
|
482
66
|
* });
|
|
483
67
|
* ```
|
|
484
|
-
*
|
|
485
|
-
* @stability 2
|
|
486
68
|
*/
|
|
487
69
|
declare const $entity: {
|
|
488
|
-
<
|
|
489
|
-
[KIND]:
|
|
70
|
+
<TSchema$1 extends TObject>(options: EntityDescriptorOptions<TSchema$1>): EntityDescriptor<TSchema$1>;
|
|
71
|
+
[KIND]: typeof EntityDescriptor;
|
|
490
72
|
};
|
|
491
|
-
interface EntityDescriptorOptions<
|
|
73
|
+
interface EntityDescriptorOptions<T extends TObject, Keys = keyof Static<T>> {
|
|
492
74
|
/**
|
|
493
75
|
* The database table name that will be created for this entity.
|
|
494
|
-
*
|
|
495
|
-
* This name:
|
|
496
|
-
* - Must be unique within your database schema
|
|
497
|
-
* - Should follow your database naming conventions (typically snake_case)
|
|
498
|
-
* - Will be used in generated SQL queries and migrations
|
|
499
|
-
* - Should be descriptive of the entity's purpose
|
|
500
|
-
*
|
|
501
|
-
* **Naming Guidelines**:
|
|
502
|
-
* - Use plural nouns for table names ("users", "products", "orders")
|
|
503
|
-
* - Use snake_case for multi-word names ("user_profiles", "order_items")
|
|
504
|
-
* - Keep names concise but descriptive
|
|
505
|
-
* - Avoid SQL reserved words
|
|
506
|
-
*
|
|
507
|
-
* @example "users"
|
|
508
|
-
* @example "product_categories"
|
|
509
|
-
* @example "user_roles"
|
|
510
|
-
* @example "audit_logs"
|
|
76
|
+
* If not provided, name will be inferred from the $repository variable name.
|
|
511
77
|
*/
|
|
512
|
-
name:
|
|
78
|
+
name: string;
|
|
513
79
|
/**
|
|
514
80
|
* TypeBox schema defining the table structure and column types.
|
|
515
|
-
*
|
|
516
|
-
* This schema:
|
|
517
|
-
* - Defines all table columns with their types and constraints
|
|
518
|
-
* - Provides full TypeScript type inference for the entity
|
|
519
|
-
* - Supports validation rules and default values
|
|
520
|
-
* - Enables automatic insert/update schema generation
|
|
521
|
-
* - Must include exactly one primary key field marked with `pg.primaryKey()`
|
|
522
|
-
*
|
|
523
|
-
* **Supported PostgreSQL Types**:
|
|
524
|
-
* - `pg.primaryKey(t.uuid())` - UUID primary key
|
|
525
|
-
* - `t.text()` - VARCHAR column
|
|
526
|
-
* - `t.integer()`, `t.number()` - Numeric columns
|
|
527
|
-
* - `t.boolean()` - Boolean column
|
|
528
|
-
* - `t.array(t.text())` - PostgreSQL array column
|
|
529
|
-
* - `t.record(t.text(), t.any())` - JSONB column
|
|
530
|
-
* - `pg.createdAt()`, `pg.updatedAt()`, `pg.deletedAt()` - Audit timestamps
|
|
531
|
-
* - `pg.version()` - Optimistic locking version field
|
|
532
|
-
*
|
|
533
|
-
* **Schema Best Practices**:
|
|
534
|
-
* - Always include a primary key
|
|
535
|
-
* - Use appropriate TypeBox constraints (minLength, format, etc.)
|
|
536
|
-
* - Add audit fields for trackability
|
|
537
|
-
* - Use optional fields for nullable columns
|
|
538
|
-
* - Include foreign key columns for relationships
|
|
539
|
-
*
|
|
540
|
-
* @example
|
|
541
|
-
* ```ts
|
|
542
|
-
* t.object({
|
|
543
|
-
* id: pg.primaryKey(t.uuid()),
|
|
544
|
-
* email: t.text({ format: "email" }),
|
|
545
|
-
* firstName: t.text({ minLength: 1, maxLength: 100 }),
|
|
546
|
-
* lastName: t.text({ minLength: 1, maxLength: 100 }),
|
|
547
|
-
* age: t.optional(t.integer({ minimum: 0, maximum: 150 })),
|
|
548
|
-
* isActive: t.boolean({ default: true }),
|
|
549
|
-
* preferences: t.optional(t.record(t.text(), t.any())),
|
|
550
|
-
* tags: t.optional(t.array(t.text())),
|
|
551
|
-
* createdAt: pg.createdAt(),
|
|
552
|
-
* updatedAt: pg.updatedAt(),
|
|
553
|
-
* version: pg.version()
|
|
554
|
-
* })
|
|
555
|
-
* ```
|
|
556
81
|
*/
|
|
557
82
|
schema: T;
|
|
558
83
|
/**
|
|
559
84
|
* Database indexes to create for query optimization.
|
|
560
|
-
*
|
|
561
|
-
* Indexes improve query performance but consume disk space and slow down writes.
|
|
562
|
-
* Choose indexes based on your actual query patterns and performance requirements.
|
|
563
|
-
*
|
|
564
|
-
* **Index Types**:
|
|
565
|
-
* - **Simple string**: Creates a single-column index
|
|
566
|
-
* - **Single column object**: Creates index on one column with options
|
|
567
|
-
* - **Multi-column object**: Creates composite index on multiple columns
|
|
568
|
-
*
|
|
569
|
-
* **Index Guidelines**:
|
|
570
|
-
* - Index frequently queried columns (WHERE, ORDER BY, JOIN conditions)
|
|
571
|
-
* - Create unique indexes for business constraints
|
|
572
|
-
* - Use composite indexes for multi-column queries
|
|
573
|
-
* - Index foreign key columns for join performance
|
|
574
|
-
* - Monitor index usage and remove unused indexes
|
|
575
|
-
*
|
|
576
|
-
* **Performance Considerations**:
|
|
577
|
-
* - Each index increases storage requirements
|
|
578
|
-
* - Indexes slow down INSERT/UPDATE/DELETE operations
|
|
579
|
-
* - PostgreSQL can use multiple indexes in complex queries
|
|
580
|
-
* - Partial indexes can be more efficient for filtered queries
|
|
581
|
-
*
|
|
582
|
-
* @example ["email", "createdAt", { column: "username", unique: true }]
|
|
583
|
-
* @example [{ columns: ["userId", "status"], name: "idx_user_status" }]
|
|
584
|
-
* @example ["categoryId", { columns: ["price", "inStock"] }]
|
|
585
85
|
*/
|
|
586
86
|
indexes?: (Keys | {
|
|
587
87
|
/**
|
|
@@ -612,35 +112,6 @@ interface EntityDescriptorOptions<TTableName extends string, T extends TObject,
|
|
|
612
112
|
})[];
|
|
613
113
|
/**
|
|
614
114
|
* Foreign key constraints to maintain referential integrity.
|
|
615
|
-
*
|
|
616
|
-
* Foreign keys ensure that values in specified columns must exist in the referenced table.
|
|
617
|
-
* They prevent orphaned records and maintain database consistency.
|
|
618
|
-
*
|
|
619
|
-
* **Foreign Key Benefits**:
|
|
620
|
-
* - Prevents invalid references to non-existent records
|
|
621
|
-
* - Maintains data integrity automatically
|
|
622
|
-
* - Provides clear schema documentation of relationships
|
|
623
|
-
* - Enables cascade operations (DELETE, UPDATE)
|
|
624
|
-
*
|
|
625
|
-
* **Considerations**:
|
|
626
|
-
* - Foreign keys can impact performance on large tables
|
|
627
|
-
* - They prevent deletion of referenced records
|
|
628
|
-
* - Consider cascade options for related data cleanup
|
|
629
|
-
*
|
|
630
|
-
* @example
|
|
631
|
-
* ```ts
|
|
632
|
-
* foreignKeys: [
|
|
633
|
-
* {
|
|
634
|
-
* name: "fk_user_role",
|
|
635
|
-
* columns: ["roleId"],
|
|
636
|
-
* foreignColumns: [Role.id]
|
|
637
|
-
* },
|
|
638
|
-
* {
|
|
639
|
-
* columns: ["createdBy"],
|
|
640
|
-
* foreignColumns: [User.id]
|
|
641
|
-
* }
|
|
642
|
-
* ]
|
|
643
|
-
* ```
|
|
644
115
|
*/
|
|
645
116
|
foreignKeys?: Array<{
|
|
646
117
|
/**
|
|
@@ -653,8 +124,9 @@ interface EntityDescriptorOptions<TTableName extends string, T extends TObject,
|
|
|
653
124
|
columns: Array<keyof Static<T>>;
|
|
654
125
|
/**
|
|
655
126
|
* Referenced columns in the foreign table.
|
|
127
|
+
* Must be EntityColumn references from other entities.
|
|
656
128
|
*/
|
|
657
|
-
foreignColumns: Array<
|
|
129
|
+
foreignColumns: Array<() => EntityColumn<any>>;
|
|
658
130
|
}>;
|
|
659
131
|
/**
|
|
660
132
|
* Additional table constraints for data validation.
|
|
@@ -666,12 +138,6 @@ interface EntityDescriptorOptions<TTableName extends string, T extends TObject,
|
|
|
666
138
|
* - **Unique constraints**: Prevent duplicate values across columns
|
|
667
139
|
* - **Check constraints**: Enforce custom validation rules with SQL expressions
|
|
668
140
|
*
|
|
669
|
-
* **Use Cases**:
|
|
670
|
-
* - Enforce unique combinations of columns
|
|
671
|
-
* - Validate value ranges or patterns
|
|
672
|
-
* - Ensure consistent data states
|
|
673
|
-
* - Implement business rule validation
|
|
674
|
-
*
|
|
675
141
|
* @example
|
|
676
142
|
* ```ts
|
|
677
143
|
* constraints: [
|
|
@@ -713,52 +179,86 @@ interface EntityDescriptorOptions<TTableName extends string, T extends TObject,
|
|
|
713
179
|
}>;
|
|
714
180
|
/**
|
|
715
181
|
* Advanced Drizzle ORM configuration for complex table setups.
|
|
716
|
-
*
|
|
717
|
-
* This allows you to use advanced Drizzle ORM features that aren't covered
|
|
718
|
-
* by the simplified options above. Use this for:
|
|
719
|
-
* - Custom index types (GIN, GIST, etc.)
|
|
720
|
-
* - Partial indexes with WHERE clauses
|
|
721
|
-
* - Advanced constraint configurations
|
|
722
|
-
* - PostgreSQL-specific features
|
|
723
|
-
*
|
|
724
|
-
* **When to Use**:
|
|
725
|
-
* - Need PostgreSQL-specific index types
|
|
726
|
-
* - Require partial indexes for performance
|
|
727
|
-
* - Want fine-grained control over table creation
|
|
728
|
-
* - Using advanced PostgreSQL features
|
|
729
|
-
*
|
|
730
|
-
* See Drizzle ORM documentation for complete configuration options.
|
|
731
|
-
*
|
|
732
|
-
* @param self - The table columns available for configuration
|
|
733
|
-
* @returns Array of Drizzle table configuration objects
|
|
734
|
-
*
|
|
735
|
-
* @example
|
|
736
|
-
* ```ts
|
|
737
|
-
* config: (table) => [
|
|
738
|
-
* // Partial index for active users only
|
|
739
|
-
* index("idx_active_users_email")
|
|
740
|
-
* .on(table.email)
|
|
741
|
-
* .where(sql`is_active = true`),
|
|
742
|
-
*
|
|
743
|
-
* // GIN index for full-text search
|
|
744
|
-
* index("idx_content_search")
|
|
745
|
-
* .using("gin", table.searchVector),
|
|
746
|
-
*
|
|
747
|
-
* // Unique constraint with custom options
|
|
748
|
-
* uniqueIndex("idx_unique_slug_per_tenant")
|
|
749
|
-
* .on(table.tenantId, table.slug)
|
|
750
|
-
* ]
|
|
751
|
-
* ```
|
|
752
182
|
*/
|
|
753
183
|
config?: (self: BuildExtraConfigColumns<string, FromSchema<T>, "pg">) => PgTableExtraConfigValue[];
|
|
754
184
|
}
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
185
|
+
declare class EntityDescriptor<T extends TObject = TObject> {
|
|
186
|
+
readonly options: EntityDescriptorOptions<T>;
|
|
187
|
+
constructor(options: EntityDescriptorOptions<T>);
|
|
188
|
+
alias(alias: string): this;
|
|
189
|
+
get cols(): EntityColumns<T>;
|
|
190
|
+
get name(): string;
|
|
191
|
+
get schema(): T;
|
|
192
|
+
get insertSchema(): TObjectInsert<T>;
|
|
193
|
+
get updateSchema(): TObjectUpdate<T>;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Convert a schema to columns.
|
|
197
|
+
*/
|
|
198
|
+
type FromSchema<T extends TObject> = { [key in keyof T["properties"]]: PgColumnBuilderBase };
|
|
199
|
+
type SchemaToTableConfig<T extends TObject> = {
|
|
200
|
+
name: string;
|
|
201
|
+
schema: string | undefined;
|
|
202
|
+
columns: { [key in keyof T["properties"]]: PgColumn };
|
|
203
|
+
dialect: string;
|
|
204
|
+
};
|
|
205
|
+
type EntityColumn<T extends TObject> = {
|
|
206
|
+
name: string;
|
|
207
|
+
entity: EntityDescriptor<T>;
|
|
208
|
+
};
|
|
209
|
+
type EntityColumns<T extends TObject> = { [key in keyof T["properties"]]: EntityColumn<T> };
|
|
210
|
+
//#endregion
|
|
211
|
+
//#region src/constants/PG_SYMBOLS.d.ts
|
|
212
|
+
declare const PG_DEFAULT: unique symbol;
|
|
213
|
+
declare const PG_PRIMARY_KEY: unique symbol;
|
|
214
|
+
declare const PG_CREATED_AT: unique symbol;
|
|
215
|
+
declare const PG_UPDATED_AT: unique symbol;
|
|
216
|
+
declare const PG_DELETED_AT: unique symbol;
|
|
217
|
+
declare const PG_VERSION: unique symbol;
|
|
218
|
+
declare const PG_IDENTITY: unique symbol;
|
|
219
|
+
declare const PG_ENUM: unique symbol;
|
|
220
|
+
declare const PG_REF: unique symbol;
|
|
221
|
+
/**
|
|
222
|
+
* @deprecated Use `PG_IDENTITY` instead.
|
|
223
|
+
*/
|
|
224
|
+
declare const PG_SERIAL: unique symbol;
|
|
225
|
+
type PgDefault = typeof PG_DEFAULT;
|
|
226
|
+
type PgRef = typeof PG_REF;
|
|
227
|
+
type PgPrimaryKey = typeof PG_PRIMARY_KEY;
|
|
228
|
+
type PgSymbols = {
|
|
229
|
+
[PG_DEFAULT]: {};
|
|
230
|
+
[PG_PRIMARY_KEY]: {};
|
|
231
|
+
[PG_CREATED_AT]: {};
|
|
232
|
+
[PG_UPDATED_AT]: {};
|
|
233
|
+
[PG_DELETED_AT]: {};
|
|
234
|
+
[PG_VERSION]: {};
|
|
235
|
+
[PG_IDENTITY]: PgIdentityOptions;
|
|
236
|
+
[PG_REF]: PgRefOptions;
|
|
237
|
+
[PG_ENUM]: PgEnumOptions;
|
|
238
|
+
/**
|
|
239
|
+
* @deprecated Use `PG_IDENTITY` instead.
|
|
240
|
+
*/
|
|
241
|
+
[PG_SERIAL]: {};
|
|
242
|
+
};
|
|
243
|
+
type PgSymbolKeys = keyof PgSymbols;
|
|
244
|
+
type PgIdentityOptions = {
|
|
245
|
+
mode: "always" | "byDefault";
|
|
246
|
+
} & PgSequenceOptions & {
|
|
247
|
+
name?: string;
|
|
761
248
|
};
|
|
249
|
+
interface PgEnumOptions {
|
|
250
|
+
name?: string;
|
|
251
|
+
}
|
|
252
|
+
interface PgRefOptions {
|
|
253
|
+
ref: () => {
|
|
254
|
+
name: string;
|
|
255
|
+
entity: EntityDescriptor;
|
|
256
|
+
};
|
|
257
|
+
actions?: {
|
|
258
|
+
onUpdate?: UpdateDeleteAction;
|
|
259
|
+
onDelete?: UpdateDeleteAction;
|
|
260
|
+
};
|
|
261
|
+
}
|
|
762
262
|
//#endregion
|
|
763
263
|
//#region src/errors/PgError.d.ts
|
|
764
264
|
declare class PgError extends AlephaError {
|
|
@@ -782,7 +282,7 @@ declare class PgError extends AlephaError {
|
|
|
782
282
|
* );
|
|
783
283
|
* ```
|
|
784
284
|
*/
|
|
785
|
-
declare const pgAttr: <T extends TSchema
|
|
285
|
+
declare const pgAttr: <T extends TSchema, Attr extends PgSymbolKeys>(type: T, attr: Attr, value?: PgSymbols[Attr]) => PgAttr<T, Attr>;
|
|
786
286
|
/**
|
|
787
287
|
* Retrieves the fields of a schema that have a specific attribute.
|
|
788
288
|
*/
|
|
@@ -790,10 +290,10 @@ declare const getAttrFields: (schema: TObject, name: PgSymbolKeys) => PgAttrFiel
|
|
|
790
290
|
/**
|
|
791
291
|
* Type representation.
|
|
792
292
|
*/
|
|
793
|
-
type PgAttr<T extends TSchema
|
|
293
|
+
type PgAttr<T extends TSchema, TAttr extends PgSymbolKeys> = T & { [K in TAttr]: PgSymbols[K] };
|
|
794
294
|
interface PgAttrField {
|
|
795
295
|
key: string;
|
|
796
|
-
type: TSchema
|
|
296
|
+
type: TSchema;
|
|
797
297
|
data: any;
|
|
798
298
|
nested?: any[];
|
|
799
299
|
one?: boolean;
|
|
@@ -1156,7 +656,10 @@ interface FilterOperators<TValue> {
|
|
|
1156
656
|
}
|
|
1157
657
|
//#endregion
|
|
1158
658
|
//#region src/interfaces/PgQueryWhere.d.ts
|
|
1159
|
-
type PgQueryWhere<T extends TObject>
|
|
659
|
+
type PgQueryWhere<T extends TObject, Relations extends PgRelationMap<TObject> | undefined = undefined> = (PgQueryWhereOperators<T> & PgQueryWhereConditions<T>) | (PgQueryWhereRelations<Relations> & PgQueryWhereOperators<T> & PgQueryWhereConditions<T, Relations>);
|
|
660
|
+
type PgQueryWhereOrSQL<T extends TObject, Relations extends PgRelationMap<TObject> | undefined = undefined> = SQLWrapper | PgQueryWhere<T, Relations>;
|
|
661
|
+
type PgQueryWhereOperators<T extends TObject> = { [Key in keyof Static<T>]?: FilterOperators<Static<T>[Key]> | Static<T>[Key] | (Static<T>[Key] extends object ? NestedJsonbQuery<Static<T>[Key]> : never) };
|
|
662
|
+
type PgQueryWhereConditions<T extends TObject, Relations extends PgRelationMap<TObject> | undefined = undefined> = {
|
|
1160
663
|
/**
|
|
1161
664
|
* Combine a list of conditions with the `and` operator. Conditions
|
|
1162
665
|
* that are equal `undefined` are automatically ignored.
|
|
@@ -1173,7 +676,7 @@ type PgQueryWhere<T extends TObject> = { [Key in keyof Static<T>]?: FilterOperat
|
|
|
1173
676
|
* )
|
|
1174
677
|
* ```
|
|
1175
678
|
*/
|
|
1176
|
-
and?: Array<PgQueryWhereOrSQL<T>>;
|
|
679
|
+
and?: Array<PgQueryWhereOrSQL<T, Relations>>;
|
|
1177
680
|
/**
|
|
1178
681
|
* Combine a list of conditions with the `or` operator. Conditions
|
|
1179
682
|
* that are equal `undefined` are automatically ignored.
|
|
@@ -1190,7 +693,7 @@ type PgQueryWhere<T extends TObject> = { [Key in keyof Static<T>]?: FilterOperat
|
|
|
1190
693
|
* )
|
|
1191
694
|
* ```
|
|
1192
695
|
*/
|
|
1193
|
-
or?: Array<PgQueryWhereOrSQL<T>>;
|
|
696
|
+
or?: Array<PgQueryWhereOrSQL<T, Relations>>;
|
|
1194
697
|
/**
|
|
1195
698
|
* Negate the meaning of an expression using the `not` keyword.
|
|
1196
699
|
*
|
|
@@ -1202,7 +705,7 @@ type PgQueryWhere<T extends TObject> = { [Key in keyof Static<T>]?: FilterOperat
|
|
|
1202
705
|
* .where(not(inArray(cars.make, ['GM', 'Ford'])))
|
|
1203
706
|
* ```
|
|
1204
707
|
*/
|
|
1205
|
-
not?: PgQueryWhereOrSQL<T>;
|
|
708
|
+
not?: PgQueryWhereOrSQL<T, Relations>;
|
|
1206
709
|
/**
|
|
1207
710
|
* Test whether a subquery evaluates to have any rows.
|
|
1208
711
|
*
|
|
@@ -1225,26 +728,11 @@ type PgQueryWhere<T extends TObject> = { [Key in keyof Static<T>]?: FilterOperat
|
|
|
1225
728
|
*/
|
|
1226
729
|
exists?: SQLWrapper;
|
|
1227
730
|
};
|
|
1228
|
-
type
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
} | {
|
|
1234
|
-
[PG_ONE]: any;
|
|
1235
|
-
};
|
|
1236
|
-
type ExtractManyRelations<T extends TObject> = { [K in keyof T["properties"] as T["properties"][K] extends RelField ? T["properties"][K] extends TArray ? T["properties"][K]["items"] extends TObject ? K : never : never : T["properties"][K] extends TObject ? K : never]?: PgQueryWhere<T["properties"][K] extends TArray ? T["properties"][K]["items"] extends TObject ? T["properties"][K]["items"] : TObject : T["properties"][K] extends TObject ? T["properties"][K] : TObject> };
|
|
1237
|
-
type RemoveManyRelations<T extends TObject> = TObject<{ [K in keyof T["properties"] as T["properties"][K] extends RelField ? never : K]: T["properties"][K] }>;
|
|
1238
|
-
type PgQueryWithMap<T extends TObject> = { [K in keyof T["properties"] as T["properties"][K] extends RelField ? K : never]?: T["properties"][K] extends TArray ? T["properties"][K]["items"] extends TObject ? PgQueryWithMany<T["properties"][K]["items"]> : never : T["properties"][K] extends TObject ? PgQueryWithOne<T["properties"][K]> : T["properties"][K] extends PgAttr<PgAttr<TOptionalAdd<infer U>, PgOne>, PgDefault> ? U extends TObject ? PgQueryWithOne<U> : never : never };
|
|
1239
|
-
type PgQueryWithOne<T extends TObject> = true | {
|
|
1240
|
-
columns?: (keyof Static<T>)[];
|
|
1241
|
-
relations?: PgQueryWithMap<T>;
|
|
1242
|
-
};
|
|
1243
|
-
type PgQueryWithMany<T extends TObject> = true | {
|
|
1244
|
-
limit?: number;
|
|
1245
|
-
columns?: (keyof Static<T>)[];
|
|
1246
|
-
relations?: PgQueryWithMap<T>;
|
|
1247
|
-
};
|
|
731
|
+
type PgQueryWhereRelations<Relations extends PgRelationMap<TObject> | undefined = undefined> = Relations extends PgRelationMap<TObject> ? { [K in keyof Relations]?: PgQueryWhere<Relations[K]["join"]["schema"], Relations[K]["with"]> } : {};
|
|
732
|
+
/**
|
|
733
|
+
* Recursively allow nested queries for JSONB object/array types
|
|
734
|
+
*/
|
|
735
|
+
type NestedJsonbQuery<T> = T extends object ? T extends Array<infer U> ? U extends object ? { [K in keyof U]?: FilterOperators<U[K]> | U[K] } : FilterOperators<U> | U : { [K in keyof T]?: FilterOperators<T[K]> | T[K] | (T[K] extends object ? NestedJsonbQuery<T[K]> : never) } : FilterOperators<T> | T;
|
|
1248
736
|
//#endregion
|
|
1249
737
|
//#region src/interfaces/PgQuery.d.ts
|
|
1250
738
|
/**
|
|
@@ -1265,32 +753,140 @@ interface OrderByClause<T> {
|
|
|
1265
753
|
* 3. Array: orderBy: [{ column: "name", direction: "asc" }, { column: "age", direction: "desc" }]
|
|
1266
754
|
*/
|
|
1267
755
|
type OrderBy<T> = keyof T | OrderByClause<T> | Array<OrderByClause<T>>;
|
|
756
|
+
/**
|
|
757
|
+
* Generic query interface for PostgreSQL entities
|
|
758
|
+
*/
|
|
1268
759
|
interface PgQuery<T extends TObject = TObject> {
|
|
1269
|
-
distinct?:
|
|
1270
|
-
|
|
760
|
+
distinct?: (keyof Static<T>)[];
|
|
761
|
+
columns?: (keyof Static<T>)[];
|
|
762
|
+
where?: PgQueryWhereOrSQL<T>;
|
|
1271
763
|
limit?: number;
|
|
1272
764
|
offset?: number;
|
|
1273
765
|
orderBy?: OrderBy<Static<T>>;
|
|
1274
766
|
groupBy?: (keyof Static<T>)[];
|
|
1275
|
-
|
|
767
|
+
}
|
|
768
|
+
type PgStatic<T extends TObject, Relations extends PgRelationMap<T>> = Static<T> & { [K in keyof Relations]: Static<Relations[K]["join"]["schema"]> & (Relations[K]["with"] extends PgRelationMap<TObject> ? PgStatic<Relations[K]["join"]["schema"], Relations[K]["with"]> : {}) };
|
|
769
|
+
interface PgQueryRelations<T extends TObject = TObject, Relations extends PgRelationMap<T> | undefined = undefined> extends PgQuery<T> {
|
|
770
|
+
with?: Relations;
|
|
771
|
+
where?: PgQueryWhereOrSQL<T, Relations>;
|
|
772
|
+
}
|
|
773
|
+
type PgRelationMap<Base extends TObject> = Record<string, PgRelation<Base>>;
|
|
774
|
+
type PgRelation<Base extends TObject> = {
|
|
775
|
+
type?: "left" | "inner" | "right";
|
|
776
|
+
join: {
|
|
777
|
+
schema: TObject;
|
|
778
|
+
name: string;
|
|
779
|
+
};
|
|
780
|
+
on: SQLWrapper | [keyof Static<Base>, {
|
|
781
|
+
name: string;
|
|
782
|
+
}];
|
|
783
|
+
with?: PgRelationMap<TObject>;
|
|
784
|
+
};
|
|
785
|
+
//#endregion
|
|
786
|
+
//#region src/descriptors/$sequence.d.ts
|
|
787
|
+
/**
|
|
788
|
+
* Creates a PostgreSQL sequence descriptor for generating unique numeric values.
|
|
789
|
+
*/
|
|
790
|
+
declare const $sequence: {
|
|
791
|
+
(options?: SequenceDescriptorOptions): SequenceDescriptor;
|
|
792
|
+
[KIND]: typeof SequenceDescriptor;
|
|
793
|
+
};
|
|
794
|
+
interface SequenceDescriptorOptions extends PgSequenceOptions {
|
|
795
|
+
/**
|
|
796
|
+
* The name of the sequence. If not provided, the property key will be used.
|
|
797
|
+
*/
|
|
798
|
+
name?: string;
|
|
799
|
+
provider?: DatabaseProvider;
|
|
800
|
+
}
|
|
801
|
+
declare class SequenceDescriptor extends Descriptor<SequenceDescriptorOptions> {
|
|
802
|
+
readonly provider: DatabaseProvider;
|
|
803
|
+
onInit(): void;
|
|
804
|
+
get name(): string;
|
|
805
|
+
next(): Promise<number>;
|
|
806
|
+
current(): Promise<number>;
|
|
807
|
+
protected $provider(): DatabaseProvider;
|
|
1276
808
|
}
|
|
1277
809
|
//#endregion
|
|
1278
|
-
//#region src/
|
|
810
|
+
//#region src/services/ModelBuilder.d.ts
|
|
811
|
+
/**
|
|
812
|
+
* Database-specific table configuration functions
|
|
813
|
+
*/
|
|
814
|
+
interface TableConfigBuilders<TConfig> {
|
|
815
|
+
index: (name: string) => {
|
|
816
|
+
on: (...columns: any[]) => TConfig;
|
|
817
|
+
};
|
|
818
|
+
uniqueIndex: (name: string) => {
|
|
819
|
+
on: (...columns: any[]) => TConfig;
|
|
820
|
+
};
|
|
821
|
+
unique: (name: string) => {
|
|
822
|
+
on: (...columns: any[]) => TConfig;
|
|
823
|
+
};
|
|
824
|
+
check: (name: string, sql: SQL) => TConfig;
|
|
825
|
+
foreignKey: (config: {
|
|
826
|
+
name: string;
|
|
827
|
+
columns: any[];
|
|
828
|
+
foreignColumns: any[];
|
|
829
|
+
}) => TConfig;
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* Abstract base class for transforming Alepha Descriptors (Entity, Sequence, etc...)
|
|
833
|
+
* into drizzle models (tables, enums, sequences, etc...).
|
|
834
|
+
*/
|
|
835
|
+
declare abstract class ModelBuilder {
|
|
836
|
+
/**
|
|
837
|
+
* Build a table from an entity descriptor.
|
|
838
|
+
*/
|
|
839
|
+
abstract buildTable(entity: EntityDescriptor, options: {
|
|
840
|
+
tables: Map<string, unknown>;
|
|
841
|
+
enums: Map<string, unknown>;
|
|
842
|
+
schema: string;
|
|
843
|
+
}): void;
|
|
844
|
+
/**
|
|
845
|
+
* Build a sequence from a sequence descriptor.
|
|
846
|
+
*/
|
|
847
|
+
abstract buildSequence(sequence: SequenceDescriptor, options: {
|
|
848
|
+
sequences: Map<string, unknown>;
|
|
849
|
+
schema: string;
|
|
850
|
+
}): void;
|
|
851
|
+
/**
|
|
852
|
+
* Convert camelCase to snake_case for column names.
|
|
853
|
+
*/
|
|
854
|
+
protected toColumnName(str: string): string;
|
|
855
|
+
/**
|
|
856
|
+
* Build the table configuration function for any database.
|
|
857
|
+
* This includes indexes, foreign keys, constraints, and custom config.
|
|
858
|
+
*
|
|
859
|
+
* @param entity - The entity descriptor
|
|
860
|
+
* @param builders - Database-specific builder functions
|
|
861
|
+
* @param tableResolver - Function to resolve entity references to table columns
|
|
862
|
+
* @param customConfigHandler - Optional handler for custom config
|
|
863
|
+
*/
|
|
864
|
+
protected buildTableConfig<TConfig, TSelf>(entity: EntityDescriptor, builders: TableConfigBuilders<TConfig>, tableResolver?: (entityName: string) => any, customConfigHandler?: (config: any, self: TSelf) => TConfig[]): ((self: TSelf) => TConfig[]) | undefined;
|
|
865
|
+
}
|
|
866
|
+
//#endregion
|
|
867
|
+
//#region src/providers/drivers/DatabaseProvider.d.ts
|
|
1279
868
|
type SQLLike = SQLWrapper | string;
|
|
1280
|
-
declare abstract class
|
|
869
|
+
declare abstract class DatabaseProvider {
|
|
1281
870
|
protected readonly alepha: Alepha;
|
|
1282
|
-
abstract
|
|
1283
|
-
readonly
|
|
871
|
+
protected abstract readonly builder: ModelBuilder;
|
|
872
|
+
abstract readonly db: PgDatabase<any>;
|
|
873
|
+
abstract readonly dialect: "postgres" | "sqlite";
|
|
874
|
+
readonly enums: Map<string, unknown>;
|
|
875
|
+
readonly tables: Map<string, unknown>;
|
|
876
|
+
readonly sequences: Map<string, unknown>;
|
|
877
|
+
table<T extends TObject>(entity: EntityDescriptor<T>): PgTableWithColumns<SchemaToTableConfig<T>>;
|
|
1284
878
|
get schema(): string;
|
|
1285
|
-
|
|
1286
|
-
|
|
879
|
+
registerEntity(entity: EntityDescriptor): void;
|
|
880
|
+
registerSequence(sequence: SequenceDescriptor): void;
|
|
881
|
+
abstract execute(statement: SQLLike): Promise<Record<string, unknown>[]>;
|
|
882
|
+
run<T extends TObject>(statement: SQLLike, schema: T): Promise<Array<Static<T>>>;
|
|
1287
883
|
}
|
|
1288
884
|
//#endregion
|
|
1289
885
|
//#region src/schemas/pageQuerySchema.d.ts
|
|
1290
|
-
declare const pageQuerySchema:
|
|
1291
|
-
page:
|
|
1292
|
-
size:
|
|
1293
|
-
sort:
|
|
886
|
+
declare const pageQuerySchema: typebox9.TObject<{
|
|
887
|
+
page: typebox9.TOptional<typebox9.TInteger>;
|
|
888
|
+
size: typebox9.TOptional<typebox9.TInteger>;
|
|
889
|
+
sort: typebox9.TOptional<typebox9.TString>;
|
|
1294
890
|
}>;
|
|
1295
891
|
type PageQuery = Static<typeof pageQuerySchema>;
|
|
1296
892
|
//#endregion
|
|
@@ -1298,9 +894,13 @@ type PageQuery = Static<typeof pageQuerySchema>;
|
|
|
1298
894
|
/**
|
|
1299
895
|
* Create a pagination schema for the given object schema.
|
|
1300
896
|
*
|
|
897
|
+
* > use `pg.page` directly.
|
|
898
|
+
*
|
|
1301
899
|
* @example
|
|
900
|
+
* ```ts
|
|
1302
901
|
* const userSchema = t.object({ id: t.int(), name: t.text() });
|
|
1303
|
-
* const
|
|
902
|
+
* const userPageSchema = pageSchema(userSchema);
|
|
903
|
+
* ```
|
|
1304
904
|
*
|
|
1305
905
|
* @see {@link $repository#paginate}
|
|
1306
906
|
*/
|
|
@@ -1317,106 +917,218 @@ type TPage<T extends TObject | TRecord> = TObject<{
|
|
|
1317
917
|
totalElements: TOptionalAdd<TInteger>;
|
|
1318
918
|
}>;
|
|
1319
919
|
}>;
|
|
920
|
+
/**
|
|
921
|
+
* Opinionated type definition for a paginated response.
|
|
922
|
+
*
|
|
923
|
+
* @example
|
|
924
|
+
* ```ts
|
|
925
|
+
* const page = {
|
|
926
|
+
* content: [ ... ]
|
|
927
|
+
* can: {
|
|
928
|
+
* next: true,
|
|
929
|
+
* previous: false
|
|
930
|
+
* },
|
|
931
|
+
* page: {
|
|
932
|
+
* number: 0,
|
|
933
|
+
* size: 10,
|
|
934
|
+
* totalElements: 1200
|
|
935
|
+
* }
|
|
936
|
+
* }
|
|
937
|
+
* ```
|
|
938
|
+
*/
|
|
1320
939
|
type Page<T> = {
|
|
940
|
+
/**
|
|
941
|
+
* Array of items on the current page.
|
|
942
|
+
*/
|
|
1321
943
|
content: T[];
|
|
1322
944
|
can: {
|
|
945
|
+
/**
|
|
946
|
+
* Indicates if there is a next page.
|
|
947
|
+
*/
|
|
1323
948
|
next: boolean;
|
|
949
|
+
/**
|
|
950
|
+
* Indicates if there is a previous page.
|
|
951
|
+
*/
|
|
1324
952
|
previous: boolean;
|
|
1325
953
|
};
|
|
1326
954
|
page: {
|
|
955
|
+
/**
|
|
956
|
+
* Page number, starting from 0.
|
|
957
|
+
*/
|
|
1327
958
|
number: number;
|
|
959
|
+
/**
|
|
960
|
+
* Number of items per page.
|
|
961
|
+
*/
|
|
1328
962
|
size: number;
|
|
963
|
+
/**
|
|
964
|
+
* Requires `count: true` in the paginate options.
|
|
965
|
+
*/
|
|
1329
966
|
totalElements?: number;
|
|
1330
967
|
};
|
|
1331
968
|
};
|
|
1332
969
|
//#endregion
|
|
970
|
+
//#region src/services/PgJsonQueryManager.d.ts
|
|
971
|
+
/**
|
|
972
|
+
* Manages JSONB query generation for nested object and array queries in PostgreSQL.
|
|
973
|
+
* This class handles complex nested queries using PostgreSQL's JSONB operators.
|
|
974
|
+
*/
|
|
975
|
+
declare class PgJsonQueryManager {
|
|
976
|
+
/**
|
|
977
|
+
* Check if a query contains nested JSONB queries.
|
|
978
|
+
* A nested query is when the value is an object with operator keys.
|
|
979
|
+
*/
|
|
980
|
+
hasNestedQuery(where: PgQueryWhere<TObject>): boolean;
|
|
981
|
+
/**
|
|
982
|
+
* Build a JSONB query condition for nested object queries.
|
|
983
|
+
* Supports deep nesting like: { profile: { contact: { email: { eq: "test@example.com" } } } }
|
|
984
|
+
*
|
|
985
|
+
* @param column The JSONB column
|
|
986
|
+
* @param path The path to the nested property (e.g., ['profile', 'contact', 'email'])
|
|
987
|
+
* @param operator The filter operator (e.g., { eq: "test@example.com" })
|
|
988
|
+
* @returns SQL condition
|
|
989
|
+
*/
|
|
990
|
+
buildJsonbCondition(column: PgColumn, path: string[], operator: FilterOperators<any>): SQL | undefined;
|
|
991
|
+
/**
|
|
992
|
+
* Build JSONB array query conditions.
|
|
993
|
+
* Supports queries like: { addresses: { city: { eq: "Wonderland" } } }
|
|
994
|
+
* which translates to: EXISTS (SELECT 1 FROM jsonb_array_elements(addresses) elem WHERE elem->>'city' = 'Wonderland')
|
|
995
|
+
*/
|
|
996
|
+
buildJsonbArrayCondition(column: PgColumn, path: string[], arrayPath: string, operator: FilterOperators<any>): SQL | undefined;
|
|
997
|
+
/**
|
|
998
|
+
* Apply a filter operator to a JSONB value.
|
|
999
|
+
*/
|
|
1000
|
+
private applyOperatorToJsonValue;
|
|
1001
|
+
/**
|
|
1002
|
+
* Parse a nested query object and extract the path and operator.
|
|
1003
|
+
* For example: { profile: { contact: { email: { eq: "test@example.com" } } } }
|
|
1004
|
+
* Returns: { path: ['profile', 'contact', 'email'], operator: { eq: "test@example.com" } }
|
|
1005
|
+
*/
|
|
1006
|
+
parseNestedQuery(nestedQuery: any, currentPath?: string[]): Array<{
|
|
1007
|
+
path: string[];
|
|
1008
|
+
operator: FilterOperators<any>;
|
|
1009
|
+
}>;
|
|
1010
|
+
/**
|
|
1011
|
+
* Determine if a property is a JSONB column based on the schema.
|
|
1012
|
+
* A column is JSONB if it's defined as an object or array in the TypeBox schema.
|
|
1013
|
+
*/
|
|
1014
|
+
isJsonbColumn(schema: TObject, columnName: string): boolean;
|
|
1015
|
+
/**
|
|
1016
|
+
* Check if an array property contains primitive types (string, number, boolean, etc.)
|
|
1017
|
+
* rather than objects. Primitive arrays should use native Drizzle operators.
|
|
1018
|
+
* @returns true if the array contains primitives, false if it contains objects
|
|
1019
|
+
*/
|
|
1020
|
+
isPrimitiveArray(schema: TObject, columnName: string): boolean;
|
|
1021
|
+
/**
|
|
1022
|
+
* Check if a nested path points to an array property.
|
|
1023
|
+
*/
|
|
1024
|
+
isArrayProperty(schema: TObject, path: string[]): boolean;
|
|
1025
|
+
}
|
|
1026
|
+
//#endregion
|
|
1027
|
+
//#region src/services/PgQueryManager.d.ts
|
|
1028
|
+
declare class PgQueryManager {
|
|
1029
|
+
protected readonly jsonQueryManager: PgJsonQueryManager;
|
|
1030
|
+
protected readonly alepha: Alepha;
|
|
1031
|
+
/**
|
|
1032
|
+
* Convert a query object to a SQL query.
|
|
1033
|
+
*/
|
|
1034
|
+
toSQL(query: PgQueryWhereOrSQL<TObject>, options: {
|
|
1035
|
+
schema: TObject;
|
|
1036
|
+
col: (key: string) => PgColumn;
|
|
1037
|
+
joins?: PgJoin[];
|
|
1038
|
+
}): SQL | undefined;
|
|
1039
|
+
/**
|
|
1040
|
+
* Build a JSONB query for nested object/array queries.
|
|
1041
|
+
*/
|
|
1042
|
+
protected buildJsonbQuery(column: PgColumn, nestedQuery: any, schema: TObject, columnName: string): SQL | undefined;
|
|
1043
|
+
/**
|
|
1044
|
+
* Check if an object has any filter operator properties.
|
|
1045
|
+
*/
|
|
1046
|
+
protected hasFilterOperatorProperties(obj: any): boolean;
|
|
1047
|
+
/**
|
|
1048
|
+
* Map a filter operator to a SQL query.
|
|
1049
|
+
*/
|
|
1050
|
+
mapOperatorToSql(operator: FilterOperators<any> | any, column: PgColumn, columnSchema?: TObject, columnName?: string): SQL | undefined;
|
|
1051
|
+
/**
|
|
1052
|
+
* Parse pagination sort string to orderBy format.
|
|
1053
|
+
* Format: "firstName,-lastName" -> [{ column: "firstName", direction: "asc" }, { column: "lastName", direction: "desc" }]
|
|
1054
|
+
* - Columns separated by comma
|
|
1055
|
+
* - Prefix with '-' for DESC direction
|
|
1056
|
+
*
|
|
1057
|
+
* @param sort Pagination sort string
|
|
1058
|
+
* @returns OrderBy array or single object
|
|
1059
|
+
*/
|
|
1060
|
+
parsePaginationSort(sort: string): Array<{
|
|
1061
|
+
column: string;
|
|
1062
|
+
direction: "asc" | "desc";
|
|
1063
|
+
}> | {
|
|
1064
|
+
column: string;
|
|
1065
|
+
direction: "asc" | "desc";
|
|
1066
|
+
};
|
|
1067
|
+
/**
|
|
1068
|
+
* Normalize orderBy parameter to array format.
|
|
1069
|
+
* Supports 3 modes:
|
|
1070
|
+
* 1. String: "name" -> [{ column: "name", direction: "asc" }]
|
|
1071
|
+
* 2. Object: { column: "name", direction: "desc" } -> [{ column: "name", direction: "desc" }]
|
|
1072
|
+
* 3. Array: [{ column: "name" }, { column: "age", direction: "desc" }] -> normalized array
|
|
1073
|
+
*
|
|
1074
|
+
* @param orderBy The orderBy parameter
|
|
1075
|
+
* @returns Normalized array of order by clauses
|
|
1076
|
+
*/
|
|
1077
|
+
normalizeOrderBy(orderBy: any): Array<{
|
|
1078
|
+
column: string;
|
|
1079
|
+
direction: "asc" | "desc";
|
|
1080
|
+
}>;
|
|
1081
|
+
/**
|
|
1082
|
+
* Create a pagination object.
|
|
1083
|
+
*
|
|
1084
|
+
* @param entities The entities to paginate.
|
|
1085
|
+
* @param limit The limit of the pagination.
|
|
1086
|
+
* @param offset The offset of the pagination.
|
|
1087
|
+
*/
|
|
1088
|
+
createPagination<T>(entities: T[], limit?: number, offset?: number): Page<T>;
|
|
1089
|
+
}
|
|
1090
|
+
interface PgJoin {
|
|
1091
|
+
table: string;
|
|
1092
|
+
schema: TObject;
|
|
1093
|
+
key: string;
|
|
1094
|
+
col: (key: string) => PgColumn;
|
|
1095
|
+
parent?: string;
|
|
1096
|
+
}
|
|
1097
|
+
//#endregion
|
|
1098
|
+
//#region src/services/PgRelationManager.d.ts
|
|
1099
|
+
declare class PgRelationManager {
|
|
1100
|
+
/**
|
|
1101
|
+
* Recursively build joins for the query builder based on the relations map
|
|
1102
|
+
*/
|
|
1103
|
+
buildJoins(provider: DatabaseProvider, builder: PgSelectBase<any, any, any>, joins: Array<PgJoin>, withRelations: PgRelationMap<TObject>, table: PgTableWithColumns<any>, parentKey?: string): void;
|
|
1104
|
+
/**
|
|
1105
|
+
* Map a row with its joined relations based on the joins definition
|
|
1106
|
+
*/
|
|
1107
|
+
mapRowWithJoins(record: Record<string, unknown>, row: Record<string, unknown>, schema: TObject, joins: PgJoin[], parentKey?: string): Record<string, unknown>;
|
|
1108
|
+
/**
|
|
1109
|
+
* Check if all values in an object are null (indicates a left join with no match)
|
|
1110
|
+
*/
|
|
1111
|
+
private isAllNull;
|
|
1112
|
+
/**
|
|
1113
|
+
* Build a schema that includes all join properties recursively
|
|
1114
|
+
*/
|
|
1115
|
+
buildSchemaWithJoins(baseSchema: TObject, joins: PgJoin[], parentPath?: string): TObject;
|
|
1116
|
+
}
|
|
1117
|
+
//#endregion
|
|
1333
1118
|
//#region src/descriptors/$repository.d.ts
|
|
1334
1119
|
/**
|
|
1335
|
-
* Creates a repository
|
|
1120
|
+
* Creates a repository for database operations on a defined entity.
|
|
1336
1121
|
*
|
|
1337
1122
|
* This descriptor provides a comprehensive, type-safe interface for performing all
|
|
1338
1123
|
* database operations on entities defined with $entity. It offers a rich set of
|
|
1339
1124
|
* CRUD operations, advanced querying capabilities, pagination, transactions, and
|
|
1340
1125
|
* built-in support for audit trails and soft deletes.
|
|
1341
|
-
*
|
|
1342
|
-
* **Key Features**
|
|
1343
|
-
*
|
|
1344
|
-
* - **Complete CRUD Operations**: Create, read, update, delete with full type safety
|
|
1345
|
-
* - **Advanced Querying**: Complex WHERE conditions, sorting, pagination, and aggregations
|
|
1346
|
-
* - **Transaction Support**: Database transactions for consistency and atomicity
|
|
1347
|
-
* - **Soft Delete Support**: Built-in soft delete functionality with `pg.deletedAt()` fields
|
|
1348
|
-
* - **Optimistic Locking**: Version-based conflict resolution with `pg.version()` fields
|
|
1349
|
-
* - **Audit Trail Integration**: Automatic handling of `createdAt`, `updatedAt` timestamps
|
|
1350
|
-
* - **Raw SQL Support**: Execute custom SQL queries when needed
|
|
1351
|
-
* - **Pagination**: Built-in pagination with metadata and navigation
|
|
1352
|
-
*
|
|
1353
|
-
* **Important Requirements**
|
|
1354
|
-
* - Must be used with an entity created by $entity
|
|
1355
|
-
* - Entity schema must include exactly one primary key field
|
|
1356
|
-
* - Database tables must be created via migrations before use
|
|
1357
|
-
*
|
|
1358
|
-
* **Use Cases**
|
|
1359
|
-
*
|
|
1360
|
-
* Essential for all database-driven applications:
|
|
1361
|
-
* - User management and authentication systems
|
|
1362
|
-
* - E-commerce product and order management
|
|
1363
|
-
* - Content management and blogging platforms
|
|
1364
|
-
* - Financial and accounting applications
|
|
1365
|
-
* - Any application requiring persistent data storage
|
|
1366
|
-
*
|
|
1367
|
-
* @example
|
|
1368
|
-
* **Basic repository with CRUD operations:**
|
|
1369
|
-
* ```ts
|
|
1370
|
-
* import { $entity, $repository } from "alepha/postgres";
|
|
1371
|
-
* import { pg, t } from "alepha";
|
|
1372
|
-
*
|
|
1373
|
-
* // First, define the entity
|
|
1374
|
-
* const User = $entity({
|
|
1375
|
-
* name: "users",
|
|
1376
|
-
* schema: t.object({
|
|
1377
|
-
* id: pg.primaryKey(t.uuid()),
|
|
1378
|
-
* email: t.text({ format: "email" }),
|
|
1379
|
-
* firstName: t.text(),
|
|
1380
|
-
* lastName: t.text(),
|
|
1381
|
-
* isActive: t.boolean({ default: true }),
|
|
1382
|
-
* createdAt: pg.createdAt(),
|
|
1383
|
-
* updatedAt: pg.updatedAt()
|
|
1384
|
-
* }),
|
|
1385
|
-
* indexes: [{ column: "email", unique: true }]
|
|
1386
|
-
* });
|
|
1387
|
-
*
|
|
1388
|
-
* class UserService {
|
|
1389
|
-
* users = $repository({ table: User });
|
|
1390
|
-
*
|
|
1391
|
-
* async createUser(userData: { email: string; firstName: string; lastName: string }) {
|
|
1392
|
-
* return await this.users.create({
|
|
1393
|
-
* id: generateUUID(),
|
|
1394
|
-
* email: userData.email,
|
|
1395
|
-
* firstName: userData.firstName,
|
|
1396
|
-
* lastName: userData.lastName,
|
|
1397
|
-
* isActive: true
|
|
1398
|
-
* });
|
|
1399
|
-
* }
|
|
1400
|
-
*
|
|
1401
|
-
* async getUserByEmail(email: string) {
|
|
1402
|
-
* return await this.users.findOne({ email });
|
|
1403
|
-
* }
|
|
1404
|
-
*
|
|
1405
|
-
* async updateUser(id: string, updates: { firstName?: string; lastName?: string }) {
|
|
1406
|
-
* return await this.users.updateById(id, updates);
|
|
1407
|
-
* }
|
|
1408
|
-
*
|
|
1409
|
-
* async deactivateUser(id: string) {
|
|
1410
|
-
* return await this.users.updateById(id, { isActive: false });
|
|
1411
|
-
* }
|
|
1412
|
-
* }
|
|
1413
|
-
* ```
|
|
1414
1126
|
*/
|
|
1415
1127
|
declare const $repository: {
|
|
1416
|
-
<
|
|
1128
|
+
<T extends TObject>(optionsOrEntity: EntityDescriptor<T> | EntityDescriptorOptions<T> | RepositoryDescriptorOptions<T>): RepositoryDescriptor<T>;
|
|
1417
1129
|
[KIND]: typeof RepositoryDescriptor;
|
|
1418
1130
|
};
|
|
1419
|
-
interface RepositoryDescriptorOptions<
|
|
1131
|
+
interface RepositoryDescriptorOptions<T extends TObject> {
|
|
1420
1132
|
/**
|
|
1421
1133
|
* The entity table definition created with $entity.
|
|
1422
1134
|
*
|
|
@@ -1451,7 +1163,7 @@ interface RepositoryDescriptorOptions<EntityTableConfig extends TableConfig, Ent
|
|
|
1451
1163
|
* const userRepository = $repository({ table: User });
|
|
1452
1164
|
* ```
|
|
1453
1165
|
*/
|
|
1454
|
-
|
|
1166
|
+
entity: EntityDescriptor<T>;
|
|
1455
1167
|
/**
|
|
1456
1168
|
* Override the default PostgreSQL database provider.
|
|
1457
1169
|
*
|
|
@@ -1474,14 +1186,16 @@ interface RepositoryDescriptorOptions<EntityTableConfig extends TableConfig, Ent
|
|
|
1474
1186
|
* @example TenantSpecificPostgresProvider
|
|
1475
1187
|
* @example TestDatabaseProvider
|
|
1476
1188
|
*/
|
|
1477
|
-
provider?:
|
|
1189
|
+
provider?: DatabaseProvider;
|
|
1190
|
+
name?: string;
|
|
1478
1191
|
}
|
|
1479
|
-
declare class RepositoryDescriptor<
|
|
1192
|
+
declare class RepositoryDescriptor<T extends TObject = TObject> extends Descriptor<RepositoryDescriptorOptions<T>> {
|
|
1193
|
+
protected readonly relationManager: PgRelationManager;
|
|
1194
|
+
protected readonly queryManager: PgQueryManager;
|
|
1480
1195
|
protected readonly dateTimeProvider: DateTimeProvider;
|
|
1481
1196
|
protected readonly alepha: Alepha;
|
|
1482
|
-
readonly provider:
|
|
1483
|
-
|
|
1484
|
-
readonly schemaInsert: TObjectInsert<EntitySchema>;
|
|
1197
|
+
readonly provider: DatabaseProvider;
|
|
1198
|
+
constructor(args: DescriptorArgs<RepositoryDescriptorOptions<T>>);
|
|
1485
1199
|
/**
|
|
1486
1200
|
* Represents the primary key of the table.
|
|
1487
1201
|
* - Key is the name of the primary key column.
|
|
@@ -1489,15 +1203,15 @@ declare class RepositoryDescriptor<EntityTableConfig extends TableConfig, Entity
|
|
|
1489
1203
|
*
|
|
1490
1204
|
* ID is mandatory. If the table does not have a primary key, it will throw an error.
|
|
1491
1205
|
*/
|
|
1492
|
-
|
|
1493
|
-
type: TSchema
|
|
1494
|
-
key: keyof
|
|
1206
|
+
get id(): {
|
|
1207
|
+
type: TSchema;
|
|
1208
|
+
key: keyof T["properties"];
|
|
1495
1209
|
col: PgColumn;
|
|
1496
1210
|
};
|
|
1497
1211
|
/**
|
|
1498
1212
|
* Get Drizzle table object.
|
|
1499
1213
|
*/
|
|
1500
|
-
get table(): PgTableWithColumns<
|
|
1214
|
+
get table(): PgTableWithColumns<SchemaToTableConfig<T>>;
|
|
1501
1215
|
/**
|
|
1502
1216
|
* Get SQL table name. (from Drizzle table object)
|
|
1503
1217
|
*/
|
|
@@ -1505,87 +1219,104 @@ declare class RepositoryDescriptor<EntityTableConfig extends TableConfig, Entity
|
|
|
1505
1219
|
/**
|
|
1506
1220
|
* Getter for the database connection from the database provider.
|
|
1507
1221
|
*/
|
|
1508
|
-
protected get db(): PgDatabase<any
|
|
1222
|
+
protected get db(): PgDatabase<any>;
|
|
1509
1223
|
/**
|
|
1510
1224
|
* Execute a SQL query.
|
|
1225
|
+
*
|
|
1226
|
+
* This method allows executing raw SQL queries against the database.
|
|
1227
|
+
* This is by far the easiest way to run custom queries that are not covered by the repository's built-in methods!
|
|
1228
|
+
*
|
|
1229
|
+
* You must use the `sql` tagged template function from Drizzle ORM to create the query. https://orm.drizzle.team/docs/sql
|
|
1230
|
+
*
|
|
1231
|
+
* @example
|
|
1232
|
+
* ```ts
|
|
1233
|
+
* class App {
|
|
1234
|
+
* repository = $repository({ ... });
|
|
1235
|
+
* async getAdults() {
|
|
1236
|
+
* const users = repository.table; // Drizzle table object
|
|
1237
|
+
* await repository.query(sql`SELECT * FROM ${users} WHERE ${users.age} > ${18}`);
|
|
1238
|
+
* // or better
|
|
1239
|
+
* await repository.query((users) => sql`SELECT * FROM ${users} WHERE ${users.age} > ${18}`);
|
|
1240
|
+
* }
|
|
1241
|
+
* }
|
|
1242
|
+
* ```
|
|
1243
|
+
*/
|
|
1244
|
+
query<R extends TObject = T>(query: SQLLike | ((table: PgTableWithColumns<SchemaToTableConfig<T>>, db: PgDatabase<any>) => SQLLike), schema?: R): Promise<Static<R>[]>;
|
|
1245
|
+
/**
|
|
1246
|
+
* Map raw database fields to entity fields. (handles column name differences)
|
|
1511
1247
|
*/
|
|
1512
|
-
|
|
1513
|
-
protected mapRawFieldsToEntity(row: any[]): any;
|
|
1248
|
+
protected mapRawFieldsToEntity(row: Record<string, unknown>): any;
|
|
1514
1249
|
/**
|
|
1515
1250
|
* Get a Drizzle column from the table by his name.
|
|
1516
|
-
*
|
|
1517
|
-
* @param name - The name of the column to get.
|
|
1518
|
-
* @returns The column from the table.
|
|
1519
1251
|
*/
|
|
1520
|
-
protected col(name: keyof
|
|
1252
|
+
protected col(name: keyof StaticEncode<T>): PgColumn;
|
|
1521
1253
|
/**
|
|
1522
1254
|
* Run a transaction.
|
|
1523
|
-
*
|
|
1524
|
-
* @param transaction
|
|
1525
|
-
* @param config
|
|
1526
1255
|
*/
|
|
1527
1256
|
transaction<T>(transaction: (tx: PgTransaction<any, Record<string, any>, any>) => Promise<T>, config?: PgTransactionConfig): Promise<T>;
|
|
1528
1257
|
/**
|
|
1529
1258
|
* Start a SELECT query on the table.
|
|
1530
|
-
*
|
|
1531
|
-
* @returns The SELECT query builder.
|
|
1532
1259
|
*/
|
|
1533
|
-
protected select(opts?: StatementOptions):
|
|
1260
|
+
protected select(opts?: StatementOptions): drizzle_orm_pg_core0.PgSelectBase<string, Record<string, PgColumn<drizzle_orm0.ColumnBaseConfig<drizzle_orm0.ColumnDataType, string>, {}, {}>>, "single", Record<string, "not-null">, false, never, {
|
|
1534
1261
|
[x: string]: unknown;
|
|
1535
1262
|
}[], {
|
|
1536
|
-
[x: string]: PgColumn<
|
|
1263
|
+
[x: string]: PgColumn<drizzle_orm0.ColumnBaseConfig<drizzle_orm0.ColumnDataType, string>, {}, {}>;
|
|
1537
1264
|
}>;
|
|
1538
|
-
|
|
1539
|
-
|
|
1265
|
+
/**
|
|
1266
|
+
* Start a SELECT DISTINCT query on the table.
|
|
1267
|
+
*/
|
|
1268
|
+
protected selectDistinct(opts?: StatementOptions, columns?: (keyof Static<T>)[]): drizzle_orm_pg_core0.PgSelectBase<string, Record<string, any>, "partial", Record<string, "not-null">, false, never, {
|
|
1269
|
+
[x: string]: any;
|
|
1540
1270
|
}[], {
|
|
1541
|
-
[x: string]:
|
|
1271
|
+
[x: string]: any;
|
|
1542
1272
|
}>;
|
|
1543
1273
|
/**
|
|
1544
1274
|
* Start an INSERT query on the table.
|
|
1545
|
-
*
|
|
1546
|
-
* @returns The INSERT query builder.
|
|
1547
1275
|
*/
|
|
1548
|
-
protected insert(opts?: StatementOptions):
|
|
1276
|
+
protected insert(opts?: StatementOptions): drizzle_orm_pg_core0.PgInsertBuilder<PgTableWithColumns<SchemaToTableConfig<T>>, any, false>;
|
|
1549
1277
|
/**
|
|
1550
1278
|
* Start an UPDATE query on the table.
|
|
1551
|
-
*
|
|
1552
|
-
* @returns The UPDATE query builder.
|
|
1553
1279
|
*/
|
|
1554
|
-
protected update(opts?: StatementOptions):
|
|
1280
|
+
protected update(opts?: StatementOptions): drizzle_orm_pg_core0.PgUpdateBuilder<PgTableWithColumns<SchemaToTableConfig<T>>, any>;
|
|
1555
1281
|
/**
|
|
1556
1282
|
* Start a DELETE query on the table.
|
|
1557
|
-
*
|
|
1558
|
-
* @returns The DELETE query builder.
|
|
1559
1283
|
*/
|
|
1560
|
-
protected delete(opts?: StatementOptions):
|
|
1284
|
+
protected delete(opts?: StatementOptions): drizzle_orm_pg_core0.PgDeleteBase<PgTableWithColumns<SchemaToTableConfig<T>>, any, undefined, undefined, false, never>;
|
|
1561
1285
|
/**
|
|
1562
|
-
*
|
|
1286
|
+
* Create a Drizzle `select` query based on a JSON query object.
|
|
1563
1287
|
*
|
|
1564
|
-
*
|
|
1565
|
-
* @param opts The statement options.
|
|
1566
|
-
* @returns The found entities.
|
|
1288
|
+
* > This method is the base for `find`, `findOne`, `findById`, and `paginate`.
|
|
1567
1289
|
*/
|
|
1568
|
-
find(query?:
|
|
1290
|
+
find<R extends PgRelationMap<T>>(query?: PgQueryRelations<T, R>, opts?: StatementOptions): Promise<PgStatic<T, R>[]>;
|
|
1569
1291
|
/**
|
|
1570
1292
|
* Find a single entity.
|
|
1293
|
+
*/
|
|
1294
|
+
findOne<R extends PgRelationMap<T>>(query: Pick<PgQueryRelations<T, R>, "with" | "where">, opts?: StatementOptions): Promise<PgStatic<T, R>>;
|
|
1295
|
+
/**
|
|
1296
|
+
* Find entities with pagination.
|
|
1571
1297
|
*
|
|
1572
|
-
*
|
|
1573
|
-
*
|
|
1574
|
-
*
|
|
1298
|
+
* It uses the same parameters as `find()`, but adds pagination metadata to the response.
|
|
1299
|
+
*
|
|
1300
|
+
* > Pagination CAN also do a count query to get the total number of elements.
|
|
1575
1301
|
*/
|
|
1576
|
-
|
|
1302
|
+
paginate<R extends PgRelationMap<T>>(pagination?: PageQuery, query?: PgQueryRelations<T, R>, opts?: StatementOptions & {
|
|
1303
|
+
count?: boolean;
|
|
1304
|
+
}): Promise<Page<PgStatic<T, R>>>;
|
|
1577
1305
|
/**
|
|
1578
1306
|
* Find an entity by ID.
|
|
1307
|
+
*
|
|
1308
|
+
* This is a convenience method for `findOne` with a where clause on the primary key.
|
|
1309
|
+
* If you need more complex queries, use `findOne` instead.
|
|
1579
1310
|
*/
|
|
1580
|
-
findById(id: string | number, opts?: StatementOptions): Promise<Static<
|
|
1311
|
+
findById(id: string | number, opts?: StatementOptions): Promise<Static<T>>;
|
|
1581
1312
|
/**
|
|
1582
|
-
*
|
|
1313
|
+
* Helper to create a type-safe query object.
|
|
1583
1314
|
*/
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
createQueryWhere(
|
|
1315
|
+
createQuery(): PgQuery<T>;
|
|
1316
|
+
/**
|
|
1317
|
+
* Helper to create a type-safe where clause.
|
|
1318
|
+
*/
|
|
1319
|
+
createQueryWhere(): PgQueryWhere<T>;
|
|
1589
1320
|
/**
|
|
1590
1321
|
* Create an entity.
|
|
1591
1322
|
*
|
|
@@ -1593,7 +1324,7 @@ declare class RepositoryDescriptor<EntityTableConfig extends TableConfig, Entity
|
|
|
1593
1324
|
* @param opts The options for creating the entity.
|
|
1594
1325
|
* @returns The ID of the created entity.
|
|
1595
1326
|
*/
|
|
1596
|
-
create(data: Static<TObjectInsert<
|
|
1327
|
+
create(data: Static<TObjectInsert<T>>, opts?: StatementOptions): Promise<Static<T>>;
|
|
1597
1328
|
/**
|
|
1598
1329
|
* Create many entities.
|
|
1599
1330
|
*
|
|
@@ -1601,11 +1332,11 @@ declare class RepositoryDescriptor<EntityTableConfig extends TableConfig, Entity
|
|
|
1601
1332
|
* @param opts The statement options.
|
|
1602
1333
|
* @returns The created entities.
|
|
1603
1334
|
*/
|
|
1604
|
-
createMany(values: Array<Static<TObjectInsert<
|
|
1335
|
+
createMany(values: Array<Static<TObjectInsert<T>>>, opts?: StatementOptions): Promise<Static<T>[]>;
|
|
1605
1336
|
/**
|
|
1606
1337
|
* Find an entity and update it.
|
|
1607
1338
|
*/
|
|
1608
|
-
updateOne(where: PgQueryWhereOrSQL<
|
|
1339
|
+
updateOne(where: PgQueryWhereOrSQL<T>, data: Partial<Static<TObjectUpdate<T>>>, opts?: StatementOptions): Promise<Static<T>>;
|
|
1609
1340
|
/**
|
|
1610
1341
|
* Save a given entity.
|
|
1611
1342
|
*
|
|
@@ -1627,132 +1358,90 @@ declare class RepositoryDescriptor<EntityTableConfig extends TableConfig, Entity
|
|
|
1627
1358
|
* @see {@link PostgresTypeProvider#version}
|
|
1628
1359
|
* @see {@link PgVersionMismatchError}
|
|
1629
1360
|
*/
|
|
1630
|
-
save(entity: Static<
|
|
1361
|
+
save(entity: Static<T>, opts?: StatementOptions): Promise<void>;
|
|
1631
1362
|
/**
|
|
1632
1363
|
* Find an entity by ID and update it.
|
|
1633
1364
|
*/
|
|
1634
|
-
updateById(id: string | number, data: Partial<Static<TObjectUpdate<
|
|
1365
|
+
updateById(id: string | number, data: Partial<Static<TObjectUpdate<T>>>, opts?: StatementOptions): Promise<Static<T>>;
|
|
1635
1366
|
/**
|
|
1636
1367
|
* Find many entities and update all of them.
|
|
1637
1368
|
*/
|
|
1638
|
-
updateMany(where: PgQueryWhereOrSQL<
|
|
1369
|
+
updateMany(where: PgQueryWhereOrSQL<T>, data: Partial<Static<TObjectUpdate<T>>>, opts?: StatementOptions): Promise<Array<number | string>>;
|
|
1639
1370
|
/**
|
|
1640
1371
|
* Find many and delete all of them.
|
|
1372
|
+
* @returns Array of deleted entity IDs
|
|
1641
1373
|
*/
|
|
1642
|
-
deleteMany(where?: PgQueryWhereOrSQL<
|
|
1374
|
+
deleteMany(where?: PgQueryWhereOrSQL<T>, opts?: StatementOptions): Promise<Array<number | string>>;
|
|
1643
1375
|
/**
|
|
1644
1376
|
* Delete all entities.
|
|
1377
|
+
* @returns Array of deleted entity IDs
|
|
1645
1378
|
*/
|
|
1646
|
-
clear(opts?: StatementOptions): Promise<
|
|
1379
|
+
clear(opts?: StatementOptions): Promise<Array<number | string>>;
|
|
1647
1380
|
/**
|
|
1648
1381
|
* Delete the given entity.
|
|
1649
1382
|
*
|
|
1650
1383
|
* You must fetch the entity first in order to delete it.
|
|
1384
|
+
* @returns Array containing the deleted entity ID
|
|
1651
1385
|
*/
|
|
1652
|
-
destroy(entity: Static<
|
|
1386
|
+
destroy(entity: Static<T>, opts?: StatementOptions): Promise<Array<number | string>>;
|
|
1653
1387
|
/**
|
|
1654
1388
|
* Find an entity and delete it.
|
|
1389
|
+
* @returns Array of deleted entity IDs (should contain at most one ID)
|
|
1655
1390
|
*/
|
|
1656
|
-
deleteOne(where?: PgQueryWhereOrSQL<
|
|
1391
|
+
deleteOne(where?: PgQueryWhereOrSQL<T>, opts?: StatementOptions): Promise<Array<number | string>>;
|
|
1657
1392
|
/**
|
|
1658
1393
|
* Find an entity by ID and delete it.
|
|
1394
|
+
* @returns Array containing the deleted entity ID
|
|
1395
|
+
* @throws PgEntityNotFoundError if the entity is not found
|
|
1659
1396
|
*/
|
|
1660
|
-
deleteById(id: string | number, opts?: StatementOptions): Promise<
|
|
1397
|
+
deleteById(id: string | number, opts?: StatementOptions): Promise<Array<number | string>>;
|
|
1661
1398
|
/**
|
|
1662
1399
|
* Count entities.
|
|
1663
1400
|
*/
|
|
1664
|
-
count(where?: PgQueryWhereOrSQL<
|
|
1401
|
+
count(where?: PgQueryWhereOrSQL<T>, opts?: StatementOptions): Promise<number>;
|
|
1665
1402
|
protected conflictMessagePattern: string;
|
|
1666
1403
|
protected handleError(error: unknown, message: string): PgError;
|
|
1667
|
-
protected withDeletedAt(where: PgQueryWhereOrSQL<
|
|
1404
|
+
protected withDeletedAt(where: PgQueryWhereOrSQL<T>, opts?: {
|
|
1668
1405
|
force?: boolean;
|
|
1669
|
-
}): PgQueryWhereOrSQL<
|
|
1670
|
-
protected get organization(): undefined;
|
|
1406
|
+
}): PgQueryWhereOrSQL<T>;
|
|
1671
1407
|
protected deletedAt(): PgAttrField | undefined;
|
|
1672
|
-
/**
|
|
1673
|
-
* Convert a query object to a SQL query.
|
|
1674
|
-
*
|
|
1675
|
-
* @param query The query object.
|
|
1676
|
-
* @param schema The schema to use.
|
|
1677
|
-
* @param col The column to use.
|
|
1678
|
-
*/
|
|
1679
|
-
protected jsonQueryToSql(query: PgQueryWhereOrSQL<EntitySchema>, schema?: TObject, col?: (key: string) => PgColumn): SQL | undefined;
|
|
1680
|
-
/**
|
|
1681
|
-
* Map a filter operator to a SQL query.
|
|
1682
|
-
*
|
|
1683
|
-
* @param operator
|
|
1684
|
-
* @param column
|
|
1685
|
-
* @protected
|
|
1686
|
-
*/
|
|
1687
|
-
protected mapOperatorToSql(operator: FilterOperators<any> | any, column: PgColumn): SQL | undefined;
|
|
1688
|
-
/**
|
|
1689
|
-
* Create a pagination object.
|
|
1690
|
-
*
|
|
1691
|
-
* @param entities The entities to paginate.
|
|
1692
|
-
* @param limit The limit of the pagination.
|
|
1693
|
-
* @param offset The offset of the pagination.
|
|
1694
|
-
*/
|
|
1695
|
-
protected createPagination(entities: Static<EntitySchema>[], limit?: number, offset?: number): Page<Static<EntitySchema>>;
|
|
1696
1408
|
/**
|
|
1697
1409
|
* Convert something to valid Pg Insert Value.
|
|
1698
1410
|
*/
|
|
1699
|
-
protected cast(data: any, insert: boolean): PgInsertValue<PgTableWithColumns<
|
|
1411
|
+
protected cast(data: any, insert: boolean): PgInsertValue<PgTableWithColumns<SchemaToTableConfig<T>>>;
|
|
1700
1412
|
/**
|
|
1701
|
-
*
|
|
1413
|
+
* Transform a row from the database into a clean entity.
|
|
1702
1414
|
*
|
|
1703
|
-
*
|
|
1704
|
-
*
|
|
1705
|
-
*
|
|
1415
|
+
* - Validate against schema
|
|
1416
|
+
* - Replace all null values by undefined
|
|
1417
|
+
* - Fix date-time and date fields to ISO strings
|
|
1418
|
+
* - Cast BigInt to string
|
|
1706
1419
|
*/
|
|
1707
|
-
protected clean<T extends TObject
|
|
1420
|
+
protected clean<T extends TObject>(row: Record<string, unknown>, schema: T): Static<T>;
|
|
1708
1421
|
/**
|
|
1709
|
-
*
|
|
1710
|
-
* Format: "firstName,-lastName" -> [{ column: "firstName", direction: "asc" }, { column: "lastName", direction: "desc" }]
|
|
1711
|
-
* - Columns separated by comma
|
|
1712
|
-
* - Prefix with '-' for DESC direction
|
|
1713
|
-
*
|
|
1714
|
-
* @param sort Pagination sort string
|
|
1715
|
-
* @returns OrderBy array or single object
|
|
1422
|
+
* Clean a row with joins recursively
|
|
1716
1423
|
*/
|
|
1717
|
-
protected
|
|
1718
|
-
column: string;
|
|
1719
|
-
direction: "asc" | "desc";
|
|
1720
|
-
}> | {
|
|
1721
|
-
column: string;
|
|
1722
|
-
direction: "asc" | "desc";
|
|
1723
|
-
};
|
|
1424
|
+
protected cleanWithJoins<T extends TObject>(row: Record<string, unknown>, schema: T, joins: PgJoin[], parentPath?: string): Static<T>;
|
|
1724
1425
|
/**
|
|
1725
|
-
*
|
|
1726
|
-
* Supports 3 modes:
|
|
1727
|
-
* 1. String: "name" -> [{ column: "name", direction: "asc" }]
|
|
1728
|
-
* 2. Object: { column: "name", direction: "desc" } -> [{ column: "name", direction: "desc" }]
|
|
1729
|
-
* 3. Array: [{ column: "name" }, { column: "age", direction: "desc" }] -> normalized array
|
|
1730
|
-
*
|
|
1731
|
-
* @param orderBy The orderBy parameter
|
|
1732
|
-
* @returns Normalized array of order by clauses
|
|
1426
|
+
* Convert a where clause to SQL.
|
|
1733
1427
|
*/
|
|
1734
|
-
protected
|
|
1735
|
-
column: string;
|
|
1736
|
-
direction: "asc" | "desc";
|
|
1737
|
-
}>;
|
|
1428
|
+
protected toSQL(where: PgQueryWhereOrSQL<T>, joins?: PgJoin[]): SQL | undefined;
|
|
1738
1429
|
/**
|
|
1739
1430
|
* Get the where clause for an ID.
|
|
1740
1431
|
*
|
|
1741
1432
|
* @param id The ID to get the where clause for.
|
|
1742
1433
|
* @returns The where clause for the ID.
|
|
1743
1434
|
*/
|
|
1744
|
-
protected getWhereId(id: string | number):
|
|
1435
|
+
protected getWhereId(id: string | number): PgQueryWhere<T>;
|
|
1745
1436
|
/**
|
|
1746
1437
|
* Find a primary key in the schema.
|
|
1747
|
-
*
|
|
1748
|
-
* @param schema
|
|
1749
|
-
* @protected
|
|
1750
1438
|
*/
|
|
1751
1439
|
protected getPrimaryKey(schema: TObject): {
|
|
1752
1440
|
key: string;
|
|
1753
|
-
col: PgColumn<
|
|
1754
|
-
type: TSchema
|
|
1441
|
+
col: PgColumn<drizzle_orm0.ColumnBaseConfig<drizzle_orm0.ColumnDataType, string>, {}, {}>;
|
|
1442
|
+
type: TSchema;
|
|
1755
1443
|
};
|
|
1444
|
+
protected $provider(): DatabaseProvider;
|
|
1756
1445
|
}
|
|
1757
1446
|
/**
|
|
1758
1447
|
* The options for a statement.
|
|
@@ -1779,374 +1468,6 @@ interface StatementOptions {
|
|
|
1779
1468
|
now?: DateTime;
|
|
1780
1469
|
}
|
|
1781
1470
|
//#endregion
|
|
1782
|
-
//#region src/descriptors/$sequence.d.ts
|
|
1783
|
-
/**
|
|
1784
|
-
* Creates a PostgreSQL sequence descriptor for generating unique numeric values.
|
|
1785
|
-
*
|
|
1786
|
-
* This descriptor provides a type-safe interface to PostgreSQL sequences, which are
|
|
1787
|
-
* database objects that generate unique numeric identifiers. Sequences are commonly
|
|
1788
|
-
* used for primary keys, order numbers, invoice numbers, and other cases where
|
|
1789
|
-
* guaranteed unique, incrementing values are needed across concurrent operations.
|
|
1790
|
-
*
|
|
1791
|
-
* **Key Features**
|
|
1792
|
-
*
|
|
1793
|
-
* - **Thread-Safe**: PostgreSQL sequences are inherently thread-safe and handle concurrency
|
|
1794
|
-
* - **Configurable Parameters**: Start value, increment, min/max bounds, and cycling behavior
|
|
1795
|
-
* - **Automatic Creation**: Sequences are created automatically when first used
|
|
1796
|
-
* - **Type Safety**: Full TypeScript support with numeric return types
|
|
1797
|
-
* - **Performance**: Optimized for high-throughput ID generation
|
|
1798
|
-
* - **Schema Support**: Works with PostgreSQL schemas for organization
|
|
1799
|
-
*
|
|
1800
|
-
* **Use Cases**
|
|
1801
|
-
*
|
|
1802
|
-
* Perfect for generating unique identifiers in concurrent environments:
|
|
1803
|
-
* - Primary key generation (alternative to UUIDs)
|
|
1804
|
-
* - Order numbers and invoice sequences
|
|
1805
|
-
* - Ticket numbers and reference IDs
|
|
1806
|
-
* - Version numbers and revision tracking
|
|
1807
|
-
* - Batch numbers for processing workflows
|
|
1808
|
-
* - Any scenario requiring guaranteed unique incrementing numbers
|
|
1809
|
-
*
|
|
1810
|
-
* @example
|
|
1811
|
-
* **Basic sequence for order numbers:**
|
|
1812
|
-
* ```ts
|
|
1813
|
-
* import { $sequence } from "alepha/postgres";
|
|
1814
|
-
*
|
|
1815
|
-
* class OrderService {
|
|
1816
|
-
* orderNumbers = $sequence({
|
|
1817
|
-
* name: "order_numbers",
|
|
1818
|
-
* start: 1000, // Start from order #1000
|
|
1819
|
-
* increment: 1 // Increment by 1 each time
|
|
1820
|
-
* });
|
|
1821
|
-
*
|
|
1822
|
-
* async createOrder(orderData: OrderData) {
|
|
1823
|
-
* const orderNumber = await this.orderNumbers.next();
|
|
1824
|
-
*
|
|
1825
|
-
* return await this.orders.create({
|
|
1826
|
-
* id: generateUUID(),
|
|
1827
|
-
* orderNumber,
|
|
1828
|
-
* ...orderData
|
|
1829
|
-
* });
|
|
1830
|
-
* }
|
|
1831
|
-
*
|
|
1832
|
-
* async getCurrentOrderNumber() {
|
|
1833
|
-
* // Get the last generated number without incrementing
|
|
1834
|
-
* return await this.orderNumbers.current();
|
|
1835
|
-
* }
|
|
1836
|
-
* }
|
|
1837
|
-
* ```
|
|
1838
|
-
*
|
|
1839
|
-
* @example
|
|
1840
|
-
* **Invoice numbering with yearly reset:**
|
|
1841
|
-
* ```ts
|
|
1842
|
-
* class InvoiceService {
|
|
1843
|
-
* // Separate sequence for each year
|
|
1844
|
-
* getInvoiceSequence(year: number) {
|
|
1845
|
-
* return $sequence({
|
|
1846
|
-
* name: `invoice_numbers_${year}`,
|
|
1847
|
-
* start: 1,
|
|
1848
|
-
* increment: 1
|
|
1849
|
-
* });
|
|
1850
|
-
* }
|
|
1851
|
-
*
|
|
1852
|
-
* async generateInvoiceNumber(): Promise<string> {
|
|
1853
|
-
* const year = new Date().getFullYear();
|
|
1854
|
-
* const sequence = this.getInvoiceSequence(year);
|
|
1855
|
-
* const number = await sequence.next();
|
|
1856
|
-
*
|
|
1857
|
-
* // Format as INV-2024-001, INV-2024-002, etc.
|
|
1858
|
-
* return `INV-${year}-${number.toString().padStart(3, '0')}`;
|
|
1859
|
-
* }
|
|
1860
|
-
* }
|
|
1861
|
-
* ```
|
|
1862
|
-
*
|
|
1863
|
-
* @example
|
|
1864
|
-
* **High-performance ID generation with custom increments:**
|
|
1865
|
-
* ```ts
|
|
1866
|
-
* class TicketService {
|
|
1867
|
-
* // Generate ticket numbers in increments of 10 for better distribution
|
|
1868
|
-
* ticketSequence = $sequence({
|
|
1869
|
-
* name: "ticket_numbers",
|
|
1870
|
-
* start: 1000,
|
|
1871
|
-
* increment: 10,
|
|
1872
|
-
* min: 1000,
|
|
1873
|
-
* max: 999999,
|
|
1874
|
-
* cycle: false // Don't cycle when max is reached
|
|
1875
|
-
* });
|
|
1876
|
-
*
|
|
1877
|
-
* priorityTicketSequence = $sequence({
|
|
1878
|
-
* name: "priority_ticket_numbers",
|
|
1879
|
-
* start: 1,
|
|
1880
|
-
* increment: 1,
|
|
1881
|
-
* min: 1,
|
|
1882
|
-
* max: 999,
|
|
1883
|
-
* cycle: true // Cycle when reaching max
|
|
1884
|
-
* });
|
|
1885
|
-
*
|
|
1886
|
-
* async generateTicketNumber(isPriority: boolean = false): Promise<number> {
|
|
1887
|
-
* if (isPriority) {
|
|
1888
|
-
* return await this.priorityTicketSequence.next();
|
|
1889
|
-
* }
|
|
1890
|
-
* return await this.ticketSequence.next();
|
|
1891
|
-
* }
|
|
1892
|
-
*
|
|
1893
|
-
* async getSequenceStatus() {
|
|
1894
|
-
* return {
|
|
1895
|
-
* currentTicketNumber: await this.ticketSequence.current(),
|
|
1896
|
-
* currentPriorityNumber: await this.priorityTicketSequence.current()
|
|
1897
|
-
* };
|
|
1898
|
-
* }
|
|
1899
|
-
* }
|
|
1900
|
-
* ```
|
|
1901
|
-
*
|
|
1902
|
-
* @example
|
|
1903
|
-
* **Batch processing with sequence-based coordination:**
|
|
1904
|
-
* ```ts
|
|
1905
|
-
* class BatchProcessor {
|
|
1906
|
-
* batchSequence = $sequence({
|
|
1907
|
-
* name: "batch_numbers",
|
|
1908
|
-
* start: 1,
|
|
1909
|
-
* increment: 1
|
|
1910
|
-
* });
|
|
1911
|
-
*
|
|
1912
|
-
* async processBatch(items: any[]) {
|
|
1913
|
-
* const batchNumber = await this.batchSequence.next();
|
|
1914
|
-
*
|
|
1915
|
-
* console.log(`Starting batch processing #${batchNumber} with ${items.length} items`);
|
|
1916
|
-
*
|
|
1917
|
-
* try {
|
|
1918
|
-
* // Process items with batch number for tracking
|
|
1919
|
-
* for (const item of items) {
|
|
1920
|
-
* await this.processItem(item, batchNumber);
|
|
1921
|
-
* }
|
|
1922
|
-
*
|
|
1923
|
-
* await this.auditLogger.log({
|
|
1924
|
-
* event: 'batch_completed',
|
|
1925
|
-
* batchNumber,
|
|
1926
|
-
* itemCount: items.length,
|
|
1927
|
-
* timestamp: new Date()
|
|
1928
|
-
* });
|
|
1929
|
-
*
|
|
1930
|
-
* return { batchNumber, processedCount: items.length };
|
|
1931
|
-
*
|
|
1932
|
-
* } catch (error) {
|
|
1933
|
-
* await this.auditLogger.log({
|
|
1934
|
-
* event: 'batch_failed',
|
|
1935
|
-
* batchNumber,
|
|
1936
|
-
* error: error.message,
|
|
1937
|
-
* timestamp: new Date()
|
|
1938
|
-
* });
|
|
1939
|
-
* throw error;
|
|
1940
|
-
* }
|
|
1941
|
-
* }
|
|
1942
|
-
*
|
|
1943
|
-
* async processItem(item: any, batchNumber: number) {
|
|
1944
|
-
* // Associate item processing with batch number
|
|
1945
|
-
* await this.items.update(item.id, {
|
|
1946
|
-
* ...item.updates,
|
|
1947
|
-
* batchNumber,
|
|
1948
|
-
* processedAt: new Date()
|
|
1949
|
-
* });
|
|
1950
|
-
* }
|
|
1951
|
-
* }
|
|
1952
|
-
* ```
|
|
1953
|
-
*
|
|
1954
|
-
* @example
|
|
1955
|
-
* **Multi-tenant sequence management:**
|
|
1956
|
-
* ```ts
|
|
1957
|
-
* class TenantSequenceService {
|
|
1958
|
-
* // Create tenant-specific sequences
|
|
1959
|
-
* getTenantSequence(tenantId: string, sequenceType: string) {
|
|
1960
|
-
* return $sequence({
|
|
1961
|
-
* name: `${tenantId}_${sequenceType}_seq`,
|
|
1962
|
-
* start: 1,
|
|
1963
|
-
* increment: 1
|
|
1964
|
-
* });
|
|
1965
|
-
* }
|
|
1966
|
-
*
|
|
1967
|
-
* async generateTenantOrderNumber(tenantId: string): Promise<string> {
|
|
1968
|
-
* const sequence = this.getTenantSequence(tenantId, 'orders');
|
|
1969
|
-
* const number = await sequence.next();
|
|
1970
|
-
*
|
|
1971
|
-
* return `${tenantId.toUpperCase()}-ORD-${number.toString().padStart(6, '0')}`;
|
|
1972
|
-
* }
|
|
1973
|
-
*
|
|
1974
|
-
* async generateTenantInvoiceNumber(tenantId: string): Promise<string> {
|
|
1975
|
-
* const sequence = this.getTenantSequence(tenantId, 'invoices');
|
|
1976
|
-
* const number = await sequence.next();
|
|
1977
|
-
*
|
|
1978
|
-
* return `${tenantId.toUpperCase()}-INV-${number.toString().padStart(6, '0')}`;
|
|
1979
|
-
* }
|
|
1980
|
-
*
|
|
1981
|
-
* async getTenantSequenceStatus(tenantId: string) {
|
|
1982
|
-
* const orderSeq = this.getTenantSequence(tenantId, 'orders');
|
|
1983
|
-
* const invoiceSeq = this.getTenantSequence(tenantId, 'invoices');
|
|
1984
|
-
*
|
|
1985
|
-
* return {
|
|
1986
|
-
* tenant: tenantId,
|
|
1987
|
-
* sequences: {
|
|
1988
|
-
* orders: {
|
|
1989
|
-
* current: await orderSeq.current(),
|
|
1990
|
-
* next: await orderSeq.next()
|
|
1991
|
-
* },
|
|
1992
|
-
* invoices: {
|
|
1993
|
-
* current: await invoiceSeq.current()
|
|
1994
|
-
* }
|
|
1995
|
-
* }
|
|
1996
|
-
* };
|
|
1997
|
-
* }
|
|
1998
|
-
* }
|
|
1999
|
-
* ```
|
|
2000
|
-
*
|
|
2001
|
-
* **Important Notes**:
|
|
2002
|
-
* - Sequences are created automatically when first used
|
|
2003
|
-
* - PostgreSQL sequences are atomic and handle high concurrency
|
|
2004
|
-
* - Sequence values are not rolled back in failed transactions
|
|
2005
|
-
* - Consider the impact of max values and cycling behavior
|
|
2006
|
-
* - Sequences are schema-scoped in PostgreSQL
|
|
2007
|
-
*
|
|
2008
|
-
* @stability 1
|
|
2009
|
-
*/
|
|
2010
|
-
declare const $sequence: {
|
|
2011
|
-
(options?: SequenceDescriptorOptions): SequenceDescriptor;
|
|
2012
|
-
[KIND]: typeof SequenceDescriptor;
|
|
2013
|
-
};
|
|
2014
|
-
interface SequenceDescriptorOptions {
|
|
2015
|
-
/**
|
|
2016
|
-
* Name of the PostgreSQL sequence to create.
|
|
2017
|
-
*
|
|
2018
|
-
* This name:
|
|
2019
|
-
* - Must be unique within the database schema
|
|
2020
|
-
* - Should follow PostgreSQL identifier conventions
|
|
2021
|
-
* - Will be used in generated SQL for sequence operations
|
|
2022
|
-
* - Should be descriptive of the sequence's purpose
|
|
2023
|
-
*
|
|
2024
|
-
* If not provided, defaults to the property key where the sequence is declared.
|
|
2025
|
-
*
|
|
2026
|
-
* **Naming Guidelines**:
|
|
2027
|
-
* - Use descriptive names like "order_numbers", "invoice_seq"
|
|
2028
|
-
* - Include the purpose or entity type in the name
|
|
2029
|
-
* - Consider adding "_seq" suffix for clarity
|
|
2030
|
-
* - Use snake_case for consistency with PostgreSQL conventions
|
|
2031
|
-
*
|
|
2032
|
-
* @example "order_numbers"
|
|
2033
|
-
* @example "invoice_sequence"
|
|
2034
|
-
* @example "ticket_numbers_seq"
|
|
2035
|
-
*/
|
|
2036
|
-
name?: string;
|
|
2037
|
-
/**
|
|
2038
|
-
* The starting value for the sequence.
|
|
2039
|
-
*
|
|
2040
|
-
* This value:
|
|
2041
|
-
* - Determines the first number that will be generated
|
|
2042
|
-
* - Can be any integer within the sequence's range
|
|
2043
|
-
* - Is useful for avoiding conflicts with existing data
|
|
2044
|
-
* - Can be set higher for business reasons (e.g., starting invoices at 1000)
|
|
2045
|
-
*
|
|
2046
|
-
* **Common Patterns**:
|
|
2047
|
-
* - Start at 1 for simple counters
|
|
2048
|
-
* - Start at 1000+ for professional-looking numbers
|
|
2049
|
-
* - Start at current max + 1 when migrating existing data
|
|
2050
|
-
*
|
|
2051
|
-
* @default 1
|
|
2052
|
-
* @example 1 // Simple counter starting at 1
|
|
2053
|
-
* @example 1000 // Professional numbering starting at 1000
|
|
2054
|
-
* @example 10000 // Large starting number for established businesses
|
|
2055
|
-
*/
|
|
2056
|
-
start?: number;
|
|
2057
|
-
/**
|
|
2058
|
-
* The increment value for each call to next().
|
|
2059
|
-
*
|
|
2060
|
-
* This value:
|
|
2061
|
-
* - Determines how much the sequence increases each time
|
|
2062
|
-
* - Can be any positive or negative integer
|
|
2063
|
-
* - Affects the gaps between generated numbers
|
|
2064
|
-
* - Can be used for number distribution strategies
|
|
2065
|
-
*
|
|
2066
|
-
* **Use Cases**:
|
|
2067
|
-
* - increment: 1 for consecutive numbering
|
|
2068
|
-
* - increment: 10 for distributed numbering (leaves gaps for manual entries)
|
|
2069
|
-
* - increment: -1 for countdown sequences
|
|
2070
|
-
*
|
|
2071
|
-
* @default 1
|
|
2072
|
-
* @example 1 // Standard consecutive numbering
|
|
2073
|
-
* @example 10 // Leave gaps between numbers
|
|
2074
|
-
* @example 100 // Large gaps for special numbering schemes
|
|
2075
|
-
*/
|
|
2076
|
-
increment?: number;
|
|
2077
|
-
/**
|
|
2078
|
-
* The minimum value the sequence can generate.
|
|
2079
|
-
*
|
|
2080
|
-
* When the sequence reaches this value:
|
|
2081
|
-
* - It cannot generate values below this minimum
|
|
2082
|
-
* - Helps prevent negative numbers in contexts where they don't make sense
|
|
2083
|
-
* - Works with cycling behavior to define the lower bound
|
|
2084
|
-
*
|
|
2085
|
-
* **Considerations**:
|
|
2086
|
-
* - Set to 1 for positive-only sequences
|
|
2087
|
-
* - Set to 0 if zero values are acceptable
|
|
2088
|
-
* - Consider business rules about minimum valid numbers
|
|
2089
|
-
*
|
|
2090
|
-
* @example 1 // No zero or negative values
|
|
2091
|
-
* @example 0 // Allow zero values
|
|
2092
|
-
* @example 1000 // Maintain minimum professional appearance
|
|
2093
|
-
*/
|
|
2094
|
-
min?: number;
|
|
2095
|
-
/**
|
|
2096
|
-
* The maximum value the sequence can generate.
|
|
2097
|
-
*
|
|
2098
|
-
* When the sequence reaches this value:
|
|
2099
|
-
* - It cannot generate values above this maximum
|
|
2100
|
-
* - Behavior depends on the cycle option
|
|
2101
|
-
* - Useful for preventing overflow or limiting number ranges
|
|
2102
|
-
*
|
|
2103
|
-
* **Planning Considerations**:
|
|
2104
|
-
* - Consider the expected volume of your application
|
|
2105
|
-
* - Account for business growth over time
|
|
2106
|
-
* - Factor in any formatting constraints (e.g., fixed-width displays)
|
|
2107
|
-
* - Remember that PostgreSQL sequences can handle very large numbers
|
|
2108
|
-
*
|
|
2109
|
-
* @example 999999 // Six-digit limit
|
|
2110
|
-
* @example 2147483647 // Maximum 32-bit signed integer
|
|
2111
|
-
* @example 9999 // Four-digit limit for display purposes
|
|
2112
|
-
*/
|
|
2113
|
-
max?: number;
|
|
2114
|
-
/**
|
|
2115
|
-
* Whether the sequence should cycle back to the minimum when it reaches the maximum.
|
|
2116
|
-
*
|
|
2117
|
-
* **cycle: true**:
|
|
2118
|
-
* - When max is reached, next value will be the minimum value
|
|
2119
|
-
* - Useful for scenarios where number reuse is acceptable
|
|
2120
|
-
* - Common for temporary identifiers or rotating references
|
|
2121
|
-
*
|
|
2122
|
-
* **cycle: false (default)**:
|
|
2123
|
-
* - When max is reached, further calls will fail with an error
|
|
2124
|
-
* - Prevents unexpected number reuse
|
|
2125
|
-
* - Better for permanent identifiers where uniqueness is critical
|
|
2126
|
-
*
|
|
2127
|
-
* **Use Cases for Cycling**:
|
|
2128
|
-
* - Temporary ticket numbers that can be reused
|
|
2129
|
-
* - Session IDs with limited lifetime
|
|
2130
|
-
* - Batch numbers in rotating systems
|
|
2131
|
-
*
|
|
2132
|
-
* **Avoid Cycling For**:
|
|
2133
|
-
* - Primary keys and permanent identifiers
|
|
2134
|
-
* - Invoice numbers and financial references
|
|
2135
|
-
* - Audit logs and compliance records
|
|
2136
|
-
*
|
|
2137
|
-
* @default false
|
|
2138
|
-
*/
|
|
2139
|
-
cycle?: boolean;
|
|
2140
|
-
}
|
|
2141
|
-
declare class SequenceDescriptor extends Descriptor<SequenceDescriptorOptions> {
|
|
2142
|
-
protected readonly provider: PostgresProvider;
|
|
2143
|
-
protected created: boolean;
|
|
2144
|
-
get name(): string;
|
|
2145
|
-
protected create(): Promise<void>;
|
|
2146
|
-
next(): Promise<number>;
|
|
2147
|
-
current(): Promise<number>;
|
|
2148
|
-
}
|
|
2149
|
-
//#endregion
|
|
2150
1471
|
//#region src/descriptors/$transaction.d.ts
|
|
2151
1472
|
/**
|
|
2152
1473
|
* Creates a transaction descriptor for database operations requiring atomicity and consistency.
|
|
@@ -2298,66 +1619,85 @@ declare class PgVersionMismatchError extends PgError {
|
|
|
2298
1619
|
constructor(table: string, id: any);
|
|
2299
1620
|
}
|
|
2300
1621
|
//#endregion
|
|
2301
|
-
//#region src/providers/
|
|
2302
|
-
declare class
|
|
2303
|
-
protected readonly log:
|
|
1622
|
+
//#region src/providers/DrizzleKitProvider.d.ts
|
|
1623
|
+
declare class DrizzleKitProvider {
|
|
1624
|
+
protected readonly log: _alepha_logger0.Logger;
|
|
2304
1625
|
protected readonly alepha: Alepha;
|
|
2305
|
-
protected get repositories(): RepositoryDescriptor<TableConfig$1, TObject>[];
|
|
2306
1626
|
/**
|
|
2307
|
-
*
|
|
1627
|
+
* Synchronize database with current schema definitions.
|
|
2308
1628
|
*
|
|
2309
|
-
*
|
|
2310
|
-
|
|
2311
|
-
getRepositories(provider?: PostgresProvider): RepositoryDescriptor<TableConfig$1, TObject>[];
|
|
2312
|
-
/**
|
|
2313
|
-
* Get all tables from the repositories.
|
|
1629
|
+
* In development mode, it will generate and execute migrations based on the current state.
|
|
1630
|
+
* In testing mode, it will generate migrations from scratch without applying them.
|
|
2314
1631
|
*
|
|
2315
|
-
*
|
|
1632
|
+
* Does nothing in production mode, you must handle migrations manually.
|
|
2316
1633
|
*/
|
|
2317
|
-
|
|
1634
|
+
synchronize(provider: DatabaseProvider): Promise<void>;
|
|
2318
1635
|
/**
|
|
2319
|
-
*
|
|
1636
|
+
* Mostly used for testing purposes. You can generate SQL migration statements without executing them.
|
|
2320
1637
|
*/
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
protected readonly log: _alepha_logger1.Logger;
|
|
2327
|
-
protected readonly alepha: Alepha;
|
|
2328
|
-
protected readonly repositoryProvider: RepositoryProvider;
|
|
2329
|
-
push(provider: PostgresProvider, schema?: string): Promise<void>;
|
|
2330
|
-
setPgSchema(provider: PostgresProvider): Promise<void>;
|
|
1638
|
+
generateMigration(provider: DatabaseProvider, prevSnapshot?: any): Promise<{
|
|
1639
|
+
statements: string[];
|
|
1640
|
+
models: Record<string, unknown>;
|
|
1641
|
+
snapshot?: any;
|
|
1642
|
+
}>;
|
|
2331
1643
|
/**
|
|
2332
|
-
*
|
|
2333
|
-
* Then, execute the migrations.
|
|
2334
|
-
*
|
|
2335
|
-
* This is useful for testing or development purposes.
|
|
2336
|
-
*
|
|
2337
|
-
* Do not use in production.
|
|
2338
|
-
*
|
|
2339
|
-
* @param provider - The Postgres provider to use.
|
|
2340
|
-
* @param schema - The schema to use.
|
|
2341
|
-
* @returns A promise that resolves once the migrations have been executed.
|
|
1644
|
+
* Load all tables, enums, sequences, etc. from the provider's repositories.
|
|
2342
1645
|
*/
|
|
2343
|
-
|
|
1646
|
+
getModels(provider: DatabaseProvider): Record<string, unknown>;
|
|
2344
1647
|
/**
|
|
2345
|
-
*
|
|
1648
|
+
* Load the migration snapshot from the database.
|
|
2346
1649
|
*/
|
|
2347
|
-
protected
|
|
2348
|
-
protected
|
|
2349
|
-
protected
|
|
2350
|
-
|
|
2351
|
-
snapshot: string;
|
|
2352
|
-
}): Promise<void>;
|
|
2353
|
-
protected executeStatements(statements: string[], provider: PostgresProvider, _schema?: string, catchErrors?: boolean): Promise<void>;
|
|
2354
|
-
protected prepareSchema(schemaName: string, provider: PostgresProvider, repositories: any[]): Promise<void>;
|
|
1650
|
+
protected loadDevMigrations(provider: DatabaseProvider): Promise<DevMigrations | undefined>;
|
|
1651
|
+
protected saveDevMigrations(provider: DatabaseProvider, curr: Record<string, any>, devMigrations?: DevMigrations): Promise<void>;
|
|
1652
|
+
protected executeStatements(statements: string[], provider: DatabaseProvider, catchErrors?: boolean): Promise<void>;
|
|
1653
|
+
protected createSchemaIfNotExists(provider: DatabaseProvider, schemaName: string): Promise<void>;
|
|
2355
1654
|
/**
|
|
2356
1655
|
* Try to load the official Drizzle Kit API.
|
|
2357
1656
|
* If not available, fallback to the local kit import.
|
|
2358
1657
|
*/
|
|
2359
1658
|
protected importDrizzleKit(): typeof DrizzleKit;
|
|
2360
|
-
|
|
1659
|
+
}
|
|
1660
|
+
declare const devMigrationsSchema: typebox9.TObject<{
|
|
1661
|
+
id: typebox9.TNumber;
|
|
1662
|
+
name: typebox9.TString;
|
|
1663
|
+
snapshot: typebox9.TString;
|
|
1664
|
+
created_at: typebox9.TString;
|
|
1665
|
+
}>;
|
|
1666
|
+
type DevMigrations = Static<typeof devMigrationsSchema>;
|
|
1667
|
+
//#endregion
|
|
1668
|
+
//#region src/services/PostgresModelBuilder.d.ts
|
|
1669
|
+
declare class PostgresModelBuilder extends ModelBuilder {
|
|
1670
|
+
protected schemas: Map<string, drizzle_orm_pg_core0.PgSchema<string>>;
|
|
1671
|
+
protected getPgSchema(name: string): any;
|
|
1672
|
+
buildTable(entity: EntityDescriptor<any>, options: {
|
|
1673
|
+
tables: Map<string, unknown>;
|
|
1674
|
+
enums: Map<string, unknown>;
|
|
1675
|
+
schema: string;
|
|
1676
|
+
}): void;
|
|
1677
|
+
buildSequence(sequence: SequenceDescriptor, options: {
|
|
1678
|
+
sequences: Map<string, unknown>;
|
|
1679
|
+
schema: string;
|
|
1680
|
+
}): void;
|
|
1681
|
+
/**
|
|
1682
|
+
* Get PostgreSQL-specific config builder for the table.
|
|
1683
|
+
*/
|
|
1684
|
+
protected getTableConfig(entity: EntityDescriptor, tables: Map<string, unknown>): ((self: BuildExtraConfigColumns<string, any, "pg">) => PgTableExtraConfigValue[]) | undefined;
|
|
1685
|
+
schemaToPgColumns: <T extends TObject>(tableName: string, schema: T, nsp: PgSchema, enums: Map<string, unknown>, tables: Map<string, unknown>) => FromSchema<T>;
|
|
1686
|
+
mapFieldToColumn: (tableName: string, fieldName: string, value: TSchema, nsp: PgSchema, enums: Map<string, any>) => any;
|
|
1687
|
+
/**
|
|
1688
|
+
* Map a string to a PG column.
|
|
1689
|
+
*
|
|
1690
|
+
* @param key The key of the field.
|
|
1691
|
+
* @param value The value of the field.
|
|
1692
|
+
*/
|
|
1693
|
+
mapStringToColumn: (key: string, value: TSchema) => drizzle_orm_pg_core0.PgUUIDBuilderInitial<string> | drizzle_orm_pg_core0.PgCustomColumnBuilder<{
|
|
1694
|
+
name: string;
|
|
1695
|
+
dataType: "custom";
|
|
1696
|
+
columnType: "PgCustomColumn";
|
|
1697
|
+
data: Buffer<ArrayBufferLike>;
|
|
1698
|
+
driverParam: unknown;
|
|
1699
|
+
enumValues: undefined;
|
|
1700
|
+
}> | drizzle_orm_pg_core0.PgTimestampStringBuilderInitial<string> | drizzle_orm_pg_core0.PgDateStringBuilderInitial<string> | drizzle_orm_pg_core0.PgTextBuilderInitial<string, [string, ...string[]]>;
|
|
2361
1701
|
}
|
|
2362
1702
|
//#endregion
|
|
2363
1703
|
//#region src/providers/drivers/NodePostgresProvider.d.ts
|
|
@@ -2385,42 +1725,33 @@ declare const envSchema: _alepha_core1.TObject<{
|
|
|
2385
1725
|
* It will generate the migration script and save it to the DB.
|
|
2386
1726
|
*
|
|
2387
1727
|
* This is recommended for development and testing purposes only.
|
|
2388
|
-
*
|
|
2389
|
-
* @default false
|
|
2390
1728
|
*/
|
|
2391
1729
|
POSTGRES_SYNCHRONIZE: _alepha_core1.TOptional<_alepha_core1.TBoolean>;
|
|
2392
|
-
/**
|
|
2393
|
-
* Push the schema to the database.
|
|
2394
|
-
* It's like `drizzle-kit push` command.
|
|
2395
|
-
* It will introspect the models from DB and generate the SQL statements to create or update the tables.
|
|
2396
|
-
*
|
|
2397
|
-
* @default false
|
|
2398
|
-
*/
|
|
2399
|
-
POSTGRES_PUSH: _alepha_core1.TOptional<_alepha_core1.TBoolean>;
|
|
2400
1730
|
}>;
|
|
2401
1731
|
interface NodePostgresProviderOptions {
|
|
2402
1732
|
migrations: MigrationConfig;
|
|
2403
1733
|
connection: postgres.Options<any>;
|
|
2404
1734
|
}
|
|
2405
|
-
declare class NodePostgresProvider extends
|
|
1735
|
+
declare class NodePostgresProvider extends DatabaseProvider {
|
|
1736
|
+
static readonly SSL_MODES: readonly ["require", "allow", "prefer", "verify-full"];
|
|
2406
1737
|
readonly dialect = "postgres";
|
|
2407
|
-
protected readonly
|
|
2408
|
-
protected readonly log: _alepha_logger1.Logger;
|
|
1738
|
+
protected readonly log: _alepha_logger0.Logger;
|
|
2409
1739
|
protected readonly env: {
|
|
2410
1740
|
DATABASE_URL?: string | undefined;
|
|
2411
1741
|
POSTGRES_SCHEMA?: string | undefined;
|
|
2412
1742
|
POSTGRES_SYNCHRONIZE?: boolean | undefined;
|
|
2413
|
-
POSTGRES_PUSH?: boolean | undefined;
|
|
2414
1743
|
};
|
|
2415
1744
|
protected readonly alepha: Alepha;
|
|
2416
1745
|
protected readonly kit: DrizzleKitProvider;
|
|
1746
|
+
protected readonly builder: PostgresModelBuilder;
|
|
2417
1747
|
protected client?: postgres.Sql;
|
|
2418
1748
|
protected pg?: PostgresJsDatabase;
|
|
2419
1749
|
readonly options: NodePostgresProviderOptions;
|
|
2420
1750
|
/**
|
|
2421
1751
|
* In testing mode, the schema name will be generated and deleted after the test.
|
|
2422
1752
|
*/
|
|
2423
|
-
protected schemaForTesting
|
|
1753
|
+
protected schemaForTesting: string | undefined;
|
|
1754
|
+
execute(statement: SQLLike): Promise<Array<Record<string, unknown>>>;
|
|
2424
1755
|
/**
|
|
2425
1756
|
* Get Postgres schema.
|
|
2426
1757
|
*/
|
|
@@ -2450,7 +1781,7 @@ declare class NodePostgresProvider extends PostgresProvider {
|
|
|
2450
1781
|
//#endregion
|
|
2451
1782
|
//#region src/providers/PostgresTypeProvider.d.ts
|
|
2452
1783
|
declare class PostgresTypeProvider {
|
|
2453
|
-
readonly attr: <T extends TSchema
|
|
1784
|
+
readonly attr: <T extends TSchema, Attr extends PgSymbolKeys>(type: T, attr: Attr, value?: PgSymbols[Attr]) => PgAttr<T, Attr>;
|
|
2454
1785
|
/**
|
|
2455
1786
|
* Creates a primary key with an identity column.
|
|
2456
1787
|
*/
|
|
@@ -2478,7 +1809,7 @@ declare class PostgresTypeProvider {
|
|
|
2478
1809
|
* Wrap a schema with "default" attribute.
|
|
2479
1810
|
* This is used to set a default value for a column in the database.
|
|
2480
1811
|
*/
|
|
2481
|
-
readonly default: <T extends TSchema
|
|
1812
|
+
readonly default: <T extends TSchema>(type: T, value?: Static<T>) => PgAttr<T, PgDefault>;
|
|
2482
1813
|
/**
|
|
2483
1814
|
* Creates a column 'version'.
|
|
2484
1815
|
*
|
|
@@ -2493,21 +1824,33 @@ declare class PostgresTypeProvider {
|
|
|
2493
1824
|
/**
|
|
2494
1825
|
* Creates a column Created At. So just a datetime column with a default value of the current timestamp.
|
|
2495
1826
|
*/
|
|
2496
|
-
readonly createdAt: (options?: TStringOptions) => PgAttr<PgAttr<TString, typeof PG_CREATED_AT>, typeof PG_DEFAULT>;
|
|
1827
|
+
readonly createdAt: (options?: TStringOptions) => PgAttr<PgAttr<typebox9.TCodec<TString, dayjs0.Dayjs>, typeof PG_CREATED_AT>, typeof PG_DEFAULT>;
|
|
2497
1828
|
/**
|
|
2498
1829
|
* Creates a column Updated At. Like createdAt, but it is updated on every update of the row.
|
|
2499
1830
|
*/
|
|
2500
|
-
readonly updatedAt: (options?: TStringOptions) => PgAttr<PgAttr<TString, typeof PG_UPDATED_AT>, typeof PG_DEFAULT>;
|
|
1831
|
+
readonly updatedAt: (options?: TStringOptions) => PgAttr<PgAttr<typebox9.TCodec<TString, dayjs0.Dayjs>, typeof PG_UPDATED_AT>, typeof PG_DEFAULT>;
|
|
2501
1832
|
/**
|
|
2502
1833
|
* Creates a column Deleted At for soft delete functionality.
|
|
2503
1834
|
* This is used to mark rows as deleted without actually removing them from the database.
|
|
2504
1835
|
* The column is nullable - NULL means not deleted, timestamp means deleted.
|
|
2505
1836
|
*/
|
|
2506
|
-
readonly deletedAt: (options?: TStringOptions) => PgAttr<
|
|
1837
|
+
readonly deletedAt: (options?: TStringOptions) => PgAttr<typebox9.TOptional<typebox9.TCodec<TString, dayjs0.Dayjs>>, typeof PG_DELETED_AT>;
|
|
1838
|
+
/**
|
|
1839
|
+
* Creates a Postgres ENUM type.
|
|
1840
|
+
*
|
|
1841
|
+
* > By default, `t.enum()` is mapped to a TEXT column in Postgres.
|
|
1842
|
+
* > Using this method, you can create a real ENUM type in the database.
|
|
1843
|
+
*
|
|
1844
|
+
* @example
|
|
1845
|
+
* ```ts
|
|
1846
|
+
* const statusEnum = pg.enum(["pending", "active", "archived"], { name: "status_enum" });
|
|
1847
|
+
* ```
|
|
1848
|
+
*/
|
|
1849
|
+
readonly enum: <T extends string[]>(values: [...T], pgEnumOptions?: PgEnumOptions, typeOptions?: TStringOptions) => PgAttr<TUnsafe<T[number]>, typeof PG_ENUM>;
|
|
2507
1850
|
/**
|
|
2508
1851
|
* Creates a reference to another table or schema. Basically a foreign key.
|
|
2509
1852
|
*/
|
|
2510
|
-
readonly ref: <T extends TSchema
|
|
1853
|
+
readonly ref: <T extends TSchema>(type: T, ref: () => any, actions?: {
|
|
2511
1854
|
onUpdate?: UpdateDeleteAction$1;
|
|
2512
1855
|
onDelete?: UpdateDeleteAction$1;
|
|
2513
1856
|
}) => PgAttr<T, PgRef>;
|
|
@@ -2516,8 +1859,6 @@ declare class PostgresTypeProvider {
|
|
|
2516
1859
|
* It's used by {@link RepositoryDescriptor#paginate} method.
|
|
2517
1860
|
*/
|
|
2518
1861
|
readonly page: <T extends TObject>(resource: T, options?: TObjectOptions) => TPage<T>;
|
|
2519
|
-
readonly many: <T extends TObject, Config extends TableConfig>(table: PgTableWithColumnsAndSchema<Config, T>, foreignKey: keyof T["properties"]) => TOptionalAdd<PgAttr<PgAttr<TArray<T>, PgMany>, PgDefault>>;
|
|
2520
|
-
readonly one: <T extends TObject, Config extends TableConfig>(table: PgTableWithColumnsAndSchema<Config, T>, foreignKey: keyof T["properties"]) => PgAttr<PgAttr<TOptionalAdd<T>, PgOne>, PgDefault>;
|
|
2521
1862
|
}
|
|
2522
1863
|
declare const pg: PostgresTypeProvider;
|
|
2523
1864
|
//#endregion
|
|
@@ -2525,13 +1866,13 @@ declare const pg: PostgresTypeProvider;
|
|
|
2525
1866
|
/**
|
|
2526
1867
|
* @deprecated Use `pg.primaryKey()` instead.
|
|
2527
1868
|
*/
|
|
2528
|
-
declare const legacyIdSchema: PgAttr<PgAttr<PgAttr<
|
|
1869
|
+
declare const legacyIdSchema: PgAttr<PgAttr<PgAttr<typebox9.TInteger, typeof PG_PRIMARY_KEY>, typeof PG_SERIAL>, typeof PG_DEFAULT>;
|
|
2529
1870
|
//#endregion
|
|
2530
1871
|
//#region src/types/schema.d.ts
|
|
2531
1872
|
/**
|
|
2532
1873
|
* Postgres schema type.
|
|
2533
1874
|
*/
|
|
2534
|
-
declare const schema: <TDocument extends TSchema
|
|
1875
|
+
declare const schema: <TDocument extends TSchema>(name: string, document: TDocument) => drizzle_orm0.$Type<drizzle_orm_pg_core0.PgCustomColumnBuilder<{
|
|
2535
1876
|
name: string;
|
|
2536
1877
|
dataType: "custom";
|
|
2537
1878
|
columnType: "PgCustomColumn";
|
|
@@ -2574,14 +1915,13 @@ declare const schema: <TDocument extends TSchema$1>(name: string, document: TDoc
|
|
|
2574
1915
|
*
|
|
2575
1916
|
* Migrations are supported via Drizzle ORM, you need to use the `drizzle-kit` CLI tool to generate and run migrations.
|
|
2576
1917
|
*
|
|
2577
|
-
* Relations are **NOT SUPPORTED** yet. If you need relations, please use the `drizzle-orm` package directly.
|
|
2578
|
-
*
|
|
2579
1918
|
* @see {@link $entity}
|
|
1919
|
+
* @see {@link $sequence}
|
|
2580
1920
|
* @see {@link $repository}
|
|
2581
1921
|
* @see {@link $transaction}
|
|
2582
1922
|
* @module alepha.postgres
|
|
2583
1923
|
*/
|
|
2584
1924
|
declare const AlephaPostgres: _alepha_core1.Service<_alepha_core1.Module<{}>>;
|
|
2585
1925
|
//#endregion
|
|
2586
|
-
export { $entity, $repository, $sequence, $transaction, AlephaPostgres, DrizzleKitProvider,
|
|
1926
|
+
export { $entity, $repository, $sequence, $transaction, AlephaPostgres, DatabaseProvider, DrizzleKitProvider, EntityColumn, EntityColumns, EntityDescriptor, EntityDescriptorOptions, FilterOperators, FromSchema, NodePostgresProvider, NodePostgresProviderOptions, OrderBy, OrderByClause, OrderDirection, PG_CREATED_AT, PG_DEFAULT, PG_DELETED_AT, PG_ENUM, PG_IDENTITY, PG_PRIMARY_KEY, PG_REF, PG_SERIAL, PG_UPDATED_AT, PG_VERSION, Page, PageQuery, PgAttr, PgAttrField, PgConflictError, PgDefault, PgEntityNotFoundError, PgEnumOptions, PgError, PgIdentityOptions, PgMigrationError, PgPrimaryKey, PgQuery, PgQueryRelations, PgQueryWhere, PgQueryWhereOrSQL, PgRef, PgRefOptions, PgRelation, PgRelationMap, PgStatic, PgSymbolKeys, PgSymbols, PgVersionMismatchError, PostgresTypeProvider, RepositoryDescriptor, RepositoryDescriptorOptions, SQLLike, SchemaToTableConfig, SequenceDescriptor, SequenceDescriptorOptions, StatementOptions, TObjectInsert, TObjectUpdate, TPage, TransactionContext, TransactionDescriptorOptions, drizzle_orm0 as drizzle, getAttrFields, insertSchema, legacyIdSchema, pageQuerySchema, pageSchema, pg, pgAttr, schema, sql, updateSchema };
|
|
2587
1927
|
//# sourceMappingURL=index.d.ts.map
|