@kernhq/module-quire 0.4.1 → 0.6.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 (49) hide show
  1. package/dist/contract/index.d.ts +1 -0
  2. package/dist/contract/index.d.ts.map +1 -1
  3. package/dist/contract/index.js +1 -0
  4. package/dist/contract/index.js.map +1 -1
  5. package/dist/contract/properties.d.ts +485 -0
  6. package/dist/contract/properties.d.ts.map +1 -0
  7. package/dist/contract/properties.js +175 -0
  8. package/dist/contract/properties.js.map +1 -0
  9. package/dist/contract/router.d.ts +1101 -0
  10. package/dist/contract/router.d.ts.map +1 -1
  11. package/dist/contract/router.js +88 -0
  12. package/dist/contract/router.js.map +1 -1
  13. package/dist/server/_impl.d.ts +1182 -0
  14. package/dist/server/_impl.d.ts.map +1 -1
  15. package/dist/server/_impl.js +113 -0
  16. package/dist/server/_impl.js.map +1 -1
  17. package/dist/server/formula.d.ts +49 -0
  18. package/dist/server/formula.d.ts.map +1 -0
  19. package/dist/server/formula.js +407 -0
  20. package/dist/server/formula.js.map +1 -0
  21. package/dist/server/schema.d.ts +696 -1
  22. package/dist/server/schema.d.ts.map +1 -1
  23. package/dist/server/schema.js +100 -1
  24. package/dist/server/schema.js.map +1 -1
  25. package/dist/server/services/access.d.ts +3 -0
  26. package/dist/server/services/access.d.ts.map +1 -1
  27. package/dist/server/services/databases.d.ts +330 -0
  28. package/dist/server/services/databases.d.ts.map +1 -0
  29. package/dist/server/services/databases.js +515 -0
  30. package/dist/server/services/databases.js.map +1 -0
  31. package/dist/server/services/index.d.ts +3 -0
  32. package/dist/server/services/index.d.ts.map +1 -1
  33. package/dist/server/services/index.js +3 -0
  34. package/dist/server/services/index.js.map +1 -1
  35. package/dist/server/services/query.d.ts +13 -0
  36. package/dist/server/services/query.d.ts.map +1 -0
  37. package/dist/server/services/query.js +154 -0
  38. package/dist/server/services/query.js.map +1 -0
  39. package/dist/server/services/versions.d.ts +6 -0
  40. package/dist/server/services/versions.d.ts.map +1 -1
  41. package/migrations/0004_databases.sql +83 -0
  42. package/migrations/0005_rows_are_pages.sql +6 -0
  43. package/migrations/meta/0004_snapshot.json +1129 -0
  44. package/migrations/meta/0005_snapshot.json +1191 -0
  45. package/migrations/meta/_journal.json +14 -0
  46. package/package.json +1 -1
  47. package/src/contract/index.ts +1 -0
  48. package/src/contract/properties.ts +201 -0
  49. package/src/contract/router.ts +115 -0
