uql-orm 0.61.0 → 0.62.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.
Files changed (43) hide show
  1. package/dist/browser/uql-browser.min.js.map +1 -1
  2. package/dist/dialect/abstractSqlDialect.d.ts +12 -7
  3. package/dist/dialect/abstractSqlDialect.js +51 -50
  4. package/dist/dialect/mysqlLikeSqlDialect.js +1 -1
  5. package/dist/dialect/pgLikeSqlDialect.d.ts +1 -0
  6. package/dist/dialect/pgLikeSqlDialect.js +8 -7
  7. package/dist/dialect/queryContext.d.ts +5 -6
  8. package/dist/dialect/queryContext.js +8 -8
  9. package/dist/entity/decorator/entity.d.ts +3 -3
  10. package/dist/entity/decorator/entity.js +2 -2
  11. package/dist/entity/decorator/members.d.ts +3 -2
  12. package/dist/entity/decorator/members.js +1 -0
  13. package/dist/entity/metadata/definition.js +12 -6
  14. package/dist/migrate/builder/migrationBuilder.js +3 -5
  15. package/dist/migrate/builder/tableBuilder.js +2 -4
  16. package/dist/migrate/builder/types.d.ts +11 -3
  17. package/dist/migrate/codegen/indexDecoratorSource.js +3 -1
  18. package/dist/migrate/generator/definitionToNode.d.ts +8 -5
  19. package/dist/migrate/generator/definitionToNode.js +13 -4
  20. package/dist/migrate/generator/mongoSchemaGenerator.d.ts +2 -0
  21. package/dist/migrate/generator/mongoSchemaGenerator.js +6 -1
  22. package/dist/migrate/schemaGenerator.d.ts +5 -3
  23. package/dist/migrate/schemaGenerator.js +9 -2
  24. package/dist/mongo/mongoDialect.js +1 -1
  25. package/dist/mssql/mssqlDialect.js +3 -5
  26. package/dist/schema/schemaASTBuilder.d.ts +6 -1
  27. package/dist/schema/schemaASTBuilder.js +17 -16
  28. package/dist/type/dialect.d.ts +15 -6
  29. package/dist/type/entity.d.ts +94 -34
  30. package/dist/type/migration.d.ts +9 -2
  31. package/dist/type/query.d.ts +3 -3
  32. package/dist/type/queryLock.d.ts +7 -7
  33. package/dist/type/queryLock.js +8 -6
  34. package/dist/type/queryRaw.d.ts +22 -30
  35. package/dist/type/queryRaw.js +3 -9
  36. package/dist/util/ddlExpression.util.d.ts +8 -13
  37. package/dist/util/ddlExpression.util.js +17 -19
  38. package/dist/util/dialect.util.d.ts +1 -1
  39. package/dist/util/dialect.util.js +3 -4
  40. package/dist/util/field.util.d.ts +1 -1
  41. package/dist/util/raw.d.ts +19 -17
  42. package/dist/util/raw.js +43 -17
  43. package/package.json +1 -1
@@ -1,36 +1,38 @@
1
- import { QueryRaw, type QueryRawFn } from '../type/index.js';
1
+ import { type EntitySql, type EntityWhere, type EntityWhereMeta, QueryRaw, type QueryRawFn, type RefMap, type Type } from '../type/index.js';
2
2
  /**
3
3
  * Create a raw SQL expression.
4
4
  *
5
5
  * As a tagged template the literal text is emitted as written and every interpolation is resolved by
6
6
  * what it is, so a value cannot become SQL whatever it holds:
7
7
  *
8
- * | Interpolated | Becomes |
9
- * | :----------------- | :---------------------- |
10
- * | any value | a bound parameter |
11
- * | a {@link QueryRaw} | that fragment, in place |
8
+ * | Interpolated | Becomes |
9
+ * | :------------------ | :------------------------------------- |
10
+ * | any value | a bound parameter; in DDL, its literal |
11
+ * | a {@link ColumnRef} | its column, escaped and qualified |
12
+ * | a {@link QueryRaw} | that fragment, in place |
12
13
  *
13
14
  * ```ts
14
- * raw`GREATEST(0, "creditsAllowance" - ${amount})`
15
- * raw`CONCAT(${col('firstName')}, ' ', ${col('lastName')})`
15
+ * const user = refs(User);
16
+ * raw`GREATEST(0, ${user.creditsAllowance} - ${amount})`
17
+ * raw`CONCAT(${user.firstName}, ' ', ${user.lastName})`
16
18
  * raw`LOG10(${points})`.as('score')
17
19
  * ```
18
20
  *
19
21
  * The callback form remains for SQL a template cannot express, such as a sub-query generated through
20
- * `dialect.find(...)`. See {@link col} for a context-aware column reference.
22
+ * `dialect.find(...)`.
21
23
  *
22
24
  * **⚠️ Security:** the tag is safe because it binds; a callback is not, since it emits whatever it
23
25
  * writes, so never build one from user input. Inside a callback, bind with `ctx.addValue()`.
24
26
  */
25
27
  export declare function raw(strings: TemplateStringsArray, ...values: readonly unknown[]): QueryRaw;
26
- export declare function raw(value: QueryRawFn, alias?: string): QueryRaw;
28
+ export declare function raw(value: QueryRawFn): QueryRaw;
27
29
  /**
28
- * A column of the entity being queried, alias-qualified and escaped for the dialect. This is what a
29
- * template cannot know on its own: the alias is decided while the statement is built, not where the
30
- * expression is written.
31
- *
32
- * Takes the column name as it exists in the database, not the entity's field name: no entity metadata
33
- * is in scope here, so a naming strategy is not applied for you. `escapedPrefix` already carries its
34
- * trailing dot, which is the detail this exists to stop you getting wrong.
30
+ * The fields of `entity` as {@link ColumnRef}s, each rendering inside `raw` as its column: named the way
31
+ * the dialect names it, so the naming strategy and `@Field({ name })` apply, and qualified by the alias
32
+ * in scope. Metadata is read when a ref renders, so the map serves before the fields are registered.
35
33
  */
