@uql/core 3.1.3 → 3.3.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/CHANGELOG.md +3 -7
- package/README.md +27 -15
- package/dist/browser/uql-browser.min.js +123 -112
- package/dist/browser/uql-browser.min.js.map +1 -1
- package/dist/migrate/cli.js +7 -7
- package/dist/migrate/cli.js.map +1 -1
- package/dist/migrate/introspection/mongoIntrospector.d.ts +2 -2
- package/dist/migrate/introspection/mongoIntrospector.d.ts.map +1 -1
- package/dist/migrate/introspection/mongoIntrospector.js +5 -5
- package/dist/migrate/introspection/mongoIntrospector.js.map +1 -1
- package/dist/migrate/introspection/mysqlIntrospector.d.ts +2 -2
- package/dist/migrate/introspection/mysqlIntrospector.d.ts.map +1 -1
- package/dist/migrate/introspection/mysqlIntrospector.js +4 -4
- package/dist/migrate/introspection/mysqlIntrospector.js.map +1 -1
- package/dist/migrate/introspection/postgresIntrospector.d.ts +2 -2
- package/dist/migrate/introspection/postgresIntrospector.d.ts.map +1 -1
- package/dist/migrate/introspection/postgresIntrospector.js +4 -4
- package/dist/migrate/introspection/postgresIntrospector.js.map +1 -1
- package/dist/migrate/introspection/sqliteIntrospector.d.ts +2 -2
- package/dist/migrate/introspection/sqliteIntrospector.d.ts.map +1 -1
- package/dist/migrate/introspection/sqliteIntrospector.js +4 -4
- package/dist/migrate/introspection/sqliteIntrospector.js.map +1 -1
- package/dist/migrate/migrator.d.ts +2 -2
- package/dist/migrate/migrator.d.ts.map +1 -1
- package/dist/migrate/migrator.js +13 -13
- package/dist/migrate/migrator.js.map +1 -1
- package/dist/migrate/storage/databaseStorage.d.ts +2 -2
- package/dist/migrate/storage/databaseStorage.d.ts.map +1 -1
- package/dist/migrate/storage/databaseStorage.js +5 -5
- package/dist/migrate/storage/databaseStorage.js.map +1 -1
- package/dist/querier/decorator/transactional.d.ts +2 -2
- package/dist/querier/decorator/transactional.d.ts.map +1 -1
- package/dist/querier/decorator/transactional.js +2 -2
- package/dist/querier/decorator/transactional.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,13 +3,9 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
# [3.3.0](https://github.com/rogerpadilla/uql/compare/@uql/core@3.2.0...@uql/core@3.3.0) (2025-12-30)
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
### Features
|
|
10
|
-
|
|
11
|
-
* add migration CLI and update core package build configuration with new build config and declaration maps while removing old path aliases. ([2b87dd4](https://github.com/rogerpadilla/uql/commit/2b87dd411d05c9844b3e3a6b0a7c74d120b9c362))
|
|
12
|
-
* Implement custom test coverage reporting and simplify README database adapter table. ([837fadf](https://github.com/rogerpadilla/uql/commit/837fadf2cfc27be3a16efc2c489f83c047cc24e1))
|
|
8
|
+
**Note:** Version bump only for package @uql/core
|
|
13
9
|
|
|
14
10
|
|
|
15
11
|
|
|
@@ -196,7 +192,7 @@ Reflect major changes in the package structure and dependencies.
|
|
|
196
192
|
- Update dependencies.
|
|
197
193
|
|
|
198
194
|
```ts
|
|
199
|
-
const ids = await
|
|
195
|
+
const ids = await pool.transaction(async (querier) => {
|
|
200
196
|
const data = await querier.findMany(...);
|
|
201
197
|
const ids = await querier.insertMany(...);
|
|
202
198
|
return ids;
|
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ const companyUsers = await userRepository.findMany({
|
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
## Why
|
|
26
|
+
## Why UQL?
|
|
27
27
|
|
|
28
28
|
See [this article](https://medium.com/@rogerpadillac/in-search-of-the-perfect-orm-e01fcc9bce3d) in medium.com.
|
|
29
29
|
|
|
@@ -92,11 +92,12 @@ bun add pg
|
|
|
92
92
|
Annotate your classes with decorators from `@uql/core`. UQL supports detailed schema metadata for precise DDL generation.
|
|
93
93
|
|
|
94
94
|
```ts
|
|
95
|
+
import { v7 as uuidv7 } from 'uuid';
|
|
95
96
|
import { Entity, Id, Field, OneToOne, OneToMany, ManyToOne, ManyToMany, type Relation } from '@uql/core';
|
|
96
97
|
|
|
97
98
|
@Entity()
|
|
98
99
|
export class User {
|
|
99
|
-
@Id()
|
|
100
|
+
@Id({ onInsert: () => uuidv7() })
|
|
100
101
|
id?: string;
|
|
101
102
|
|
|
102
103
|
@Field({ length: 100, index: true })
|
|
@@ -114,7 +115,7 @@ export class User {
|
|
|
114
115
|
|
|
115
116
|
@Entity()
|
|
116
117
|
export class Profile {
|
|
117
|
-
@Id()
|
|
118
|
+
@Id({ onInsert: () => uuidv7() })
|
|
118
119
|
id?: string;
|
|
119
120
|
|
|
120
121
|
@Field()
|
|
@@ -147,7 +148,7 @@ export class Post {
|
|
|
147
148
|
|
|
148
149
|
@Entity()
|
|
149
150
|
export class Tag {
|
|
150
|
-
@Id()
|
|
151
|
+
@Id({ onInsert: () => uuidv7() })
|
|
151
152
|
id?: string;
|
|
152
153
|
|
|
153
154
|
@Field()
|
|
@@ -156,7 +157,7 @@ export class Tag {
|
|
|
156
157
|
|
|
157
158
|
@Entity()
|
|
158
159
|
export class PostTag {
|
|
159
|
-
@Id()
|
|
160
|
+
@Id({ onInsert: () => uuidv7() })
|
|
160
161
|
id?: string;
|
|
161
162
|
|
|
162
163
|
@Field({ reference: () => Post })
|
|
@@ -178,7 +179,7 @@ A querier-pool can be set in any of the bootstrap files of your app (e.g. in the
|
|
|
178
179
|
import { SnakeCaseNamingStrategy } from '@uql/core';
|
|
179
180
|
import { PgQuerierPool } from '@uql/core/postgres';
|
|
180
181
|
|
|
181
|
-
export const
|
|
182
|
+
export const pool = new PgQuerierPool(
|
|
182
183
|
{
|
|
183
184
|
host: 'localhost',
|
|
184
185
|
user: 'theUser',
|
|
@@ -211,10 +212,10 @@ Repositories provide a clean, Data-Mapper style interface for your entities.
|
|
|
211
212
|
```ts
|
|
212
213
|
import { GenericRepository } from '@uql/core';
|
|
213
214
|
import { User } from './shared/models/index.js';
|
|
214
|
-
import {
|
|
215
|
+
import { pool } from './shared/orm.js';
|
|
215
216
|
|
|
216
217
|
// Get a querier from the pool
|
|
217
|
-
const querier = await
|
|
218
|
+
const querier = await pool.getQuerier();
|
|
218
219
|
|
|
219
220
|
try {
|
|
220
221
|
const userRepository = new GenericRepository(User, querier);
|
|
@@ -246,10 +247,10 @@ UQL's query syntax is context-aware. When you query a relation, the available fi
|
|
|
246
247
|
|
|
247
248
|
```ts
|
|
248
249
|
import { GenericRepository } from '@uql/core';
|
|
249
|
-
import {
|
|
250
|
+
import { pool } from './shared/orm.js';
|
|
250
251
|
import { User } from './shared/models/index.js';
|
|
251
252
|
|
|
252
|
-
const authorsWithPopularPosts = await
|
|
253
|
+
const authorsWithPopularPosts = await pool.transaction(async (querier) => {
|
|
253
254
|
const userRepository = new GenericRepository(User, querier);
|
|
254
255
|
|
|
255
256
|
return userRepository.findMany({
|
|
@@ -282,6 +283,7 @@ const authorsWithPopularPosts = await querierPool.transaction(async (querier) =>
|
|
|
282
283
|
Define complex logic directly in your entities using `raw` functions from `uql/util`. These are highly efficient as they are resolved during SQL generation.
|
|
283
284
|
|
|
284
285
|
```ts
|
|
286
|
+
import { v7 as uuidv7 } from 'uuid';
|
|
285
287
|
import { Entity, Id, Field, raw } from '@uql/core';
|
|
286
288
|
import { ItemTag } from './shared/models/index.js';
|
|
287
289
|
|
|
@@ -313,10 +315,10 @@ export class Item {
|
|
|
313
315
|
UQL ensures your operations are serialized and thread-safe.
|
|
314
316
|
|
|
315
317
|
```ts
|
|
316
|
-
import {
|
|
318
|
+
import { pool } from './shared/orm.js';
|
|
317
319
|
import { User, Profile } from './shared/models/index.js';
|
|
318
320
|
|
|
319
|
-
const result = await
|
|
321
|
+
const result = await pool.transaction(async (querier) => {
|
|
320
322
|
const user = await querier.findOne(User, { $where: { email: '...' } });
|
|
321
323
|
const profileId = await querier.insertOne(Profile, { userId: user.id, ... });
|
|
322
324
|
return { userId: user.id, profileId };
|
|
@@ -339,7 +341,7 @@ import { PgQuerierPool } from '@uql/core/postgres';
|
|
|
339
341
|
import { User, Post } from './shared/models/index.js';
|
|
340
342
|
|
|
341
343
|
export default {
|
|
342
|
-
|
|
344
|
+
pool: new PgQuerierPool({ /* config */ }),
|
|
343
345
|
entities: [User, Post],
|
|
344
346
|
migrationsPath: './migrations',
|
|
345
347
|
};
|
|
@@ -377,9 +379,9 @@ In development, you can use `autoSync` to automatically keep your database in sy
|
|
|
377
379
|
|
|
378
380
|
```ts
|
|
379
381
|
import { Migrator } from '@uql/core/migrate';
|
|
380
|
-
import {
|
|
382
|
+
import { pool } from './shared/orm.js';
|
|
381
383
|
|
|
382
|
-
const migrator = new Migrator(
|
|
384
|
+
const migrator = new Migrator(pool);
|
|
383
385
|
await migrator.autoSync({ logging: true });
|
|
384
386
|
```
|
|
385
387
|
|
|
@@ -406,3 +408,13 @@ For those who want to see the "engine under the hood," check out these resources
|
|
|
406
408
|
- [PostgreSQL Spec](https://github.com/rogerpadilla/uql/blob/main/packages/core/src/postgres/postgresDialect.spec.ts) | [MySQL Spec](https://github.com/rogerpadilla/uql/blob/main/packages/core/src/mysql/mysqlDialect.spec.ts) | [SQLite Spec](https://github.com/rogerpadilla/uql/blob/main/packages/core/src/sqlite/sqliteDialect.spec.ts).
|
|
407
409
|
- [Querier Integration Tests](https://github.com/rogerpadilla/uql/blob/main/packages/core/src/querier/abstractSqlQuerier-spec.ts): Testing the interaction between SQL generation and connection management.
|
|
408
410
|
- [MongoDB Migration Tests](https://github.com/rogerpadilla/uql/blob/main/packages/core/src/migrate/migrator-mongo.it.ts): Integration tests ensuring correct collection and index synchronization for MongoDB.
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## Built with ❤️ and supported by
|
|
415
|
+
|
|
416
|
+
UQL is an open-source project driven by the community and proudly sponsored by **[Variability.ai](https://variability.ai)**.
|
|
417
|
+
|
|
418
|
+
> "Intelligence in Every Fluctuation"
|
|
419
|
+
|
|
420
|
+
Their support helps us maintain and evolve the "Smartest ORM" for developers everywhere. Thank you for being part of our journey!
|
|
@@ -1,97 +1,108 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { escapeSqlId, getKeys } from '../util/index.js';
|
|
6
|
-
import { readdir, readFile, mkdir, writeFile } from 'node:fs/promises';
|
|
7
|
-
import { join, basename, extname, dirname } from 'node:path';
|
|
8
|
-
import { pathToFileURL } from 'node:url';
|
|
1
|
+
import sqlstring from 'sqlstring-sqlite';
|
|
2
|
+
import { AbstractSqlDialect } from '../dialect/index.js';
|
|
3
|
+
import { getMeta } from '../entity/index.js';
|
|
4
|
+
import { AbstractSqlQuerier, AbstractQuerierPool } from '../querier/index.js';
|
|
9
5
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
constructor(namingStrategy, escapeIdChar = '`'){
|
|
14
|
-
super(namingStrategy), this.escapeIdChar = escapeIdChar;
|
|
6
|
+
class SqliteDialect extends AbstractSqlDialect {
|
|
7
|
+
constructor(namingStrategy){
|
|
8
|
+
super(namingStrategy, '`', 'BEGIN TRANSACTION');
|
|
15
9
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
addValue(values, value) {
|
|
11
|
+
if (value instanceof Date) {
|
|
12
|
+
value = value.getTime();
|
|
13
|
+
} else if (typeof value === 'boolean') {
|
|
14
|
+
value = value ? 1 : 0;
|
|
15
|
+
}
|
|
16
|
+
return super.addValue(values, value);
|
|
20
17
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return sql;
|
|
18
|
+
compare(ctx, entity, key, val, opts) {
|
|
19
|
+
if (key === '$text') {
|
|
20
|
+
const meta = getMeta(entity);
|
|
21
|
+
const search = val;
|
|
22
|
+
const fields = search.$fields.map((fKey)=>{
|
|
23
|
+
const field = meta.fields[fKey];
|
|
24
|
+
const columnName = this.resolveColumnName(fKey, field);
|
|
25
|
+
return this.escapeId(columnName);
|
|
26
|
+
});
|
|
27
|
+
const tableName = this.resolveTableName(entity, meta);
|
|
28
|
+
ctx.append(`${this.escapeId(tableName)} MATCH {${fields.join(' ')}} : `);
|
|
29
|
+
ctx.addValue(search.$value);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
super.compare(ctx, entity, key, val, opts);
|
|
37
33
|
}
|
|
38
|
-
|
|
34
|
+
compareFieldOperator(ctx, entity, key, op, val, opts = {}) {
|
|
35
|
+
super.compareFieldOperator(ctx, entity, key, op, val, opts);
|
|
36
|
+
}
|
|
37
|
+
upsert(ctx, entity, conflictPaths, payload) {
|
|
39
38
|
const meta = getMeta(entity);
|
|
40
|
-
const
|
|
41
|
-
|
|
39
|
+
const update = this.getUpsertUpdateAssignments(ctx, meta, conflictPaths, payload, (name)=>`EXCLUDED.${name}`);
|
|
40
|
+
const keysStr = this.getUpsertConflictPathsStr(meta, conflictPaths);
|
|
41
|
+
const onConflict = update ? `DO UPDATE SET ${update}` : 'DO NOTHING';
|
|
42
|
+
this.insert(ctx, entity, payload);
|
|
43
|
+
ctx.append(` ON CONFLICT (${keysStr}) ${onConflict}`);
|
|
42
44
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
statements.push(this.generateCreateIndex(diff.tableName, index));
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
// Drop indexes
|
|
74
|
-
if (diff.indexesToDrop?.length) {
|
|
75
|
-
for (const indexName of diff.indexesToDrop){
|
|
76
|
-
statements.push(this.generateDropIndex(diff.tableName, indexName));
|
|
77
|
-
}
|
|
45
|
+
escape(value) {
|
|
46
|
+
return sqlstring.escape(value);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
class SqliteQuerier extends AbstractSqlQuerier {
|
|
51
|
+
constructor(db, extra){
|
|
52
|
+
super(new SqliteDialect(extra?.namingStrategy)), this.db = db, this.extra = extra;
|
|
53
|
+
}
|
|
54
|
+
async internalAll(query, values) {
|
|
55
|
+
this.extra?.logger?.(query, values);
|
|
56
|
+
return this.db.prepare(query).all(values || []);
|
|
57
|
+
}
|
|
58
|
+
async internalRun(query, values) {
|
|
59
|
+
this.extra?.logger?.(query, values);
|
|
60
|
+
const { changes, lastInsertRowid } = this.db.prepare(query).run(values || []);
|
|
61
|
+
const firstId = lastInsertRowid ? Number(lastInsertRowid) - (changes - 1) : undefined;
|
|
62
|
+
const ids = firstId ? Array(changes).fill(firstId).map((i, index)=>i + index) : [];
|
|
63
|
+
return {
|
|
64
|
+
changes,
|
|
65
|
+
ids,
|
|
66
|
+
firstId
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
async internalRelease() {
|
|
70
|
+
if (this.hasOpenTransaction) {
|
|
71
|
+
throw TypeError('pending transaction');
|
|
78
72
|
}
|
|
79
|
-
|
|
73
|
+
// no-op
|
|
80
74
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
class Sqlite3QuerierPool extends AbstractQuerierPool {
|
|
78
|
+
constructor(filename, opts, extra){
|
|
79
|
+
super('sqlite', extra), this.filename = filename, this.opts = opts;
|
|
80
|
+
}
|
|
81
|
+
async getQuerier() {
|
|
82
|
+
if (!this.querier) {
|
|
83
|
+
let db;
|
|
84
|
+
if (typeof Bun !== 'undefined') {
|
|
85
|
+
const { Database } = await import('bun:sqlite');
|
|
86
|
+
db = new Database(this.filename, this.opts);
|
|
87
|
+
db.run('PRAGMA journal_mode = WAL');
|
|
88
|
+
} else {
|
|
89
|
+
const { default: Database } = await import('better-sqlite3');
|
|
90
|
+
db = new Database(this.filename, this.opts);
|
|
91
|
+
db.pragma('journal_mode = WAL');
|
|
88
92
|
}
|
|
93
|
+
this.querier = new SqliteQuerier(db, this.extra);
|
|
89
94
|
}
|
|
90
|
-
return
|
|
95
|
+
return this.querier;
|
|
91
96
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
97
|
+
async end() {
|
|
98
|
+
await this.querier.db.close();
|
|
99
|
+
delete this.querier;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export { Sqlite3QuerierPool, SqliteDialect, SqliteQuerier };
|
|
104
|
+
//# sourceMappingURL=uql-browser.min.js.map
|
|
105
|
+
>this.escapeId(c)).join(', ');
|
|
95
106
|
return `CREATE ${unique}INDEX ${this.escapeId(index.name)} ON ${this.escapeId(tableName)} (${columns});`;
|
|
96
107
|
}
|
|
97
108
|
generateDropIndex(tableName, indexName) {
|
|
@@ -609,8 +620,8 @@ import { pathToFileURL } from 'node:url';
|
|
|
609
620
|
* MySQL/MariaDB schema introspector.
|
|
610
621
|
* Works with both MySQL and MariaDB as they share the same information_schema structure.
|
|
611
622
|
*/ class MysqlSchemaIntrospector {
|
|
612
|
-
constructor(
|
|
613
|
-
this.
|
|
623
|
+
constructor(pool){
|
|
624
|
+
this.pool = pool;
|
|
614
625
|
}
|
|
615
626
|
async getTableSchema(tableName) {
|
|
616
627
|
const querier = await this.getQuerier();
|
|
@@ -673,7 +684,7 @@ import { pathToFileURL } from 'node:url';
|
|
|
673
684
|
return (results[0]?.count ?? 0) > 0;
|
|
674
685
|
}
|
|
675
686
|
async getQuerier() {
|
|
676
|
-
const querier = await this.
|
|
687
|
+
const querier = await this.pool.getQuerier();
|
|
677
688
|
if (!isSqlQuerier(querier)) {
|
|
678
689
|
await querier.release();
|
|
679
690
|
throw new Error('MysqlSchemaIntrospector requires a SQL-based querier');
|
|
@@ -831,8 +842,8 @@ import { pathToFileURL } from 'node:url';
|
|
|
831
842
|
/**
|
|
832
843
|
* PostgreSQL schema introspector
|
|
833
844
|
*/ class PostgresSchemaIntrospector {
|
|
834
|
-
constructor(
|
|
835
|
-
this.
|
|
845
|
+
constructor(pool){
|
|
846
|
+
this.pool = pool;
|
|
836
847
|
}
|
|
837
848
|
async getTableSchema(tableName) {
|
|
838
849
|
const querier = await this.getQuerier();
|
|
@@ -896,7 +907,7 @@ import { pathToFileURL } from 'node:url';
|
|
|
896
907
|
return results[0]?.exists ?? false;
|
|
897
908
|
}
|
|
898
909
|
async getQuerier() {
|
|
899
|
-
const querier = await this.
|
|
910
|
+
const querier = await this.pool.getQuerier();
|
|
900
911
|
if (!isSqlQuerier(querier)) {
|
|
901
912
|
await querier.release();
|
|
902
913
|
throw new Error('PostgresSchemaIntrospector requires a SQL-based querier');
|
|
@@ -1104,8 +1115,8 @@ import { pathToFileURL } from 'node:url';
|
|
|
1104
1115
|
/**
|
|
1105
1116
|
* SQLite schema introspector
|
|
1106
1117
|
*/ class SqliteSchemaIntrospector {
|
|
1107
|
-
constructor(
|
|
1108
|
-
this.
|
|
1118
|
+
constructor(pool){
|
|
1119
|
+
this.pool = pool;
|
|
1109
1120
|
}
|
|
1110
1121
|
async getTableSchema(tableName) {
|
|
1111
1122
|
const querier = await this.getQuerier();
|
|
@@ -1168,7 +1179,7 @@ import { pathToFileURL } from 'node:url';
|
|
|
1168
1179
|
return (results[0]?.count ?? 0) > 0;
|
|
1169
1180
|
}
|
|
1170
1181
|
async getQuerier() {
|
|
1171
|
-
const querier = await this.
|
|
1182
|
+
const querier = await this.pool.getQuerier();
|
|
1172
1183
|
if (!isSqlQuerier(querier)) {
|
|
1173
1184
|
await querier.release();
|
|
1174
1185
|
throw new Error('SqliteSchemaIntrospector requires a SQL-based querier');
|
|
@@ -1425,11 +1436,11 @@ class MongoSchemaGenerator extends AbstractDialect {
|
|
|
1425
1436
|
}
|
|
1426
1437
|
|
|
1427
1438
|
class MongoSchemaIntrospector {
|
|
1428
|
-
constructor(
|
|
1429
|
-
this.
|
|
1439
|
+
constructor(pool){
|
|
1440
|
+
this.pool = pool;
|
|
1430
1441
|
}
|
|
1431
1442
|
async getTableSchema(tableName) {
|
|
1432
|
-
const querier = await this.
|
|
1443
|
+
const querier = await this.pool.getQuerier();
|
|
1433
1444
|
try {
|
|
1434
1445
|
const { db } = querier;
|
|
1435
1446
|
const collections = await db.listCollections({
|
|
@@ -1454,7 +1465,7 @@ class MongoSchemaIntrospector {
|
|
|
1454
1465
|
}
|
|
1455
1466
|
}
|
|
1456
1467
|
async getTableNames() {
|
|
1457
|
-
const querier = await this.
|
|
1468
|
+
const querier = await this.pool.getQuerier();
|
|
1458
1469
|
try {
|
|
1459
1470
|
const { db } = querier;
|
|
1460
1471
|
const collections = await db.listCollections().toArray();
|
|
@@ -1473,8 +1484,8 @@ class MongoSchemaIntrospector {
|
|
|
1473
1484
|
* Stores migration state in a database table.
|
|
1474
1485
|
* Uses the querier's dialect for escaping and placeholders.
|
|
1475
1486
|
*/ class DatabaseMigrationStorage {
|
|
1476
|
-
constructor(
|
|
1477
|
-
this.
|
|
1487
|
+
constructor(pool, options = {}){
|
|
1488
|
+
this.pool = pool;
|
|
1478
1489
|
this.storageInitialized = false;
|
|
1479
1490
|
this.tableName = options.tableName ?? 'uql_migrations';
|
|
1480
1491
|
}
|
|
@@ -1482,7 +1493,7 @@ class MongoSchemaIntrospector {
|
|
|
1482
1493
|
if (this.storageInitialized) {
|
|
1483
1494
|
return;
|
|
1484
1495
|
}
|
|
1485
|
-
const querier = await this.
|
|
1496
|
+
const querier = await this.pool.getQuerier();
|
|
1486
1497
|
if (!isSqlQuerier(querier)) {
|
|
1487
1498
|
await querier.release();
|
|
1488
1499
|
throw new Error('DatabaseMigrationStorage requires a SQL-based querier');
|
|
@@ -1506,7 +1517,7 @@ class MongoSchemaIntrospector {
|
|
|
1506
1517
|
}
|
|
1507
1518
|
async executed() {
|
|
1508
1519
|
await this.ensureStorage();
|
|
1509
|
-
const querier = await this.
|
|
1520
|
+
const querier = await this.pool.getQuerier();
|
|
1510
1521
|
if (!isSqlQuerier(querier)) {
|
|
1511
1522
|
await querier.release();
|
|
1512
1523
|
throw new Error('DatabaseMigrationStorage requires a SQL-based querier');
|
|
@@ -1545,10 +1556,10 @@ class MongoSchemaIntrospector {
|
|
|
1545
1556
|
/**
|
|
1546
1557
|
* Main class for managing database migrations
|
|
1547
1558
|
*/ class Migrator {
|
|
1548
|
-
constructor(
|
|
1549
|
-
this.
|
|
1550
|
-
this.dialect = options.dialect ??
|
|
1551
|
-
this.storage = options.storage ?? new DatabaseMigrationStorage(
|
|
1559
|
+
constructor(pool, options = {}){
|
|
1560
|
+
this.pool = pool;
|
|
1561
|
+
this.dialect = options.dialect ?? pool.dialect ?? 'postgres';
|
|
1562
|
+
this.storage = options.storage ?? new DatabaseMigrationStorage(pool, {
|
|
1552
1563
|
tableName: options.tableName
|
|
1553
1564
|
});
|
|
1554
1565
|
this.migrationsPath = options.migrationsPath ?? './migrations';
|
|
@@ -1565,15 +1576,15 @@ class MongoSchemaIntrospector {
|
|
|
1565
1576
|
createIntrospector() {
|
|
1566
1577
|
switch(this.dialect){
|
|
1567
1578
|
case 'postgres':
|
|
1568
|
-
return new PostgresSchemaIntrospector(this.
|
|
1579
|
+
return new PostgresSchemaIntrospector(this.pool);
|
|
1569
1580
|
case 'mysql':
|
|
1570
|
-
return new MysqlSchemaIntrospector(this.
|
|
1581
|
+
return new MysqlSchemaIntrospector(this.pool);
|
|
1571
1582
|
case 'mariadb':
|
|
1572
|
-
return new MariadbSchemaIntrospector(this.
|
|
1583
|
+
return new MariadbSchemaIntrospector(this.pool);
|
|
1573
1584
|
case 'sqlite':
|
|
1574
|
-
return new SqliteSchemaIntrospector(this.
|
|
1585
|
+
return new SqliteSchemaIntrospector(this.pool);
|
|
1575
1586
|
case 'mongodb':
|
|
1576
|
-
return new MongoSchemaIntrospector(this.
|
|
1587
|
+
return new MongoSchemaIntrospector(this.pool);
|
|
1577
1588
|
default:
|
|
1578
1589
|
return undefined;
|
|
1579
1590
|
}
|
|
@@ -1687,7 +1698,7 @@ class MongoSchemaIntrospector {
|
|
|
1687
1698
|
* Run a single migration within a transaction
|
|
1688
1699
|
*/ async runMigration(migration, direction) {
|
|
1689
1700
|
const startTime = Date.now();
|
|
1690
|
-
const querier = await this.
|
|
1701
|
+
const querier = await this.pool.getQuerier();
|
|
1691
1702
|
if (!isSqlQuerier(querier)) {
|
|
1692
1703
|
await querier.release();
|
|
1693
1704
|
throw new Error('Migrator requires a SQL-based querier');
|
|
@@ -1829,7 +1840,7 @@ class MongoSchemaIntrospector {
|
|
|
1829
1840
|
throw new Error('Schema generator not set. Call setSchemaGenerator() first.');
|
|
1830
1841
|
}
|
|
1831
1842
|
const entities = this.entities.length > 0 ? this.entities : getEntities();
|
|
1832
|
-
const querier = await this.
|
|
1843
|
+
const querier = await this.pool.getQuerier();
|
|
1833
1844
|
if (!isSqlQuerier(querier)) {
|
|
1834
1845
|
await querier.release();
|
|
1835
1846
|
throw new Error('Migrator requires a SQL-based querier');
|
|
@@ -1901,7 +1912,7 @@ class MongoSchemaIntrospector {
|
|
|
1901
1912
|
return filteredDiff;
|
|
1902
1913
|
}
|
|
1903
1914
|
async executeSyncStatements(statements, options) {
|
|
1904
|
-
const querier = await this.
|
|
1915
|
+
const querier = await this.pool.getQuerier();
|
|
1905
1916
|
try {
|
|
1906
1917
|
if (this.dialect === 'mongodb') {
|
|
1907
1918
|
await this.executeMongoSyncStatements(statements, options, querier);
|