@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/BaseModel.ts
ADDED
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AsyncDatabaseConnection,
|
|
3
|
+
TransactionOptions,
|
|
4
|
+
} from "./adapters/NapiDbAdapter.js";
|
|
5
|
+
import { BaseEntity } from "./BaseEntity.js";
|
|
6
|
+
import { BaseRepository, type DatabaseConnection } from "./BaseRepository.js";
|
|
7
|
+
import { ensureEntityMetadata } from "./decorators/entity.js";
|
|
8
|
+
import { AtlasError } from "./errors.js";
|
|
9
|
+
import { getConnection, getDb } from "./services/db.js";
|
|
10
|
+
import type { TransactionClient } from "./Transaction.js";
|
|
11
|
+
import { isTransactionClient } from "./utils/transactionBrand.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Options accepted by the static finders/creators — Adonis Lucid's
|
|
15
|
+
* `{ client: trx }`. Routes the operation through a transaction client instead
|
|
16
|
+
* of the model's own connection.
|
|
17
|
+
*/
|
|
18
|
+
export interface ModelClientOptions {
|
|
19
|
+
client?: DatabaseConnection;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Narrow the optional trailing argument of an overloaded finder (which is a
|
|
24
|
+
* value in the `(column, value)` form, or the options in the `(clause)` form) to
|
|
25
|
+
* client options — without a cast. An options object without a `client` reads as
|
|
26
|
+
* "no options", which is the same as passing none.
|
|
27
|
+
*/
|
|
28
|
+
function isClientOptions(x: unknown): x is ModelClientOptions {
|
|
29
|
+
return typeof x === "object" && x !== null && "client" in x;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** A concrete BaseModel subclass: a `new()` constructor plus the static façade. */
|
|
33
|
+
type ModelClass<T extends BaseModel> = (new () => T) & typeof BaseModel;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* AdonisJS Lucid–style Active Record façade. Subclass this (instead of
|
|
37
|
+
* `BaseEntity`) to get static finders/creators + `instance.save()/delete()`
|
|
38
|
+
* that delegate to a per-connection {@link BaseRepository}, while still
|
|
39
|
+
* inheriting `fill`/`merge`/`refresh`, dirty-tracking and the model-state flags
|
|
40
|
+
* (`$isPersisted`, `$isNew`, …) from BaseEntity.
|
|
41
|
+
*
|
|
42
|
+
* class User extends BaseModel {
|
|
43
|
+
* @PrimaryKey() declare id: number
|
|
44
|
+
* @Column() declare email: string
|
|
45
|
+
* }
|
|
46
|
+
* const u = await User.find(1)
|
|
47
|
+
* if (u) { u.email = "x@y"; await u.save() }
|
|
48
|
+
*
|
|
49
|
+
* `@Entity('table')` is OPTIONAL on a BaseModel — the table name is inferred
|
|
50
|
+
* from the class name via the naming strategy (or `static table`). The
|
|
51
|
+
* Data-Mapper `BaseRepository` remains available for those who prefer it.
|
|
52
|
+
*/
|
|
53
|
+
export abstract class BaseModel extends BaseEntity {
|
|
54
|
+
/** Override the inferred table name (AdonisJS `static table`). */
|
|
55
|
+
static table?: string;
|
|
56
|
+
/** Bind to a named connection (AdonisJS `static connection`); default otherwise. */
|
|
57
|
+
static connection?: string;
|
|
58
|
+
/** Override the primary-key column name (AdonisJS `static primaryKey`); `@PrimaryKey()` otherwise. */
|
|
59
|
+
static primaryKey?: string;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Ensure `@Entity` metadata exists — infer the table name from the class name
|
|
63
|
+
* (naming strategy) or `static table` when the decorator is absent. Idempotent;
|
|
64
|
+
* runs on first repository access.
|
|
65
|
+
*/
|
|
66
|
+
static $boot<T extends BaseModel>(this: ModelClass<T>): void {
|
|
67
|
+
ensureEntityMetadata(this);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Resolve this model's connection (named via `static connection`, else default). */
|
|
71
|
+
static $connection(): AsyncDatabaseConnection {
|
|
72
|
+
const conn = this.connection ? getConnection(this.connection) : getDb();
|
|
73
|
+
if (conn === undefined) {
|
|
74
|
+
throw new AtlasError(
|
|
75
|
+
"MISSING_CONNECTION",
|
|
76
|
+
this.connection
|
|
77
|
+
? `No connection named '${this.connection}' is registered for model '${this.name}'.`
|
|
78
|
+
: `No default database connection for model '${this.name}' — is AtlasProvider booted?`,
|
|
79
|
+
{
|
|
80
|
+
hint: "Boot AtlasProvider (config/database.ts) before using models, or register the named connection.",
|
|
81
|
+
},
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
return conn;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The {@link BaseRepository} backing this model on its resolved connection.
|
|
89
|
+
* Pass `{ client: trx }` (Adonis Lucid) to bind the repository to a
|
|
90
|
+
* transaction, so every finder/creator routed through it runs on that trx.
|
|
91
|
+
*/
|
|
92
|
+
static $repo<T extends BaseModel>(
|
|
93
|
+
this: ModelClass<T>,
|
|
94
|
+
options?: ModelClientOptions,
|
|
95
|
+
): BaseRepository<T> {
|
|
96
|
+
this.$boot();
|
|
97
|
+
const repo = new BaseRepository<T>(this, this.$connection());
|
|
98
|
+
return options?.client ? repo.useTransaction(options.client) : repo;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Start a transaction on THIS model's connection (Adonis Lucid
|
|
103
|
+
* `Model.transaction`) — handy when the model overrides `static connection`.
|
|
104
|
+
* Managed when given a callback (auto commit on success, rollback on throw),
|
|
105
|
+
* manual otherwise. On the default connection it is equivalent to
|
|
106
|
+
* `db.transaction(...)`. Accepts an `isolationLevel` via the options.
|
|
107
|
+
*/
|
|
108
|
+
static transaction<T>(
|
|
109
|
+
this: ModelClass<BaseModel>,
|
|
110
|
+
callback: (trx: TransactionClient) => Promise<T> | T,
|
|
111
|
+
options?: TransactionOptions,
|
|
112
|
+
): Promise<T>;
|
|
113
|
+
static transaction(
|
|
114
|
+
this: ModelClass<BaseModel>,
|
|
115
|
+
options?: TransactionOptions,
|
|
116
|
+
): Promise<TransactionClient>;
|
|
117
|
+
static transaction(
|
|
118
|
+
this: ModelClass<BaseModel>,
|
|
119
|
+
callbackOrOptions?:
|
|
120
|
+
| ((trx: TransactionClient) => unknown)
|
|
121
|
+
| TransactionOptions,
|
|
122
|
+
options?: TransactionOptions,
|
|
123
|
+
): Promise<unknown> {
|
|
124
|
+
const conn = this.$connection();
|
|
125
|
+
if (typeof conn.transaction !== "function") {
|
|
126
|
+
throw new AtlasError(
|
|
127
|
+
"E_NO_INTERACTIVE_TRANSACTION",
|
|
128
|
+
`Model '${this.name}' connection has no interactive transaction().`,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
if (typeof callbackOrOptions === "function") {
|
|
132
|
+
return conn.transaction(callbackOrOptions, options);
|
|
133
|
+
}
|
|
134
|
+
// Manual mode: forward the isolation options if any (the overload rejects an
|
|
135
|
+
// explicit `undefined`, so call with no args when none were passed).
|
|
136
|
+
return callbackOrOptions === undefined
|
|
137
|
+
? conn.transaction()
|
|
138
|
+
: conn.transaction(callbackOrOptions);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// — Static finders (AdonisJS Lucid) —
|
|
142
|
+
|
|
143
|
+
static find<T extends BaseModel>(
|
|
144
|
+
this: ModelClass<T>,
|
|
145
|
+
id: string | number,
|
|
146
|
+
options?: ModelClientOptions,
|
|
147
|
+
): Promise<T | null> {
|
|
148
|
+
return this.$repo(options).find(id);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
static findOrFail<T extends BaseModel>(
|
|
152
|
+
this: ModelClass<T>,
|
|
153
|
+
id: string | number,
|
|
154
|
+
options?: ModelClientOptions,
|
|
155
|
+
): Promise<T> {
|
|
156
|
+
return this.$repo(options).findOrFail(id);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
static findBy<T extends BaseModel>(
|
|
160
|
+
this: ModelClass<T>,
|
|
161
|
+
column: string,
|
|
162
|
+
value: unknown,
|
|
163
|
+
options?: ModelClientOptions,
|
|
164
|
+
): Promise<T | null>;
|
|
165
|
+
static findBy<T extends BaseModel>(
|
|
166
|
+
this: ModelClass<T>,
|
|
167
|
+
clause: Record<string, unknown>,
|
|
168
|
+
options?: ModelClientOptions,
|
|
169
|
+
): Promise<T | null>;
|
|
170
|
+
static findBy<T extends BaseModel>(
|
|
171
|
+
this: ModelClass<T>,
|
|
172
|
+
columnOrClause: string | Record<string, unknown>,
|
|
173
|
+
valueOrOptions?: unknown,
|
|
174
|
+
options?: ModelClientOptions,
|
|
175
|
+
): Promise<T | null> {
|
|
176
|
+
if (typeof columnOrClause === "string") {
|
|
177
|
+
return this.$repo(options).findBy(columnOrClause, valueOrOptions);
|
|
178
|
+
}
|
|
179
|
+
const opts = isClientOptions(valueOrOptions) ? valueOrOptions : undefined;
|
|
180
|
+
return this.$repo(opts).findBy(columnOrClause);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
static findByOrFail<T extends BaseModel>(
|
|
184
|
+
this: ModelClass<T>,
|
|
185
|
+
column: string,
|
|
186
|
+
value: unknown,
|
|
187
|
+
options?: ModelClientOptions,
|
|
188
|
+
): Promise<T>;
|
|
189
|
+
static findByOrFail<T extends BaseModel>(
|
|
190
|
+
this: ModelClass<T>,
|
|
191
|
+
clause: Record<string, unknown>,
|
|
192
|
+
options?: ModelClientOptions,
|
|
193
|
+
): Promise<T>;
|
|
194
|
+
static findByOrFail<T extends BaseModel>(
|
|
195
|
+
this: ModelClass<T>,
|
|
196
|
+
columnOrClause: string | Record<string, unknown>,
|
|
197
|
+
valueOrOptions?: unknown,
|
|
198
|
+
options?: ModelClientOptions,
|
|
199
|
+
): Promise<T> {
|
|
200
|
+
if (typeof columnOrClause === "string") {
|
|
201
|
+
return this.$repo(options).findByOrFail(columnOrClause, valueOrOptions);
|
|
202
|
+
}
|
|
203
|
+
const opts = isClientOptions(valueOrOptions) ? valueOrOptions : undefined;
|
|
204
|
+
return this.$repo(opts).findByOrFail(columnOrClause);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
static findMany<T extends BaseModel>(
|
|
208
|
+
this: ModelClass<T>,
|
|
209
|
+
ids: Array<string | number>,
|
|
210
|
+
options?: ModelClientOptions,
|
|
211
|
+
): Promise<T[]> {
|
|
212
|
+
return this.$repo(options).findMany(ids);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
static findManyBy<T extends BaseModel>(
|
|
216
|
+
this: ModelClass<T>,
|
|
217
|
+
column: string,
|
|
218
|
+
values: Array<string | number>,
|
|
219
|
+
options?: ModelClientOptions,
|
|
220
|
+
): Promise<T[]>;
|
|
221
|
+
static findManyBy<T extends BaseModel>(
|
|
222
|
+
this: ModelClass<T>,
|
|
223
|
+
clause: Record<string, unknown>,
|
|
224
|
+
options?: ModelClientOptions,
|
|
225
|
+
): Promise<T[]>;
|
|
226
|
+
static findManyBy<T extends BaseModel>(
|
|
227
|
+
this: ModelClass<T>,
|
|
228
|
+
columnOrClause: string | Record<string, unknown>,
|
|
229
|
+
valuesOrOptions?: Array<string | number> | ModelClientOptions,
|
|
230
|
+
options?: ModelClientOptions,
|
|
231
|
+
): Promise<T[]> {
|
|
232
|
+
if (typeof columnOrClause === "string") {
|
|
233
|
+
const values = Array.isArray(valuesOrOptions) ? valuesOrOptions : [];
|
|
234
|
+
return this.$repo(options).findManyBy(columnOrClause, values);
|
|
235
|
+
}
|
|
236
|
+
const opts = isClientOptions(valuesOrOptions) ? valuesOrOptions : undefined;
|
|
237
|
+
return this.$repo(opts).findManyBy(columnOrClause);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
static all<T extends BaseModel>(
|
|
241
|
+
this: ModelClass<T>,
|
|
242
|
+
options?: ModelClientOptions,
|
|
243
|
+
): Promise<T[]> {
|
|
244
|
+
return this.$repo(options).all();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
static query<T extends BaseModel>(
|
|
248
|
+
this: ModelClass<T>,
|
|
249
|
+
options?: ModelClientOptions,
|
|
250
|
+
): ReturnType<BaseRepository<T>["query"]> {
|
|
251
|
+
return this.$repo(options).query();
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
static first<T extends BaseModel>(
|
|
255
|
+
this: ModelClass<T>,
|
|
256
|
+
options?: ModelClientOptions,
|
|
257
|
+
): Promise<T | null> {
|
|
258
|
+
return this.$repo(options).query().first();
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
static firstOrFail<T extends BaseModel>(
|
|
262
|
+
this: ModelClass<T>,
|
|
263
|
+
options?: ModelClientOptions,
|
|
264
|
+
): Promise<T> {
|
|
265
|
+
return this.$repo(options).query().firstOrFail();
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// — Static creators (AdonisJS Lucid) —
|
|
269
|
+
|
|
270
|
+
static create<T extends BaseModel>(
|
|
271
|
+
this: ModelClass<T>,
|
|
272
|
+
data: Partial<Record<string, unknown>>,
|
|
273
|
+
options?: ModelClientOptions & { allowExtraProperties?: boolean },
|
|
274
|
+
): Promise<T> {
|
|
275
|
+
return this.$repo(options).create(data, {
|
|
276
|
+
allowExtraProperties: options?.allowExtraProperties ?? false,
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
static createMany<T extends BaseModel>(
|
|
281
|
+
this: ModelClass<T>,
|
|
282
|
+
rows: Array<Partial<Record<string, unknown>>>,
|
|
283
|
+
options?: ModelClientOptions,
|
|
284
|
+
): Promise<T[]> {
|
|
285
|
+
return this.$repo(options).createMany(rows);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/** {@link create} without firing lifecycle hooks (AdonisJS Lucid `createQuietly`). */
|
|
289
|
+
static createQuietly<T extends BaseModel>(
|
|
290
|
+
this: ModelClass<T>,
|
|
291
|
+
data: Partial<Record<string, unknown>>,
|
|
292
|
+
options?: ModelClientOptions,
|
|
293
|
+
): Promise<T> {
|
|
294
|
+
return this.$repo(options).createQuietly(data);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/** {@link createMany} without firing lifecycle hooks (AdonisJS Lucid `createManyQuietly`). */
|
|
298
|
+
static createManyQuietly<T extends BaseModel>(
|
|
299
|
+
this: ModelClass<T>,
|
|
300
|
+
rows: Array<Partial<Record<string, unknown>>>,
|
|
301
|
+
options?: ModelClientOptions,
|
|
302
|
+
): Promise<T[]> {
|
|
303
|
+
return this.$repo(options).createManyQuietly(rows);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
static firstOrCreate<T extends BaseModel>(
|
|
307
|
+
this: ModelClass<T>,
|
|
308
|
+
search: Record<string, unknown>,
|
|
309
|
+
values?: Record<string, unknown>,
|
|
310
|
+
options?: ModelClientOptions,
|
|
311
|
+
): Promise<T> {
|
|
312
|
+
return this.$repo(options).firstOrCreate(search, values);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
static firstOrNew<T extends BaseModel>(
|
|
316
|
+
this: ModelClass<T>,
|
|
317
|
+
search: Record<string, unknown>,
|
|
318
|
+
values?: Record<string, unknown>,
|
|
319
|
+
options?: ModelClientOptions,
|
|
320
|
+
): Promise<T> {
|
|
321
|
+
return this.$repo(options).firstOrNew(search, values);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
static updateOrCreate<T extends BaseModel>(
|
|
325
|
+
this: ModelClass<T>,
|
|
326
|
+
search: Record<string, unknown>,
|
|
327
|
+
values: Record<string, unknown>,
|
|
328
|
+
options?: ModelClientOptions,
|
|
329
|
+
): Promise<T> {
|
|
330
|
+
return this.$repo(options).updateOrCreate(search, values);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
static updateOrCreateMany<T extends BaseModel>(
|
|
334
|
+
this: ModelClass<T>,
|
|
335
|
+
key: string | string[],
|
|
336
|
+
rows: Array<Record<string, unknown>>,
|
|
337
|
+
options?: ModelClientOptions,
|
|
338
|
+
): Promise<T[]> {
|
|
339
|
+
return this.$repo(options).updateOrCreateMany(key, rows);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
static fetchOrCreateMany<T extends BaseModel>(
|
|
343
|
+
this: ModelClass<T>,
|
|
344
|
+
key: string | string[],
|
|
345
|
+
rows: Array<Record<string, unknown>>,
|
|
346
|
+
options?: ModelClientOptions,
|
|
347
|
+
): Promise<T[]> {
|
|
348
|
+
return this.$repo(options).fetchOrCreateMany(key, rows);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
static fetchOrNewUpMany<T extends BaseModel>(
|
|
352
|
+
this: ModelClass<T>,
|
|
353
|
+
key: string | string[],
|
|
354
|
+
rows: Array<Record<string, unknown>>,
|
|
355
|
+
options?: ModelClientOptions,
|
|
356
|
+
): Promise<T[]> {
|
|
357
|
+
return this.$repo(options).fetchOrNewUpMany(key, rows);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/** Empty this model's table (AdonisJS `Model.truncate`). `cascade` is Postgres-only. */
|
|
361
|
+
static truncate<T extends BaseModel>(
|
|
362
|
+
this: ModelClass<T>,
|
|
363
|
+
cascade = false,
|
|
364
|
+
options?: ModelClientOptions,
|
|
365
|
+
): Promise<void> {
|
|
366
|
+
return this.$repo(options).truncate(cascade);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// — Instance persistence (AdonisJS Lucid) —
|
|
370
|
+
|
|
371
|
+
/** Transaction bound to this instance via {@link useTransaction}, if any. */
|
|
372
|
+
#trx?: DatabaseConnection;
|
|
373
|
+
/** Named connection bound at runtime via {@link useConnection}, if any. */
|
|
374
|
+
#connectionOverride?: string;
|
|
375
|
+
|
|
376
|
+
/** The transaction bound to this instance, if any (AdonisJS Lucid `$trx`). */
|
|
377
|
+
get $trx(): DatabaseConnection | undefined {
|
|
378
|
+
return this.#trx;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Bind this instance to a transaction so subsequent `save()` / `delete()` run
|
|
383
|
+
* inside it (AdonisJS Lucid `model.useTransaction`). Chainable.
|
|
384
|
+
*
|
|
385
|
+
* The binding is released when the transaction settles: Lucid clears `$trx`
|
|
386
|
+
* on commit/rollback so a reused instance falls back to the connection pool
|
|
387
|
+
* instead of a finished client. We mirror that by unbinding iff we are still
|
|
388
|
+
* bound to the same trx (a later `useTransaction` to another trx wins).
|
|
389
|
+
*/
|
|
390
|
+
useTransaction(trx: DatabaseConnection): this {
|
|
391
|
+
this.#trx = trx;
|
|
392
|
+
// `.after` lives on the transaction client (a plain pool connection has no
|
|
393
|
+
// settle event). In practice useTransaction always receives a trx; guard so
|
|
394
|
+
// the type narrows and a non-trx connection is simply left bound (Lucid too
|
|
395
|
+
// only resets $trx for real transactions).
|
|
396
|
+
if (isTransactionClient(trx)) {
|
|
397
|
+
const release = () => {
|
|
398
|
+
if (this.#trx === trx) this.#trx = undefined;
|
|
399
|
+
};
|
|
400
|
+
trx.after("commit", release);
|
|
401
|
+
trx.after("rollback", release);
|
|
402
|
+
}
|
|
403
|
+
return this;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* The repository backing this instance — transaction-bound when
|
|
408
|
+
* {@link useTransaction} was called. `this.constructor` is the concrete
|
|
409
|
+
* BaseModel subclass at runtime; TS types it only as `Function`, hence the
|
|
410
|
+
* single unavoidable narrowing (the pattern Lucid's own BaseModel uses).
|
|
411
|
+
*/
|
|
412
|
+
/**
|
|
413
|
+
* Bind this instance to a named connection at runtime (AdonisJS Lucid
|
|
414
|
+
* `model.useConnection`) — subsequent `save()`/`delete()`/relations run on it.
|
|
415
|
+
* A per-instance override of the class's `static connection`. Chainable.
|
|
416
|
+
*/
|
|
417
|
+
useConnection(name: string): this {
|
|
418
|
+
this.#connectionOverride = name;
|
|
419
|
+
return this;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
#repo(): BaseRepository<this> {
|
|
423
|
+
const model = this.constructor as ModelClass<this>;
|
|
424
|
+
if (this.#connectionOverride !== undefined) {
|
|
425
|
+
const conn = getConnection(this.#connectionOverride);
|
|
426
|
+
if (!conn) {
|
|
427
|
+
throw new AtlasError(
|
|
428
|
+
"MISSING_CONNECTION",
|
|
429
|
+
`Model '${model.name}': no connection named '${this.#connectionOverride}' is registered.`,
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
model.$boot();
|
|
433
|
+
const repo = new BaseRepository<this>(model, conn);
|
|
434
|
+
return this.#trx ? repo.useTransaction(this.#trx) : repo;
|
|
435
|
+
}
|
|
436
|
+
const repo = model.$repo();
|
|
437
|
+
return this.#trx ? repo.useTransaction(this.#trx) : repo;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/** INSERT this instance if new, else UPDATE its dirty columns. Returns `this`. */
|
|
441
|
+
async save(): Promise<this> {
|
|
442
|
+
await this.#repo().save(this);
|
|
443
|
+
return this;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/** {@link save} without firing lifecycle hooks (AdonisJS Lucid `saveQuietly`). Returns `this`. */
|
|
447
|
+
async saveQuietly(): Promise<this> {
|
|
448
|
+
await this.#repo().saveQuietly(this);
|
|
449
|
+
return this;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/** DELETE this instance's row (soft-delete aware). Sets `$isDeleted`. */
|
|
453
|
+
async delete(): Promise<void> {
|
|
454
|
+
await this.#repo().delete(this);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/** {@link delete} without firing lifecycle hooks (AdonisJS Lucid `deleteQuietly`). */
|
|
458
|
+
async deleteQuietly(): Promise<void> {
|
|
459
|
+
await this.#repo().deleteQuietly(this);
|
|
460
|
+
}
|
|
461
|
+
}
|