uql-orm 0.4.5 → 0.5.2
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 +12 -19
- package/README.md +53 -56
- package/dist/browser/uql-browser.min.js +167 -193
- package/dist/browser/uql-browser.min.js.map +1 -1
- package/dist/cockroachdb/cockroachDialect.d.ts +12 -0
- package/dist/cockroachdb/cockroachDialect.d.ts.map +1 -0
- package/dist/cockroachdb/cockroachDialect.js +13 -0
- package/dist/cockroachdb/cockroachDialect.js.map +1 -0
- package/dist/cockroachdb/crdbQuerier.d.ts +14 -0
- package/dist/cockroachdb/crdbQuerier.d.ts.map +1 -0
- package/dist/cockroachdb/crdbQuerier.js +35 -0
- package/dist/cockroachdb/crdbQuerier.js.map +1 -0
- package/dist/cockroachdb/crdbQuerierPool.d.ts +14 -0
- package/dist/cockroachdb/crdbQuerierPool.d.ts.map +1 -0
- package/dist/cockroachdb/crdbQuerierPool.js +20 -0
- package/dist/cockroachdb/crdbQuerierPool.js.map +1 -0
- package/dist/cockroachdb/index.d.ts +4 -0
- package/dist/cockroachdb/index.d.ts.map +1 -0
- package/dist/cockroachdb/index.js +4 -0
- package/dist/cockroachdb/index.js.map +1 -0
- package/dist/dialect/dialectConfig.d.ts +6 -0
- package/dist/dialect/dialectConfig.d.ts.map +1 -1
- package/dist/dialect/dialectConfig.js +46 -1
- package/dist/dialect/dialectConfig.js.map +1 -1
- package/dist/migrate/migrator.d.ts.map +1 -1
- package/dist/migrate/migrator.js +1 -0
- package/dist/migrate/migrator.js.map +1 -1
- package/dist/postgres/postgresDialect.d.ts +2 -2
- package/dist/postgres/postgresDialect.d.ts.map +1 -1
- package/dist/postgres/postgresDialect.js +2 -2
- package/dist/postgres/postgresDialect.js.map +1 -1
- package/dist/schema/canonicalType.d.ts.map +1 -1
- package/dist/schema/canonicalType.js +39 -34
- package/dist/schema/canonicalType.js.map +1 -1
- package/dist/type/query.d.ts +1 -1
- package/dist/type/query.d.ts.map +1 -1
- package/package.json +12 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,28 +1,21 @@
|
|
|
1
|
-
# Change Log
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
-
|
|
6
|
-
## [0.4.5](https://github.com/rogerpadilla/uql/compare/uql-orm@0.4.0...uql-orm@0.4.5) (2026-03-14)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
### Features
|
|
10
|
-
|
|
11
|
-
* add vector search integration tests for `findMany` with `$sort: { $vector }` and update test infrastructure. ([c920cde](https://github.com/rogerpadilla/uql/commit/c920cde46dbb4985d07a1926dfc3ac845862244c))
|
|
12
|
-
* implement cursor-based stream with across all queriers and deprecate in favor of ([2d6c2ea](https://github.com/rogerpadilla/uql/commit/2d6c2ea0851d9c20ca9d092717087eaa65e5f937))
|
|
13
|
-
* upgrade to Vite 8 and TypeScript 6, removing redundant compiler options and `vite-tsconfig-paths` plugin. ([f81563c](https://github.com/rogerpadilla/uql/commit/f81563cfe5246bfa59966f08493fd9786a817e02))
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
1
|
# Changelog
|
|
20
2
|
|
|
21
3
|
All notable changes to this project will be documented in this file. Please add new changes to the top.
|
|
22
4
|
|
|
23
5
|
date format is [yyyy-mm-dd]
|
|
24
6
|
|
|
25
|
-
## [0.
|
|
7
|
+
## [0.5.1] - 2026-03-15
|
|
8
|
+
### Chore
|
|
9
|
+
- **Documentation**: Unified documentation strategy using NPM lifecycle scripts across subpackages.
|
|
10
|
+
- **Maintenance**: Removed redundant `copyfiles` dependency and cleaned up build scripts.
|
|
11
|
+
- **README**: Refined technical copy and visual feedback sections for a better developer documentation experience.
|
|
12
|
+
|
|
13
|
+
## [0.5.0] - 2026-03-15
|
|
14
|
+
### Features
|
|
15
|
+
- **CockroachDB Support**: Full integration with a new dialect, querier, and Docker Compose configuration. Supports native upsert and mapped driver execution.
|
|
16
|
+
### New Features
|
|
17
|
+
- **CockroachDB Support**: Added first-class support for `cockroachdb` dialect, leveraging its PostgreSQL wire-compatibility. Includes native `upsert` support and seamlessly mapped driver execution.
|
|
18
|
+
|
|
26
19
|
### Testing
|
|
27
20
|
- **Vector search integration tests**: Added 7 end-to-end tests for `findMany` with `$sort: { $vector }` against a real Postgres+pgvector database — covers cosine/L2 similarity ordering, `$project` distance projection, filter+sort combo, `$limit`, and empty-table edge case.
|
|
28
21
|
- Docker Postgres image switched to `pgvector/pgvector:pg18` for pgvector extension support.
|
package/README.md
CHANGED
|
@@ -4,11 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://github.com/rogerpadilla/uql) [](https://coveralls.io/github/rogerpadilla/uql?branch=main) [](https://github.com/rogerpadilla/uql/blob/main/LICENSE) [](https://www.npmjs.com/package/uql-orm)
|
|
6
6
|
|
|
7
|
-
**[UQL](https://uql-orm.dev)** is
|
|
8
|
-
|
|
7
|
+
**[UQL](https://uql-orm.dev)** is a clean, ultra-fast TypeScript ORM designed for developers who value portability and performance. It eliminates the friction between SQL and MongoDB, providing a unified, type-safe experience without proprietary DSLs or heavy codegen steps.
|
|
9
8
|
|
|
10
9
|
```ts
|
|
11
|
-
const
|
|
10
|
+
const results = await querier.findMany(User, {
|
|
12
11
|
$select: { name: true, profile: { $select: { picture: true } } },
|
|
13
12
|
$where: { name: { $istartsWith: 'a' }, posts: { tags: { name: 'typescript' } } },
|
|
14
13
|
$sort: { createdAt: 'desc' },
|
|
@@ -20,22 +19,22 @@ const users = await querier.findMany(User, {
|
|
|
20
19
|
|
|
21
20
|
## Features
|
|
22
21
|
|
|
23
|
-
| Feature
|
|
24
|
-
|
|
|
25
|
-
| **[Intelligent Querying](https://uql-orm.dev/querying/relations)**
|
|
26
|
-
| **Serializable JSON**
|
|
27
|
-
| **Unified Dialects**
|
|
28
|
-
| **[Naming Strategies](https://uql-orm.dev/naming-strategy)**
|
|
29
|
-
| **Smart SQL Engine**
|
|
30
|
-
| **Thread-Safe by Design**
|
|
31
|
-
| **[Declarative Transactions](https://uql-orm.dev/querying/transactions)**
|
|
32
|
-
| **[Lifecycle Hooks](https://uql-orm.dev/entities/lifecycle-hooks)
|
|
33
|
-
| **[Aggregate Queries](https://uql-orm.dev/querying/aggregate)** | `GROUP BY`, `HAVING`,
|
|
34
|
-
| **[Semantic Search](https://uql-orm.dev/querying/semantic-search)** |
|
|
35
|
-
| **[Cursor Streaming](https://uql-orm.dev/querying/streaming)** |
|
|
36
|
-
| **[Modern & Versatile](https://uql-orm.dev/entities/virtual-fields)** |
|
|
37
|
-
| **[Database Migrations](https://www.uql-orm.dev/migrations)**
|
|
38
|
-
| **[Logging & Monitoring](https://www.uql-orm.dev/logging)**
|
|
22
|
+
| Feature | Why it matters |
|
|
23
|
+
| :--- | :--- |
|
|
24
|
+
| **[Intelligent Querying](https://uql-orm.dev/querying/relations)** | Deep auto-completion for operators and relations at any depth—no more guessing property names. |
|
|
25
|
+
| **Serializable JSON** | 100% valid JSON queries. Send your query logic over HTTP or WebSockets as easily as a string. |
|
|
26
|
+
| **Unified Dialects** | Write once, run anywhere. Seamlessly switch between PostgreSQL, MySQL, SQLite, and MongoDB. |
|
|
27
|
+
| **[Naming Strategies](https://uql-orm.dev/naming-strategy)** | No more `camelCase` vs `snake_case` headaches. Map your code to your database automatically. |
|
|
28
|
+
| **Smart SQL Engine** | Zero-allocation SQL generation. Built for high-throughput apps where every millisecond counts. |
|
|
29
|
+
| **Thread-Safe by Design** | Protect your data integrity with centralized task queues and the `@Serialized()` decorator. |
|
|
30
|
+
| **[Declarative Transactions](https://uql-orm.dev/querying/transactions)** | Clean `@Transactional()` decorators that work beautifully with modern DI frameworks like NestJS. |
|
|
31
|
+
| **[Lifecycle Hooks](https://uql-orm.dev/entities/lifecycle-hooks)** | Automate validation, timestamps, and computed logic with intuitive class-based decorators. |
|
|
32
|
+
| **[Aggregate Queries](https://uql-orm.dev/querying/aggregate)** | Real-time analytics with `GROUP BY`, `HAVING`, and native math operators across all dialects. |
|
|
33
|
+
| **[Semantic Search](https://uql-orm.dev/querying/semantic-search)** | Native vector similarity search. Rank results by meaning using standard ORM operators. |
|
|
34
|
+
| **[Cursor Streaming](https://uql-orm.dev/querying/streaming)** | Process millions of rows with a stable memory footprint using native driver-level cursors. |
|
|
35
|
+
| **[Modern & Versatile](https://uql-orm.dev/entities/virtual-fields)** | Pure ESM, high-res timing, built-in soft-delete, and first-class JSONB/JSON support. |
|
|
36
|
+
| **[Database Migrations](https://www.uql-orm.dev/migrations)** | Entity-First synchronization. DDL is auto-generated by diffing your code against the live DB. |
|
|
37
|
+
| **[Logging & Monitoring](https://www.uql-orm.dev/logging)** | High-visibility debugging with slow-query detection and high-contrast terminal output. |
|
|
39
38
|
|
|
40
39
|
|
|
41
40
|
|
|
@@ -50,15 +49,16 @@ npm install uql-orm # or bun add / pnpm add
|
|
|
50
49
|
|
|
51
50
|
### Supported Drivers (pick according to your database)
|
|
52
51
|
|
|
53
|
-
| Database
|
|
54
|
-
|
|
|
55
|
-
| **PostgreSQL** (incl. Neon, Cockroach, Yugabyte) | `npm install pg`
|
|
56
|
-
| **MySQL** (incl. TiDB, Aurora)
|
|
57
|
-
| **MariaDB**
|
|
58
|
-
| **SQLite**
|
|
59
|
-
| **LibSQL** (incl. Turso)
|
|
60
|
-
| **MongoDB**
|
|
61
|
-
| **
|
|
52
|
+
| Database | Command |
|
|
53
|
+
| :--- | :--- |
|
|
54
|
+
| **PostgreSQL** (incl. Neon, Cockroach, Yugabyte) | `npm install pg` |
|
|
55
|
+
| **MySQL** (incl. TiDB, Aurora) | `npm install mysql2` |
|
|
56
|
+
| **MariaDB** | `npm install mariadb` |
|
|
57
|
+
| **SQLite** | `npm install better-sqlite3` |
|
|
58
|
+
| **LibSQL** (incl. Turso) | `npm install @libsql/client` |
|
|
59
|
+
| **MongoDB** | `npm install mongodb` |
|
|
60
|
+
| **CockroachDB** | `npm install pg` |
|
|
61
|
+
| **Cloudflare D1** | _Native (no driver needed)_ |
|
|
62
62
|
|
|
63
63
|
### TypeScript Configuration
|
|
64
64
|
|
|
@@ -75,30 +75,28 @@ Ensure your `tsconfig.json` is configured to support decorators and metadata:
|
|
|
75
75
|
|
|
76
76
|
**Note:** UQL is Modern Pure ESM — ensure your project's `module` supports ESM imports (e.g., `NodeNext`, `ESNext`, `Bundler`).
|
|
77
77
|
|
|
78
|
-
## 2. Define
|
|
78
|
+
## 2. Define your Entities
|
|
79
79
|
|
|
80
80
|
Annotate your classes with decorators. UQL's engine uses this metadata for both type-safe querying and precise DDL generation.
|
|
81
81
|
|
|
82
82
|
### Core Decorators
|
|
83
83
|
|
|
84
|
-
| Decorator
|
|
85
|
-
|
|
|
86
|
-
| `@Entity()`
|
|
87
|
-
| `@Id()`
|
|
88
|
-
| `@Field()`
|
|
89
|
-
| `@Index()`
|
|
90
|
-
| `@OneToOne`
|
|
91
|
-
| `@OneToMany`
|
|
92
|
-
| `@ManyToOne`
|
|
93
|
-
| `@ManyToMany` | Defines a many-to-many relationship.
|
|
94
|
-
| `@BeforeInsert`
|
|
95
|
-
| `@
|
|
96
|
-
| `@BeforeDelete` / `@AfterDelete` | Lifecycle hooks fired around `delete` operations. |
|
|
97
|
-
| `@AfterLoad` | Lifecycle hook fired after loading entities from the database. |
|
|
84
|
+
| Decorator | Purpose |
|
|
85
|
+
| :--- | :--- |
|
|
86
|
+
| `@Entity()` | Marks a class as a database table/collection. |
|
|
87
|
+
| `@Id()` | Defines the Primary Key with support for `onInsert` generators. |
|
|
88
|
+
| `@Field()` | Standard column. Use `{ references: ... }` for Foreign Keys. |
|
|
89
|
+
| `@Index()` | Defines a composite or custom index on one or more columns. |
|
|
90
|
+
| `@OneToOne` | Defines a one-to-one relationship. |
|
|
91
|
+
| `@OneToMany` | Defines a one-to-many relationship. |
|
|
92
|
+
| `@ManyToOne` | Defines a many-to-one relationship. |
|
|
93
|
+
| `@ManyToMany` | Defines a many-to-many relationship. |
|
|
94
|
+
| `@BeforeInsert` | Lifecycle hooks fired around database operations. |
|
|
95
|
+
| `@AfterLoad` | Lifecycle hook fired after loading entities. |
|
|
98
96
|
|
|
99
97
|
### Type Abstraction: Logical vs. Physical
|
|
100
98
|
|
|
101
|
-
UQL separates the **intent** of your data from its **storage**. Both properties are **optional**; if omitted, UQL performs a *best-effort inference* using the TypeScript types from your class
|
|
99
|
+
UQL separates the **intent** of your data from its **storage**. Both properties are **optional**; if omitted, UQL performs a *best-effort inference* using the TypeScript types from your class.
|
|
102
100
|
|
|
103
101
|
| Property | Purpose | Values |
|
|
104
102
|
| :--- | :--- | :--- |
|
|
@@ -226,7 +224,7 @@ export class PostTag {
|
|
|
226
224
|
}
|
|
227
225
|
```
|
|
228
226
|
|
|
229
|
-
> **
|
|
227
|
+
> **Senior Insight**: Use the `Relation<T>` utility type for relationship properties. It prevents TypeScript circular dependency errors while maintaining full type-safety throughout your app.
|
|
230
228
|
|
|
231
229
|
|
|
232
230
|
|
|
@@ -255,7 +253,7 @@ export default {
|
|
|
255
253
|
} satisfies Config;
|
|
256
254
|
```
|
|
257
255
|
|
|
258
|
-
> **
|
|
256
|
+
> **Senior Insight**: Don't overcomplicate your setup. Reusing the same connection pool for both your application and migrations reduces overhead and ensures consistent behavior (like naming strategies) across your entire stack.
|
|
259
257
|
|
|
260
258
|
|
|
261
259
|
|
|
@@ -268,20 +266,19 @@ UQL provides a straightforward API to interact with your data. **Always ensure q
|
|
|
268
266
|
```ts
|
|
269
267
|
const querier = await pool.getQuerier();
|
|
270
268
|
try {
|
|
271
|
-
const
|
|
269
|
+
const results = await querier.findMany(User, {
|
|
272
270
|
$select: {
|
|
273
271
|
name: true,
|
|
274
272
|
profile: { $select: { bio: true }, $required: true } // INNER JOIN
|
|
275
273
|
},
|
|
276
274
|
$where: {
|
|
277
275
|
status: 'active',
|
|
278
|
-
name: { $istartsWith: 'a' }
|
|
276
|
+
name: { $istartsWith: 'a' }
|
|
279
277
|
},
|
|
280
278
|
$limit: 10,
|
|
281
|
-
$skip: 0
|
|
282
279
|
});
|
|
283
280
|
} finally {
|
|
284
|
-
await querier.release(); //
|
|
281
|
+
await querier.release(); // Always release back to the pool
|
|
285
282
|
}
|
|
286
283
|
```
|
|
287
284
|
|
|
@@ -347,7 +344,7 @@ const posts = await querier.findMany(Post, {
|
|
|
347
344
|
|
|
348
345
|
**PostgreSQL:** `WHERE EXISTS (SELECT 1 FROM "PostTag" WHERE "PostTag"."postId" = "Post"."id" AND "PostTag"."tagId" IN (SELECT "Tag"."id" FROM "Tag" WHERE "Tag"."name" = $1))`
|
|
349
346
|
|
|
350
|
-
> **
|
|
347
|
+
> **Senior Insight**: Wrap your JSON fields with `Json<T>` to get deep autocompletion for dot-notation paths. It turns a "guess and check" process into a type-safe workflow.
|
|
351
348
|
|
|
352
349
|
|
|
353
350
|
|
|
@@ -459,10 +456,10 @@ try {
|
|
|
459
456
|
|
|
460
457
|
## 5. Migrations & Synchronization
|
|
461
458
|
|
|
462
|
-
UQL takes an **Entity-First** approach
|
|
459
|
+
UQL takes an **Entity-First** approach. You modify your TypeScript classes, and UQL handles the heavy lifting—auto-generating migration files by diffing your code against the live database.
|
|
463
460
|
|
|
464
461
|
```bash
|
|
465
|
-
# 1. Update your entity (add a field, change a type,
|
|
462
|
+
# 1. Update your entity (add a field, change a type, etc.)
|
|
466
463
|
# 2. Auto-generate the migration
|
|
467
464
|
npx uql-migrate generate:entities add_user_nickname
|
|
468
465
|
|
|
@@ -470,7 +467,7 @@ npx uql-migrate generate:entities add_user_nickname
|
|
|
470
467
|
npx uql-migrate up
|
|
471
468
|
```
|
|
472
469
|
|
|
473
|
-
> **Your entities are the single source of truth
|
|
470
|
+
> **Senior Insight**: Your entities are the single source of truth. This workflow eliminates the "drift" between what's in your code and what's in production.
|
|
474
471
|
|
|
475
472
|
### 1. Unified Configuration
|
|
476
473
|
|
|
@@ -587,7 +584,7 @@ UQL features a professional-grade, structured logging system designed for high v
|
|
|
587
584
|
|
|
588
585
|
### Visual Feedback
|
|
589
586
|
|
|
590
|
-
The `DefaultLogger` provides high-contrast, colored output
|
|
587
|
+
The `DefaultLogger` provides high-contrast, colored output that makes debugging feel like a premium experience:
|
|
591
588
|
|
|
592
589
|
```text
|
|
593
590
|
query: SELECT * FROM "user" WHERE "id" = $1 -- [123] [2ms]
|
|
@@ -595,7 +592,7 @@ slow query: UPDATE "post" SET "title" = $1 -- ["New Title"] [1250ms]
|
|
|
595
592
|
error: Failed to connect to database: Connection timeout
|
|
596
593
|
```
|
|
597
594
|
|
|
598
|
-
> **
|
|
595
|
+
> **Senior Insight**: In production, keep your logs lean. By setting `logger: ['error', 'warn', 'slowQuery']`, UQL stays silent until a performance bottleneck actually occurs.
|
|
599
596
|
|
|
600
597
|
|
|
601
598
|
|
|
@@ -1,207 +1,181 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
1
|
+
import { _ as _apply_decs_2203_r } from './cc-BEf4wTUm.js';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { Id, Field, ManyToOne, Entity, OneToOne, OneToMany, ManyToMany } from '../entity/index.js';
|
|
4
|
+
import '../type/index.js';
|
|
5
|
+
import { raw, lowerFirst, upperFirst, getKeys } from '../util/index.js';
|
|
6
|
+
import 'reflect-metadata';
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
case '$size':
|
|
52
|
-
// SQLite: Check JSON array length
|
|
53
|
-
// e.g., json_array_length(roles) = 3, or json_array_length(roles) >= 2
|
|
54
|
-
this.buildSizeComparison(ctx, ()=>{
|
|
55
|
-
ctx.append('json_array_length(');
|
|
56
|
-
this.getComparisonKey(ctx, entity, key, opts);
|
|
57
|
-
ctx.append(')');
|
|
58
|
-
}, val);
|
|
59
|
-
break;
|
|
60
|
-
default:
|
|
61
|
-
super.compareFieldOperator(ctx, entity, key, op, val, opts);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Build $elemMatch condition for SQLite JSON arrays.
|
|
66
|
-
* Uses EXISTS with json_each and supports nested operators.
|
|
67
|
-
*/ buildElemMatchCondition(ctx, _entity, key, match, opts) {
|
|
68
|
-
ctx.append('EXISTS (SELECT 1 FROM json_each(');
|
|
69
|
-
this.getComparisonKey(ctx, _entity, key, opts);
|
|
70
|
-
ctx.append(') WHERE ');
|
|
71
|
-
const conditions = [];
|
|
72
|
-
for (const [field, value] of Object.entries(match)){
|
|
73
|
-
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
74
|
-
// Value is an operator object
|
|
75
|
-
const ops = value;
|
|
76
|
-
for (const [op, opVal] of Object.entries(ops)){
|
|
77
|
-
conditions.push(this.buildJsonFieldOperator(ctx, field, op, opVal));
|
|
78
|
-
}
|
|
79
|
-
} else {
|
|
80
|
-
// Simple equality
|
|
81
|
-
ctx.pushValue(value);
|
|
82
|
-
conditions.push(`json_extract(value, '$.${field}') = ?`);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
ctx.append(conditions.join(' AND '));
|
|
86
|
-
ctx.append(')');
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Build a comparison condition for a JSON field with an operator.
|
|
90
|
-
*/ buildJsonFieldOperator(ctx, field, op, value) {
|
|
91
|
-
return this.buildJsonFieldCondition(ctx, {
|
|
92
|
-
...this.getBaseJsonConfig(),
|
|
93
|
-
fieldAccessor: (f)=>`json_extract(value, '$.${f}')`
|
|
94
|
-
}, field, op, value);
|
|
95
|
-
}
|
|
96
|
-
getJsonFieldConfig(escapedColumn, jsonPath) {
|
|
97
|
-
return {
|
|
98
|
-
...this.getBaseJsonConfig(),
|
|
99
|
-
fieldAccessor: ()=>`json_extract(${escapedColumn}, '$.${jsonPath}')`
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
getBaseJsonConfig() {
|
|
103
|
-
return {
|
|
104
|
-
...super.getBaseJsonConfig(),
|
|
105
|
-
numericCast: (expr)=>`CAST(${expr} AS REAL)`,
|
|
106
|
-
neExpr: (f, ph)=>`${f} IS NOT ${ph}`
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
upsert(ctx, entity, conflictPaths, payload) {
|
|
110
|
-
this.onConflictUpsert(ctx, entity, conflictPaths, payload, this.insert.bind(this));
|
|
111
|
-
}
|
|
112
|
-
formatJsonMerge(ctx, escapedCol, value) {
|
|
113
|
-
let expr = escapedCol;
|
|
114
|
-
if (hasKeys(value.$merge)) {
|
|
115
|
-
ctx.pushValue(JSON.stringify(value.$merge));
|
|
116
|
-
expr = `json_patch(COALESCE(${escapedCol}, '{}'), ?)`;
|
|
117
|
-
}
|
|
118
|
-
if (value.$unset?.length) {
|
|
119
|
-
const paths = value.$unset.map((k)=>`'$.${this.escapeJsonKey(k)}'`).join(', ');
|
|
120
|
-
expr = `json_remove(${expr}, ${paths})`;
|
|
121
|
-
}
|
|
122
|
-
ctx.append(`${escapedCol} = ${expr}`);
|
|
123
|
-
}
|
|
8
|
+
var _dec, _dec1, _dec2, _dec3, _dec4, _dec5, _dec6, /**
|
|
9
|
+
* auto-generated primary-key (when the `onInsert` property is omitted).
|
|
10
|
+
*/ _init_id, /**
|
|
11
|
+
* foreign-keys are really simple to specify with the `reference` property.
|
|
12
|
+
*/ _init_companyId, /**
|
|
13
|
+
* The `Relation` wrapper type can be used in ESM projects for the relations to
|
|
14
|
+
* avoid circular dependency issues.
|
|
15
|
+
*/ _init_company, _init_creatorId, _init_creator, /**
|
|
16
|
+
* 'onInsert' property can be used to specify a custom mechanism for
|
|
17
|
+
* obtaining the value of a field when inserting:
|
|
18
|
+
*/ _init_createdAt, /**
|
|
19
|
+
* 'onUpdate' property can be used to specify a custom mechanism for
|
|
20
|
+
* obtaining the value of a field when updating:
|
|
21
|
+
*/ _init_updatedAt, _initProto, _dec7, _initClass, _BaseEntity, _dec8, _dec9, _dec10, _init_name, _init_description, _init_kind, _initProto1, _dec11, _initClass1, _BaseEntity1, _dec12, _dec13, /**
|
|
22
|
+
* an entity can specify its own ID Field and still inherit the others
|
|
23
|
+
* columns/relations from its parent entity.
|
|
24
|
+
*/ _init_pk, _init_picture, _initProto2, _dec14, _initClass2, _BaseEntity2, _dec15, _dec16, _dec17, _dec18, _dec19, _init_name1, _init_email, _init_password, /**
|
|
25
|
+
* `mappedBy` property can be a callback or a string (callback is useful for auto-refactoring).
|
|
26
|
+
*/ _init_profile, _init_users, _initProto3, _dec20, _initClass3, _dec21, _dec22, _init_id1, _init_name2, _initProto4, _dec23, _initClass4, _BaseEntity3, _dec24, _dec25, _dec26, _dec27, _init_name3, _init_description1, _init_parentLedgerId, _init_parentLedger, _initProto5, _dec28, _initClass5, _BaseEntity4, _dec29, _dec30, _dec31, /**
|
|
27
|
+
* an entity can override the ID Field and still inherit the others
|
|
28
|
+
* columns/relations from its parent entity.
|
|
29
|
+
* 'onInsert' property can be used to specify a custom mechanism for
|
|
30
|
+
* auto-generating the primary-key's value when inserting.
|
|
31
|
+
*/ _init_pk1, _init_name4, _init_description2, _initProto6, _dec32, _initClass6, _BaseEntity5, _dec33, _dec34, _dec35, _dec36, _dec37, _init_name5, _init_percentage, _init_categoryId, _init_category, _init_description3, _initProto7, _dec38, _initClass7, _BaseEntity6, _dec39, _dec40, _dec41, _init_name6, _init_measureUnits, /**
|
|
32
|
+
* `onDelete` callback allows to specify which field will be used when deleting/querying this entity.
|
|
33
|
+
*/ _init_deletedAt, _initProto8, _dec42, _initClass8, _BaseEntity7, _dec43, _dec44, _dec45, _dec46, _init_name7, _init_categoryId1, _init_category1, _init_deletedAt1, _initProto9, _dec47, _initClass9, _BaseEntity8, _dec48, _dec49, _dec50, _init_name8, _init_address, _init_description4, _initProto10, _dec51, _initClass10, _BaseEntity9, _dec52, _dec53, _dec54, _dec55, _dec56, _dec57, _dec58, _dec59, _dec60, _dec61, _dec62, _dec63, _dec64, _dec65, _dec66, _init_name9, _init_description5, _init_code, _init_buyLedgerAccountId, _init_buyLedgerAccount, _init_saleLedgerAccountId, _init_saleLedgerAccount, _init_taxId, _init_tax, _init_measureUnitId, _init_measureUnit, _init_salePrice, _init_inventoryable, _init_tags, _init_tagsCount, _initProto11, _dec67, _initClass11, _BaseEntity10, _dec68, _dec69, _dec70, _init_name10, _init_items, _init_itemsCount, _initProto12, _dec71, _initClass12, _dec72, _dec73, _dec74, _init_id2, _init_itemId, _init_tagId, _initProto13, _dec75, _initClass13, _BaseEntity11, _dec76, _dec77, _dec78, _init_itemAdjustments, _init_date, _init_description6, _initProto14, _dec79, _initClass14, _BaseEntity12, _dec80, _dec81, _dec82, _dec83, _dec84, _dec85, _dec86, _dec87, _init_itemId1, _init_item, _init_number, _init_buyPrice, _init_storehouseId, _init_storehouse, _init_inventoryAdjustmentId, _init_inventoryAdjustment, _initProto15, _dec88, _initClass15, _dec89, _dec90, _dec91, _init_id3, _init_name11, _init_vec, _initProto16;
|
|
34
|
+
_dec = Id(), _dec1 = Field({
|
|
35
|
+
references: ()=>_Company
|
|
36
|
+
}), _dec2 = ManyToOne({
|
|
37
|
+
entity: ()=>_Company
|
|
38
|
+
}), _dec3 = Field({
|
|
39
|
+
references: ()=>_User
|
|
40
|
+
}), _dec4 = ManyToOne({
|
|
41
|
+
entity: ()=>_User
|
|
42
|
+
}), _dec5 = Field({
|
|
43
|
+
onInsert: Date.now
|
|
44
|
+
}), _dec6 = Field({
|
|
45
|
+
onUpdate: Date.now
|
|
46
|
+
});
|
|
47
|
+
/**
|
|
48
|
+
* an `abstract` class can (optionally) be used as the base "template" for the entities
|
|
49
|
+
* (so common fields' declaration is easily reused).
|
|
50
|
+
*/ class BaseEntity {
|
|
124
51
|
static{
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
52
|
+
({ e: [_init_id, _init_companyId, _init_company, _init_creatorId, _init_creator, _init_createdAt, _init_updatedAt, _initProto] } = _apply_decs_2203_r(this, [
|
|
53
|
+
[
|
|
54
|
+
_dec,
|
|
55
|
+
0,
|
|
56
|
+
"id"
|
|
57
|
+
],
|
|
58
|
+
[
|
|
59
|
+
_dec1,
|
|
60
|
+
0,
|
|
61
|
+
"companyId"
|
|
62
|
+
],
|
|
63
|
+
[
|
|
64
|
+
_dec2,
|
|
65
|
+
0,
|
|
66
|
+
"company"
|
|
67
|
+
],
|
|
68
|
+
[
|
|
69
|
+
_dec3,
|
|
70
|
+
0,
|
|
71
|
+
"creatorId"
|
|
72
|
+
],
|
|
73
|
+
[
|
|
74
|
+
_dec4,
|
|
75
|
+
0,
|
|
76
|
+
"creator"
|
|
77
|
+
],
|
|
78
|
+
[
|
|
79
|
+
_dec5,
|
|
80
|
+
0,
|
|
81
|
+
"createdAt"
|
|
82
|
+
],
|
|
83
|
+
[
|
|
84
|
+
_dec6,
|
|
85
|
+
0,
|
|
86
|
+
"updatedAt"
|
|
87
|
+
]
|
|
88
|
+
], []));
|
|
130
89
|
}
|
|
131
|
-
|
|
132
|
-
this.
|
|
90
|
+
constructor(){
|
|
91
|
+
this.id = (_initProto(this), _init_id(this));
|
|
92
|
+
this.companyId = _init_companyId(this);
|
|
93
|
+
this.company = _init_company(this);
|
|
94
|
+
this.creatorId = _init_creatorId(this);
|
|
95
|
+
this.creator = _init_creator(this);
|
|
96
|
+
this.createdAt = _init_createdAt(this);
|
|
97
|
+
this.updatedAt = _init_updatedAt(this);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
let _Company;
|
|
101
|
+
_dec7 = Entity(), _dec8 = Field(), _dec9 = Field(), _dec10 = Field({
|
|
102
|
+
type: 'jsonb'
|
|
103
|
+
});
|
|
104
|
+
class Company extends (_BaseEntity = BaseEntity) {
|
|
105
|
+
static{
|
|
106
|
+
({ e: [_init_name, _init_description, _init_kind, _initProto1], c: [_Company, _initClass] } = _apply_decs_2203_r(this, [
|
|
107
|
+
[
|
|
108
|
+
_dec8,
|
|
109
|
+
0,
|
|
110
|
+
"name"
|
|
111
|
+
],
|
|
112
|
+
[
|
|
113
|
+
_dec9,
|
|
114
|
+
0,
|
|
115
|
+
"description"
|
|
116
|
+
],
|
|
117
|
+
[
|
|
118
|
+
_dec10,
|
|
119
|
+
0,
|
|
120
|
+
"kind"
|
|
121
|
+
]
|
|
122
|
+
], [
|
|
123
|
+
_dec7
|
|
124
|
+
], _BaseEntity));
|
|
133
125
|
}
|
|
134
|
-
|
|
135
|
-
|
|
126
|
+
static{
|
|
127
|
+
_initClass();
|
|
136
128
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
class AbstractSqliteQuerier extends AbstractSqlQuerier {
|
|
140
|
-
buildUpdateResult(changes, lastInsertRowid) {
|
|
141
|
-
const firstId = lastInsertRowid ? Number(lastInsertRowid) - (changes - 1) : undefined;
|
|
142
|
-
const ids = firstId ? Array(changes).fill(firstId).map((i, index)=>i + index) : [];
|
|
143
|
-
return {
|
|
144
|
-
changes,
|
|
145
|
-
ids,
|
|
146
|
-
firstId
|
|
147
|
-
};
|
|
129
|
+
constructor(...args){
|
|
130
|
+
super(...args), this.name = (_initProto1(this), _init_name(this)), this.description = _init_description(this), this.kind = _init_kind(this);
|
|
148
131
|
}
|
|
149
132
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
133
|
+
let _Profile;
|
|
134
|
+
_dec11 = Entity({
|
|
135
|
+
name: 'user_profile'
|
|
136
|
+
}), _dec12 = Id(), _dec13 = Field({
|
|
137
|
+
name: 'image'
|
|
138
|
+
});
|
|
139
|
+
class Profile extends (_BaseEntity1 = BaseEntity) {
|
|
140
|
+
static{
|
|
141
|
+
({ e: [_init_pk, _init_picture, _initProto2], c: [_Profile, _initClass1] } = _apply_decs_2203_r(this, [
|
|
142
|
+
[
|
|
143
|
+
_dec12,
|
|
144
|
+
0,
|
|
145
|
+
"pk"
|
|
146
|
+
],
|
|
147
|
+
[
|
|
148
|
+
_dec13,
|
|
149
|
+
0,
|
|
150
|
+
"picture"
|
|
151
|
+
]
|
|
152
|
+
], [
|
|
153
|
+
_dec11
|
|
154
|
+
], _BaseEntity1));
|
|
172
155
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
class Sqlite3QuerierPool extends AbstractQuerierPool {
|
|
176
|
-
constructor(filename, opts, extra){
|
|
177
|
-
super('sqlite', extra), this.filename = filename, this.opts = opts;
|
|
178
|
-
}
|
|
179
|
-
async getQuerier() {
|
|
180
|
-
if (!this.querier) {
|
|
181
|
-
let db;
|
|
182
|
-
if (typeof Bun !== 'undefined') {
|
|
183
|
-
const { Database: BunDatabase } = await import('bun:sqlite');
|
|
184
|
-
const bunDb = new BunDatabase(this.filename, this.opts);
|
|
185
|
-
bunDb.run('PRAGMA journal_mode = WAL');
|
|
186
|
-
db = bunDb;
|
|
187
|
-
} else {
|
|
188
|
-
const { default: BetterSqlite3 } = await import('better-sqlite3');
|
|
189
|
-
db = new BetterSqlite3(this.filename, this.opts);
|
|
190
|
-
db.pragma('journal_mode = WAL');
|
|
191
|
-
}
|
|
192
|
-
this.querier = new SqliteQuerier(db, this.extra);
|
|
193
|
-
}
|
|
194
|
-
return this.querier;
|
|
156
|
+
static{
|
|
157
|
+
_initClass1();
|
|
195
158
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
this.querier = undefined;
|
|
159
|
+
constructor(...args){
|
|
160
|
+
super(...args), this.pk = (_initProto2(this), _init_pk(this)), this.picture = _init_picture(this);
|
|
199
161
|
}
|
|
200
162
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
163
|
+
let _User;
|
|
164
|
+
_dec14 = Entity(), _dec15 = Field(), _dec16 = Field({
|
|
165
|
+
updatable: false
|
|
166
|
+
}), _dec17 = Field({
|
|
167
|
+
eager: false
|
|
168
|
+
}), _dec18 = OneToOne({
|
|
169
|
+
entity: ()=>_Profile,
|
|
170
|
+
mappedBy: (profile)=>profile.creator,
|
|
171
|
+
cascade: true
|
|
172
|
+
}), _dec19 = OneToMany({
|
|
173
|
+
entity: ()=>_User,
|
|
174
|
+
mappedBy: 'creator'
|
|
175
|
+
});
|
|
176
|
+
class User extends (_BaseEntity2 = BaseEntity) {
|
|
177
|
+
static{
|
|
178
|
+
({ e: [_init_name1, _init_email, _init_password, _init_profile, _init_users, _initProto3], c: [_User, _initClass2] } = _apply_decs_2203_r(this, [
|
|
205
179
|
[
|
|
206
180
|
_dec15,
|
|
207
181
|
0,
|