@c9up/atlas 0.1.19 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -14
- package/db.darwin-arm64.node +0 -0
- package/db.darwin-x64.node +0 -0
- package/db.linux-arm64-gnu.node +0 -0
- package/db.linux-x64-gnu.node +0 -0
- package/db.win32-x64-msvc.node +0 -0
- package/dist/AtlasProvider.d.ts +66 -7
- package/dist/AtlasProvider.d.ts.map +1 -1
- package/dist/AtlasProvider.js +205 -39
- package/dist/AtlasProvider.js.map +1 -1
- package/dist/BaseEntity.d.ts +181 -5
- package/dist/BaseEntity.d.ts.map +1 -1
- package/dist/BaseEntity.js +339 -33
- package/dist/BaseEntity.js.map +1 -1
- package/dist/BaseModel.d.ts +127 -0
- package/dist/BaseModel.d.ts.map +1 -0
- package/dist/BaseModel.js +250 -0
- package/dist/BaseModel.js.map +1 -0
- package/dist/BaseRepository.d.ts +81 -15
- package/dist/BaseRepository.d.ts.map +1 -1
- package/dist/BaseRepository.js +1433 -387
- package/dist/BaseRepository.js.map +1 -1
- package/dist/ConnectionManager.d.ts +106 -0
- package/dist/ConnectionManager.d.ts.map +1 -0
- package/dist/ConnectionManager.js +228 -0
- package/dist/ConnectionManager.js.map +1 -0
- package/dist/ModelQuery.d.ts +577 -41
- package/dist/ModelQuery.d.ts.map +1 -1
- package/dist/ModelQuery.js +2188 -291
- package/dist/ModelQuery.js.map +1 -1
- package/dist/Transaction.d.ts +71 -1
- package/dist/Transaction.d.ts.map +1 -1
- package/dist/Transaction.js +138 -24
- package/dist/Transaction.js.map +1 -1
- package/dist/adapters/NapiDbAdapter.d.ts +44 -4
- package/dist/adapters/NapiDbAdapter.d.ts.map +1 -1
- package/dist/adapters/NapiDbAdapter.js +131 -13
- package/dist/adapters/NapiDbAdapter.js.map +1 -1
- package/dist/console/contract.d.ts +62 -0
- package/dist/console/contract.d.ts.map +1 -0
- package/dist/console/contract.js +38 -0
- package/dist/console/contract.js.map +1 -0
- package/dist/console/factoryCommands.d.ts +23 -0
- package/dist/console/factoryCommands.d.ts.map +1 -0
- package/dist/console/factoryCommands.js +62 -0
- package/dist/console/factoryCommands.js.map +1 -0
- package/dist/console/migrationCommands.d.ts +78 -0
- package/dist/console/migrationCommands.d.ts.map +1 -0
- package/dist/console/migrationCommands.js +327 -0
- package/dist/console/migrationCommands.js.map +1 -0
- package/dist/console/schemaCheckCommand.d.ts +11 -17
- package/dist/console/schemaCheckCommand.d.ts.map +1 -1
- package/dist/console/schemaCheckCommand.js +21 -15
- package/dist/console/schemaCheckCommand.js.map +1 -1
- package/dist/console/schemaDumpCommand.d.ts +30 -0
- package/dist/console/schemaDumpCommand.d.ts.map +1 -0
- package/dist/console/schemaDumpCommand.js +69 -0
- package/dist/console/schemaDumpCommand.js.map +1 -0
- package/dist/console/schemaGenerateCommand.d.ts +100 -0
- package/dist/console/schemaGenerateCommand.d.ts.map +1 -0
- package/dist/console/schemaGenerateCommand.js +246 -0
- package/dist/console/schemaGenerateCommand.js.map +1 -0
- package/dist/console/seederCommands.d.ts +46 -0
- package/dist/console/seederCommands.d.ts.map +1 -0
- package/dist/console/seederCommands.js +136 -0
- package/dist/console/seederCommands.js.map +1 -0
- package/dist/decorators/entity.d.ts +50 -8
- package/dist/decorators/entity.d.ts.map +1 -1
- package/dist/decorators/entity.js +42 -2
- package/dist/decorators/entity.js.map +1 -1
- package/dist/decorators/hooks.d.ts +3 -3
- package/dist/decorators/hooks.d.ts.map +1 -1
- package/dist/decorators/hooks.js.map +1 -1
- package/dist/events.d.ts +69 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +82 -0
- package/dist/events.js.map +1 -0
- package/dist/factories.d.ts +8 -0
- package/dist/factories.d.ts.map +1 -0
- package/dist/factories.js +8 -0
- package/dist/factories.js.map +1 -0
- package/dist/index.d.ts +15 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -3
- package/dist/index.js.map +1 -1
- package/dist/lucid-schema.d.ts +15 -0
- package/dist/lucid-schema.d.ts.map +1 -0
- package/dist/lucid-schema.js +16 -0
- package/dist/lucid-schema.js.map +1 -0
- package/dist/metadata-keys.d.ts +3 -2
- package/dist/metadata-keys.d.ts.map +1 -1
- package/dist/naming/NamingStrategy.d.ts +7 -0
- package/dist/naming/NamingStrategy.d.ts.map +1 -1
- package/dist/naming/NamingStrategy.js +16 -0
- package/dist/naming/NamingStrategy.js.map +1 -1
- package/dist/orm.d.ts +14 -0
- package/dist/orm.d.ts.map +1 -0
- package/dist/orm.js +14 -0
- package/dist/orm.js.map +1 -0
- package/dist/query/DatabaseQueryBuilder.d.ts +557 -0
- package/dist/query/DatabaseQueryBuilder.d.ts.map +1 -0
- package/dist/query/DatabaseQueryBuilder.js +1798 -0
- package/dist/query/DatabaseQueryBuilder.js.map +1 -0
- package/dist/query/DmlBuilder.d.ts +62 -0
- package/dist/query/DmlBuilder.d.ts.map +1 -0
- package/dist/query/DmlBuilder.js +84 -0
- package/dist/query/DmlBuilder.js.map +1 -0
- package/dist/query/QueryBuilder.d.ts +5 -0
- package/dist/query/QueryBuilder.d.ts.map +1 -1
- package/dist/query/QueryBuilder.js +7 -0
- package/dist/query/QueryBuilder.js.map +1 -1
- package/dist/query/RawQueryBuilder.d.ts +47 -0
- package/dist/query/RawQueryBuilder.d.ts.map +1 -0
- package/dist/query/RawQueryBuilder.js +138 -0
- package/dist/query/RawQueryBuilder.js.map +1 -0
- package/dist/query/interpolate.d.ts +45 -0
- package/dist/query/interpolate.d.ts.map +1 -0
- package/dist/query/interpolate.js +51 -0
- package/dist/query/interpolate.js.map +1 -0
- package/dist/query/native.d.ts +8 -0
- package/dist/query/native.d.ts.map +1 -1
- package/dist/query/native.js +14 -0
- package/dist/query/native.js.map +1 -1
- package/dist/query/operators.d.ts +4 -0
- package/dist/query/operators.d.ts.map +1 -0
- package/dist/query/operators.js +27 -0
- package/dist/query/operators.js.map +1 -0
- package/dist/schema/Migration.d.ts +50 -3
- package/dist/schema/Migration.d.ts.map +1 -1
- package/dist/schema/Migration.js +60 -24
- package/dist/schema/Migration.js.map +1 -1
- package/dist/schema/MigrationRunner.d.ts +95 -34
- package/dist/schema/MigrationRunner.d.ts.map +1 -1
- package/dist/schema/MigrationRunner.js +523 -68
- package/dist/schema/MigrationRunner.js.map +1 -1
- package/dist/schema/Schema.d.ts +114 -0
- package/dist/schema/Schema.d.ts.map +1 -1
- package/dist/schema/Schema.js +272 -3
- package/dist/schema/Schema.js.map +1 -1
- package/dist/schema/SchemaDumper.d.ts +121 -0
- package/dist/schema/SchemaDumper.d.ts.map +1 -0
- package/dist/schema/SchemaDumper.js +365 -0
- package/dist/schema/SchemaDumper.js.map +1 -0
- package/dist/schema/Seeder.d.ts +13 -0
- package/dist/schema/Seeder.d.ts.map +1 -1
- package/dist/schema/Seeder.js +28 -5
- package/dist/schema/Seeder.js.map +1 -1
- package/dist/schema/TableBuilder.d.ts +274 -16
- package/dist/schema/TableBuilder.d.ts.map +1 -1
- package/dist/schema/TableBuilder.js +656 -52
- package/dist/schema/TableBuilder.js.map +1 -1
- package/dist/schema/catalog.d.ts +71 -0
- package/dist/schema/catalog.d.ts.map +1 -0
- package/dist/schema/catalog.js +158 -0
- package/dist/schema/catalog.js.map +1 -0
- package/dist/schema/introspect.d.ts +1 -1
- package/dist/schema/introspect.d.ts.map +1 -1
- package/dist/schema/introspect.js +26 -11
- package/dist/schema/introspect.js.map +1 -1
- package/dist/schema/types.d.ts +150 -1
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/types.js +11 -0
- package/dist/schema/types.js.map +1 -1
- package/dist/seeders.d.ts +7 -0
- package/dist/seeders.d.ts.map +1 -0
- package/dist/seeders.js +7 -0
- package/dist/seeders.js.map +1 -0
- package/dist/services/db.d.ts +122 -5
- package/dist/services/db.d.ts.map +1 -1
- package/dist/services/db.js +187 -14
- package/dist/services/db.js.map +1 -1
- package/dist/testing/DatabaseCleanup.d.ts +33 -7
- package/dist/testing/DatabaseCleanup.d.ts.map +1 -1
- package/dist/testing/DatabaseCleanup.js +54 -24
- package/dist/testing/DatabaseCleanup.js.map +1 -1
- package/dist/testing/DbAssertions.d.ts +48 -0
- package/dist/testing/DbAssertions.d.ts.map +1 -0
- package/dist/testing/DbAssertions.js +80 -0
- package/dist/testing/DbAssertions.js.map +1 -0
- package/dist/testing/Factory.d.ts +166 -15
- package/dist/testing/Factory.d.ts.map +1 -1
- package/dist/testing/Factory.js +497 -23
- package/dist/testing/Factory.js.map +1 -1
- package/dist/testing/TestUtils.d.ts +49 -0
- package/dist/testing/TestUtils.d.ts.map +1 -0
- package/dist/testing/TestUtils.js +79 -0
- package/dist/testing/TestUtils.js.map +1 -0
- package/dist/testing/index.d.ts +3 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +3 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/types/relations.d.ts +31 -0
- package/dist/types/relations.d.ts.map +1 -0
- package/dist/types/relations.js +20 -0
- package/dist/types/relations.js.map +1 -0
- package/index.darwin-arm64.node +0 -0
- package/index.darwin-x64.node +0 -0
- package/index.linux-arm64-gnu.node +0 -0
- package/index.linux-x64-gnu.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +32 -2
- package/scripts/guard-publish.mjs +15 -0
- package/src/AtlasProvider.ts +305 -52
- package/src/BaseEntity.ts +460 -41
- package/src/BaseModel.ts +461 -0
- package/src/BaseRepository.ts +1710 -421
- package/src/ConnectionManager.ts +298 -0
- package/src/ModelQuery.ts +2998 -335
- package/src/Transaction.ts +227 -30
- package/src/adapters/NapiDbAdapter.ts +224 -17
- package/src/console/contract.ts +96 -0
- package/src/console/factoryCommands.ts +73 -0
- package/src/console/migrationCommands.ts +448 -0
- package/src/console/schemaCheckCommand.ts +26 -22
- package/src/console/schemaDumpCommand.ts +96 -0
- package/src/console/schemaGenerateCommand.ts +380 -0
- package/src/console/seederCommands.ts +174 -0
- package/src/decorators/entity.ts +71 -8
- package/src/decorators/hooks.ts +5 -3
- package/src/events.ts +117 -0
- package/src/factories.ts +10 -0
- package/src/index.ts +69 -3
- package/src/lucid-schema.ts +22 -0
- package/src/metadata-keys.ts +3 -2
- package/src/naming/NamingStrategy.ts +23 -0
- package/src/orm.ts +13 -0
- package/src/query/DatabaseQueryBuilder.ts +2724 -0
- package/src/query/DmlBuilder.ts +131 -0
- package/src/query/QueryBuilder.ts +8 -0
- package/src/query/RawQueryBuilder.ts +173 -0
- package/src/query/interpolate.ts +73 -0
- package/src/query/native.ts +29 -0
- package/src/query/operators.ts +27 -0
- package/src/schema/Migration.ts +71 -3
- package/src/schema/MigrationRunner.ts +676 -69
- package/src/schema/Schema.ts +359 -3
- package/src/schema/SchemaDumper.ts +518 -0
- package/src/schema/Seeder.ts +47 -10
- package/src/schema/TableBuilder.ts +783 -52
- package/src/schema/catalog.ts +236 -0
- package/src/schema/introspect.ts +26 -9
- package/src/schema/types.ts +137 -2
- package/src/seeders.ts +16 -0
- package/src/services/db.ts +361 -21
- package/src/testing/DatabaseCleanup.ts +78 -25
- package/src/testing/DbAssertions.ts +127 -0
- package/src/testing/Factory.ts +837 -40
- package/src/testing/TestUtils.ts +123 -0
- package/src/testing/index.ts +12 -1
- package/src/types/relations.ts +43 -0
package/src/decorators/entity.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
COMPUTED_KEY,
|
|
11
11
|
type ColumnSerializeConfig,
|
|
12
12
|
} from "../metadata-keys.js";
|
|
13
|
+
import { getNamingStrategy } from "../naming/NamingStrategy.js";
|
|
13
14
|
|
|
14
15
|
const ENTITY_KEY = Symbol("atlas:entity");
|
|
15
16
|
const COLUMNS_KEY = Symbol("atlas:columns");
|
|
@@ -62,8 +63,14 @@ export interface ColumnAdapter {
|
|
|
62
63
|
*
|
|
63
64
|
* MUST stay synchronous; the bind layer cannot await before handing values
|
|
64
65
|
* to the Rust DML compiler. Returning a Promise throws.
|
|
66
|
+
*
|
|
67
|
+
* Signature mirrors Adonis Lucid: `(value, attribute, model)`. `attribute` is
|
|
68
|
+
* the model property key; `model` is the entity instance being persisted, or
|
|
69
|
+
* `undefined` on query-builder paths that carry no instance (e.g.
|
|
70
|
+
* `updateWhere`). Both extra args are optional — a one-argument adapter keeps
|
|
71
|
+
* working unchanged.
|
|
65
72
|
*/
|
|
66
|
-
prepare?: (value: unknown) => unknown;
|
|
73
|
+
prepare?: (value: unknown, attribute?: string, model?: unknown) => unknown;
|
|
67
74
|
/**
|
|
68
75
|
* Transform the raw DB value into the model attribute (DB → model). Mirror
|
|
69
76
|
* of Adonis Lucid's `@column.consume`. For entity columns, runs in
|
|
@@ -76,8 +83,12 @@ export interface ColumnAdapter {
|
|
|
76
83
|
* null/undefined inputs to preserve nullable semantics.
|
|
77
84
|
*
|
|
78
85
|
* MUST stay synchronous (same constraint as `prepare`).
|
|
86
|
+
*
|
|
87
|
+
* Signature mirrors Adonis Lucid: `(value, attribute, model)`. `attribute` is
|
|
88
|
+
* the model property key; `model` is the entity being hydrated. Both extra
|
|
89
|
+
* args are optional — a one-argument adapter keeps working unchanged.
|
|
79
90
|
*/
|
|
80
|
-
consume?: (value: unknown) => unknown;
|
|
91
|
+
consume?: (value: unknown, attribute?: string, model?: unknown) => unknown;
|
|
81
92
|
}
|
|
82
93
|
|
|
83
94
|
export interface ColumnMetadata extends ColumnAdapter {
|
|
@@ -86,17 +97,25 @@ export interface ColumnMetadata extends ColumnAdapter {
|
|
|
86
97
|
nullable?: boolean;
|
|
87
98
|
default?: unknown;
|
|
88
99
|
serializeAs?: string | null;
|
|
89
|
-
serialize?: (value: unknown) => unknown;
|
|
100
|
+
serialize?: (value: unknown, attribute?: string, model?: unknown) => unknown;
|
|
101
|
+
/** Explicit DB column name override (AdonisJS Lucid `columnName`). */
|
|
102
|
+
columnName?: string;
|
|
90
103
|
}
|
|
91
104
|
|
|
92
105
|
export interface ColumnOptions extends ColumnAdapter {
|
|
93
106
|
type?: string;
|
|
94
107
|
nullable?: boolean;
|
|
95
108
|
default?: unknown;
|
|
109
|
+
/**
|
|
110
|
+
* Map this property to an explicitly-named DB column (AdonisJS Lucid
|
|
111
|
+
* `columnName`), instead of the default `camelCase → snake_case` convention.
|
|
112
|
+
* For legacy/non-conventional schemas, e.g. `@Column({ columnName: 'USR_MAIL' })`.
|
|
113
|
+
*/
|
|
114
|
+
columnName?: string;
|
|
96
115
|
/** Rename this column at `toJSON` time. Use `null` to hide it entirely. */
|
|
97
116
|
serializeAs?: string | null;
|
|
98
117
|
/** Transform the value at `toJSON` time (e.g. mask a phone number, coerce a Date). */
|
|
99
|
-
serialize?: (value: unknown) => unknown;
|
|
118
|
+
serialize?: (value: unknown, attribute?: string, model?: unknown) => unknown;
|
|
100
119
|
}
|
|
101
120
|
|
|
102
121
|
type Constructor = new (...args: unknown[]) => unknown;
|
|
@@ -108,6 +127,12 @@ export interface ManyToManyOptions {
|
|
|
108
127
|
foreignKey?: string;
|
|
109
128
|
/** Foreign key in the pivot table pointing to the RELATED entity (default: `${relatedTable}_id`). */
|
|
110
129
|
otherKey?: string;
|
|
130
|
+
/**
|
|
131
|
+
* The column ON THE RELATED model that `otherKey` references (Adonis Lucid
|
|
132
|
+
* `relatedKey`). Defaults to the related model's primary key; override when the
|
|
133
|
+
* pivot points at a non-PK column of the related side.
|
|
134
|
+
*/
|
|
135
|
+
relatedKey?: string;
|
|
111
136
|
/** Pivot extra columns to project into `$extras.pivot_<col>` on loaded relations (Story 31.8). */
|
|
112
137
|
pivotColumns?: string[];
|
|
113
138
|
/** Auto-write `created_at`/`updated_at` on `attach`/`sync` (Story 31.8). */
|
|
@@ -119,8 +144,7 @@ export interface ManyToManyOptions {
|
|
|
119
144
|
* `@Column({ prepare, consume })` for entity columns: `prepare` runs on
|
|
120
145
|
* every `attach()` / `sync()` write, before the value reaches the SQL bind
|
|
121
146
|
* layer; `consume` runs on every load that projects the extra into
|
|
122
|
-
* `$extras.pivot_<col>` (
|
|
123
|
-
* the load-side hook is dormant).
|
|
147
|
+
* `$extras.pivot_<col>` (Adonis Lucid signature `(value, attribute, model)`).
|
|
124
148
|
*
|
|
125
149
|
* Keys are pivot-row column names as written in the SQL (e.g. `amount`);
|
|
126
150
|
* adapters are reused verbatim from `@c9up/atom/atlas` and friends so a
|
|
@@ -202,6 +226,7 @@ export function Column(options?: ColumnOptions): PropertyDecorator {
|
|
|
202
226
|
serialize: options?.serialize,
|
|
203
227
|
prepare: options?.prepare,
|
|
204
228
|
consume: options?.consume,
|
|
229
|
+
columnName: options?.columnName,
|
|
205
230
|
});
|
|
206
231
|
Reflect.defineMetadata(COLUMNS_KEY, columns, target.constructor);
|
|
207
232
|
}
|
|
@@ -445,7 +470,12 @@ export function HasMany(
|
|
|
445
470
|
};
|
|
446
471
|
}
|
|
447
472
|
|
|
448
|
-
/**
|
|
473
|
+
/**
|
|
474
|
+
* `@HasOneThrough(() => Related, () => Through, { firstKey, secondKey, localKey, secondLocalKey, onQuery })`
|
|
475
|
+
*
|
|
476
|
+
* An atlas addition — Lucid has no hasOneThrough relation. Same two-hop
|
|
477
|
+
* traversal as {@link HasManyThrough}, returning a single row.
|
|
478
|
+
*/
|
|
449
479
|
export function HasOneThrough(
|
|
450
480
|
target: () => Constructor,
|
|
451
481
|
through: () => Constructor,
|
|
@@ -490,12 +520,27 @@ export function ManyToMany(
|
|
|
490
520
|
type: "manyToMany",
|
|
491
521
|
target,
|
|
492
522
|
pivot: options,
|
|
523
|
+
// `localKey` selects which parent column the pivot FK references
|
|
524
|
+
// (default: the parent PK). Without copying it here the value the type
|
|
525
|
+
// accepts is silently dropped and the pivot always targets the PK.
|
|
526
|
+
localKey: options.localKey,
|
|
493
527
|
onQuery: options.onQuery,
|
|
494
528
|
serializeAs: options.serializeAs,
|
|
495
529
|
});
|
|
496
530
|
};
|
|
497
531
|
}
|
|
498
532
|
|
|
533
|
+
// camelCase aliases matching Adonis Lucid's decorator naming (`@belongsTo`,
|
|
534
|
+
// `@hasMany`, `@manyToMany`, …), alongside atlas's PascalCase originals — so a
|
|
535
|
+
// migration/model copied from Lucid resolves without renaming. Same decorators,
|
|
536
|
+
// same options; just the Lucid-idiomatic spelling.
|
|
537
|
+
export const belongsTo = BelongsTo;
|
|
538
|
+
export const hasOne = HasOne;
|
|
539
|
+
export const hasMany = HasMany;
|
|
540
|
+
export const hasOneThrough = HasOneThrough;
|
|
541
|
+
export const hasManyThrough = HasManyThrough;
|
|
542
|
+
export const manyToMany = ManyToMany;
|
|
543
|
+
|
|
499
544
|
function addRelation(target: object, relation: RelationMetadata): void {
|
|
500
545
|
const relations: RelationMetadata[] =
|
|
501
546
|
Reflect.getOwnMetadata(RELATIONS_KEY, target) ?? [];
|
|
@@ -510,13 +555,31 @@ export function getEntityMetadata(
|
|
|
510
555
|
return Reflect.getMetadata(ENTITY_KEY, target);
|
|
511
556
|
}
|
|
512
557
|
|
|
558
|
+
/**
|
|
559
|
+
* Return the class's `@Entity` metadata, SYNTHESIZING it when the decorator is
|
|
560
|
+
* absent: the table name is inferred from the class name via the naming strategy
|
|
561
|
+
* (or an explicit `static table`). AdonisJS Lucid parity — a model needs no
|
|
562
|
+
* explicit `@Entity('table')`. Used by both `BaseModel` and the `BaseRepository`
|
|
563
|
+
* constructor so the Data-Mapper and Active-Record paths share one convention.
|
|
564
|
+
*/
|
|
565
|
+
export function ensureEntityMetadata(target: Constructor): EntityMetadata {
|
|
566
|
+
const existing = getEntityMetadata(target);
|
|
567
|
+
if (existing) return existing;
|
|
568
|
+
const staticTable = (target as { table?: string }).table;
|
|
569
|
+
const table = staticTable ?? getNamingStrategy(target).tableName(target.name);
|
|
570
|
+
Entity(table)(target);
|
|
571
|
+
return getEntityMetadata(target) ?? { tableName: table };
|
|
572
|
+
}
|
|
573
|
+
|
|
513
574
|
/** Get column metadata for a class (returns a copy). */
|
|
514
575
|
export function getColumnMetadata(target: Constructor): ColumnMetadata[] {
|
|
515
576
|
return [...(Reflect.getMetadata(COLUMNS_KEY, target) ?? [])];
|
|
516
577
|
}
|
|
517
578
|
|
|
518
|
-
/** Get primary key property name. */
|
|
579
|
+
/** Get primary key property name. A `static primaryKey` (AdonisJS Lucid) wins over the `@PrimaryKey()` decorator. */
|
|
519
580
|
export function getPrimaryKey(target: Constructor): string | undefined {
|
|
581
|
+
const staticPk = (target as { primaryKey?: string }).primaryKey;
|
|
582
|
+
if (staticPk) return staticPk;
|
|
520
583
|
return Reflect.getMetadata(PRIMARY_KEY, target);
|
|
521
584
|
}
|
|
522
585
|
|
package/src/decorators/hooks.ts
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
import "reflect-metadata";
|
|
22
22
|
import type { BaseEntity } from "../BaseEntity.js";
|
|
23
|
-
import type { ModelQuery } from "../ModelQuery.js";
|
|
23
|
+
import type { ModelQuery, Paginator } from "../ModelQuery.js";
|
|
24
24
|
|
|
25
25
|
/** All hook kinds Atlas supports — mirrors Lucid's surface. */
|
|
26
26
|
export type HookKind =
|
|
@@ -53,8 +53,10 @@ export interface HookArgs {
|
|
|
53
53
|
afterFind: BaseEntity | null;
|
|
54
54
|
beforeFetch: ModelQuery<BaseEntity>;
|
|
55
55
|
afterFetch: BaseEntity[];
|
|
56
|
-
|
|
57
|
-
afterPaginate
|
|
56
|
+
// Adonis Lucid: beforePaginate receives the [countQuery, query] tuple (mutate
|
|
57
|
+
// both to keep count and results in sync); afterPaginate receives the paginator.
|
|
58
|
+
beforePaginate: [ModelQuery<BaseEntity>, ModelQuery<BaseEntity>];
|
|
59
|
+
afterPaginate: Paginator<BaseEntity>;
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
/** A hook handler is a static function that receives the kind-specific arg. */
|
package/src/events.ts
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query observability — atlas's equivalent of Lucid's `db:query` event.
|
|
3
|
+
*
|
|
4
|
+
* Agnostic by design: atlas cannot import the framework's emitter (it is a
|
|
5
|
+
* standalone package), so it owns a tiny listener registry instead. An
|
|
6
|
+
* integration package bridges it to whatever emitter the app uses:
|
|
7
|
+
*
|
|
8
|
+
* onDbQuery((event) => emitter.emit('db:query', event))
|
|
9
|
+
*
|
|
10
|
+
* Emission is opt-in. It costs a `performance.now()` pair per query, so it only
|
|
11
|
+
* happens when a connection is configured with `debug: true` or a single query
|
|
12
|
+
* asks via `.debug()` — and even then, only if someone is listening.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A single executed SQL statement. Mirrors Lucid's `db:query` payload, minus
|
|
17
|
+
* the fields that only make sense inside AdonisJS.
|
|
18
|
+
*/
|
|
19
|
+
export interface DbQueryEvent {
|
|
20
|
+
/** The SQL as sent to the driver, placeholders included. */
|
|
21
|
+
sql: string;
|
|
22
|
+
/** The bound parameters. Never interpolated into `sql`. */
|
|
23
|
+
bindings: readonly unknown[];
|
|
24
|
+
/** Wall-clock duration in milliseconds, including the NAPI round-trip. */
|
|
25
|
+
duration: number;
|
|
26
|
+
/** Connection name, when the app named it. */
|
|
27
|
+
connection?: string;
|
|
28
|
+
/** Entity class name, when the query came from a repository/model. */
|
|
29
|
+
model?: string;
|
|
30
|
+
/** The call that produced it (`exec`, `first`, `paginate`, …). */
|
|
31
|
+
method?: string;
|
|
32
|
+
/** True for schema statements (migrations), false for DML/queries. */
|
|
33
|
+
ddl?: boolean;
|
|
34
|
+
/** True when the statement ran inside an interactive transaction. */
|
|
35
|
+
inTransaction?: boolean;
|
|
36
|
+
/** Set when the statement threw — the event is emitted either way. */
|
|
37
|
+
error?: Error;
|
|
38
|
+
/**
|
|
39
|
+
* Arbitrary metadata a caller attached via `query.reporterData({...})`
|
|
40
|
+
* (Adonis Lucid `reporterData`) — request id, user id, feature flag, …
|
|
41
|
+
*/
|
|
42
|
+
reporterData?: Record<string, unknown>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type DbQueryListener = (event: DbQueryEvent) => void;
|
|
46
|
+
|
|
47
|
+
const listeners = new Set<DbQueryListener>();
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Subscribe to every observed query. Returns an unsubscribe function.
|
|
51
|
+
*
|
|
52
|
+
* A listener that throws would otherwise take down the query that triggered it,
|
|
53
|
+
* so throws are swallowed — observability must never change behaviour.
|
|
54
|
+
*/
|
|
55
|
+
export function onDbQuery(listener: DbQueryListener): () => void {
|
|
56
|
+
listeners.add(listener);
|
|
57
|
+
return () => {
|
|
58
|
+
listeners.delete(listener);
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Remove every listener. Intended for test teardown. */
|
|
63
|
+
export function clearDbQueryListeners(): void {
|
|
64
|
+
listeners.clear();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Whether anyone is listening. Checked before timing a query so the
|
|
69
|
+
* instrumentation costs nothing when unused.
|
|
70
|
+
*/
|
|
71
|
+
export function hasDbQueryListeners(): boolean {
|
|
72
|
+
return listeners.size > 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Emit to every listener. Package-internal. */
|
|
76
|
+
export function emitDbQuery(event: DbQueryEvent): void {
|
|
77
|
+
for (const listener of listeners) {
|
|
78
|
+
try {
|
|
79
|
+
listener(event);
|
|
80
|
+
} catch {
|
|
81
|
+
// A broken listener must not fail the query it is reporting on.
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Render a query event as a single log line (Lucid's `prettyPrint`).
|
|
88
|
+
*
|
|
89
|
+
* The bindings are appended as JSON, NOT interpolated into the SQL: an
|
|
90
|
+
* interpolated line reads like runnable SQL while having none of the escaping
|
|
91
|
+
* that made the real statement safe, and it is exactly the string someone
|
|
92
|
+
* copies into a console later.
|
|
93
|
+
*/
|
|
94
|
+
export function prettyPrintQuery(event: DbQueryEvent): string {
|
|
95
|
+
const parts = [`${event.duration.toFixed(2)}ms`];
|
|
96
|
+
if (event.connection) parts.push(event.connection);
|
|
97
|
+
if (event.model) parts.push(event.model);
|
|
98
|
+
if (event.method) parts.push(event.method);
|
|
99
|
+
if (event.inTransaction) parts.push("trx");
|
|
100
|
+
if (event.error) parts.push(`ERROR: ${event.error.message}`);
|
|
101
|
+
|
|
102
|
+
const head = `[atlas] ${parts.join(" ")}`;
|
|
103
|
+
const bindings =
|
|
104
|
+
event.bindings.length > 0 ? ` -- ${safeJson(event.bindings)}` : "";
|
|
105
|
+
return `${head} ${event.sql}${bindings}`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** JSON that can't throw on a circular / non-serialisable binding. */
|
|
109
|
+
function safeJson(value: unknown): string {
|
|
110
|
+
try {
|
|
111
|
+
return JSON.stringify(value, (_k, v) =>
|
|
112
|
+
typeof v === "bigint" ? `${v}n` : v,
|
|
113
|
+
);
|
|
114
|
+
} catch {
|
|
115
|
+
return "[unserialisable bindings]";
|
|
116
|
+
}
|
|
117
|
+
}
|
package/src/factories.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@c9up/atlas/factories` — Adonis Lucid `@adonisjs/lucid/factories` parity
|
|
3
|
+
* subpath. The model factory: `Factory.define(Model, cb).build()` (or the
|
|
4
|
+
* `factory()` shorthand) for generating and persisting test data.
|
|
5
|
+
*/
|
|
6
|
+
export {
|
|
7
|
+
type FactoryCommandOptions,
|
|
8
|
+
makeFactoryCommand,
|
|
9
|
+
} from "./console/factoryCommands.js";
|
|
10
|
+
export { Factory, type FactoryBuilder, factory } from "./testing/Factory.js";
|
package/src/index.ts
CHANGED
|
@@ -10,18 +10,59 @@ export { SQLITE_PROD_PRAGMAS } from "./AtlasProvider.js";
|
|
|
10
10
|
export type {
|
|
11
11
|
AsyncDatabaseConnection,
|
|
12
12
|
ConnectRetryOptions,
|
|
13
|
+
ObservabilityOptions,
|
|
14
|
+
QueryMeta,
|
|
13
15
|
} from "./adapters/NapiDbAdapter.js";
|
|
14
16
|
export { createNapiConnection } from "./adapters/NapiDbAdapter.js";
|
|
15
17
|
export type { DomainEvent } from "./BaseEntity.js";
|
|
16
18
|
export { BaseEntity } from "./BaseEntity.js";
|
|
19
|
+
export { BaseModel } from "./BaseModel.js";
|
|
17
20
|
export type { DatabaseConnection } from "./BaseRepository.js";
|
|
18
21
|
export { BaseRepository } from "./BaseRepository.js";
|
|
19
22
|
export { defineConfig } from "./config.js";
|
|
20
23
|
export { configure } from "./configure.js";
|
|
21
24
|
export {
|
|
22
|
-
type
|
|
25
|
+
type ArgumentMetaData,
|
|
26
|
+
argument,
|
|
27
|
+
type CommandOptions,
|
|
28
|
+
type FlagMetaData,
|
|
29
|
+
flag,
|
|
30
|
+
} from "./console/contract.js";
|
|
31
|
+
export {
|
|
32
|
+
type FactoryCommandOptions,
|
|
33
|
+
makeFactoryCommand,
|
|
34
|
+
} from "./console/factoryCommands.js";
|
|
35
|
+
export {
|
|
36
|
+
dbWipeCommand,
|
|
37
|
+
type MigrationCommandOptions,
|
|
38
|
+
makeMigrationCommand,
|
|
39
|
+
migrationFreshCommand,
|
|
40
|
+
migrationRefreshCommand,
|
|
41
|
+
migrationResetCommand,
|
|
42
|
+
migrationRollbackCommand,
|
|
43
|
+
migrationRunCommand,
|
|
44
|
+
migrationStatusCommand,
|
|
45
|
+
migrationUnlockCommand,
|
|
46
|
+
} from "./console/migrationCommands.js";
|
|
47
|
+
export {
|
|
48
|
+
type AtlasCommandClass,
|
|
23
49
|
schemaCheckCommand,
|
|
24
50
|
} from "./console/schemaCheckCommand.js";
|
|
51
|
+
export {
|
|
52
|
+
type SchemaDumpCommandOptions,
|
|
53
|
+
schemaDumpCommand,
|
|
54
|
+
} from "./console/schemaDumpCommand.js";
|
|
55
|
+
export {
|
|
56
|
+
generateSchemaFile,
|
|
57
|
+
renderSchemaFile,
|
|
58
|
+
type SchemaGenerateOptions,
|
|
59
|
+
schemaGenerateCommand,
|
|
60
|
+
} from "./console/schemaGenerateCommand.js";
|
|
61
|
+
export {
|
|
62
|
+
dbSeedCommand,
|
|
63
|
+
makeSeederCommand,
|
|
64
|
+
type SeederCommandOptions,
|
|
65
|
+
} from "./console/seederCommands.js";
|
|
25
66
|
export type {
|
|
26
67
|
ColumnAdapter,
|
|
27
68
|
ColumnMetadata,
|
|
@@ -34,6 +75,7 @@ export type {
|
|
|
34
75
|
} from "./decorators/entity.js";
|
|
35
76
|
export {
|
|
36
77
|
BelongsTo,
|
|
78
|
+
belongsTo,
|
|
37
79
|
Column,
|
|
38
80
|
column,
|
|
39
81
|
computed,
|
|
@@ -47,8 +89,13 @@ export {
|
|
|
47
89
|
HasManyThrough,
|
|
48
90
|
HasOne,
|
|
49
91
|
HasOneThrough,
|
|
92
|
+
hasMany,
|
|
93
|
+
hasManyThrough,
|
|
94
|
+
hasOne,
|
|
95
|
+
hasOneThrough,
|
|
50
96
|
hasSoftDeletes,
|
|
51
97
|
ManyToMany,
|
|
98
|
+
manyToMany,
|
|
52
99
|
PrimaryKey,
|
|
53
100
|
SoftDeletes,
|
|
54
101
|
} from "./decorators/entity.js";
|
|
@@ -77,6 +124,12 @@ export {
|
|
|
77
124
|
OptimisticLockError,
|
|
78
125
|
RelationNotLoadedError,
|
|
79
126
|
} from "./errors.js";
|
|
127
|
+
export type { DbQueryEvent, DbQueryListener } from "./events.js";
|
|
128
|
+
export {
|
|
129
|
+
clearDbQueryListeners,
|
|
130
|
+
onDbQuery,
|
|
131
|
+
prettyPrintQuery,
|
|
132
|
+
} from "./events.js";
|
|
80
133
|
export {
|
|
81
134
|
isAtlasStrictMode,
|
|
82
135
|
ModelQuery,
|
|
@@ -103,7 +156,9 @@ export {
|
|
|
103
156
|
type IntrospectedColumn,
|
|
104
157
|
introspectTable,
|
|
105
158
|
} from "./schema/introspect.js";
|
|
106
|
-
|
|
159
|
+
// `BaseSchema` is Lucid's name for the migration base class; `Migration` is the
|
|
160
|
+
// atlas alias kept for back-compat. Prefer `extends BaseSchema` (AdonisJS parity).
|
|
161
|
+
export { Migration, Migration as BaseSchema } from "./schema/Migration.js";
|
|
107
162
|
export type {
|
|
108
163
|
DatabaseAdapter,
|
|
109
164
|
MigrationRecord,
|
|
@@ -124,6 +179,17 @@ export {
|
|
|
124
179
|
typesCompatible,
|
|
125
180
|
verifySchema,
|
|
126
181
|
} from "./schema/SchemaCheck.js";
|
|
182
|
+
export {
|
|
183
|
+
type PgForeignKey,
|
|
184
|
+
readSchemaDumpManifest,
|
|
185
|
+
renderPgCreateTable,
|
|
186
|
+
renderPgForeignKeyDdl,
|
|
187
|
+
SchemaDumper,
|
|
188
|
+
type SchemaDumperOptions,
|
|
189
|
+
type SchemaDumpManifest,
|
|
190
|
+
type SchemaDumpResult,
|
|
191
|
+
schemaDumpManifestPath,
|
|
192
|
+
} from "./schema/SchemaDumper.js";
|
|
127
193
|
export {
|
|
128
194
|
BaseSeeder,
|
|
129
195
|
runSeederDirectory,
|
|
@@ -133,4 +199,4 @@ export {
|
|
|
133
199
|
export type { TransactionClient } from "./Transaction.js";
|
|
134
200
|
export { transaction } from "./Transaction.js";
|
|
135
201
|
export { truncateAll, useTransaction } from "./testing/DatabaseCleanup.js";
|
|
136
|
-
export { factory } from "./testing/Factory.js";
|
|
202
|
+
export { Factory, factory } from "./testing/Factory.js";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@c9up/atlas/schema` — Adonis Lucid `@adonisjs/lucid/schema` parity subpath.
|
|
3
|
+
*
|
|
4
|
+
* The migration base class ({@link Migration}, Lucid's `BaseSchema`), the schema
|
|
5
|
+
* builder and the table builder — everything for authoring migrations. (The file
|
|
6
|
+
* is named `lucid-schema` to avoid colliding with the `schema/` source folder;
|
|
7
|
+
* the public subpath is `@c9up/atlas/schema`.)
|
|
8
|
+
*/
|
|
9
|
+
export { RawSql } from "./query/QueryBuilder.js";
|
|
10
|
+
export * from "./schema/Migration.js";
|
|
11
|
+
// Lucid's name for the migration base class (`extends BaseSchema`).
|
|
12
|
+
export { Migration as BaseSchema } from "./schema/Migration.js";
|
|
13
|
+
export * from "./schema/Schema.js";
|
|
14
|
+
export {
|
|
15
|
+
readSchemaDumpManifest,
|
|
16
|
+
SchemaDumper,
|
|
17
|
+
type SchemaDumperOptions,
|
|
18
|
+
type SchemaDumpManifest,
|
|
19
|
+
type SchemaDumpResult,
|
|
20
|
+
schemaDumpManifestPath,
|
|
21
|
+
} from "./schema/SchemaDumper.js";
|
|
22
|
+
export * from "./schema/TableBuilder.js";
|
package/src/metadata-keys.ts
CHANGED
|
@@ -17,6 +17,7 @@ export const COLUMN_SERIALIZE_KEY = Symbol.for("atlas:columnSerialize");
|
|
|
17
17
|
export interface ColumnSerializeConfig {
|
|
18
18
|
/** Rename this column at toJSON time (e.g. `password` → `passwordHash`). Null = hidden. */
|
|
19
19
|
serializeAs?: string | null;
|
|
20
|
-
/** Transform function applied to the value at toJSON time.
|
|
21
|
-
|
|
20
|
+
/** Transform function applied to the value at toJSON time. Signature mirrors
|
|
21
|
+
* Adonis Lucid: `(value, attribute, model)`; extra args optional. */
|
|
22
|
+
serialize?: (value: unknown, attribute?: string, model?: unknown) => unknown;
|
|
22
23
|
}
|
|
@@ -38,6 +38,12 @@ export interface NamingStrategy {
|
|
|
38
38
|
): string;
|
|
39
39
|
/** Default pivot table name for a manyToMany relation. */
|
|
40
40
|
relationPivotTable(aClass: string, bClass: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* Remap the pagination `meta` key names emitted by `Paginator.toJSON()`
|
|
43
|
+
* (AdonisJS Lucid `paginationMetaKeys`), e.g. `{ total: 'count', perPage:
|
|
44
|
+
* 'per_page' }`. Optional — omitted keys keep their default name.
|
|
45
|
+
*/
|
|
46
|
+
paginationMetaKeys?(): Record<string, string>;
|
|
41
47
|
}
|
|
42
48
|
|
|
43
49
|
/**
|
|
@@ -84,6 +90,23 @@ export class CamelCaseNamingStrategy implements NamingStrategy {
|
|
|
84
90
|
const [x, y] = [camelToSnake(aClass), camelToSnake(bClass)].sort();
|
|
85
91
|
return `${x}_${y}`;
|
|
86
92
|
}
|
|
93
|
+
|
|
94
|
+
paginationMetaKeys(): Record<string, string> {
|
|
95
|
+
// snake_case, matching Adonis Lucid's default paginator meta shape — even
|
|
96
|
+
// though model attributes serialize as camelCase, Lucid emits pagination
|
|
97
|
+
// meta in snake_case. Override this method to customize.
|
|
98
|
+
return {
|
|
99
|
+
total: "total",
|
|
100
|
+
perPage: "per_page",
|
|
101
|
+
currentPage: "current_page",
|
|
102
|
+
lastPage: "last_page",
|
|
103
|
+
firstPage: "first_page",
|
|
104
|
+
firstPageUrl: "first_page_url",
|
|
105
|
+
lastPageUrl: "last_page_url",
|
|
106
|
+
nextPageUrl: "next_page_url",
|
|
107
|
+
previousPageUrl: "previous_page_url",
|
|
108
|
+
};
|
|
109
|
+
}
|
|
87
110
|
}
|
|
88
111
|
|
|
89
112
|
/** The default singleton — used when an entity doesn't override `static namingStrategy`. */
|
package/src/orm.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@c9up/atlas/orm` — Adonis Lucid `@adonisjs/lucid/orm` parity subpath.
|
|
3
|
+
*
|
|
4
|
+
* The Active Record model, the Data Mapper repository, the column/relation
|
|
5
|
+
* decorators and the model lifecycle hooks — everything for defining and
|
|
6
|
+
* querying models. Import organisation mirrors Lucid; the symbols are the same
|
|
7
|
+
* ones re-exported from the package root (`@c9up/atlas`).
|
|
8
|
+
*/
|
|
9
|
+
export * from "./BaseEntity.js";
|
|
10
|
+
export * from "./BaseModel.js";
|
|
11
|
+
export * from "./BaseRepository.js";
|
|
12
|
+
export * from "./decorators/entity.js";
|
|
13
|
+
export * from "./decorators/hooks.js";
|