@byline/db-postgres 0.9.3

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 (99) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +18 -0
  3. package/dist/database/schema/auth.d.ts +857 -0
  4. package/dist/database/schema/auth.d.ts.map +1 -0
  5. package/dist/database/schema/auth.js +176 -0
  6. package/dist/database/schema/auth.js.map +1 -0
  7. package/dist/database/schema/index.d.ts +2955 -0
  8. package/dist/database/schema/index.d.ts.map +1 -0
  9. package/dist/database/schema/index.js +500 -0
  10. package/dist/database/schema/index.js.map +1 -0
  11. package/dist/index.d.ts +31 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +30 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/lib/test-helper.d.ts +17 -0
  16. package/dist/lib/test-helper.d.ts.map +1 -0
  17. package/dist/lib/test-helper.js +47 -0
  18. package/dist/lib/test-helper.js.map +1 -0
  19. package/dist/modules/admin/admin-permissions-repository.d.ts +17 -0
  20. package/dist/modules/admin/admin-permissions-repository.d.ts.map +1 -0
  21. package/dist/modules/admin/admin-permissions-repository.js +76 -0
  22. package/dist/modules/admin/admin-permissions-repository.js.map +1 -0
  23. package/dist/modules/admin/admin-roles-repository.d.ts +12 -0
  24. package/dist/modules/admin/admin-roles-repository.d.ts.map +1 -0
  25. package/dist/modules/admin/admin-roles-repository.js +168 -0
  26. package/dist/modules/admin/admin-roles-repository.js.map +1 -0
  27. package/dist/modules/admin/admin-store.d.ts +20 -0
  28. package/dist/modules/admin/admin-store.d.ts.map +1 -0
  29. package/dist/modules/admin/admin-store.js +28 -0
  30. package/dist/modules/admin/admin-store.js.map +1 -0
  31. package/dist/modules/admin/admin-users-repository.d.ts +12 -0
  32. package/dist/modules/admin/admin-users-repository.d.ts.map +1 -0
  33. package/dist/modules/admin/admin-users-repository.js +208 -0
  34. package/dist/modules/admin/admin-users-repository.js.map +1 -0
  35. package/dist/modules/admin/index.d.ts +27 -0
  36. package/dist/modules/admin/index.d.ts.map +1 -0
  37. package/dist/modules/admin/index.js +27 -0
  38. package/dist/modules/admin/index.js.map +1 -0
  39. package/dist/modules/admin/refresh-tokens-repository.d.ts +16 -0
  40. package/dist/modules/admin/refresh-tokens-repository.d.ts.map +1 -0
  41. package/dist/modules/admin/refresh-tokens-repository.js +132 -0
  42. package/dist/modules/admin/refresh-tokens-repository.js.map +1 -0
  43. package/dist/modules/admin/tests/auth-integration.test.d.ts +9 -0
  44. package/dist/modules/admin/tests/auth-integration.test.d.ts.map +1 -0
  45. package/dist/modules/admin/tests/auth-integration.test.js +392 -0
  46. package/dist/modules/admin/tests/auth-integration.test.js.map +1 -0
  47. package/dist/modules/admin/tests/session-provider.test.d.ts +9 -0
  48. package/dist/modules/admin/tests/session-provider.test.d.ts.map +1 -0
  49. package/dist/modules/admin/tests/session-provider.test.js +370 -0
  50. package/dist/modules/admin/tests/session-provider.test.js.map +1 -0
  51. package/dist/modules/storage/@types.d.ts +116 -0
  52. package/dist/modules/storage/@types.d.ts.map +1 -0
  53. package/dist/modules/storage/@types.js +9 -0
  54. package/dist/modules/storage/@types.js.map +1 -0
  55. package/dist/modules/storage/storage-commands.d.ts +136 -0
  56. package/dist/modules/storage/storage-commands.d.ts.map +1 -0
  57. package/dist/modules/storage/storage-commands.js +272 -0
  58. package/dist/modules/storage/storage-commands.js.map +1 -0
  59. package/dist/modules/storage/storage-flatten.d.ts +19 -0
  60. package/dist/modules/storage/storage-flatten.d.ts.map +1 -0
  61. package/dist/modules/storage/storage-flatten.js +261 -0
  62. package/dist/modules/storage/storage-flatten.js.map +1 -0
  63. package/dist/modules/storage/storage-insert.d.ts +22 -0
  64. package/dist/modules/storage/storage-insert.d.ts.map +1 -0
  65. package/dist/modules/storage/storage-insert.js +115 -0
  66. package/dist/modules/storage/storage-insert.js.map +1 -0
  67. package/dist/modules/storage/storage-queries.d.ts +377 -0
  68. package/dist/modules/storage/storage-queries.d.ts.map +1 -0
  69. package/dist/modules/storage/storage-queries.js +976 -0
  70. package/dist/modules/storage/storage-queries.js.map +1 -0
  71. package/dist/modules/storage/storage-restore.d.ts +19 -0
  72. package/dist/modules/storage/storage-restore.d.ts.map +1 -0
  73. package/dist/modules/storage/storage-restore.js +350 -0
  74. package/dist/modules/storage/storage-restore.js.map +1 -0
  75. package/dist/modules/storage/storage-store-manifest.d.ts +71 -0
  76. package/dist/modules/storage/storage-store-manifest.d.ts.map +1 -0
  77. package/dist/modules/storage/storage-store-manifest.js +294 -0
  78. package/dist/modules/storage/storage-store-manifest.js.map +1 -0
  79. package/dist/modules/storage/storage-utils.d.ts +23 -0
  80. package/dist/modules/storage/storage-utils.d.ts.map +1 -0
  81. package/dist/modules/storage/storage-utils.js +72 -0
  82. package/dist/modules/storage/storage-utils.js.map +1 -0
  83. package/dist/modules/storage/tests/storage-field-types.test.d.ts +9 -0
  84. package/dist/modules/storage/tests/storage-field-types.test.d.ts.map +1 -0
  85. package/dist/modules/storage/tests/storage-field-types.test.js +146 -0
  86. package/dist/modules/storage/tests/storage-field-types.test.js.map +1 -0
  87. package/dist/modules/storage/tests/storage-flatten-reconstruct.test.d.ts +9 -0
  88. package/dist/modules/storage/tests/storage-flatten-reconstruct.test.d.ts.map +1 -0
  89. package/dist/modules/storage/tests/storage-flatten-reconstruct.test.js +327 -0
  90. package/dist/modules/storage/tests/storage-flatten-reconstruct.test.js.map +1 -0
  91. package/dist/modules/storage/tests/storage-store-manifest.test.d.ts +9 -0
  92. package/dist/modules/storage/tests/storage-store-manifest.test.d.ts.map +1 -0
  93. package/dist/modules/storage/tests/storage-store-manifest.test.js +141 -0
  94. package/dist/modules/storage/tests/storage-store-manifest.test.js.map +1 -0
  95. package/dist/modules/storage/tests/storage-versioning.test.d.ts +9 -0
  96. package/dist/modules/storage/tests/storage-versioning.test.d.ts.map +1 -0
  97. package/dist/modules/storage/tests/storage-versioning.test.js +336 -0
  98. package/dist/modules/storage/tests/storage-versioning.test.js.map +1 -0
  99. package/package.json +81 -0
