cogsbox-shape 0.5.194 → 0.5.195

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/dist/schema.js CHANGED
@@ -723,9 +723,10 @@ export function createSchema(schema, relations) {
723
723
  });
724
724
  }
725
725
  let refinedClientInputSchema = finalClientInputSchema;
726
+ let refinedClientSchema = finalClientSchema;
726
727
  if (refinements?.client) {
727
728
  const clientRefine = refinements.client;
728
- refinedClientInputSchema = finalClientInputSchema.superRefine((data, ctx) => {
729
+ const refineFn = (data, ctx) => {
729
730
  const result = clientRefine(data);
730
731
  if (!result)
731
732
  return;
@@ -737,6 +738,25 @@ export function createSchema(schema, relations) {
737
738
  path: err.path,
738
739
  });
739
740
  }
741
+ };
742
+ refinedClientInputSchema = finalClientInputSchema.superRefine(refineFn);
743
+ refinedClientSchema = finalClientSchema.superRefine(refineFn);
744
+ }
745
+ let refinedSqlSchema = finalSqlSchema;
746
+ if (refinements?.server) {
747
+ const serverRefine = refinements.server;
748
+ refinedSqlSchema = finalSqlSchema.superRefine((data, ctx) => {
749
+ const result = serverRefine(data);
750
+ if (!result)
751
+ return;
752
+ const errors = Array.isArray(result) ? result : [result];
753
+ for (const err of errors) {
754
+ ctx.addIssue({
755
+ code: z.ZodIssueCode.custom,
756
+ message: err.message,
757
+ path: err.path,
758
+ });
759
+ }
740
760
  });
741
761
  }
742
762
  return {
@@ -745,9 +765,9 @@ export function createSchema(schema, relations) {
745
765
  deriveDependencies,
746
766
  refineDependencies,
747
767
  isClientRecord,
748
- sqlSchema: finalSqlSchema,
768
+ sqlSchema: refinedSqlSchema,
749
769
  clientInputSchema: refinedClientInputSchema,
750
- clientSchema: finalClientSchema,
770
+ clientSchema: refinedClientSchema,
751
771
  serverSchema: refinedValidationSchema,
752
772
  defaultValues: defaultValues,
753
773
  stateType: {},
@@ -763,7 +783,7 @@ export function createSchema(schema, relations) {
763
783
  return toDb(validPatch);
764
784
  },
765
785
  parseFromDb: (dbData) => {
766
- const parsed = finalSqlSchema.parse(dbData);
786
+ const parsed = refinedSqlSchema.parse(dbData);
767
787
  return toClient(parsed);
768
788
  },
769
789
  };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,88 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import z from "zod";
3
+ import { s, schema, createSchemaBox } from "../schema.js";
4
+ describe("refine runtime behavior", () => {
5
+ function makeRefinedBox() {
6
+ const rules = schema({
7
+ _tableName: "rules",
8
+ id: s.sqlite({ type: "int", pk: true }),
9
+ min: s.sqlite({ type: "int", nullable: true }).clientInput({ value: null, schema: z.number().nullable() }),
10
+ max: s.sqlite({ type: "int", nullable: true }).clientInput({ value: null, schema: z.number().nullable() }),
11
+ label: s.sqlite({ type: "varchar" }).clientInput({ value: "" }),
12
+ }).refine({
13
+ client: (row) => {
14
+ if (row.min !== null && row.max !== null && row.min >= row.max) {
15
+ return { path: ["max"], message: "Max must be > min" };
16
+ }
17
+ return undefined;
18
+ },
19
+ server: (row) => {
20
+ if (row.min !== null && row.max !== null && row.min >= row.max) {
21
+ return { path: ["max"], message: "Max must be > min" };
22
+ }
23
+ if (!row.label) {
24
+ return { path: ["label"], message: "Label required" };
25
+ }
26
+ return undefined;
27
+ },
28
+ });
29
+ return createSchemaBox({ rules }, { rules: {} });
30
+ }
31
+ it("schemas.clientInput catches client refine", () => {
32
+ const box = makeRefinedBox();
33
+ const good = box.rules.schemas.clientInput.safeParse({ id: 1, min: 1, max: 10, label: "x" });
34
+ expect(good.success).toBe(true);
35
+ const bad = box.rules.schemas.clientInput.safeParse({ id: 1, min: 10, max: 1, label: "x" });
36
+ expect(bad.success).toBe(false);
37
+ if (!bad.success) {
38
+ expect(bad.error.issues[0].message).toBe("Max must be > min");
39
+ }
40
+ });
41
+ it("schemas.client catches client refine", () => {
42
+ const box = makeRefinedBox();
43
+ const bad = box.rules.schemas.client.safeParse({ id: 1, min: 10, max: 1, label: "x" });
44
+ expect(bad.success).toBe(false);
45
+ if (!bad.success) {
46
+ expect(bad.error.issues[0].message).toBe("Max must be > min");
47
+ }
48
+ });
49
+ it("schemas.server catches server refine", () => {
50
+ const box = makeRefinedBox();
51
+ const bad = box.rules.schemas.server.safeParse({ id: 1, min: 1, max: 10, label: "" });
52
+ expect(bad.success).toBe(false);
53
+ if (!bad.success) {
54
+ expect(bad.error.issues[0].message).toBe("Label required");
55
+ }
56
+ });
57
+ it("schemas.sql catches server refine", () => {
58
+ const box = makeRefinedBox();
59
+ const bad = box.rules.schemas.sql.safeParse({ id: 1, min: 1, max: 10, label: "" });
60
+ expect(bad.success).toBe(false);
61
+ if (!bad.success) {
62
+ expect(bad.error.issues[0].message).toBe("Label required");
63
+ }
64
+ });
65
+ it("parseForDb rejects invalid data via server refine", () => {
66
+ const box = makeRefinedBox();
67
+ expect(() => box.rules.transforms.parseForDb({ id: 1, min: 10, max: 1, label: "" })).toThrow();
68
+ });
69
+ it("parseFromDb rejects invalid DB data via server refine", () => {
70
+ const box = makeRefinedBox();
71
+ expect(() => box.rules.transforms.parseFromDb({ id: 1, min: 1, max: 10, label: "" })).toThrow("Label required");
72
+ });
73
+ it("parsePatchForDb does NOT run refine (uses partial base)", () => {
74
+ const box = makeRefinedBox();
75
+ expect(() => box.rules.transforms.parsePatchForDb({ min: 10, max: 1 })).not.toThrow();
76
+ });
77
+ it("unrefined box has no refine on any schema", () => {
78
+ const rules = schema({
79
+ _tableName: "rules",
80
+ id: s.sqlite({ type: "int", pk: true }),
81
+ min: s.sqlite({ type: "int", nullable: true }).clientInput({ value: null, schema: z.number().nullable() }),
82
+ max: s.sqlite({ type: "int", nullable: true }).clientInput({ value: null, schema: z.number().nullable() }),
83
+ });
84
+ const box = createSchemaBox({ rules }, { rules: {} });
85
+ const good = box.rules.schemas.clientInput.safeParse({ id: 1, min: 10, max: 1 });
86
+ expect(good.success).toBe(true);
87
+ });
88
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cogsbox-shape",
3
- "version": "0.5.194",
3
+ "version": "0.5.195",
4
4
  "description": "A TypeScript library for creating type-safe database schemas with Zod validation, SQL type definitions, and automatic client/server transformations. Unifies client, server, and database types through a single schema definition, with built-in support for relationships and serialization.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",