@byline/core 4.6.1 → 4.7.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.
@@ -0,0 +1,215 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ *
8
+ * The dialect-independent column manifest for the EAV store tables.
9
+ *
10
+ * Every adapter's UNION ALL over its `store_*` tables projects into the same
11
+ * unified row shape (see `UnifiedFieldValue`). Instead of each adapter
12
+ * hand-maintaining its own list of columns, adapters generate their SELECT
13
+ * lists from this single manifest — adding a column or a new store table is
14
+ * a one-line change here rather than N hand-synchronized SQL fragments.
15
+ *
16
+ * This module is pure data: no SQL, no drizzle-orm, no pg. Each adapter owns
17
+ * its own SQL generation (e.g. `@byline/db-postgres`'s `storeSelectList()` +
18
+ * `pgNullCast()`) consuming this manifest.
19
+ */
20
+ /** Store table names, keyed by StoreType. Shared naming convention across adapters. */
21
+ export const storeTableNames = {
22
+ text: 'byline_store_text',
23
+ numeric: 'byline_store_numeric',
24
+ boolean: 'byline_store_boolean',
25
+ datetime: 'byline_store_datetime',
26
+ json: 'byline_store_json',
27
+ relation: 'byline_store_relation',
28
+ file: 'byline_store_file',
29
+ };
30
+ /**
31
+ * Canonical column order for the unified UNION ALL output.
32
+ *
33
+ * The first 7 columns are shared across all store tables (base columns).
34
+ * The remaining columns are type-specific — each one declares which store
35
+ * table(s) provide it and what source column to read.
36
+ */
37
+ export const storeColumnManifest = [
38
+ // -- Base columns (provided by every store table) -------------------------
39
+ { name: 'id', nullCast: 'uuid' },
40
+ { name: 'document_version_id', nullCast: 'uuid' },
41
+ { name: 'collection_id', nullCast: 'uuid' },
42
+ // field_type is handled specially — see each adapter's SELECT-list builder.
43
+ { name: 'field_path', nullCast: 'varchar' },
44
+ { name: 'field_name', nullCast: 'varchar' },
45
+ { name: 'locale', nullCast: 'varchar' },
46
+ { name: 'parent_path', nullCast: 'varchar' },
47
+ // -- Text -----------------------------------------------------------------
48
+ {
49
+ name: 'text_value',
50
+ nullCast: 'text',
51
+ sources: { text: 'value' },
52
+ },
53
+ // -- Boolean --------------------------------------------------------------
54
+ {
55
+ name: 'boolean_value',
56
+ nullCast: 'boolean',
57
+ sources: { boolean: 'value' },
58
+ },
59
+ // -- JSON -----------------------------------------------------------------
60
+ {
61
+ name: 'json_value',
62
+ nullCast: 'jsonb',
63
+ sources: { json: 'value' },
64
+ },
65
+ // -- DateTime -------------------------------------------------------------
66
+ {
67
+ name: 'date_type',
68
+ nullCast: 'varchar',
69
+ sources: { datetime: 'date_type' },
70
+ },
71
+ {
72
+ name: 'value_date',
73
+ nullCast: 'date',
74
+ sources: { datetime: 'value_date' },
75
+ },
76
+ {
77
+ name: 'value_time',
78
+ nullCast: 'time',
79
+ sources: { datetime: 'value_time' },
80
+ },
81
+ {
82
+ name: 'value_timestamp_tz',
83
+ nullCast: 'timestamp',
84
+ sources: { datetime: 'value_timestamp_tz' },
85
+ },
86
+ // -- File -----------------------------------------------------------------
87
+ {
88
+ name: 'file_id',
89
+ nullCast: 'uuid',
90
+ sources: { file: 'file_id' },
91
+ },
92
+ {
93
+ name: 'filename',
94
+ nullCast: 'varchar',
95
+ sources: { file: 'filename' },
96
+ },
97
+ {
98
+ name: 'original_filename',
99
+ nullCast: 'varchar',
100
+ sources: { file: 'original_filename' },
101
+ },
102
+ {
103
+ name: 'mime_type',
104
+ nullCast: 'varchar',
105
+ sources: { file: 'mime_type' },
106
+ },
107
+ {
108
+ name: 'file_size',
109
+ nullCast: 'bigint',
110
+ sources: { file: 'file_size' },
111
+ },
112
+ {
113
+ name: 'storage_provider',
114
+ nullCast: 'varchar',
115
+ sources: { file: 'storage_provider' },
116
+ },
117
+ {
118
+ name: 'storage_path',
119
+ nullCast: 'text',
120
+ sources: { file: 'storage_path' },
121
+ },
122
+ {
123
+ name: 'storage_url',
124
+ nullCast: 'text',
125
+ sources: { file: 'storage_url' },
126
+ },
127
+ {
128
+ name: 'file_hash',
129
+ nullCast: 'varchar',
130
+ sources: { file: 'file_hash' },
131
+ },
132
+ {
133
+ name: 'image_width',
134
+ nullCast: 'integer',
135
+ sources: { file: 'image_width' },
136
+ },
137
+ {
138
+ name: 'image_height',
139
+ nullCast: 'integer',
140
+ sources: { file: 'image_height' },
141
+ },
142
+ {
143
+ name: 'image_format',
144
+ nullCast: 'varchar',
145
+ sources: { file: 'image_format' },
146
+ },
147
+ {
148
+ name: 'processing_status',
149
+ nullCast: 'varchar',
150
+ sources: { file: 'processing_status' },
151
+ },
152
+ {
153
+ name: 'thumbnail_generated',
154
+ nullCast: 'boolean',
155
+ sources: { file: 'thumbnail_generated' },
156
+ },
157
+ {
158
+ name: 'variants',
159
+ nullCast: 'jsonb',
160
+ sources: { file: 'variants' },
161
+ },
162
+ // -- Relation -------------------------------------------------------------
163
+ {
164
+ name: 'target_document_id',
165
+ nullCast: 'uuid',
166
+ sources: { relation: 'target_document_id' },
167
+ },
168
+ {
169
+ name: 'target_collection_id',
170
+ nullCast: 'uuid',
171
+ sources: { relation: 'target_collection_id' },
172
+ },
173
+ {
174
+ name: 'relationship_type',
175
+ nullCast: 'varchar',
176
+ sources: { relation: 'relationship_type' },
177
+ },
178
+ {
179
+ name: 'cascade_delete',
180
+ nullCast: 'boolean',
181
+ sources: { relation: 'cascade_delete' },
182
+ },
183
+ // -- JSON extras ----------------------------------------------------------
184
+ {
185
+ name: 'json_schema',
186
+ nullCast: 'varchar',
187
+ sources: { json: 'json_schema' },
188
+ },
189
+ {
190
+ name: 'object_keys',
191
+ nullCast: 'text[]',
192
+ sources: { json: 'object_keys' },
193
+ },
194
+ // -- Numeric --------------------------------------------------------------
195
+ {
196
+ name: 'number_type',
197
+ nullCast: 'varchar',
198
+ sources: { numeric: 'number_type' },
199
+ },
200
+ {
201
+ name: 'value_integer',
202
+ nullCast: 'integer',
203
+ sources: { numeric: 'value_integer' },
204
+ },
205
+ {
206
+ name: 'value_decimal',
207
+ nullCast: 'decimal',
208
+ sources: { numeric: 'value_decimal' },
209
+ },
210
+ {
211
+ name: 'value_float',
212
+ nullCast: 'real',
213
+ sources: { numeric: 'value_float' },
214
+ },
215
+ ];
@@ -0,0 +1,8 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ export {};
@@ -0,0 +1,128 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ import { describe, expect, it } from 'vitest';
9
+ import { ALL_STORE_TYPES } from './field-store-map.js';
10
+ import { storeColumnManifest, storeTableNames } from './store-manifest.js';
11
+ /**
12
+ * Data-level pins for the shared store-column manifest. SQL-generation
13
+ * behaviour (buildSelectList, NULL casts, field_type literal placement) is
14
+ * exercised by the Postgres adapter's own test — this file only pins the
15
+ * dialect-independent manifest data every adapter consumes.
16
+ */
17
+ describe('store-manifest', () => {
18
+ it('pins the manifest column count', () => {
19
+ expect(storeColumnManifest.length).toBe(39);
20
+ });
21
+ it('pins the manifest column order', () => {
22
+ expect(storeColumnManifest.map((col) => col.name)).toEqual([
23
+ 'id',
24
+ 'document_version_id',
25
+ 'collection_id',
26
+ 'field_path',
27
+ 'field_name',
28
+ 'locale',
29
+ 'parent_path',
30
+ 'text_value',
31
+ 'boolean_value',
32
+ 'json_value',
33
+ 'date_type',
34
+ 'value_date',
35
+ 'value_time',
36
+ 'value_timestamp_tz',
37
+ 'file_id',
38
+ 'filename',
39
+ 'original_filename',
40
+ 'mime_type',
41
+ 'file_size',
42
+ 'storage_provider',
43
+ 'storage_path',
44
+ 'storage_url',
45
+ 'file_hash',
46
+ 'image_width',
47
+ 'image_height',
48
+ 'image_format',
49
+ 'processing_status',
50
+ 'thumbnail_generated',
51
+ 'variants',
52
+ 'target_document_id',
53
+ 'target_collection_id',
54
+ 'relationship_type',
55
+ 'cascade_delete',
56
+ 'json_schema',
57
+ 'object_keys',
58
+ 'number_type',
59
+ 'value_integer',
60
+ 'value_decimal',
61
+ 'value_float',
62
+ ]);
63
+ });
64
+ it('has a table name for every StoreType', () => {
65
+ for (const storeType of ALL_STORE_TYPES) {
66
+ expect(storeTableNames[storeType], `Missing table name for ${storeType}`).toBeTruthy();
67
+ }
68
+ });
69
+ it('every StoreType has at least one sources entry for its value columns', () => {
70
+ for (const storeType of ALL_STORE_TYPES) {
71
+ const owned = storeColumnManifest.filter((col) => col.sources?.[storeType] != null);
72
+ expect(owned.length, `Expected ${storeType} to own at least one manifest column`).toBeGreaterThan(0);
73
+ }
74
+ });
75
+ it('pins the exact set of columns each StoreType owns', () => {
76
+ const ownedNames = (storeType) => storeColumnManifest.filter((col) => col.sources?.[storeType] != null).map((col) => col.name);
77
+ expect(ownedNames('text')).toEqual(['text_value']);
78
+ expect(ownedNames('boolean')).toEqual(['boolean_value']);
79
+ expect(ownedNames('json')).toEqual(['json_value', 'json_schema', 'object_keys']);
80
+ expect(ownedNames('datetime')).toEqual([
81
+ 'date_type',
82
+ 'value_date',
83
+ 'value_time',
84
+ 'value_timestamp_tz',
85
+ ]);
86
+ expect(ownedNames('relation')).toEqual([
87
+ 'target_document_id',
88
+ 'target_collection_id',
89
+ 'relationship_type',
90
+ 'cascade_delete',
91
+ ]);
92
+ expect(ownedNames('numeric')).toEqual([
93
+ 'number_type',
94
+ 'value_integer',
95
+ 'value_decimal',
96
+ 'value_float',
97
+ ]);
98
+ expect(ownedNames('file')).toEqual([
99
+ 'file_id',
100
+ 'filename',
101
+ 'original_filename',
102
+ 'mime_type',
103
+ 'file_size',
104
+ 'storage_provider',
105
+ 'storage_path',
106
+ 'storage_url',
107
+ 'file_hash',
108
+ 'image_width',
109
+ 'image_height',
110
+ 'image_format',
111
+ 'processing_status',
112
+ 'thumbnail_generated',
113
+ 'variants',
114
+ ]);
115
+ });
116
+ it('base columns (no sources) are id, document_version_id, collection_id, field_path, field_name, locale, parent_path', () => {
117
+ const baseNames = storeColumnManifest.filter((col) => !col.sources).map((col) => col.name);
118
+ expect(baseNames).toEqual([
119
+ 'id',
120
+ 'document_version_id',
121
+ 'collection_id',
122
+ 'field_path',
123
+ 'field_name',
124
+ 'locale',
125
+ 'parent_path',
126
+ ]);
127
+ });
128
+ });
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@byline/core",
3
3
  "private": false,
4
4
  "license": "MPL-2.0",
5
- "version": "4.6.1",
5
+ "version": "4.7.0",
6
6
  "engines": {
7
7
  "node": ">=20.9.0"
8
8
  },
@@ -80,8 +80,9 @@
80
80
  "dotenv": "^17.4.2",
81
81
  "pino": "^10.3.1",
82
82
  "sharp": "^0.35.3",
83
+ "uuid": "^14.0.1",
83
84
  "zod": "^4.4.3",
84
- "@byline/auth": "4.6.1"
85
+ "@byline/auth": "4.7.0"
85
86
  },
86
87
  "devDependencies": {
87
88
  "@biomejs/biome": "2.5.4",