bazis 0.104.0 → 0.104.1

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.
@@ -232,7 +232,7 @@ export class CodexAppServerClient implements CodexClient {
232
232
  if (method === "account/updated") this.modelCache = undefined;
233
233
  }, () => { this.clearLogin(); this.modelCache = undefined; });
234
234
  const initialized = await client.request("initialize", {
235
- clientInfo: { name: "bazis", title: "Bazis", version: "0.104.0" }, capabilities: { experimentalApi: true },
235
+ clientInfo: { name: "bazis", title: "Bazis", version: "0.104.1" }, capabilities: { experimentalApi: true },
236
236
  }, 15_000, signal);
237
237
  if (resolve(text(initialized.codexHome, 4096)) !== this.paths.home) throw new CodexError("PROTOCOL_ERROR");
238
238
  client.notify("initialized");
@@ -13,6 +13,12 @@ export interface ValueConverter<TModel = unknown, TProvider = unknown> {
13
13
  * the query fails instead of silently matching nothing.
14
14
  */
15
15
  readonly comparable?: boolean;
16
+ /**
17
+ * `true`: the converter also gets `null` (both ways), for example to store
18
+ * `null` as `""`. By default `null` stays SQL NULL and the converter is
19
+ * not called, as in EF Core.
20
+ */
21
+ readonly convertsNulls?: boolean;
16
22
  }
17
23
 
18
24
  /** Thrown by an encrypted column that cannot be read: another key, or the stored value was changed. */
@@ -2,16 +2,24 @@ import { OrmError } from "../errors";
2
2
  import type { PropertyModel } from "../Metadata/types";
3
3
  import type { SqlDialect, SqlParam } from "./types";
4
4
 
5
+ /**
6
+ * Whether the converter of the property applies to the value: `null` and
7
+ * `undefined` stay SQL NULL unless the converter declares `convertsNulls`.
8
+ */
9
+ export function convertsValue(property: PropertyModel, value: unknown): boolean {
10
+ return property.converter !== undefined && (property.converter.convertsNulls === true || (value !== null && value !== undefined));
11
+ }
12
+
5
13
  /** Encodes a property value: converter -> dialect. */
6
14
  export function encodeProperty(property: PropertyModel, value: unknown, dialect: SqlDialect): SqlParam {
7
- const modelValue = property.converter ? property.converter.toProvider(value) : value;
15
+ const modelValue = convertsValue(property, value) ? property.converter!.toProvider(value) : value;
8
16
  return dialect.encode(modelValue, property.type);
9
17
  }
10
18
 
11
19
  /** Decodes a column value: dialect -> converter. A converter failure names the entity and the property. */
12
20
  export function decodeProperty(property: PropertyModel, value: unknown, dialect: SqlDialect, owner?: string): unknown {
13
21
  const providerValue = dialect.decode(value, property.type);
14
- if (!property.converter) return providerValue;
22
+ if (!property.converter || !convertsValue(property, providerValue)) return providerValue;
15
23
  try {
16
24
  return property.converter.fromProvider(providerValue);
17
25
  } catch (error) {
@@ -1,6 +1,7 @@
1
1
  import { types } from "node:util";
2
2
  import { OrmError, OrmTrackedMutationConflictError, OrmUndeclaredConflictTargetError, OrmUnsafeImmediateMutationError } from "../errors";
3
3
  import { isDatabaseGenerated, type EntityModel, type PropertyModel } from "../Metadata/types";
4
+ import { convertsValue } from "../Providers/propertyConversion";
4
5
  import type { DbContextRuntime } from "../runtime";
5
6
  import { hasTrackedEntriesForModel } from "../Tracking/ChangeTracker";
6
7
  import { isPostgresJsonScalarParameter } from "../Providers/PostgresDialect";
@@ -136,11 +137,11 @@ function admitInsertValues<T extends object>(model: EntityModel, entity: T): rea
136
137
  }
137
138
  function unsetKey(value: unknown): boolean { return value === undefined || value === null || value === "" || value === 0; }
138
139
  function encodeAssignments(runtime: DbContextRuntime, assignments: readonly AdmittedAssignment[]): readonly { readonly property: PropertyModel; readonly value: SqlParam }[] {
139
- return Object.freeze(assignments.map(({ property, value }) => Object.freeze({ property, value: value === null ? null : encode(runtime, property, value) })));
140
+ return Object.freeze(assignments.map(({ property, value }) => Object.freeze({ property, value: value === null && !convertsValue(property, null) ? null : encode(runtime, property, value) })));
140
141
  }
141
142
  function encode(runtime: DbContextRuntime, property: PropertyModel, input: unknown, allowNull = false): SqlParam {
142
143
  try {
143
- const providerValue = property.converter ? property.converter.toProvider(input) : input;
144
+ const providerValue = convertsValue(property, input) ? property.converter!.toProvider(input) : input;
144
145
  const safeProvider = storageValue(providerValue, property.type, allowNull);
145
146
  return snapshotEncodedSqlParam(runtime.provider.dialect.encode(safeProvider, property.type));
146
147
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bazis",
3
- "version": "0.104.0",
3
+ "version": "0.104.1",
4
4
  "description": "Modular backend framework for Bun in TypeScript: DI wired by codegen, HTTP, a PostgreSQL ORM, JWT, WebSocket, agents and a CLI.",
5
5
  "license": "MIT",
6
6
  "author": "Alexander Alenin",