kern-orm 0.8.0 → 0.10.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.
@@ -1,3 +1,6 @@
1
+ import { SqlQuery } from "kern-db/builder";
2
+ import * as dbTypes from "kern-db/types";
3
+ import { defineType, isType } from "kern-db";
1
4
  // src/ast/nodes.ts
2
5
  /** Freezes an expression node; nodes are shared between queries and never change. */
3
6
  function createNode(node) {
@@ -189,57 +192,46 @@ function markKey(column, keyKind) {
189
192
  });
190
193
  }
191
194
  // src/type/type.ts
192
- /** Runtime mark of types, which tells them apart from columns and other objects. */
195
+ /** Runtime mark of types, which tells them apart from columns, types of kern-db without operators, and other objects. */
193
196
  const typeBrand = Symbol("kern-orm.type");
197
+ function defineType$1(definition) {
198
+ return createType(isType(definition) ? definition : defineType(definition), Object.freeze({}));
199
+ }
200
+ /** Tells whether `value` is a type, as opposed to a column, a type of kern-db without operators, or another object. */
201
+ function isType$1(value) {
202
+ return typeof value === "object" && value !== null && typeBrand in value;
203
+ }
194
204
  /**
195
- * Defines a type whose values are the PostgreSQL text representations as they are.
205
+ * Describes `value`, which a function that takes a type rejected as not a type, for its error: a type of kern-db, which has no operators, with the hints of `kern-orm/types` and `defineType`.
196
206
  *
197
- * `transform` converts them to other values, such as `number[]` for `vector`.
207
+ * It returns `undefined` for a value that is not a type of kern-db; a type of kern-orm is one too, so the caller rejects only values other than types.
198
208
  */
