uql-orm 0.26.0 → 0.26.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/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
<h3>The smartest TypeScript ORM</h3>
|
|
11
11
|
|
|
12
|
-
<p>
|
|
12
|
+
<p>Serializable queries, type-safe to the leaf, no codegen, and one API across every SQL database, MongoDB, and every runtime. And the <a href="https://uql-orm.dev/benchmark">fastest</a>.</p>
|
|
13
13
|
|
|
14
14
|
<p>
|
|
15
15
|
<a href="https://uql-orm.dev"><b>Website</b></a> ·
|
|
@@ -50,8 +50,8 @@ from the browser to the server. The same object runs on every supported database
|
|
|
50
50
|
|
|
51
51
|
## Why UQL?
|
|
52
52
|
|
|
53
|
+
- **Serializable queries (JSON), not method chains.** Plain JSON in, typed rows out. No DSL to learn.
|
|
53
54
|
- **Type-safe to the leaf, nothing to generate.** Every key is checked against your entity, down into populated relations and [JSON/JSONB](https://uql-orm.dev/querying/json) dot-paths, so `$like` on a numeric column is a compile error. Entities are plain classes: no `.prisma` file, no generated client, no build step.
|
|
54
|
-
- **Queries are data (JSON), not method chains.** Plain JSON in, typed rows out. No DSL to learn.
|
|
55
55
|
- **One API, everywhere it runs.** PostgreSQL, CockroachDB, MySQL, MariaDB, SQLite, Turso, libSQL, Neon, Cloudflare D1, Bun's native SQL, and even MongoDB. The same code on Node 24+, Bun, Deno, [Cloudflare Workers](https://uql-orm.dev/cloudflare-d1), [AWS Lambda and Vercel](https://uql-orm.dev/serverless), and [the browser](https://uql-orm.dev/browser), with no native binaries on the `fetch`-based drivers.
|
|
56
56
|
- **Relations without N+1.** [`$populate`](https://uql-orm.dev/querying/relations) loads a to-many with one query for all parents, not one per parent. Nothing is lazy, so nothing fires behind your back in a serializer.
|
|
57
57
|
- **Migrations you read before they run.** Edit an entity, run `uql-migrate generate:entities`, review the SQL in the PR like any other file. [`drift:check`](https://uql-orm.dev/migrations) catches a database that no longer matches.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { decodeColumn } from '../dialect/hydrateColumn.js';
|
|
2
2
|
import { getMeta } from '../entity/index.js';
|
|
3
|
-
import { buildUpdateResult, clone, getInsertFieldKeys, getRelationRequestSummary, isAutoIncrement, obtainAttrsPaths, throwNoPendingTransaction, throwPendingTransaction, unflatObject, unflatObjects, withoutSoftDeleteFilter, } from '../util/index.js';
|
|
3
|
+
import { buildUpdateResult, cascadesOnDelete, clone, getInsertFieldKeys, getRelationRequestSummary, isAutoIncrement, obtainAttrsPaths, throwNoPendingTransaction, throwPendingTransaction, unflatObject, unflatObjects, withoutSoftDeleteFilter, } from '../util/index.js';
|
|
4
4
|
import { AbstractQuerier } from './abstractQuerier.js';
|
|
5
5
|
import { enrichError } from './queryError.js';
|
|
6
6
|
export class AbstractSqlQuerier extends AbstractQuerier {
|
|
@@ -222,6 +222,17 @@ export class AbstractSqlQuerier extends AbstractQuerier {
|
|
|
222
222
|
}
|
|
223
223
|
async internalDeleteMany(entity, q, opts) {
|
|
224
224
|
const meta = getMeta(entity);
|
|
225
|
+
// Resolving the ids first is what makes the two hard cases work at all: a cascade needs its
|
|
226
|
+
// parents' ids to find their children, and no engine but MySQL accepts `ORDER BY`/`LIMIT` on a
|
|
227
|
+
// DELETE, so a paged delete has to name the rows it settled on. A plain predicate needs neither,
|
|
228
|
+
// and there the round trip buys nothing: the statement can say what the caller already said.
|
|
229
|
+
const hasPagination = q.$sort !== undefined || q.$limit !== undefined || q.$skip !== undefined;
|
|
230
|
+
if (!hasPagination && !cascadesOnDelete(meta)) {
|
|
231
|
+
const ctx = this.dialect.createContext();
|
|
232
|
+
this.dialect.delete(ctx, entity, q, opts);
|
|
233
|
+
const { changes = 0 } = await this.run(ctx.sql, ctx.values);
|
|
234
|
+
return changes;
|
|
235
|
+
}
|
|
225
236
|
// A hard delete also targets already-soft-deleted rows, so drop the soft-delete filter when finding ids.
|
|
226
237
|
const findOpts = opts?.hardDelete ? { ...opts, filters: withoutSoftDeleteFilter(opts.filters) } : opts;
|
|
227
238
|
const findCtx = this.dialect.createContext();
|
package/dist/type/entity.d.ts
CHANGED
|
@@ -314,7 +314,7 @@ export type OnFieldCallback<V = TsTypeOf<FieldType>> = V | QueryRaw | (() => V |
|
|
|
314
314
|
* `type` allowed. A decorator has it the other way round: `@Field({ type: String })` is checked before
|
|
315
315
|
* the class exists, so the only way to reach the property is to state what `type: String` implies and
|
|
316
316
|
* let the decorator's context position compare it against the real field. Neither can be derived from
|
|
317
|
-
* the other by inference, so `entityOptions.
|
|
317
|
+
* the other by inference, so `entityOptions.test-d.ts` asserts they agree instead.
|
|
318
318
|
*/
|
|
319
319
|
export type TsTypeOf<T> = T extends StringConstructor ? string : T extends NumberConstructor ? number : T extends BigIntConstructor ? bigint : T extends BooleanConstructor ? boolean : T extends DateConstructor ? Date : T extends StringColumnType ? string : T extends NumericColumnType ? number | bigint : T extends BooleanColumnType ? boolean : T extends DateColumnType ? Date : T extends JsonColumnType ? Json<unknown> | readonly Json<unknown>[] : T extends BlobColumnType ? Uint8Array : T extends VectorColumnType ? readonly number[] : unknown;
|
|
320
320
|
/**
|
|
@@ -35,6 +35,11 @@ export declare function fillOnFields<E>(meta: EntityMeta<E>, payload: E | E[], c
|
|
|
35
35
|
* or `meta.relations` itself to enumerate every cascadable relation).
|
|
36
36
|
*/
|
|
37
37
|
export declare function filterPersistableRelationKeys<E>(meta: EntityMeta<E>, payload: object, action: CascadeType): RelationKey<E>[];
|
|
38
|
+
/**
|
|
39
|
+
* Whether deleting this entity has to delete anything else, which is the reason a delete resolves the
|
|
40
|
+
* matching ids before issuing anything: a child is reached through the ids of its parent.
|
|
41
|
+
*/
|
|
42
|
+
export declare function cascadesOnDelete<E>(meta: EntityMeta<E>): boolean;
|
|
38
43
|
export declare function isCascadable(action: CascadeType, configuration?: boolean | CascadeType): boolean;
|
|
39
44
|
/**
|
|
40
45
|
* The map form of a `$select` value, or `undefined` for the raw-array form. Centralizes the one
|
|
@@ -83,6 +83,13 @@ export function filterPersistableRelationKeys(meta, payload, action) {
|
|
|
83
83
|
return relOpts && isCascadable(action, relOpts.cascade);
|
|
84
84
|
});
|
|
85
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Whether deleting this entity has to delete anything else, which is the reason a delete resolves the
|
|
88
|
+
* matching ids before issuing anything: a child is reached through the ids of its parent.
|
|
89
|
+
*/
|
|
90
|
+
export function cascadesOnDelete(meta) {
|
|
91
|
+
return filterPersistableRelationKeys(meta, meta.relations, 'delete').length > 0;
|
|
92
|
+
}
|
|
86
93
|
export function isCascadable(action, configuration) {
|
|
87
94
|
if (typeof configuration === 'boolean') {
|
|
88
95
|
return configuration;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"homepage": "https://uql-orm.dev",
|
|
4
4
|
"description": "Extremely fast, type-safe TypeScript ORM - one API for every database",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"version": "0.26.
|
|
6
|
+
"version": "0.26.2",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"engines": {
|
|
9
9
|
"node": ">=24"
|
|
@@ -127,9 +127,9 @@
|
|
|
127
127
|
"devDependencies": {
|
|
128
128
|
"@libsql/client": "^0.17.4",
|
|
129
129
|
"@neondatabase/serverless": "^1.1.0",
|
|
130
|
-
"@nestjs/common": "^11.1.
|
|
131
|
-
"@nestjs/core": "^11.1.
|
|
132
|
-
"@nestjs/testing": "^11.1.
|
|
130
|
+
"@nestjs/common": "^11.1.29",
|
|
131
|
+
"@nestjs/core": "^11.1.29",
|
|
132
|
+
"@nestjs/testing": "^11.1.29",
|
|
133
133
|
"@tursodatabase/database": "^0.7.2",
|
|
134
134
|
"@tursodatabase/serverless": "^1.4.0",
|
|
135
135
|
"@types/better-sqlite3": "^9.6.0",
|
|
@@ -140,7 +140,7 @@
|
|
|
140
140
|
"express": "^5.2.1",
|
|
141
141
|
"mariadb": "^3.5.3",
|
|
142
142
|
"mongodb": "^7.5.0",
|
|
143
|
-
"mysql2": "^3.23.
|
|
143
|
+
"mysql2": "^3.23.3",
|
|
144
144
|
"pg": "^8.23.0",
|
|
145
145
|
"pg-query-stream": "^4.17.0",
|
|
146
146
|
"rxjs": "^7.8.2",
|