uql-orm 0.31.1 → 0.31.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
@@ -70,7 +70,7 @@ Release notes live in [CHANGELOG.md](https://github.com/rogerpadilla/uql/blob/ma
70
70
 
71
71
  ## Made with UQL
72
72
 
73
- **[Variability.ai](https://variability.ai)** - AI meeting recorder and video summarizer for Zoom, Meet, and Teams. Instant summaries with action items in 35+ languages.
73
+ **[Variability.ai](https://variability.ai)** - AI meeting ntetaker and video summarizer for Zoom, Meet, Slack, and Teams. Instant summaries with action items in 35+ languages. Built by UQL's author.
74
74
 
75
75
  Built something? [Open a PR](https://github.com/rogerpadilla/uql/blob/main/CONTRIBUTING.md) and add it here.
76
76
 
@@ -13,17 +13,21 @@ export declare const idKey: unique symbol;
13
13
  export type Key<E> = keyof E & string;
14
14
  /**
15
15
  * Infers the field names of an entity.
16
- * Includes scalar fields, JSON fields, and scalar arrays (e.g. vector `number[]`).
16
+ * Includes scalar fields, JSON fields, scalar arrays (e.g. vector `number[]`) and arrays of JSON.
17
17
  * The `-?` modifier strips optionality so the indexed access yields clean key unions
18
18
  * (without it, optional properties leak `undefined` into the union).
19
19
  *
20
+ * `readonly Json[]` is its own arm because the brand sits on the element, so the `Json` arm cannot
21
+ * see it. What keeps a to-many relation out of that arm is the weak-type check: `Json<unknown>` is
22
+ * all-optional, which a class with named properties is not assignable to.
23
+ *
20
24
  * The check is bracketed so `any` resolves once rather than matching both this and
21
25
  * {@link RelationKey}: an unbracketed `any extends X` satisfies either branch. It reads
22
26
  * `readonly Scalar[]`, which every mutable one satisfies too, so declaring a vector or a scalar
23
27
  * array `readonly` does not push the field over into {@link RelationKey}.
24
28
  */
25
29
  export type FieldKey<E> = {
26
- readonly [K in keyof E]-?: [NonNullable<E[K]>] extends [Scalar | readonly Scalar[] | Json] ? K : never;
30
+ readonly [K in keyof E]-?: [NonNullable<E[K]>] extends [Scalar | readonly Scalar[] | Json | readonly Json[]] ? K : never;
27
31
  }[Key<E>];
28
32
  /**
29
33
  * Infers the relation names of an entity: whatever is left once its fields and its methods are
@@ -41,10 +45,21 @@ type IsJson<T> = '__json' extends keyof T ? true : false;
41
45
  /** The payload `P` of a branded `Json<P>`, or `never` for any non-JSON type. */
42
46
  type UnwrapJson<T> = IsJson<T> extends true ? (T extends Json<infer P> ? P : never) : never;
43
47
  /**
44
- * The `Json` payload of a field value `V`: both `Json<T>` and `Json<T>[]` yield `T` (via
45
- * `Unpacked`, a no-op for the non-array case); `never` when `V` is not a JSON field.
48
+ * The one branded value a field value `V` holds: `Json<T>` for both `Json<T>` and `Json<T>[]`, via
49
+ * `Unpacked`, a no-op for the non-array case.
50
+ */
51
+ type JsonElement<V> = NonNullable<Unpacked<NonNullable<V>>>;
52
+ /** The `Json` payload of a field value `V`; `never` when `V` is not a JSON field. */
53
+ type JsonPayload<V> = UnwrapJson<JsonElement<V>>;
54
+ /**
55
+ * The fields carrying the `Json` brand, `never` on an entity with none - which is most of them, and
56
+ * what makes {@link JsonFieldPaths} collapse to `never` without deriving a path for anything. Tests
57
+ * the brand rather than the payload, whose extra `Json<infer P>` inference is only worth doing once
58
+ * a field is known to be JSON.
46
59
  */
47
- type JsonPayload<V> = UnwrapJson<NonNullable<Unpacked<NonNullable<V>>>>;
60
+ type JsonFieldKey<E> = {
61
+ readonly [K in keyof E]-?: IsJson<JsonElement<E[K]>> extends true ? K : never;
62
+ }[Key<E>];
48
63
  /**
49
64
  * Recursively derives dot-notation key paths from a JSON payload type. Handles every shape at
50
65
  * entry: an untyped (`unknown`) payload accepts any suffix via a `string` pattern, scalars are
@@ -57,15 +72,15 @@ type DeepJsonKeys<T, D extends unknown[] = []> = unknown extends T ? string : No
57
72
  }[keyof NonNullable<T> & string];
58
73
  /**
59
74
  * Extracts dot-notation paths from `Json<T>` values, handling both scalar JSON
60
- * and arrays of JSON (e.g., `Json<{foo: string}>[]` in MongoDB).
75
+ * and arrays of JSON (`Json<{foo: string}>[]`, a column holding a list of documents).
61
76
  * For `kind?: Json<{ public: number; theme: { color: string } }>`,
62
77
  * produces `'kind.public' | 'kind.theme' | 'kind.theme.color'`.
63
78
  * For `items?: Json<{id: string}>[]`, produces `'items.id'`.
64
79
  * An untyped `Json<unknown>` field yields the scoped pattern `` `${K}.${string}` ``.
65
80
  */
66
81
  export type JsonFieldPaths<E> = {
67
- readonly [K in FieldKey<E>]: [JsonPayload<E[K]>] extends [never] ? never : `${K & string}.${Exclude<DeepJsonKeys<JsonPayload<E[K]>>, '__json'>}`;
68
- }[FieldKey<E>];
82
+ readonly [K in JsonFieldKey<E>]: `${K & string}.${DeepJsonKeys<JsonPayload<E[K]>>}`;
83
+ }[JsonFieldKey<E>];
69
84
  /**
70
85
  * The value type inside `T` at dot-path `P`; `unknown` when unresolvable (e.g. through a
71
86
  * `Record<string, unknown>` leaf). Arrays are stepped into via their element type.
@@ -73,9 +88,10 @@ export type JsonFieldPaths<E> = {
73
88
  type PathValue<T, P extends string> = unknown extends T ? unknown : NonNullable<T> extends readonly (infer U)[] ? PathValue<NonNullable<U>, P> : P extends `${infer K}.${infer Rest}` ? K extends keyof NonNullable<T> ? PathValue<NonNullable<T>[K], Rest> : unknown : P extends keyof NonNullable<T> ? NonNullable<T>[P] : unknown;
74
89
  /**
75
90
  * The value type at a JSON dot-path `P` of entity `E`; `unknown` when unresolvable, which keeps
76
- * untyped paths fully permissive in `$where`.
91
+ * untyped paths fully permissive in `$where`. Gated on {@link JsonFieldKey}, the same predicate
92
+ * {@link JsonFieldPaths} derives its keys from, so a path that is offered always resolves a value.
77
93
  */
78
- export type JsonFieldPathValue<E, P extends string> = P extends `${infer F}.${infer Rest}` ? F extends FieldKey<E> ? [JsonPayload<E[F]>] extends [never] ? unknown : PathValue<JsonPayload<E[F]>, Rest> : unknown : unknown;
94
+ export type JsonFieldPathValue<E, P extends string> = P extends `${infer F}.${infer Rest}` ? F extends JsonFieldKey<E> ? PathValue<JsonPayload<E[F]>, Rest> : unknown : unknown;
79
95
  /**
80
96
  * Extracts only the array-typed keys from `T`, mapping each to its element type via `Unpacked`.
81
97
  * Used by `$push` and `$pull` to provide type-safe element targets.
@@ -25,7 +25,8 @@ export type PrimaryKey = string | number | bigint;
25
25
  /**
26
26
  * Marker type for JSON/JSONB fields.
27
27
  * Wrapping a field's TypeScript type with `Json<T>` ensures it is classified as a `FieldKey`
28
- * (not a `RelationKey`), enabling type-safe usage in `$where`, `$select`, and `$sort`.
28
+ * (not a `RelationKey`), enabling type-safe usage in `$where`, `$select`, and `$sort`. A column
29
+ * holding a list of documents is `Json<T>[]`, also a field, whose dot-paths address the element.
29
30
  *
30
31
  * @example
31
32
  * ```ts
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "homepage": "https://uql-orm.dev",
4
4
  "description": "JSON-native TypeScript ORM for Node.js, Bun and Deno. Supports PostgreSQL, PGlite, MySQL, MariaDB, SQLite, CockroachDB, Turso, Neon, Cloudflare D1 and MongoDB. Queries are plain JSON, typed to the leaf.",
5
5
  "license": "MIT",
6
- "version": "0.31.1",
6
+ "version": "0.31.2",
7
7
  "type": "module",
8
8
  "engines": {
9
9
  "node": ">=24"
@@ -129,13 +129,13 @@
129
129
  }
130
130
  },
131
131
  "devDependencies": {
132
- "@electric-sql/pglite": "0.5.7",
133
- "@electric-sql/pglite-pgvector": "0.0.8",
132
+ "@electric-sql/pglite": "0.5.8",
133
+ "@electric-sql/pglite-pgvector": "0.0.9",
134
134
  "@libsql/client": "^0.17.4",
135
135
  "@neondatabase/serverless": "^1.1.0",
136
- "@nestjs/common": "^11.2.1",
137
- "@nestjs/core": "^11.2.1",
138
- "@nestjs/testing": "^11.2.1",
136
+ "@nestjs/common": "^12.0.1",
137
+ "@nestjs/core": "^12.0.1",
138
+ "@nestjs/testing": "^12.0.1",
139
139
  "@tursodatabase/database": "^0.7.2",
140
140
  "@tursodatabase/serverless": "^1.4.0",
141
141
  "@types/better-sqlite3": "^9.6.0",
@@ -145,8 +145,8 @@
145
145
  "better-sqlite3": "^13.0.3",
146
146
  "express": "^5.2.1",
147
147
  "mariadb": "^3.5.3",
148
- "mongodb": "^7.5.0",
149
- "mysql2": "^3.23.4",
148
+ "mongodb": "^7.6.0",
149
+ "mysql2": "^3.24.2",
150
150
  "pg": "^8.23.0",
151
151
  "pg-query-stream": "^4.17.0",
152
152
  "rxjs": "^7.8.2",