199
- function defineType(options) {
200
- if (options.castType === void 0 && options.sqlType.includes("(")) throw new TypeError(`Define the type parameters of "${options.sqlType}" using withParameters(), or set castType`);
201
- return createType({
202
- sqlType: options.sqlType,
203
- castType: options.castType ?? options.sqlType,
204
- encode: (value) => value,
205
- decode: (text) => text,
206
- operators: Object.freeze({}),
207
- isNullable: false,
208
- formatSqlType: void 0
209
- });
210
- }
211
- /** Tells whether `value` is a type, as opposed to a column or another object. */
212
- function isType(value) {
213
- return typeof value === "object" && value !== null && typeBrand in value;
209
+ function describeRejectedDbType(value) {
210
+ return isType(value) ? "a type of kern-db, which has no operators; take a built-in type from kern-orm/types, or create a type from it with defineType() of kern-orm" : void 0;
214
211
  }
215
- function createType(state) {
216
- const derive = (changes) => createType({
217
- ...state,
218
- ...changes
219
- });
220
- const { formatSqlType } = state;
212
+ /** Creates the type of the values of `dbType` whose expressions have `operators`. */
213
+ function createType(dbType, operators) {
214
+ const derive = (derived) => createType(derived, operators);
221
215
  const type = Object.freeze({
222
- ...state,
216
+ ...dbType,
223
217
  [typeBrand]: true,
218
+ operators,
224
219
  withOperators(extra) {
225
- const operators = { ...state.operators };
220
+ const merged = { ...operators };
226
221
  for (const name of Object.keys(extra)) {
227
222
  if (name === "then") throw new TypeError("Operator \"then\" is not allowed: it would make expressions thenable");
228
223
  const operator = extra[name];
229
- Object.defineProperty(operators, name, {
224
+ Object.defineProperty(merged, name, {
230
225
  value: isGenericOperator(operator) ? operator : (self, ...args) => operator(getType(self) === type ? self : toExpression(toNode(self), type), ...args),
231
226
  enumerable: true
232
227
  });
233
228
  }
234
- return derive({ operators: Object.freeze(operators) });
229
+ return createType(dbType, Object.freeze(merged));
235
230
  },
236
- transform: ({ decode, encode }) => derive({
237
- encode: encode ? (value) => state.encode(encode(value)) : state.encode,
238
- decode: (text) => decode(state.decode(text))
239
- }),
240
- withParameters: (format) => derive({ formatSqlType: format }),
241
- ...formatSqlType && { with: (...parameters) => derive({ sqlType: formatSqlType(...parameters) }) },
242
- nullable: () => derive({ isNullable: true }),
231
+ transform: (options) => derive(dbType.transform(options)),
232
+ withParameters: (format) => derive(dbType.withParameters(format)),
233
+ ..."with" in dbType && { with: (...parameters) => derive(dbType.with(...parameters)) },
234
+ nullable: () => derive(dbType.nullable()),
243
235
  of: () => type,
244
236
  columnName: (name) => new Column(type, {
245
237
  name,
@@ -268,10 +260,7 @@ function createType(state) {
268
260
  let booleanType;
269
261
  /** Returns the shared Boolean type used by built-in expressions and columns. */
270
262
  function getBooleanType() {
271
- booleanType ??= defineType({ sqlType: "boolean" }).transform({
272
- decode: (text) => text === "t",
273
- encode: (value) => value ? "t" : "f"
274
- }).withOperators(equalityOperators);
263
+ booleanType ??= defineType$1(dbTypes.boolean).withOperators(equalityOperators);
275
264
  return booleanType;
276
265
  }
277
266
  // src/expression/expression.ts
@@ -332,7 +321,7 @@ function isExpression(value) {
332
321
  function getType(expression) {
333
322
  return expression[expressionType];
334
323
  }
335
- /** Exposes a Boolean node with the shared codec and operators. */
324
+ /** Exposes a Boolean node with the shared Boolean type and its operators. */
336
325
  function toBooleanExpression(node) {
337
326
  return toExpression(node, getBooleanType());
338
327
  }
@@ -343,16 +332,23 @@ function isOperandSource(value) {
343
332
  /**
344
333
  * Converts an operand into a node: an expression or a query by the method of `operandNode`, or a plain value, bound as a parameter encoded with `type`.
345
334
  *
346
- * The method of a query takes a query of one value of a table, which lowering replaces with a scalar subquery, or with `EXISTS` for a query of `exists`, and rejects another query, such as of records or of `$query`.
335
+ * The method of a query takes a query of one value of a table, which lowering replaces with a scalar subquery, or with `EXISTS` for a query of `exists`, and rejects another query, such as of records; it rejects a query of SQL text too.
347
336
  */
348
337
  function toValueNode(value, type) {
349
- if (typeof value === "object" && value !== null && operandNode in value) return value[operandNode]();
338
+ if (typeof value === "object" && value !== null) {
339
+ if (operandNode in value) return value[operandNode]();
340
+ if (value instanceof SqlQuery) rejectSqlQueryOperand();
341
+ }
350
342
  return createNode({
351
343
  kind: "param",
352
344
  value,
353
345
  type
354
346
  });
355
347
  }
348
+ /** Rejects a query of SQL text as an operand of an expression. */
349
+ function rejectSqlQueryOperand() {
350
+ throw new TypeError("An expression takes a query of one value of a table, such as of get, an aggregate, or exists, not a query of SQL text");
351
+ }
356
352
  /** Converts an operand into a node as `toValueNode` does, casting a plain value to `type`, so that its parameter has the type even where nothing else in the statement determines it. */
357
353
  function toCastValueNode(value, type) {
358
354
  const node = toValueNode(value, type);
@@ -400,31 +396,25 @@ function createComparison(operator) {
400
396
  return defineGenericOperator((self, value) => compare(self, operator, value));
401
397
  }
402
398
  // src/type/number.ts
403
- /** Defines a type of numbers with the operators of the built-in ones. */
404
- function defineNumberType(sqlType) {
405
- return defineType({ sqlType }).transform({
406
- decode: Number,
407
- encode: (value) => String(value)
408
- }).withOperators(orderingOperators);
399
+ /** Defines a type from a type of kern-db of numbers with the built-in ordering operators. */
400
+ function defineNumberType(dbType) {
401
+ return defineType$1(dbType).withOperators(orderingOperators);
409
402
  }
410
403
  let integerType;
411
404
  /** Returns the shared `integer` type used by built-in expressions and columns. */
412
405
  function getIntegerType() {
413
- integerType ??= defineNumberType("integer");
406
+ integerType ??= defineNumberType(dbTypes.integer);
414
407
  return integerType;
415
408
  }
416
409
  // src/type/text.ts
417
- /** Defines a text type with the operators of the built-in text types. */
418
- function defineTextType(sqlType, castType) {
419
- return defineType({
420
- sqlType,
421
- castType
422
- }).withOperators(orderingOperators).withOperators(textOperators);
410
+ /** Defines a type from a type of kern-db of strings with the built-in text operators. */
411
+ function defineTextType(dbType) {
412
+ return defineType$1(dbType).withOperators(orderingOperators).withOperators(textOperators);
423
413
  }
424
414
  let textType;
425
415
  /** Returns the shared `text` type used by built-in expressions and columns. */
426
416
  function getTextType() {
427
- textType ??= defineTextType("text");
417
+ textType ??= defineTextType(dbTypes.text);
428
418
  return textType;
429
419
  }
430
420
  // src/expression/operators/text.ts
@@ -451,44 +441,11 @@ function createTextConversion(name) {
451
441
  function callTextFunction(name, self, type) {
452
442
  return toExpression(createList(`${name}(`, [toNode(self)], ")"), type);
453
443
  }
454
- // src/type/codecs/bytea.ts
455
- const hexDigits = "0123456789abcdef";
456
- /** Encodes bytes as a hex `bytea` literal, such as `\\x00ff`. */
457
- function encodeBytea(bytes) {
458
- let text = "\\x";
459
- for (const byte of bytes) text += hexDigits[byte >> 4] + hexDigits[byte & 15];
460
- return text;
461
- }
462
- /** Decodes a hex `bytea` literal into bytes. */
463
- function decodeBytea(text) {
464
- if (!text.startsWith("\\x")) throw new Error("Unsupported bytea value; kern-orm expects bytea_output hex");
465
- const bytes = new Uint8Array((text.length - 2) / 2);
466
- for (let index = 0; index < bytes.length; index++) bytes[index] = readHexDigit(text, 2 + index * 2) << 4 | readHexDigit(text, 3 + index * 2);
467
- return bytes;
468
- }
469
- /** Reads the hex digit at `index`, in either case. */
470
- function readHexDigit(text, index) {
471
- const code = text.charCodeAt(index);
472
- return code <= 57 ? code - 48 : (code | 32) - 87;
473
- }
474
- // src/type/codecs/json.ts
475
- /** Serializes a value as JSON text; values without a JSON representation, such as functions, are rejected. */
476
- function stringifyJson(value) {
477
- const text = JSON.stringify(value);
478
- if (text === void 0) throw new TypeError(`Cannot encode ${typeof value} as JSON`);
479
- return text;
480
- }
481
- // src/type/type-name.ts
482
- /** Appends type parameters, such as the precision and scale in `numeric(10,2)`, to a type name. */
483
- function formatTypeName(name, ...parameters) {
484
- const defined = parameters.filter((parameter) => parameter !== void 0);
485
- return defined.length === 0 ? name : `${name}(${defined.join(",")})`;
486
- }
487
444
  // src/type/builtins/text.ts
488
445
  /** Variable-length string without a limit. */
489
446
  const text = /* @__PURE__ */ getTextType();
490
447
  /** Variable-length string; `varchar.with(length)` limits its length. */
491
- const varchar = /* @__PURE__ */ defineTextType("varchar").withParameters((length) => formatTypeName("varchar", length));
448
+ const varchar = /* @__PURE__ */ defineTextType(dbTypes.varchar);
492
449
  /** Fixed-length string that PostgreSQL pads with spaces; `char` alone has length 1, and `char.with(length)` sets the length. */
493
- const char = /* @__PURE__ */ defineTextType("char", "bpchar").withParameters((length) => formatTypeName("char", length));
494
- export { hasEquality as A, noOrder as B, toNode as C, isType as D, defineType as E, createNode as F, oneNode as H, createSelectNode as I, falseNode as L, valuesQueryNode as M, defineGenericOperator as N, Column as O, createList as P, noFilters as R, toFunctionOperandNode as S, getBooleanType as T, trueNode as U, noProjections as V, isOperandSource as _, stringifyJson as a, toCastValueNode as b, textOperators as c, orderingOperators as d, compare as f, isExpression as g, getType as h, formatTypeName as i, isEqualityCompatible as j, equalityOperators as k, defineNumberType as l, createIsNullNode as m, text as n, decodeBytea as o, compareNodes as p, varchar as r, encodeBytea as s, char as t, getIntegerType as u, operandNode as v, toValueNode as w, toExpression as x, toBooleanExpression as y, noJoins as z };
450
+ const char = /* @__PURE__ */ defineTextType(dbTypes.char);
451
+ export { valuesQueryNode as A, oneNode as B, defineType$1 as C, equalityOperators as D, Column as E, falseNode as F, noFilters as I, noJoins as L, createList as M, createNode as N, hasEquality as O, createSelectNode as P, noOrder as R, getBooleanType as S, isType$1 as T, trueNode as V, toCastValueNode as _, defineNumberType as a, toNode as b, compare as c, getType as d, isExpression as f, toBooleanExpression as g, rejectSqlQueryOperand as h, textOperators as i, defineGenericOperator as j, isEqualityCompatible as k, compareNodes as l, operandNode as m, text as n, getIntegerType as o, isOperandSource as p, varchar as r, orderingOperators as s, char as t, createIsNullNode as u, toExpression as v, describeRejectedDbType as w, toValueNode as x, toFunctionOperandNode as y, noProjections as z };
package/dist/types.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { E as AnyExpression, Gi as Type, Jr as HasEquality, Kr as EqualityOperator, Qr as ComparisonSignature, S as TextTypeOperators, Ui as BaseType, Yr as InSignature, aa as NoOperators, ia as MergeOperators, oa as OperatorDefinitions, qr as EqualityOperators, sa as GenericOperator, w as NumberTypeOperators, x as TextOperators } from "./index-B1aH5Ht0.mjs";
1
+ import { Qi as Type, Zi as BaseType, da as OperatorDefinitions, di as EqualityOperators, dt as AnyExpression, fa as GenericOperator, fi as HasEquality, gi as ComparisonSignature, ia as Column, la as MergeOperators, lt as NumberTypeOperators, ot as TextOperators, pi as InSignature, st as TextTypeOperators, ua as NoOperators, ui as EqualityOperator } from "./index-aiyU5HR5.mjs";
2
2
  /**
3
3
  * Creates a one-dimensional array type of `element` values.
4
4
  *
@@ -62,7 +62,7 @@ export declare const interval: BaseType<string, string, MergeOperators<NoOperato
62
62
  gte: GenericOperator<ComparisonSignature, AnyExpression<unknown, unknown>>;
63
63
  }>, undefined>;
64
64
  /** Creates a type of an existing PostgreSQL enum; values are ordered as declared in the enum. */
65
- declare function enumOf<const Values extends readonly string[]>(name: string, _values: Values): BaseType<Values[number], Values[number], MergeOperators<NoOperators, {
65
+ declare function enumOf<const Values extends readonly string[]>(name: string, values: Values): BaseType<Values[number], Values[number], MergeOperators<NoOperators, {
66
66
  eq: EqualityOperator<ComparisonSignature>;
67
67
  ne: EqualityOperator<ComparisonSignature>;
68
68
  in: EqualityOperator<InSignature>;
@@ -179,4 +179,4 @@ export declare const uuid: BaseType<string, string, MergeOperators<NoOperators,
179
179
  gt: GenericOperator<ComparisonSignature, AnyExpression<unknown, unknown>>;
180
180
  gte: GenericOperator<ComparisonSignature, AnyExpression<unknown, unknown>>;
181
181
  }>, undefined>;
182
- export { enumOf as enum };
182
+ export { type AnyExpression, type BaseType, type Column, type ComparisonSignature, type EqualityOperator, type EqualityOperators, type GenericOperator, type InSignature, type MergeOperators, type NoOperators, type NumberTypeOperators, type TextOperators, type TextTypeOperators, type Type, enumOf as enum };
package/dist/types.mjs CHANGED
@@ -1,3 +1,63 @@
1
- import { n as text, r as varchar, t as char } from "./text-CIUxPWPl.mjs";
2
- import { _ as timestamptz, a as numeric, b as array, c as cidr, d as jsonb, f as enumOf, g as timestamp, h as time, i as integer, l as inet, m as interval, n as bigint, o as real, p as date, r as doublePrecision, s as smallint, t as uuid, u as json, v as boolean, y as bytea } from "./types-D3d35qR2.mjs";
1
+ import { C as defineType, D as equalityOperators, O as hasEquality, S as getBooleanType, a as defineNumberType, n as text, o as getIntegerType, r as varchar, s as orderingOperators, t as char } from "./text-ucmJCsCN.mjs";
2
+ import * as dbTypes from "kern-db/types";
3
+ // src/type/builtins/array.ts
4
+ /**
5
+ * Creates a one-dimensional array type of `element` values.
6
+ *
7
+ * A `NULL` element decodes to `null`; a nullable `element` type, such as `array(text.nullable())`, types such elements.
8
+ * Elements are separated by commas, as in arrays of all built-in types; a custom type with another delimiter, such as `box`, is not supported.
9
+ * An array has `eq`, `ne`, and `in` when its element type has SQL `=`.
10
+ */
11
+ function array(element) {
12
+ const type = defineType(dbTypes.array(element));
13
+ return hasEquality(element) ? type.withOperators(equalityOperators) : type;
14
+ }
15
+ // src/type/builtins/binary.ts
16
+ /** Binary data; PostgreSQL represents it in hex, which requires the default `bytea_output` setting. */
17
+ const bytea = /* @__PURE__ */ defineType(dbTypes.bytea).withOperators(equalityOperators);
18
+ // src/type/builtins/boolean.ts
19
+ /** `boolean` values. */
20
+ const boolean = /* @__PURE__ */ getBooleanType();
21
+ // src/type/builtins/datetime.ts
22
+ /** Point in time as a UTC ISO 8601 string with microseconds, such as `2026-01-15T07:00:00.123456Z`; accepts a `Date` too. */
23
+ const timestamptz = /* @__PURE__ */ defineType(dbTypes.timestamptz).withOperators(orderingOperators);
24
+ /** Date and time without a time zone as an ISO 8601 string with microseconds, such as `2026-01-15T10:00:00.000000`. */
25
+ const timestamp = /* @__PURE__ */ defineType(dbTypes.timestamp).withOperators(orderingOperators);
26
+ /** Calendar date as an ISO 8601 string, such as `2026-01-15`. */
27
+ const date = /* @__PURE__ */ defineType(dbTypes.date).withOperators(orderingOperators);
28
+ /** Time of day as a string with microseconds, such as `10:00:00.000000`. */
29
+ const time = /* @__PURE__ */ defineType(dbTypes.time).withOperators(orderingOperators);
30
+ /** Interval in the PostgreSQL output format, such as `1 day 02:00:00`. */
31
+ const interval = /* @__PURE__ */ defineType(dbTypes.interval).withOperators(orderingOperators);
32
+ // src/type/builtins/enum.ts
33
+ /** Creates a type of an existing PostgreSQL enum; values are ordered as declared in the enum. */
34
+ function enumOf(name, values) {
35
+ return defineType(dbTypes.enum(name, values)).withOperators(orderingOperators);
36
+ }
37
+ // src/type/builtins/json.ts
38
+ /** `json` values; `json.of<T>()` declares their shape. PostgreSQL has no `=` for `json`, so its expressions have no `eq`, `ne`, or `in`. */
39
+ const json = /* @__PURE__ */ defineType(dbTypes.json);
40
+ /** `jsonb` values; `jsonb.of<T>()` declares their shape. */
41
+ const jsonb = /* @__PURE__ */ defineType(dbTypes.jsonb).withOperators(equalityOperators);
42
+ // src/type/builtins/network.ts
43
+ /** IP address with an optional netmask as a string, such as `192.168.0.1`. */
44
+ const inet = /* @__PURE__ */ defineType(dbTypes.inet).withOperators(orderingOperators);
45
+ /** IP network as a string, such as `10.0.0.0/8`. */
46
+ const cidr = /* @__PURE__ */ defineType(dbTypes.cidr).withOperators(orderingOperators);
47
+ // src/type/builtins/numeric.ts
48
+ /** 2-byte integer as a `number`. */
49
+ const smallint = /* @__PURE__ */ defineNumberType(dbTypes.smallint);
50
+ /** 4-byte integer as a `number`. */
51
+ const integer = /* @__PURE__ */ getIntegerType();
52
+ /** 8-byte integer as a `bigint`, which keeps values beyond `Number.MAX_SAFE_INTEGER`; accepts a `number` too. */
53
+ const bigint = /* @__PURE__ */ defineType(dbTypes.bigint).withOperators(orderingOperators);
54
+ /** 4-byte floating-point number as a `number`. */
55
+ const real = /* @__PURE__ */ defineNumberType(dbTypes.real);
56
+ /** 8-byte floating-point number as a `number`. */
57
+ const doublePrecision = /* @__PURE__ */ defineNumberType(dbTypes.doublePrecision);
58
+ /** Exact number as a decimal string, so that no precision is lost; `numeric.with(precision, scale)` constrains it. */
59
+ const numeric = /* @__PURE__ */ defineType(dbTypes.numeric).withOperators(orderingOperators);
60
+ // src/type/builtins/uuid.ts
61
+ /** UUID as a string. */
62
+ const uuid = /* @__PURE__ */ defineType(dbTypes.uuid).withOperators(orderingOperators);
3
63
  export { array, bigint, boolean, bytea, char, cidr, date, doublePrecision, enumOf as enum, inet, integer, interval, json, jsonb, numeric, real, smallint, text, time, timestamp, timestamptz, uuid, varchar };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kern-orm",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "Fully typed relational query builder for PostgreSQL with ambient transactions and single-query relation loading",
5
5
  "keywords": [
6
6
  "orm",
@@ -18,7 +18,7 @@
18
18
  "repository": {
19
19
  "type": "git",
20
20
  "url": "git+https://github.com/IlyaSemenov/kern-orm.git",
21
- "directory": "packages/kern-orm"
21
+ "directory": "packages/orm"
22
22
  },
23
23
  "files": [
24
24
  "README.md",
@@ -29,6 +29,10 @@
29
29
  "types": "./dist/index.d.mts",
30
30
  "exports": {
31
31
  ".": "./dist/index.mjs",
32
+ "./db": "./dist/db.mjs",
33
+ "./db/node-postgres": "./dist/db/node-postgres.mjs",
34
+ "./db/postgres-js": "./dist/db/postgres-js.mjs",
35
+ "./db/types": "./dist/db/types.mjs",
32
36
  "./testing": "./dist/testing.mjs",
33
37
  "./types": "./dist/types.mjs",
34
38
  "./package.json": "./package.json"
@@ -40,8 +44,11 @@
40
44
  "build": "tsdown",
41
45
  "prepublishOnly": "bun run build"
42
46
  },
47
+ "dependencies": {
48
+ "kern-db": "^0.1.0"
49
+ },
43
50
  "devDependencies": {
44
- "@kern-orm/postgres-js": "workspace:*",
51
+ "@kern-orm/test-harness": "workspace:*",
45
52
  "postgres": "catalog:",
46
53
  "typescript-6": "catalog:"
47
54
  },