36
- export declare function col(column: string): QueryRaw;
34
+ export declare function refs<E>(entity: Type<E>): RefMap<E>;
35
+ /** SQL a definition writes, a callback's refs read off {@link MEMBER_REFS}. */
36
+ export declare function entitySql<E>(sql: EntitySql<E>): QueryRaw;
37
+ /** A definition's predicate, its callback resolved the way {@link entitySql} resolves one. */
38
+ export declare function entityWhere<E>(where: EntityWhere<E>): EntityWhereMeta<E>;
package/dist/util/raw.js CHANGED
@@ -1,13 +1,9 @@
1
- import { QueryRaw } from '../type/index.js';
1
+ import { getMeta } from '../entity/metadata/definition.js';
2
+ import { QueryRaw, } from '../type/index.js';
3
+ import { isInlinedExpression } from './field.util.js';
2
4
  export function raw(value, ...rest) {
3
- const [alias] = rest;
4
5
  if (!isTemplateStrings(value)) {
5
- return new QueryRaw(value, typeof alias === 'string' ? alias : undefined);
6
- }
7
- if (!rest.length) {
8
- // Nothing to bind, so this is the string form: keep it one, for the DDL paths that need to read
9
- // the expression back as text (an index expression cannot carry a parameter).
10
- return new QueryRaw(value[0]);
6
+ return new QueryRaw(value);
11
7
  }
12
8
  return new QueryRaw((opts) => {
13
9
  const { ctx } = opts;
@@ -24,16 +20,46 @@ export function raw(value, ...rest) {
24
20
  });
25
21
  }
26
22
  /**
27
- * A column of the entity being queried, alias-qualified and escaped for the dialect. This is what a
28
- * template cannot know on its own: the alias is decided while the statement is built, not where the
29
- * expression is written.
30
- *
31
- * Takes the column name as it exists in the database, not the entity's field name: no entity metadata
32
- * is in scope here, so a naming strategy is not applied for you. `escapedPrefix` already carries its
33
- * trailing dot, which is the detail this exists to stop you getting wrong.
23
+ * The fields of `entity` as {@link ColumnRef}s, each rendering inside `raw` as its column: named the way
24
+ * the dialect names it, so the naming strategy and `@Field({ name })` apply, and qualified by the alias
25
+ * in scope. Metadata is read when a ref renders, so the map serves before the fields are registered.
34
26
  */
35
- export function col(column) {
36
- return new QueryRaw(({ escapedPrefix, dialect }) => escapedPrefix + dialect.escapeId(column, true));
27
+ export function refs(entity) {
28
+ return new Proxy({}, { get: (_, key) => columnRef(entity, String(key)) });
29
+ }
30
+ /**
31
+ * The refs a definition's callback reads. A member decorator sees no class, so these name no entity and
32
+ * resolve against the one rendering them: a computed field's own, or the one whose schema is built.
33
+ */
34
+ const MEMBER_REFS = new Proxy({}, { get: (_, key) => columnRef(undefined, String(key)) });
35
+ /** SQL a definition writes, a callback's refs read off {@link MEMBER_REFS}. */
36
+ export function entitySql(sql) {
37
+ return sql instanceof QueryRaw ? sql : sql(MEMBER_REFS);
38
+ }
39
+ /** A definition's predicate, its callback resolved the way {@link entitySql} resolves one. */
40
+ export function entityWhere(where) {
41
+ return typeof where === 'function' ? where(MEMBER_REFS) : where;
42
+ }
43
+ /** One field as SQL, against its own entity or, read off a definition, the entity rendering it. */
44
+ function columnRef(entity, key) {
45
+ return new QueryRaw((opts) => {
46
+ const owner = entity ?? opts.entity;
47
+ if (!owner) {
48
+ throw new TypeError(`'${key}' was read off a definition's refs, so it renders only inside its entity's SQL`);
49
+ }
50
+ renderColumn(getMeta(owner), key, { ...opts, entity: owner });
51
+ });
52
+ }
53
+ /** A field's column, or the expression an inlined computed one stands for, as a `$where` on it reads it. */
54
+ function renderColumn(meta, key, opts) {
55
+ const field = meta.fields[key];
56
+ if (field && isInlinedExpression(field)) {
57
+ opts.ctx.append('(');
58
+ field.computed.render(opts);
59
+ opts.ctx.append(')');
60
+ return;
61
+ }
62
+ opts.ctx.append(opts.escapedPrefix + opts.dialect.escapeId(opts.dialect.columnOf(meta, key), true));
37
63
  }
38
64
  /** A tag call passes the frozen strings array, which carries its own `raw` counterpart. */
39
65
  function isTemplateStrings(value) {
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "homepage": "https://uql-orm.dev",
4
4
  "description": "The JSON-native TypeScript ORM for Bun, Browsers, Edge, Deno, Node, Workers. Supports PostgreSQL, PGlite, MySQL, MariaDB, SQLite, CockroachDB, SQL Server, Turso, Neon, Cloudflare D1 and MongoDB. Queries are plain JSON, typed to the leaf.",
5
5
  "license": "MIT",
6
- "version": "0.61.0",
6
+ "version": "0.62.0",
7
7
  "type": "module",
8
8
  "engines": {
9
9
  "node": ">=24"