@@ -0,0 +1,136 @@
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 type { CollectionDefinition, ICollectionCommands, IDocumentCommands } from '@byline/core';
9
+ import type { NodePgDatabase } from 'drizzle-orm/node-postgres';
10
+ import type * as schema from '../../database/schema/index.js';
11
+ type DatabaseConnection = NodePgDatabase<typeof schema>;
12
+ /**
13
+ * CollectionCommands
14
+ */
15
+ export declare class CollectionCommands implements ICollectionCommands {
16
+ private db;
17
+ constructor(db: DatabaseConnection);
18
+ create(path: string, config: CollectionDefinition, opts?: {
19
+ version?: number;
20
+ schemaHash?: string;
21
+ }): Promise<{
22
+ id: string;
23
+ created_at: Date | null;
24
+ updated_at: Date | null;
25
+ path: string;
26
+ singular: string;
27
+ plural: string;
28
+ config: unknown;
29
+ version: number;
30
+ schema_hash: string | null;
31
+ }[]>;
32
+ update(id: string, patch: {
33
+ config?: CollectionDefinition;
34
+ version?: number;
35
+ schemaHash?: string;
36
+ }): Promise<{
37
+ id: string;
38
+ path: string;
39
+ singular: string;
40
+ plural: string;
41
+ config: unknown;
42
+ version: number;
43
+ schema_hash: string | null;
44
+ created_at: Date | null;
45
+ updated_at: Date | null;
46
+ }[]>;
47
+ delete(id: string): Promise<import("pg").QueryResult<never>>;
48
+ }
49
+ /**
50
+ * DocumentCommands
51
+ */
52
+ export declare class DocumentCommands implements IDocumentCommands {
53
+ private db;
54
+ constructor(db: DatabaseConnection);
55
+ /**
56
+ * createDocumentVersion
57
+ *
58
+ * Creates a new document or a new version of an existing document.
59
+ *
60
+ * @param params - Options for creating the document
61
+ * @returns The created document and the number of field values inserted
62
+ */
63
+ createDocumentVersion(params: {
64
+ documentId?: string;
65
+ collectionId: string;
66
+ collectionVersion: number;
67
+ collectionConfig: CollectionDefinition;
68
+ action: string;
69
+ documentData: any;
70
+ path: string;
71
+ locale?: string;
72
+ status?: string;
73
+ createdBy?: string;
74
+ previousVersionId?: string;
75
+ }): Promise<{
76
+ document: {
77
+ id: string;
78
+ created_at: Date | null;
79
+ updated_at: Date | null;
80
+ path: string;
81
+ collection_id: string;
82
+ document_id: string;
83
+ collection_version: number;
84
+ doc: unknown;
85
+ event_type: string;
86
+ status: string | null;
87
+ is_deleted: boolean | null;
88
+ created_by: string | null;
89
+ change_summary: string | null;
90
+ };
91
+ fieldCount: number;
92
+ }>;
93
+ /**
94
+ * setDocumentStatus
95
+ *
96
+ * Mutate the status field on an existing document version row.
97
+ * This is the one case where we UPDATE a version in-place — status is
98
+ * lifecycle metadata, not content.
99
+ */
100
+ setDocumentStatus(params: {
101
+ document_version_id: string;
102
+ status: string;
103
+ }): Promise<void>;
104
+ /**
105
+ * archivePublishedVersions
106
+ *
107
+ * Set ALL versions of a document that currently have `currentStatus`
108
+ * (defaults to 'published') to 'archived'. Optionally exclude a specific
109
+ * version so the caller can protect the version it is about to publish.
110
+ *
111
+ * Returns the number of rows updated.
112
+ */
113
+ archivePublishedVersions(params: {
114
+ document_id: string;
115
+ currentStatus?: string;
116
+ excludeVersionId?: string;
117
+ }): Promise<number>;
118
+ /**
119
+ * softDeleteDocument
120
+ *
121
+ * Mark ALL versions of a document as deleted by setting `is_deleted = true`.
122
+ * The `current_documents` view filters these out, so the document disappears
123
+ * from listings without physically removing data.
124
+ *
125
+ * Returns the number of version rows marked as deleted.
126
+ */
127
+ softDeleteDocument(params: {
128
+ document_id: string;
129
+ }): Promise<number>;
130
+ }
131
+ export declare function createCommandBuilders(db: DatabaseConnection): {
132
+ collections: CollectionCommands;
133
+ documents: DocumentCommands;
134
+ };
135
+ export {};
136
+ //# sourceMappingURL=storage-commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-commands.d.ts","sourceRoot":"","sources":["../../../src/modules/storage/storage-commands.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAEhG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAmB/D,OAAO,KAAK,KAAK,MAAM,MAAM,gCAAgC,CAAA;AAE7D,KAAK,kBAAkB,GAAG,cAAc,CAAC,OAAO,MAAM,CAAC,CAAA;AAEvD;;GAEG;AACH,qBAAa,kBAAmB,YAAW,mBAAmB;IAChD,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,kBAAkB;IAEpC,MAAM,CACV,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,oBAAoB,EAC5B,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE;;;;;;;;;;;IAgB5C,MAAM,CACV,EAAE,EAAE,MAAM,EACV,KAAK,EAAE;QACL,MAAM,CAAC,EAAE,oBAAoB,CAAA;QAC7B,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,UAAU,CAAC,EAAE,MAAM,CAAA;KACpB;;;;;;;;;;;IASG,MAAM,CAAC,EAAE,EAAE,MAAM;CAGxB;AAED;;GAEG;AACH,qBAAa,gBAAiB,YAAW,iBAAiB;IAC5C,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,kBAAkB;IAE1C;;;;;;;OAOG;IACG,qBAAqB,CAAC,MAAM,EAAE;QAClC,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,YAAY,EAAE,MAAM,CAAA;QACpB,iBAAiB,EAAE,MAAM,CAAA;QACzB,gBAAgB,EAAE,oBAAoB,CAAA;QACtC,MAAM,EAAE,MAAM,CAAA;QACd,YAAY,EAAE,GAAG,CAAA;QACjB,IAAI,EAAE,MAAM,CAAA;QACZ,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,iBAAiB,CAAC,EAAE,MAAM,CAAA;KAC3B;;;;;;;;;;;;;;;;;;IA0KD;;;;;;OAMG;IACG,iBAAiB,CAAC,MAAM,EAAE;QAAE,mBAAmB,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAU/F;;;;;;;;OAQG;IACG,wBAAwB,CAAC,MAAM,EAAE;QACrC,WAAW,EAAE,MAAM,CAAA;QACnB,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAC1B,GAAG,OAAO,CAAC,MAAM,CAAC;IAgBnB;;;;;;;;OAQG;IACG,kBAAkB,CAAC,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC;CAU3E;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,kBAAkB;;;EAK3D"}
@@ -0,0 +1,272 @@
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 { and, eq, ne, sql } from 'drizzle-orm';
9
+ import { v7 as uuidv7 } from 'uuid';
10
+ import { booleanStore, collections, datetimeStore, documents, documentVersions, fileStore, jsonStore, metaStore, numericStore, relationStore, textStore, } from '../../database/schema/index.js';
11
+ import { flattenFieldSetData } from './storage-flatten.js';
12
+ import { prepareFieldInsertBuckets } from './storage-insert.js';
13
+ import { getFirstOrThrow } from './storage-utils.js';
14
+ /**
15
+ * CollectionCommands
16
+ */
17
+ export class CollectionCommands {
18
+ db;
19
+ constructor(db) {
20
+ this.db = db;
21
+ }
22
+ async create(path, config, opts) {
23
+ return await this.db
24
+ .insert(collections)
25
+ .values({
26
+ id: uuidv7(),
27
+ path,
28
+ singular: config.labels.singular || path, // Default to path if singular not provided
29
+ plural: config.labels.plural || `${path}s`, // Default to pluralized path if not
30
+ config,
31
+ ...(opts?.version !== undefined ? { version: opts.version } : {}),
32
+ ...(opts?.schemaHash !== undefined ? { schema_hash: opts.schemaHash } : {}),
33
+ })
34
+ .returning();
35
+ }
36
+ async update(id, patch) {
37
+ const set = { updated_at: new Date() };
38
+ if (patch.config !== undefined)
39
+ set.config = patch.config;
40
+ if (patch.version !== undefined)
41
+ set.version = patch.version;
42
+ if (patch.schemaHash !== undefined)
43
+ set.schema_hash = patch.schemaHash;
44
+ return await this.db.update(collections).set(set).where(eq(collections.id, id)).returning();
45
+ }
46
+ async delete(id) {
47
+ return await this.db.delete(collections).where(eq(collections.id, id));
48
+ }
49
+ }
50
+ /**
51
+ * DocumentCommands
52
+ */
53
+ export class DocumentCommands {
54
+ db;
55
+ constructor(db) {
56
+ this.db = db;
57
+ }
58
+ /**
59
+ * createDocumentVersion
60
+ *
61
+ * Creates a new document or a new version of an existing document.
62
+ *
63
+ * @param params - Options for creating the document
64
+ * @returns The created document and the number of field values inserted
65
+ */
66
+ async createDocumentVersion(params) {
67
+ return await this.db.transaction(async (tx) => {
68
+ let documentId = params.documentId;
69
+ // 1. Create the main document if needed
70
+ if (documentId == null) {
71
+ documentId = uuidv7();
72
+ const _document = await tx
73
+ .insert(documents)
74
+ .values({
75
+ id: documentId,
76
+ collection_id: params.collectionId,
77
+ })
78
+ .returning()
79
+ .then(getFirstOrThrow('Failed to create document'));
80
+ }
81
+ // 2. Create the document version
82
+ const documentVersion = await tx
83
+ .insert(documentVersions)
84
+ .values({
85
+ id: uuidv7(), // Document version id
86
+ document_id: documentId,
87
+ collection_id: params.collectionId,
88
+ collection_version: params.collectionVersion,
89
+ path: params.path,
90
+ event_type: params.action ?? 'create',
91
+ status: params.status ?? 'draft',
92
+ })
93
+ .returning()
94
+ .then(getFirstOrThrow('Failed to create document version'));
95
+ // 3. Flatten the document data to field values
96
+ const flattenedFields = flattenFieldSetData(params.collectionConfig.fields, params.documentData, params.locale ?? 'all');
97
+ // 4. Batch-insert all field values, grouped by store type
98
+ const storeBuckets = prepareFieldInsertBuckets(flattenedFields, documentVersion.id, params.collectionId);
99
+ if (storeBuckets.text.length > 0) {
100
+ await tx.insert(textStore).values(storeBuckets.text);
101
+ }
102
+ if (storeBuckets.numeric.length > 0) {
103
+ await tx.insert(numericStore).values(storeBuckets.numeric);
104
+ }
105
+ if (storeBuckets.boolean.length > 0) {
106
+ await tx.insert(booleanStore).values(storeBuckets.boolean);
107
+ }
108
+ if (storeBuckets.datetime.length > 0) {
109
+ await tx.insert(datetimeStore).values(storeBuckets.datetime);
110
+ }
111
+ if (storeBuckets.file.length > 0) {
112
+ await tx.insert(fileStore).values(storeBuckets.file);
113
+ }
114
+ if (storeBuckets.relation.length > 0) {
115
+ await tx.insert(relationStore).values(storeBuckets.relation);
116
+ }
117
+ if (storeBuckets.json.length > 0) {
118
+ await tx.insert(jsonStore).values(storeBuckets.json);
119
+ }
120
+ if (storeBuckets.meta.length > 0) {
121
+ await tx.insert(metaStore).values(storeBuckets.meta);
122
+ }
123
+ // 5. Copy field-value rows for other locales from the previous version.
124
+ // When saving in a specific locale (e.g. 'fr'), only rows for that locale
125
+ // and locale='all' are written above. Any existing rows for other locales
126
+ // (e.g. 'en', 'es') from the previous version must be carried forward so
127
+ // per-locale content is not lost under immutable versioning.
128
+ //
129
+ // Each store table is copied in a separate execute() call because
130
+ // node-postgres does not support multiple statements in a single
131
+ // parameterised query. All calls share the same transaction.
132
+ if (params.previousVersionId && params.locale && params.locale !== 'all') {
133
+ const prevId = params.previousVersionId;
134
+ const newId = documentVersion.id;
135
+ const activeLoc = params.locale;
136
+ await tx.execute(sql `
137
+ INSERT INTO byline_store_text
138
+ (id, document_version_id, collection_id, field_path, field_name, locale, parent_path, value, word_count, created_at, updated_at)
139
+ SELECT gen_random_uuid(), ${newId}::uuid, collection_id, field_path, field_name, locale, parent_path, value, word_count, NOW(), NOW()
140
+ FROM byline_store_text
141
+ WHERE document_version_id = ${prevId}::uuid
142
+ AND locale NOT IN ('all', ${activeLoc})
143
+ ON CONFLICT (document_version_id, field_path, locale) DO NOTHING
144
+ `);
145
+ await tx.execute(sql `
146
+ INSERT INTO byline_store_numeric
147
+ (id, document_version_id, collection_id, field_path, field_name, locale, parent_path, number_type, value_integer, value_decimal, value_float, created_at, updated_at)
148
+ SELECT gen_random_uuid(), ${newId}::uuid, collection_id, field_path, field_name, locale, parent_path, number_type, value_integer, value_decimal, value_float, NOW(), NOW()
149
+ FROM byline_store_numeric
150
+ WHERE document_version_id = ${prevId}::uuid
151
+ AND locale NOT IN ('all', ${activeLoc})
152
+ ON CONFLICT (document_version_id, field_path, locale) DO NOTHING
153
+ `);
154
+ await tx.execute(sql `
155
+ INSERT INTO byline_store_boolean
156
+ (id, document_version_id, collection_id, field_path, field_name, locale, parent_path, value, created_at, updated_at)
157
+ SELECT gen_random_uuid(), ${newId}::uuid, collection_id, field_path, field_name, locale, parent_path, value, NOW(), NOW()
158
+ FROM byline_store_boolean
159
+ WHERE document_version_id = ${prevId}::uuid
160
+ AND locale NOT IN ('all', ${activeLoc})
161
+ ON CONFLICT (document_version_id, field_path, locale) DO NOTHING
162
+ `);
163
+ await tx.execute(sql `
164
+ INSERT INTO byline_store_datetime
165
+ (id, document_version_id, collection_id, field_path, field_name, locale, parent_path, date_type, value_date, value_time, value_timestamp_tz, created_at, updated_at)
166
+ SELECT gen_random_uuid(), ${newId}::uuid, collection_id, field_path, field_name, locale, parent_path, date_type, value_date, value_time, value_timestamp_tz, NOW(), NOW()
167
+ FROM byline_store_datetime
168
+ WHERE document_version_id = ${prevId}::uuid
169
+ AND locale NOT IN ('all', ${activeLoc})
170
+ ON CONFLICT (document_version_id, field_path, locale) DO NOTHING
171
+ `);
172
+ await tx.execute(sql `
173
+ INSERT INTO byline_store_json
174
+ (id, document_version_id, collection_id, field_path, field_name, locale, parent_path, value, json_schema, object_keys, created_at, updated_at)
175
+ SELECT gen_random_uuid(), ${newId}::uuid, collection_id, field_path, field_name, locale, parent_path, value, json_schema, object_keys, NOW(), NOW()
176
+ FROM byline_store_json
177
+ WHERE document_version_id = ${prevId}::uuid
178
+ AND locale NOT IN ('all', ${activeLoc})
179
+ ON CONFLICT (document_version_id, field_path, locale) DO NOTHING
180
+ `);
181
+ await tx.execute(sql `
182
+ INSERT INTO byline_store_relation
183
+ (id, document_version_id, collection_id, field_path, field_name, locale, parent_path, target_document_id, target_collection_id, relationship_type, cascade_delete, created_at, updated_at)
184
+ SELECT gen_random_uuid(), ${newId}::uuid, collection_id, field_path, field_name, locale, parent_path, target_document_id, target_collection_id, relationship_type, cascade_delete, NOW(), NOW()
185
+ FROM byline_store_relation
186
+ WHERE document_version_id = ${prevId}::uuid
187
+ AND locale NOT IN ('all', ${activeLoc})
188
+ ON CONFLICT (document_version_id, field_path, locale) DO NOTHING
189
+ `);
190
+ await tx.execute(sql `
191
+ INSERT INTO byline_store_file
192
+ (id, document_version_id, collection_id, field_path, field_name, locale, parent_path, file_id, filename, original_filename, mime_type, file_size, file_hash, storage_provider, storage_path, storage_url, image_width, image_height, image_format, processing_status, thumbnail_generated, created_at, updated_at)
193
+ SELECT gen_random_uuid(), ${newId}::uuid, collection_id, field_path, field_name, locale, parent_path, file_id, filename, original_filename, mime_type, file_size, file_hash, storage_provider, storage_path, storage_url, image_width, image_height, image_format, processing_status, thumbnail_generated, NOW(), NOW()
194
+ FROM byline_store_file
195
+ WHERE document_version_id = ${prevId}::uuid
196
+ AND locale NOT IN ('all', ${activeLoc})
197
+ ON CONFLICT (document_version_id, field_path, locale) DO NOTHING
198
+ `);
199
+ }
200
+ return {
201
+ document: documentVersion,
202
+ fieldCount: flattenedFields.length,
203
+ };
204
+ });
205
+ }
206
+ /**
207
+ * setDocumentStatus
208
+ *
209
+ * Mutate the status field on an existing document version row.
210
+ * This is the one case where we UPDATE a version in-place — status is
211
+ * lifecycle metadata, not content.
212
+ */
213
+ async setDocumentStatus(params) {
214
+ await this.db
215
+ .update(documentVersions)
216
+ .set({
217
+ status: params.status,
218
+ updated_at: new Date(),
219
+ })
220
+ .where(eq(documentVersions.id, params.document_version_id));
221
+ }
222
+ /**
223
+ * archivePublishedVersions
224
+ *
225
+ * Set ALL versions of a document that currently have `currentStatus`
226
+ * (defaults to 'published') to 'archived'. Optionally exclude a specific
227
+ * version so the caller can protect the version it is about to publish.
228
+ *
229
+ * Returns the number of rows updated.
230
+ */
231
+ async archivePublishedVersions(params) {
232
+ const targetStatus = params.currentStatus ?? 'published';
233
+ const conditions = [
234
+ eq(documentVersions.document_id, params.document_id),
235
+ eq(documentVersions.status, targetStatus),
236
+ ];
237
+ if (params.excludeVersionId) {
238
+ conditions.push(ne(documentVersions.id, params.excludeVersionId));
239
+ }
240
+ const result = await this.db
241
+ .update(documentVersions)
242
+ .set({ status: 'archived', updated_at: new Date() })
243
+ .where(and(...conditions));
244
+ return result.rowCount ?? 0;
245
+ }
246
+ /**
247
+ * softDeleteDocument
248
+ *
249
+ * Mark ALL versions of a document as deleted by setting `is_deleted = true`.
250
+ * The `current_documents` view filters these out, so the document disappears
251
+ * from listings without physically removing data.
252
+ *
253
+ * Returns the number of version rows marked as deleted.
254
+ */
255
+ async softDeleteDocument(params) {
256
+ const result = await this.db
257
+ .update(documentVersions)
258
+ .set({
259
+ is_deleted: true,
260
+ updated_at: new Date(),
261
+ })
262
+ .where(eq(documentVersions.document_id, params.document_id));
263
+ return result.rowCount ?? 0;
264
+ }
265
+ }
266
+ export function createCommandBuilders(db) {
267
+ return {
268
+ collections: new CollectionCommands(db),
269
+ documents: new DocumentCommands(db),
270
+ };
271
+ }
272
+ //# sourceMappingURL=storage-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-commands.js","sourceRoot":"","sources":["../../../src/modules/storage/storage-commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
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 type { FieldSet } from '@byline/core';
9
+ import type { FlattenedFieldValue } from './@types.js';
10
+ /**
11
+ * Main entrypoint for flattening a document's (nested) field data into a flat
12
+ * array of field values.
13
+ *
14
+ * @param fields - The field definitions for the collection.
15
+ * @param data - The document's field data to flatten.
16
+ * @param locale - The locale to flatten for (or 'all' to flatten all locales).
17
+ */
18
+ export declare const flattenFieldSetData: (fields: FieldSet, data: unknown, locale: string) => FlattenedFieldValue[];
19
+ //# sourceMappingURL=storage-flatten.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-flatten.d.ts","sourceRoot":"","sources":["../../../src/modules/storage/storage-flatten.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAEV,QAAQ,EAIT,MAAM,cAAc,CAAA;AAIrB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAOtD;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,QAAQ,EAChB,MAAM,OAAO,EACb,QAAQ,MAAM,KACb,mBAAmB,EAErB,CAAA"}