@@ -0,0 +1,154 @@
1
+ import { KernError } from '@kernhq/kernel';
2
+ import { sql } from 'drizzle-orm';
3
+ /**
4
+ * Turning a view's filters and sorts into SQL over a row's `props` column.
5
+ *
6
+ * Done in SQL rather than in memory, because filtering after the fact breaks pagination: a page of
7
+ * fifty rows filtered down to three is not a page of three, and the caller has no way to ask for
8
+ * the rest. That means every comparison has to be expressible against `jsonb`.
9
+ *
10
+ * **A property key is never interpolated before it is looked up.** The key comes from the request,
11
+ * and `props->>'…'` is a string in the query text rather than a parameter — so the only safe path is
12
+ * to find the property first and use the key the *database* already knows about. An unknown key is
13
+ * refused rather than passed through.
14
+ */
15
+ const numeric = (key) => sql `nullif(props->>${key}, '')::numeric`;
16
+ const timestamp = (key) => sql `nullif(props->>${key}, '')::timestamptz`;
17
+ const text = (key) => sql `props->>${key}`;
18
+ /** Whether a value is "nothing" — absent, null, empty string, or an empty array. */
19
+ const emptyExpr = (key) => sql `(props->${key} is null or props->>${key} = '' or props->${key} = '[]'::jsonb or props->${key} = 'null'::jsonb)`;
20
+ export function filterToSql(filter, property) {
21
+ const key = property.key;
22
+ const value = filter.value;
23
+ switch (filter.operator) {
24
+ case 'is_empty':
25
+ return emptyExpr(key);
26
+ case 'is_not_empty':
27
+ return sql `not ${emptyExpr(key)}`;
28
+ default:
29
+ break;
30
+ }
31
+ switch (property.type) {
32
+ case 'number':
33
+ case 'formula':
34
+ case 'rollup': {
35
+ const n = Number(value);
36
+ if (Number.isNaN(n))
37
+ return null;
38
+ switch (filter.operator) {
39
+ case 'equals':
40
+ return sql `${numeric(key)} = ${n}`;
41
+ case 'not_equals':
42
+ return sql `${numeric(key)} is distinct from ${n}`;
43
+ case 'greater_than':
44
+ return sql `${numeric(key)} > ${n}`;
45
+ case 'less_than':
46
+ return sql `${numeric(key)} < ${n}`;
47
+ default:
48
+ return null;
49
+ }
50
+ }
51
+ case 'date':
52
+ case 'created_time':
53
+ case 'edited_time': {
54
+ const at = typeof value === 'string' ? value : null;
55
+ if (!at)
56
+ return null;
57
+ switch (filter.operator) {
58
+ case 'equals':
59
+ return sql `date_trunc('day', ${timestamp(key)}) = date_trunc('day', ${at}::timestamptz)`;
60
+ case 'on_or_before':
61
+ return sql `${timestamp(key)} <= ${at}::timestamptz`;
62
+ case 'on_or_after':
63
+ return sql `${timestamp(key)} >= ${at}::timestamptz`;
64
+ case 'greater_than':
65
+ return sql `${timestamp(key)} > ${at}::timestamptz`;
66
+ case 'less_than':
67
+ return sql `${timestamp(key)} < ${at}::timestamptz`;
68
+ default:
69
+ return null;
70
+ }
71
+ }
72
+ case 'checkbox': {
73
+ const wanted = value === true || value === 'true';
74
+ // An unset checkbox is false, not null: a filter for "not done" must include rows nobody has
75
+ // touched, which is most of them.
76
+ return wanted
77
+ ? sql `(props->>${key})::boolean is true`
78
+ : sql `coalesce((props->>${key})::boolean, false) is false`;
79
+ }
80
+ case 'multi_select':
81
+ case 'person':
82
+ case 'files':
83
+ case 'relation': {
84
+ // Array-valued. `?` asks whether the array contains a string; `?|` whether it contains any.
85
+ const many = Array.isArray(value) ? value.map(String) : [String(value)];
86
+ switch (filter.operator) {
87
+ case 'contains':
88
+ case 'is_any_of':
89
+ return sql `props->${key} ?| ${sql.param(many)}::text[]`;
90
+ case 'not_contains':
91
+ case 'is_none_of':
92
+ return sql `not (props->${key} ?| ${sql.param(many)}::text[])`;
93
+ default:
94
+ return null;
95
+ }
96
+ }
97
+ default: {
98
+ // Everything else compares as text.
99
+ const v = value === null || value === undefined ? '' : String(value);
100
+ switch (filter.operator) {
101
+ case 'equals':
102
+ return sql `${text(key)} = ${v}`;
103
+ case 'not_equals':
104
+ return sql `${text(key)} is distinct from ${v}`;
105
+ case 'contains':
106
+ return sql `${text(key)} ilike ${`%${v}%`}`;
107
+ case 'not_contains':
108
+ return sql `coalesce(${text(key)}, '') not ilike ${`%${v}%`}`;
109
+ case 'starts_with':
110
+ return sql `${text(key)} ilike ${`${v}%`}`;
111
+ case 'ends_with':
112
+ return sql `${text(key)} ilike ${`%${v}`}`;
113
+ case 'is_any_of':
114
+ return sql `${text(key)} = any(${sql.param(Array.isArray(value) ? value.map(String) : [v])}::text[])`;
115
+ case 'is_none_of':
116
+ return sql `coalesce(${text(key)}, '') <> all(${sql.param(Array.isArray(value) ? value.map(String) : [v])}::text[])`;
117
+ default:
118
+ return null;
119
+ }
120
+ }
121
+ }
122
+ }
123
+ /**
124
+ * The ordering expression for a sort.
125
+ *
126
+ * Typed rather than lexicographic: `props->>'estimate'` sorts 10 before 9, which is the sort of
127
+ * thing nobody reports as a bug and everybody works around.
128
+ */
129
+ export function sortToSql(sort, property) {
130
+ const key = property.key;
131
+ const direction = sort.direction === 'desc' ? sql `desc` : sql `asc`;
132
+ switch (property.type) {
133
+ case 'number':
134
+ case 'formula':
135
+ case 'rollup':
136
+ return sql `${numeric(key)} ${direction} nulls last`;
137
+ case 'date':
138
+ case 'created_time':
139
+ case 'edited_time':
140
+ return sql `${timestamp(key)} ${direction} nulls last`;
141
+ case 'checkbox':
142
+ return sql `coalesce((props->>${key})::boolean, false) ${direction}`;
143
+ default:
144
+ return sql `${text(key)} ${direction} nulls last`;
145
+ }
146
+ }
147
+ /** The property a filter or sort names, or a refusal. Never trust the key that arrived. */
148
+ export function propertyFor(properties, key) {
149
+ const found = properties.find((p) => p.key === key);
150
+ if (!found)
151
+ throw KernError.badRequest(`No such property: ${key}`);
152
+ return found;
153
+ }
154
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../../../src/server/services/query.ts"],"names":[],"mappings":"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"}
@@ -81,6 +81,9 @@ export declare function quireVersions(kernel: Kernel, access: QuireAccess): {
81
81
  publishedVersionId: string | null;
82
82
  hasUnpublishedChanges: boolean;
83
83
  text: string;
84
+ databaseId: string | null;
85
+ props: unknown;
86
+ computed: unknown;
84
87
  createdBy: string | null;
85
88
  updatedBy: string | null;
86
89
  createdAt: Date;
@@ -102,6 +105,9 @@ export declare function quireVersions(kernel: Kernel, access: QuireAccess): {
102
105
  publishedVersionId: string | null;
103
106
  hasUnpublishedChanges: boolean;
104
107
  text: string;
108
+ databaseId: string | null;
109
+ props: unknown;
110
+ computed: unknown;
105
111
  createdBy: string | null;
106
112
  updatedBy: string | null;
107
113
  createdAt: Date;
@@ -1 +1 @@
1
- {"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../../../src/server/services/versions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAuB,SAAS,EAAE,MAAM,mBAAmB,CAAA;AACvE,OAAO,EAAa,KAAK,MAAM,EAAE,KAAK,EAAE,EAAU,MAAM,gBAAgB,CAAA;AAExE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAS,YAAY,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAG9C,KAAK,UAAU,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAKlD,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,CAalF;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW;IAS7D;;;;;;OAMG;gBAEG,EAAE,eACO,MAAM,UACX,MAAM,QACR;QAAE,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GACnF,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;aAgCd,EAAE,eAAe,MAAM,UAAU,MAAM,SAAS,MAAM,UAAU,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;YAkB9E,EAAE,eAAe,MAAM,aAAa,MAAM;;;;;;;;;;;;;IAUxD;;;;;;;OAOG;gBACe,EAAE,aAAa,SAAS,eAAe,MAAM,aAAa,MAAM;;;;;;;;;;;;;IAsBlF,kEAAkE;gBAChD,EAAE,aAAa,SAAS,eAAe,MAAM,UAAU,MAAM,SAAS,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;;;;;;IAyBrG,wEAAwE;eACvD,EAAE,aAAa,SAAS,eAAe,MAAM,UAAU,MAAM;;;;;;;;;;;;;;;;;;;;IAyB9E,2FAA2F;uBAClE,EAAE,eAAe,MAAM,UAAU,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAUvF,wFAAwF;+BAC7D,MAAM,UAAU,MAAM;;;;;;EAMpD;AACD,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAA"}
1
+ {"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../../../src/server/services/versions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAuB,SAAS,EAAE,MAAM,mBAAmB,CAAA;AACvE,OAAO,EAAa,KAAK,MAAM,EAAE,KAAK,EAAE,EAAU,MAAM,gBAAgB,CAAA;AAExE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAS,YAAY,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAG9C,KAAK,UAAU,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAKlD,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,CAalF;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW;IAS7D;;;;;;OAMG;gBAEG,EAAE,eACO,MAAM,UACX,MAAM,QACR;QAAE,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GACnF,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;aAgCd,EAAE,eAAe,MAAM,UAAU,MAAM,SAAS,MAAM,UAAU,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;YAkB9E,EAAE,eAAe,MAAM,aAAa,MAAM;;;;;;;;;;;;;IAUxD;;;;;;;OAOG;gBACe,EAAE,aAAa,SAAS,eAAe,MAAM,aAAa,MAAM;;;;;;;;;;;;;IAsBlF,kEAAkE;gBAChD,EAAE,aAAa,SAAS,eAAe,MAAM,UAAU,MAAM,SAAS,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;;;;;;;;;IAyBrG,wEAAwE;eACvD,EAAE,aAAa,SAAS,eAAe,MAAM,UAAU,MAAM;;;;;;;;;;;;;;;;;;;;;;;IAyB9E,2FAA2F;uBAClE,EAAE,eAAe,MAAM,UAAU,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAUvF,wFAAwF;+BAC7D,MAAM,UAAU,MAAM;;;;;;EAMpD;AACD,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAA"}
@@ -0,0 +1,83 @@
1
+ CREATE TABLE IF NOT EXISTS "mod_quire"."databases" (
2
+ "id" uuid PRIMARY KEY DEFAULT uuidv7() NOT NULL,
3
+ "workspace_id" uuid NOT NULL,
4
+ "space_id" uuid NOT NULL,
5
+ "page_id" uuid NOT NULL,
6
+ "name" text DEFAULT '' NOT NULL,
7
+ "description" text DEFAULT '' NOT NULL,
8
+ "inline" boolean DEFAULT false NOT NULL,
9
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
10
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
11
+ );
12
+ --> statement-breakpoint
13
+ CREATE TABLE IF NOT EXISTS "mod_quire"."properties" (
14
+ "id" uuid PRIMARY KEY DEFAULT uuidv7() NOT NULL,
15
+ "workspace_id" uuid NOT NULL,
16
+ "database_id" uuid NOT NULL,
17
+ "key" text NOT NULL,
18
+ "name" text NOT NULL,
19
+ "type" text NOT NULL,
20
+ "config" jsonb DEFAULT '{}'::jsonb NOT NULL,
21
+ "position" text NOT NULL,
22
+ "hidden" boolean DEFAULT false NOT NULL,
23
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL
24
+ );
25
+ --> statement-breakpoint
26
+ CREATE TABLE IF NOT EXISTS "mod_quire"."relations" (
27
+ "id" uuid PRIMARY KEY DEFAULT uuidv7() NOT NULL,
28
+ "workspace_id" uuid NOT NULL,
29
+ "property_id" uuid NOT NULL,
30
+ "from_page_id" uuid NOT NULL,
31
+ "to_page_id" uuid NOT NULL,
32
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL
33
+ );
34
+ --> statement-breakpoint
35
+ CREATE TABLE IF NOT EXISTS "mod_quire"."views" (
36
+ "id" uuid PRIMARY KEY DEFAULT uuidv7() NOT NULL,
37
+ "workspace_id" uuid NOT NULL,
38
+ "database_id" uuid NOT NULL,
39
+ "name" text NOT NULL,
40
+ "kind" text DEFAULT 'table' NOT NULL,
41
+ "config" jsonb DEFAULT '{}'::jsonb NOT NULL,
42
+ "position" text NOT NULL,
43
+ "is_default" boolean DEFAULT false NOT NULL,
44
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
45
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
46
+ );
47
+ --> statement-breakpoint
48
+ CREATE INDEX IF NOT EXISTS "databases_ws_page_idx" ON "mod_quire"."databases" USING btree ("workspace_id","page_id");--> statement-breakpoint
49
+ CREATE UNIQUE INDEX IF NOT EXISTS "properties_db_key_uq" ON "mod_quire"."properties" USING btree ("workspace_id","database_id","key");--> statement-breakpoint
50
+ CREATE INDEX IF NOT EXISTS "properties_ws_db_idx" ON "mod_quire"."properties" USING btree ("workspace_id","database_id","position");--> statement-breakpoint
51
+ CREATE UNIQUE INDEX IF NOT EXISTS "relations_uq" ON "mod_quire"."relations" USING btree ("workspace_id","property_id","from_page_id","to_page_id");--> statement-breakpoint
52
+ CREATE INDEX IF NOT EXISTS "relations_ws_from_idx" ON "mod_quire"."relations" USING btree ("workspace_id","from_page_id");--> statement-breakpoint
53
+ CREATE INDEX IF NOT EXISTS "relations_ws_to_idx" ON "mod_quire"."relations" USING btree ("workspace_id","to_page_id");--> statement-breakpoint
54
+ CREATE INDEX IF NOT EXISTS "views_ws_db_idx" ON "mod_quire"."views" USING btree ("workspace_id","database_id","position");--> statement-breakpoint
55
+
56
+ -- Row-level security, the same triple every tenant table gets.
57
+ ALTER TABLE "mod_quire"."databases" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
58
+ ALTER TABLE "mod_quire"."databases" FORCE ROW LEVEL SECURITY;--> statement-breakpoint
59
+ DROP POLICY IF EXISTS "databases_ws_isolation" ON "mod_quire"."databases";--> statement-breakpoint
60
+ CREATE POLICY "databases_ws_isolation" ON "mod_quire"."databases"
61
+ USING (workspace_id::text = current_setting('app.workspace_id', true))
62
+ WITH CHECK (workspace_id::text = current_setting('app.workspace_id', true));--> statement-breakpoint
63
+
64
+ ALTER TABLE "mod_quire"."properties" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
65
+ ALTER TABLE "mod_quire"."properties" FORCE ROW LEVEL SECURITY;--> statement-breakpoint
66
+ DROP POLICY IF EXISTS "properties_ws_isolation" ON "mod_quire"."properties";--> statement-breakpoint
67
+ CREATE POLICY "properties_ws_isolation" ON "mod_quire"."properties"
68
+ USING (workspace_id::text = current_setting('app.workspace_id', true))
69
+ WITH CHECK (workspace_id::text = current_setting('app.workspace_id', true));--> statement-breakpoint
70
+
71
+ ALTER TABLE "mod_quire"."views" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
72
+ ALTER TABLE "mod_quire"."views" FORCE ROW LEVEL SECURITY;--> statement-breakpoint
73
+ DROP POLICY IF EXISTS "views_ws_isolation" ON "mod_quire"."views";--> statement-breakpoint
74
+ CREATE POLICY "views_ws_isolation" ON "mod_quire"."views"
75
+ USING (workspace_id::text = current_setting('app.workspace_id', true))
76
+ WITH CHECK (workspace_id::text = current_setting('app.workspace_id', true));--> statement-breakpoint
77
+
78
+ ALTER TABLE "mod_quire"."relations" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
79
+ ALTER TABLE "mod_quire"."relations" FORCE ROW LEVEL SECURITY;--> statement-breakpoint
80
+ DROP POLICY IF EXISTS "relations_ws_isolation" ON "mod_quire"."relations";--> statement-breakpoint
81
+ CREATE POLICY "relations_ws_isolation" ON "mod_quire"."relations"
82
+ USING (workspace_id::text = current_setting('app.workspace_id', true))
83
+ WITH CHECK (workspace_id::text = current_setting('app.workspace_id', true));
@@ -0,0 +1,6 @@
1
+ -- Additive: nullable column and defaults, so the image before this one still reads the table.
2
+ ALTER TABLE "mod_quire"."pages" ADD COLUMN IF NOT EXISTS "database_id" uuid;--> statement-breakpoint
3
+ ALTER TABLE "mod_quire"."pages" ADD COLUMN IF NOT EXISTS "props" jsonb DEFAULT '{}'::jsonb NOT NULL;--> statement-breakpoint
4
+ ALTER TABLE "mod_quire"."pages" ADD COLUMN IF NOT EXISTS "computed" jsonb DEFAULT '{}'::jsonb NOT NULL;--> statement-breakpoint
5
+ CREATE INDEX IF NOT EXISTS "pages_ws_database_idx" ON "mod_quire"."pages" USING btree ("workspace_id","database_id","id");--> statement-breakpoint
6
+ CREATE INDEX IF NOT EXISTS "pages_props_idx" ON "mod_quire"."pages" USING gin ("props");