@uql/core 3.1.4 → 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 +2 -2
- package/README.md +26 -14
- package/dist/browser/uql-browser.min.js +29 -29
- 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,7 +3,7 @@
|
|
|
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
8
|
**Note:** Version bump only for package @uql/core
|
|
9
9
|
|
|
@@ -192,7 +192,7 @@ Reflect major changes in the package structure and dependencies.
|
|
|
192
192
|
- Update dependencies.
|
|
193
193
|
|
|
194
194
|
```ts
|
|
195
|
-
const ids = await
|
|
195
|
+
const ids = await pool.transaction(async (querier) => {
|
|
196
196
|
const data = await querier.findMany(...);
|
|
197
197
|
const ids = await querier.insertMany(...);
|
|
198
198
|
return ids;
|
package/README.md
CHANGED
|
@@ -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!
|
|
@@ -620,8 +620,8 @@ export { Sqlite3QuerierPool, SqliteDialect, SqliteQuerier };
|
|
|
620
620
|
* MySQL/MariaDB schema introspector.
|
|
621
621
|
* Works with both MySQL and MariaDB as they share the same information_schema structure.
|
|
622
622
|
*/ class MysqlSchemaIntrospector {
|
|
623
|
-
constructor(
|
|
624
|
-
this.
|
|
623
|
+
constructor(pool){
|
|
624
|
+
this.pool = pool;
|
|
625
625
|
}
|
|
626
626
|
async getTableSchema(tableName) {
|
|
627
627
|
const querier = await this.getQuerier();
|
|
@@ -684,7 +684,7 @@ export { Sqlite3QuerierPool, SqliteDialect, SqliteQuerier };
|
|
|
684
684
|
return (results[0]?.count ?? 0) > 0;
|
|
685
685
|
}
|
|
686
686
|
async getQuerier() {
|
|
687
|
-
const querier = await this.
|
|
687
|
+
const querier = await this.pool.getQuerier();
|
|
688
688
|
if (!isSqlQuerier(querier)) {
|
|
689
689
|
await querier.release();
|
|
690
690
|
throw new Error('MysqlSchemaIntrospector requires a SQL-based querier');
|
|
@@ -842,8 +842,8 @@ export { Sqlite3QuerierPool, SqliteDialect, SqliteQuerier };
|
|
|
842
842
|
/**
|
|
843
843
|
* PostgreSQL schema introspector
|
|
844
844
|
*/ class PostgresSchemaIntrospector {
|
|
845
|
-
constructor(
|
|
846
|
-
this.
|
|
845
|
+
constructor(pool){
|
|
846
|
+
this.pool = pool;
|
|
847
847
|
}
|
|
848
848
|
async getTableSchema(tableName) {
|
|
849
849
|
const querier = await this.getQuerier();
|
|
@@ -907,7 +907,7 @@ export { Sqlite3QuerierPool, SqliteDialect, SqliteQuerier };
|
|
|
907
907
|
return results[0]?.exists ?? false;
|
|
908
908
|
}
|
|
909
909
|
async getQuerier() {
|
|
910
|
-
const querier = await this.
|
|
910
|
+
const querier = await this.pool.getQuerier();
|
|
911
911
|
if (!isSqlQuerier(querier)) {
|
|
912
912
|
await querier.release();
|
|
913
913
|
throw new Error('PostgresSchemaIntrospector requires a SQL-based querier');
|
|
@@ -1115,8 +1115,8 @@ export { Sqlite3QuerierPool, SqliteDialect, SqliteQuerier };
|
|
|
1115
1115
|
/**
|
|
1116
1116
|
* SQLite schema introspector
|
|
1117
1117
|
*/ class SqliteSchemaIntrospector {
|
|
1118
|
-
constructor(
|
|
1119
|
-
this.
|
|
1118
|
+
constructor(pool){
|
|
1119
|
+
this.pool = pool;
|
|
1120
1120
|
}
|
|
1121
1121
|
async getTableSchema(tableName) {
|
|
1122
1122
|
const querier = await this.getQuerier();
|
|
@@ -1179,7 +1179,7 @@ export { Sqlite3QuerierPool, SqliteDialect, SqliteQuerier };
|
|
|
1179
1179
|
return (results[0]?.count ?? 0) > 0;
|
|
1180
1180
|
}
|
|
1181
1181
|
async getQuerier() {
|
|
1182
|
-
const querier = await this.
|
|
1182
|
+
const querier = await this.pool.getQuerier();
|
|
1183
1183
|
if (!isSqlQuerier(querier)) {
|
|
1184
1184
|
await querier.release();
|
|
1185
1185
|
throw new Error('SqliteSchemaIntrospector requires a SQL-based querier');
|
|
@@ -1436,11 +1436,11 @@ class MongoSchemaGenerator extends AbstractDialect {
|
|
|
1436
1436
|
}
|
|
1437
1437
|
|
|
1438
1438
|
class MongoSchemaIntrospector {
|
|
1439
|
-
constructor(
|
|
1440
|
-
this.
|
|
1439
|
+
constructor(pool){
|
|
1440
|
+
this.pool = pool;
|
|
1441
1441
|
}
|
|
1442
1442
|
async getTableSchema(tableName) {
|
|
1443
|
-
const querier = await this.
|
|
1443
|
+
const querier = await this.pool.getQuerier();
|
|
1444
1444
|
try {
|
|
1445
1445
|
const { db } = querier;
|
|
1446
1446
|
const collections = await db.listCollections({
|
|
@@ -1465,7 +1465,7 @@ class MongoSchemaIntrospector {
|
|
|
1465
1465
|
}
|
|
1466
1466
|
}
|
|
1467
1467
|
async getTableNames() {
|
|
1468
|
-
const querier = await this.
|
|
1468
|
+
const querier = await this.pool.getQuerier();
|
|
1469
1469
|
try {
|
|
1470
1470
|
const { db } = querier;
|
|
1471
1471
|
const collections = await db.listCollections().toArray();
|
|
@@ -1484,8 +1484,8 @@ class MongoSchemaIntrospector {
|
|
|
1484
1484
|
* Stores migration state in a database table.
|
|
1485
1485
|
* Uses the querier's dialect for escaping and placeholders.
|
|
1486
1486
|
*/ class DatabaseMigrationStorage {
|
|
1487
|
-
constructor(
|
|
1488
|
-
this.
|
|
1487
|
+
constructor(pool, options = {}){
|
|
1488
|
+
this.pool = pool;
|
|
1489
1489
|
this.storageInitialized = false;
|
|
1490
1490
|
this.tableName = options.tableName ?? 'uql_migrations';
|
|
1491
1491
|
}
|
|
@@ -1493,7 +1493,7 @@ class MongoSchemaIntrospector {
|
|
|
1493
1493
|
if (this.storageInitialized) {
|
|
1494
1494
|
return;
|
|
1495
1495
|
}
|
|
1496
|
-
const querier = await this.
|
|
1496
|
+
const querier = await this.pool.getQuerier();
|
|
1497
1497
|
if (!isSqlQuerier(querier)) {
|
|
1498
1498
|
await querier.release();
|
|
1499
1499
|
throw new Error('DatabaseMigrationStorage requires a SQL-based querier');
|
|
@@ -1517,7 +1517,7 @@ class MongoSchemaIntrospector {
|
|
|
1517
1517
|
}
|
|
1518
1518
|
async executed() {
|
|
1519
1519
|
await this.ensureStorage();
|
|
1520
|
-
const querier = await this.
|
|
1520
|
+
const querier = await this.pool.getQuerier();
|
|
1521
1521
|
if (!isSqlQuerier(querier)) {
|
|
1522
1522
|
await querier.release();
|
|
1523
1523
|
throw new Error('DatabaseMigrationStorage requires a SQL-based querier');
|
|
@@ -1556,10 +1556,10 @@ class MongoSchemaIntrospector {
|
|
|
1556
1556
|
/**
|
|
1557
1557
|
* Main class for managing database migrations
|
|
1558
1558
|
*/ class Migrator {
|
|
1559
|
-
constructor(
|
|
1560
|
-
this.
|
|
1561
|
-
this.dialect = options.dialect ??
|
|
1562
|
-
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, {
|
|
1563
1563
|
tableName: options.tableName
|
|
1564
1564
|
});
|
|
1565
1565
|
this.migrationsPath = options.migrationsPath ?? './migrations';
|
|
@@ -1576,15 +1576,15 @@ class MongoSchemaIntrospector {
|
|
|
1576
1576
|
createIntrospector() {
|
|
1577
1577
|
switch(this.dialect){
|
|
1578
1578
|
case 'postgres':
|
|
1579
|
-
return new PostgresSchemaIntrospector(this.
|
|
1579
|
+
return new PostgresSchemaIntrospector(this.pool);
|
|
1580
1580
|
case 'mysql':
|
|
1581
|
-
return new MysqlSchemaIntrospector(this.
|
|
1581
|
+
return new MysqlSchemaIntrospector(this.pool);
|
|
1582
1582
|
case 'mariadb':
|
|
1583
|
-
return new MariadbSchemaIntrospector(this.
|
|
1583
|
+
return new MariadbSchemaIntrospector(this.pool);
|
|
1584
1584
|
case 'sqlite':
|
|
1585
|
-
return new SqliteSchemaIntrospector(this.
|
|
1585
|
+
return new SqliteSchemaIntrospector(this.pool);
|
|
1586
1586
|
case 'mongodb':
|
|
1587
|
-
return new MongoSchemaIntrospector(this.
|
|
1587
|
+
return new MongoSchemaIntrospector(this.pool);
|
|
1588
1588
|
default:
|
|
1589
1589
|
return undefined;
|
|
1590
1590
|
}
|
|
@@ -1698,7 +1698,7 @@ class MongoSchemaIntrospector {
|
|
|
1698
1698
|
* Run a single migration within a transaction
|
|
1699
1699
|
*/ async runMigration(migration, direction) {
|
|
1700
1700
|
const startTime = Date.now();
|
|
1701
|
-
const querier = await this.
|
|
1701
|
+
const querier = await this.pool.getQuerier();
|
|
1702
1702
|
if (!isSqlQuerier(querier)) {
|
|
1703
1703
|
await querier.release();
|
|
1704
1704
|
throw new Error('Migrator requires a SQL-based querier');
|
|
@@ -1840,7 +1840,7 @@ class MongoSchemaIntrospector {
|
|
|
1840
1840
|
throw new Error('Schema generator not set. Call setSchemaGenerator() first.');
|
|
1841
1841
|
}
|
|
1842
1842
|
const entities = this.entities.length > 0 ? this.entities : getEntities();
|
|
1843
|
-
const querier = await this.
|
|
1843
|
+
const querier = await this.pool.getQuerier();
|
|
1844
1844
|
if (!isSqlQuerier(querier)) {
|
|
1845
1845
|
await querier.release();
|
|
1846
1846
|
throw new Error('Migrator requires a SQL-based querier');
|
|
@@ -1912,7 +1912,7 @@ class MongoSchemaIntrospector {
|
|
|
1912
1912
|
return filteredDiff;
|
|
1913
1913
|
}
|
|
1914
1914
|
async executeSyncStatements(statements, options) {
|
|
1915
|
-
const querier = await this.
|
|
1915
|
+
const querier = await this.pool.getQuerier();
|
|
1916
1916
|
try {
|
|
1917
1917
|
if (this.dialect === 'mongodb') {
|
|
1918
1918
|
await this.executeMongoSyncStatements(statements, options, querier);
|