opacacms 0.3.16 → 0.3.18

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 (134) hide show
  1. package/dist/admin/{stores → features/collections}/admin-queries.d.ts +1 -1
  2. package/dist/admin/{ui/views → features/collections}/collection-list-view.d.ts +1 -1
  3. package/dist/admin/{ui/views → features/collections}/document-edit-view.d.ts +2 -1
  4. package/dist/admin/{ui/views → features/collections}/global-edit-view.d.ts +1 -1
  5. package/dist/admin/{ui/components → features/collections}/versions-sheet.d.ts +3 -3
  6. package/dist/admin/{ui/views → features/dashboard}/dashboard-view.d.ts +1 -1
  7. package/dist/admin/{ui/components/media/AssetManagerModal.d.ts → features/media/components/asset-manager-modal.d.ts} +1 -2
  8. package/dist/admin/features/media/media-registry-view.d.ts +7 -0
  9. package/dist/admin/{ui/components/PluginSettingsForm.d.ts → features/settings/plugin-settings-form.d.ts} +3 -3
  10. package/dist/admin/{ui/views → features/settings}/settings-view.d.ts +2 -2
  11. package/dist/admin/{stores → features/ui-shell}/config.d.ts +1 -1
  12. package/dist/admin/{stores → features/ui-shell}/ui.d.ts +1 -1
  13. package/dist/admin/index.d.ts +8 -8
  14. package/dist/admin/index.js +4 -4
  15. package/dist/admin/ui/{components/ui → core}/blocks.d.ts +1 -1
  16. package/dist/admin/ui/core/breadcrumbs.d.ts +21 -0
  17. package/dist/admin/ui/{components/ui → core}/button.d.ts +4 -4
  18. package/dist/admin/ui/{components/ui → core}/collapsible.d.ts +2 -2
  19. package/dist/admin/ui/core/context-menu.d.ts +29 -0
  20. package/dist/admin/ui/core/dialog.d.ts +20 -0
  21. package/dist/admin/ui/{components/ui → core}/group.d.ts +2 -2
  22. package/dist/admin/ui/core/index.d.ts +17 -0
  23. package/dist/admin/ui/{components/ui → core}/input.d.ts +2 -2
  24. package/dist/admin/ui/{components/ui → core}/join.d.ts +1 -1
  25. package/dist/admin/ui/core/label.d.ts +4 -0
  26. package/dist/admin/ui/core/popover.d.ts +10 -0
  27. package/dist/admin/ui/{components/ui → core}/radio-group.d.ts +2 -2
  28. package/dist/admin/ui/{components/ui → core}/relationship.d.ts +1 -1
  29. package/dist/admin/ui/{components/ui → core}/scroll-area.d.ts +1 -1
  30. package/dist/admin/ui/core/select.d.ts +15 -0
  31. package/dist/admin/ui/{components/ui → core}/sheet.d.ts +6 -6
  32. package/dist/admin/ui/core/sidebar.d.ts +69 -0
  33. package/dist/admin/ui/core/skeleton.d.ts +2 -0
  34. package/dist/admin/ui/core/switch.d.ts +6 -0
  35. package/dist/admin/ui/core/table.d.ts +10 -0
  36. package/dist/admin/ui/core/tabs.d.ts +11 -0
  37. package/dist/admin/ui/hooks/use-mobile.d.ts +1 -0
  38. package/dist/admin/ui/{admin-client.d.ts → layout/admin-client.d.ts} +1 -1
  39. package/dist/admin/ui/{admin-layout.d.ts → layout/admin-layout.d.ts} +2 -2
  40. package/dist/admin/ui/{components → shared}/column-visibility-toggle.d.ts +1 -1
  41. package/dist/admin/ui/{components → shared}/detail-sheet.d.ts +2 -2
  42. package/dist/admin/ui/{components/fields/ArrayField.d.ts → shared/fields/array-field.d.ts} +1 -1
  43. package/dist/admin/ui/shared/fields/blocks-field.d.ts +25 -0
  44. package/dist/admin/ui/{components/fields/BooleanField.d.ts → shared/fields/boolean-field.d.ts} +1 -1
  45. package/dist/admin/ui/{components/fields/CollapsibleField.d.ts → shared/fields/collapsible-field.d.ts} +1 -1
  46. package/dist/admin/ui/{components/fields/FileField.d.ts → shared/fields/file-field.d.ts} +13 -3
  47. package/dist/admin/ui/{components/fields/GroupField.d.ts → shared/fields/group-field.d.ts} +1 -1
  48. package/dist/admin/ui/shared/fields/index.d.ts +28 -0
  49. package/dist/admin/ui/{components/fields/JoinField.d.ts → shared/fields/join-field.d.ts} +1 -1
  50. package/dist/admin/ui/{components/fields/RelationshipField.d.ts → shared/fields/relationship-field.d.ts} +1 -1
  51. package/dist/admin/ui/{components → shared}/fields/richtext-editor/index.d.ts +2 -2
  52. package/dist/admin/ui/{components/fields/richtext-editor/nodes/ImageNode.d.ts → shared/fields/richtext-editor/nodes/image-node.d.ts} +3 -3
  53. package/dist/admin/ui/{components/fields/TabsField.d.ts → shared/fields/tabs-field.d.ts} +1 -1
  54. package/dist/admin/ui/{components/fields/VirtualField.d.ts → shared/fields/virtual-field.d.ts} +1 -1
  55. package/dist/admin/ui/{components → shared}/toast.d.ts +1 -1
  56. package/dist/admin/webcomponent.js +34 -34
  57. package/dist/admin.css +1 -1
  58. package/dist/{chunk-5y0mkt7x.js → chunk-2abqb0h6.js} +2 -2
  59. package/dist/{chunk-m83ybzf8.js → chunk-hrxq1x98.js} +1 -1
  60. package/dist/{chunk-nch158fe.js → chunk-y3ehzvp4.js} +1 -1
  61. package/dist/{chunk-vmz9ncf1.js → chunk-yw9w63kr.js} +3 -3
  62. package/dist/cli/commands/init.d.ts +1 -0
  63. package/dist/cli/core/seeding/auto-seed.d.ts +1 -1
  64. package/dist/cli/index.js +28 -3
  65. package/dist/config.d.ts +2 -6
  66. package/dist/db/adapter.d.ts +1 -1
  67. package/dist/db/better-sqlite.d.ts +1 -1
  68. package/dist/db/better-sqlite.js +587 -9
  69. package/dist/db/bun-sqlite.js +590 -9
  70. package/dist/db/d1.d.ts +1 -1
  71. package/dist/db/d1.js +605 -9
  72. package/dist/db/index.d.ts +0 -5
  73. package/dist/db/index.js +0 -35
  74. package/dist/db/kysely/plugins/draft-swapper.d.ts +2 -2
  75. package/dist/db/kysely/plugins/i18n-fallback.d.ts +2 -2
  76. package/dist/db/kysely/plugins/json-flattener.d.ts +2 -2
  77. package/dist/db/kysely/plugins/virtual-field-resolver.d.ts +2 -2
  78. package/dist/db/kysely/schema-builder.d.ts +1 -1
  79. package/dist/db/kysely/snapshot/snapshot-manager.d.ts +1 -1
  80. package/dist/db/postgres.js +613 -9
  81. package/dist/db/sqlite.d.ts +1 -1
  82. package/dist/db/sqlite.js +602 -9
  83. package/dist/runtimes/bun.js +1 -1
  84. package/dist/runtimes/cloudflare-workers.js +1 -1
  85. package/dist/runtimes/next.js +1 -1
  86. package/dist/runtimes/node.js +1 -1
  87. package/dist/server.js +4 -4
  88. package/dist/types.d.ts +3 -3
  89. package/package.json +25 -7
  90. package/dist/admin/ui/components/Table.d.ts +0 -10
  91. package/dist/admin/ui/components/fields/BlocksField.d.ts +0 -17
  92. package/dist/admin/ui/components/fields/index.d.ts +0 -28
  93. package/dist/admin/ui/components/ui/breadcrumbs.d.ts +0 -7
  94. package/dist/admin/ui/components/ui/dialog.d.ts +0 -27
  95. package/dist/admin/ui/components/ui/index.d.ts +0 -17
  96. package/dist/admin/ui/components/ui/label.d.ts +0 -3
  97. package/dist/admin/ui/components/ui/select.d.ts +0 -37
  98. package/dist/admin/ui/components/ui/tabs.d.ts +0 -17
  99. package/dist/admin/ui/views/media-registry-view.d.ts +0 -7
  100. package/dist/chunk-5b9eqr34.js +0 -608
  101. package/dist/chunk-dz5bh1bd.js +0 -586
  102. package/dist/chunk-nz6xhtja.js +0 -601
  103. package/dist/chunk-qsefknd3.js +0 -593
  104. package/dist/chunk-tsmhn78f.js +0 -616
  105. /package/dist/admin/{stores → features/auth}/auth.d.ts +0 -0
  106. /package/dist/admin/{ui/views → features/auth}/login-view.d.ts +0 -0
  107. /package/dist/admin/{ui/components → features/collections}/data-detail-view.d.ts +0 -0
  108. /package/dist/admin/{ui/views → features/init}/init-view.d.ts +0 -0
  109. /package/dist/admin/{stores → features/media}/media.d.ts +0 -0
  110. /package/dist/admin/{stores → features/ui-shell}/column-visibility.d.ts +0 -0
  111. /package/dist/admin/{stores → features/ui-shell}/query.d.ts +0 -0
  112. /package/dist/admin/ui/{components/ui → core}/accordion.d.ts +0 -0
  113. /package/dist/admin/ui/{components/ui → core}/alert-dialog.d.ts +0 -0
  114. /package/dist/admin/ui/{components/ui → core}/separator.d.ts +0 -0
  115. /package/dist/admin/ui/{components/ui → core}/tooltip.d.ts +0 -0
  116. /package/dist/admin/ui/{components/ui → core}/utils.d.ts +0 -0
  117. /package/dist/admin/ui/{components → shared}/custom-alert.d.ts +0 -0
  118. /package/dist/admin/ui/{components/fields/DateField.d.ts → shared/fields/date-field.d.ts} +0 -0
  119. /package/dist/admin/ui/{components/fields/FieldLabel.d.ts → shared/fields/field-label.d.ts} +0 -0
  120. /package/dist/admin/ui/{components/fields/NumberField.d.ts → shared/fields/number-field.d.ts} +0 -0
  121. /package/dist/admin/ui/{components/fields/RadioField.d.ts → shared/fields/radio-field.d.ts} +0 -0
  122. /package/dist/admin/ui/{components/fields/richtext-editor/nodes/ImageComponent.d.ts → shared/fields/richtext-editor/nodes/image-component.d.ts} +0 -0
  123. /package/dist/admin/ui/{components/fields/richtext-editor/plugins/ComponentPickerPlugin.d.ts → shared/fields/richtext-editor/plugins/component-picker-plugin.d.ts} +0 -0
  124. /package/dist/admin/ui/{components/fields/richtext-editor/plugins/EditableSyncPlugin.d.ts → shared/fields/richtext-editor/plugins/editable-sync-plugin.d.ts} +0 -0
  125. /package/dist/admin/ui/{components/fields/richtext-editor/plugins/NotionToolbarPlugin.d.ts → shared/fields/richtext-editor/plugins/notion-toolbar-plugin.d.ts} +0 -0
  126. /package/dist/admin/ui/{components/fields/richtext-editor/plugins/SimpleToolbarPlugin.d.ts → shared/fields/richtext-editor/plugins/simple-toolbar-plugin.d.ts} +0 -0
  127. /package/dist/admin/ui/{components/fields/richtext-editor/plugins/ValueSyncPlugin.d.ts → shared/fields/richtext-editor/plugins/value-sync-plugin.d.ts} +0 -0
  128. /package/dist/admin/ui/{components/fields/RowField.d.ts → shared/fields/row-field.d.ts} +0 -0
  129. /package/dist/admin/ui/{components/fields/SelectField.d.ts → shared/fields/select-field.d.ts} +0 -0
  130. /package/dist/admin/ui/{components/fields/TextAreaField.d.ts → shared/fields/text-area-field.d.ts} +0 -0
  131. /package/dist/admin/ui/{components/fields/TextField.d.ts → shared/fields/text-field.d.ts} +0 -0
  132. /package/dist/admin/ui/{components → shared}/fields/utils.d.ts +0 -0
  133. /package/dist/admin/ui/{components → shared}/link.d.ts +0 -0
  134. /package/dist/admin/ui/{components → shared}/plugin-iframe.d.ts +0 -0
@@ -1,586 +0,0 @@
1
- import {
2
- buildKyselyWhere,
3
- flattenPayload,
4
- pushSchema,
5
- unflattenRow
6
- } from "./chunk-re459gm9.js";
7
- import {
8
- BaseDatabaseAdapter
9
- } from "./chunk-s8mqwnm1.js";
10
- import {
11
- requestContext
12
- } from "./chunk-q5sb5dcr.js";
13
- import {
14
- flattenFields,
15
- getRelationalFields,
16
- toSnakeCase
17
- } from "./chunk-5xpf5jxd.js";
18
- import {
19
- logger
20
- } from "./chunk-jq1drsen.js";
21
- import {
22
- __require
23
- } from "./chunk-8sqjbsgt.js";
24
-
25
- // src/db/better-sqlite.ts
26
- import fs from "node:fs/promises";
27
- import path from "node:path";
28
- import { pathToFileURL } from "node:url";
29
- import {
30
- CompiledQuery,
31
- FileMigrationProvider,
32
- Migrator,
33
- SqliteDialect
34
- } from "kysely";
35
- class BetterSQLiteAdapter extends BaseDatabaseAdapter {
36
- path;
37
- name = "better-sqlite3";
38
- _rawDb;
39
- _db = null;
40
- _collections = [];
41
- _globals = [];
42
- push;
43
- migrationDir;
44
- pushDestructive;
45
- get raw() {
46
- return this._rawDb;
47
- }
48
- get db() {
49
- if (!this._db)
50
- throw new Error("Database not connected. Call connect() first.");
51
- return this._db;
52
- }
53
- constructor(path2, options) {
54
- super();
55
- this.path = path2;
56
- this.push = options?.push ?? true;
57
- this.pushDestructive = options?.pushDestructive ?? false;
58
- this.migrationDir = options?.migrationDir ?? "./migrations";
59
- }
60
- async connect() {
61
- if (this._db)
62
- return;
63
- const { createRequire } = await import("node:module");
64
- const require2 = createRequire(import.meta.url);
65
- const Database = require2("better-sqlite3");
66
- this._rawDb = new Database(this.path);
67
- const { createOpacaKysely } = await import("./chunk-gzbz5jwy.js");
68
- this._db = createOpacaKysely({
69
- dialect: new SqliteDialect({
70
- database: this._rawDb
71
- }),
72
- config: {
73
- collections: this._collections,
74
- globals: this._globals,
75
- db: { name: "better-sqlite3" }
76
- }
77
- });
78
- }
79
- async disconnect() {
80
- if (this._db)
81
- await this.db.destroy();
82
- }
83
- async unsafe(query, params) {
84
- if (!this._db)
85
- await this.connect();
86
- const compiled = CompiledQuery.raw(query, params || []);
87
- const result = await this.db.executeQuery(compiled);
88
- return result.rows;
89
- }
90
- async count(collection, query) {
91
- const tableName = toSnakeCase(collection);
92
- let qb = this.db.selectFrom(tableName).select((eb) => eb.fn.count("id").as("count"));
93
- if (query && Object.keys(query).length > 0) {
94
- qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
95
- }
96
- const result = await qb.executeTakeFirst();
97
- return Number(result?.count || 0);
98
- }
99
- async create(collection, data) {
100
- const tableName = toSnakeCase(collection);
101
- return this.db.transaction().execute(async (tx) => {
102
- const colDef = this._collections.find((c) => c.slug === collection);
103
- const flatData = flattenPayload(data);
104
- const relationalFields = getRelationalFields(colDef?.fields || []);
105
- const hasManyData = {};
106
- const blocksData = {};
107
- for (const key in flatData) {
108
- if (Array.isArray(flatData[key])) {
109
- const isHasMany = colDef?.fields.some((f) => f.type === "relationship" && ("hasMany" in f) && f.hasMany && f.name === key);
110
- if (isHasMany) {
111
- hasManyData[key] = flatData[key];
112
- } else {
113
- blocksData[key] = flatData[key];
114
- }
115
- delete flatData[key];
116
- }
117
- }
118
- const dbFields = flattenFields(colDef?.fields || []);
119
- const validCols = new Set(dbFields.map((f) => toSnakeCase(f.name)));
120
- validCols.add("id");
121
- validCols.add(toSnakeCase("createdAt"));
122
- validCols.add(toSnakeCase("updatedAt"));
123
- const filteredData = {};
124
- for (const col of Object.keys(flatData)) {
125
- if (validCols.has(col)) {
126
- filteredData[col] = flatData[col];
127
- }
128
- }
129
- if (!filteredData.id) {
130
- filteredData.id = crypto.randomUUID();
131
- flatData.id = filteredData.id;
132
- }
133
- await tx.insertInto(tableName).values(filteredData).execute();
134
- for (const [key, values] of Object.entries(hasManyData)) {
135
- const joinTableName = `${tableName}_${toSnakeCase(key)}_relations`.toLowerCase();
136
- if (values.length > 0) {
137
- const joinData = values.map((val, idx) => {
138
- const tId = typeof val === "object" ? val.id : val;
139
- return { id: crypto.randomUUID(), source_id: flatData.id, target_id: tId, order: idx };
140
- });
141
- await tx.insertInto(joinTableName).values(joinData).execute();
142
- }
143
- }
144
- for (const [key, blocks] of Object.entries(blocksData)) {
145
- for (let i = 0;i < blocks.length; i++) {
146
- const block = blocks[i];
147
- if (!block.blockType)
148
- continue;
149
- const blockTableName = `${tableName}_${toSnakeCase(key)}_${block.blockType}`.toLowerCase();
150
- const bId = block.id || crypto.randomUUID();
151
- const blockDef = colDef?.fields.find((f) => f.name === key && f.type === "blocks");
152
- const blockConfig = blockDef?.blocks?.find((b) => b.slug === block.blockType);
153
- const blockJsonFields = blockConfig?.fields.filter((f) => ["richtext", "json", "file"].includes(f.type)).map((f) => f.name) || [];
154
- const blockFlatData = flattenPayload({ ...block, id: bId }, "", blockJsonFields);
155
- for (const f of blockJsonFields) {
156
- if (blockFlatData[f] && typeof blockFlatData[f] === "object") {
157
- blockFlatData[f] = JSON.stringify(blockFlatData[f]);
158
- }
159
- }
160
- delete blockFlatData.blockType;
161
- const blockData = {
162
- ...blockFlatData,
163
- _parent_id: flatData.id,
164
- _order: i,
165
- block_type: block.blockType
166
- };
167
- await tx.insertInto(blockTableName).values(blockData).execute();
168
- }
169
- }
170
- return this.findOne(collection, { id: flatData.id }, tx);
171
- });
172
- }
173
- async findOne(collection, query, tx) {
174
- const tableName = toSnakeCase(collection);
175
- const executor = tx || this.db;
176
- let qb = executor.selectFrom(tableName).selectAll();
177
- if (query && Object.keys(query).length > 0) {
178
- qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
179
- }
180
- const row = await qb.executeTakeFirst();
181
- if (!row)
182
- return null;
183
- const unflattened = unflattenRow(row);
184
- const colDef = this._collections.find((c) => c.slug === collection);
185
- if (colDef) {
186
- const { getRelationalFields: getRelationalFields2, toSnakeCase: toSnakeCase2 } = await import("./chunk-z9ek88xr.js");
187
- const relationalFields = getRelationalFields2(colDef.fields);
188
- for (const field of relationalFields) {
189
- if (!field.name)
190
- continue;
191
- const snakeName = toSnakeCase2(field.name);
192
- if (field.type === "relationship" && "hasMany" in field && field.hasMany) {
193
- const joinTableName = `${tableName}_${snakeName}_relations`.toLowerCase();
194
- try {
195
- const relations = await executor.selectFrom(joinTableName).selectAll().where("source_id", "=", row.id).orderBy("order", "asc").execute();
196
- unflattened[field.name] = relations.map((r) => r.target_id);
197
- } catch (e) {}
198
- } else if (field.type === "blocks" && field.blocks) {
199
- const blockData = [];
200
- for (const b of field.blocks) {
201
- const blockTableName = `${tableName}_${snakeName}_${b.slug}`.toLowerCase();
202
- try {
203
- const blocks = await executor.selectFrom(blockTableName).selectAll().where("_parent_id", "=", row.id).execute();
204
- for (const blk of blocks) {
205
- const uf = unflattenRow(blk);
206
- uf.blockType = blk.block_type;
207
- blockData.push(uf);
208
- }
209
- } catch (e) {}
210
- }
211
- blockData.sort((a, b) => a._order - b._order);
212
- blockData.forEach((b) => {
213
- delete b._order;
214
- delete b._parent_id;
215
- });
216
- unflattened[field.name] = blockData;
217
- }
218
- }
219
- }
220
- return unflattened;
221
- }
222
- async find(collection, query, options) {
223
- const page = options?.page || 1;
224
- const limit = options?.limit || 10;
225
- const offset = (page - 1) * limit;
226
- const cursorColumn = options?.cursorColumn || "id";
227
- const total = await this.count(collection, query);
228
- const tableName = toSnakeCase(collection);
229
- let qb = this.db.selectFrom(tableName).selectAll().limit(limit);
230
- if (options?.after) {
231
- qb = qb.where(cursorColumn, ">", options.after);
232
- } else if (options?.before) {
233
- qb = qb.where(cursorColumn, "<", options.before);
234
- } else {
235
- qb = qb.offset(offset);
236
- }
237
- if (query && Object.keys(query).length > 0) {
238
- qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
239
- }
240
- if (options?.sort) {
241
- const isDesc = options.sort.startsWith("-");
242
- const col = isDesc ? options.sort.substring(1) : options.sort;
243
- qb = qb.orderBy(col, isDesc ? "desc" : "asc");
244
- } else {
245
- qb = qb.orderBy(cursorColumn, "desc");
246
- }
247
- const rows = await qb.execute();
248
- if (rows.length === 0) {
249
- const totalPages2 = Math.ceil(total / limit);
250
- const afterAnchor = options?.after;
251
- const beforeAnchor = options?.before;
252
- return {
253
- docs: [],
254
- totalDocs: total,
255
- limit,
256
- totalPages: totalPages2,
257
- page,
258
- pagingCounter: offset + 1,
259
- hasNextPage: false,
260
- hasPrevPage: !!afterAnchor || page > 1,
261
- prevPage: null,
262
- nextPage: null,
263
- nextCursor: null,
264
- prevCursor: afterAnchor ? afterAnchor : null
265
- };
266
- }
267
- const rowIds = rows.map((r) => r.id);
268
- const docs = rows.map((r) => unflattenRow(r));
269
- const colDef = this._collections.find((c) => c.slug === collection);
270
- if (colDef) {
271
- const relationalFields = getRelationalFields(colDef.fields);
272
- for (const field of relationalFields) {
273
- if (!field.name)
274
- continue;
275
- const snakeName = toSnakeCase(field.name);
276
- if (field.type === "relationship" && "hasMany" in field && field.hasMany) {
277
- const joinTableName = `${toSnakeCase(collection)}_${snakeName}_relations`.toLowerCase();
278
- try {
279
- const allRelations = await this.db.selectFrom(joinTableName).selectAll().where("source_id", "in", rowIds).orderBy("order", "asc").execute();
280
- const relationsBySource = allRelations.reduce((acc, r) => {
281
- if (!acc[r.source_id])
282
- acc[r.source_id] = [];
283
- acc[r.source_id].push(r.target_id);
284
- return acc;
285
- }, {});
286
- const parts = field.name.split("__");
287
- for (let docIdx = 0;docIdx < docs.length; docIdx++) {
288
- const rowId = rowIds[docIdx];
289
- let current = docs[docIdx];
290
- for (let i = 0;i < parts.length - 1; i++) {
291
- if (!current[parts[i]])
292
- current[parts[i]] = {};
293
- current = current[parts[i]];
294
- }
295
- current[parts[parts.length - 1]] = relationsBySource[rowId] || [];
296
- }
297
- } catch (e) {}
298
- } else if (field.type === "blocks" && field.blocks) {
299
- const blocksBySource = {};
300
- for (const b of field.blocks) {
301
- const blockTableName = `${collection}_${snakeName}_${toSnakeCase(b.slug)}`.toLowerCase();
302
- try {
303
- const allBlocks = await this.db.selectFrom(blockTableName).selectAll().where("_parent_id", "in", rowIds).execute();
304
- for (const blk of allBlocks) {
305
- const uf = unflattenRow(blk);
306
- uf.blockType = blk.block_type;
307
- if (!blocksBySource[blk._parent_id])
308
- blocksBySource[blk._parent_id] = [];
309
- blocksBySource[blk._parent_id].push(uf);
310
- }
311
- } catch (e) {}
312
- }
313
- const parts = field.name.split("__");
314
- for (let docIdx = 0;docIdx < docs.length; docIdx++) {
315
- const rowId = rowIds[docIdx];
316
- const blockData = blocksBySource[rowId] || [];
317
- blockData.sort((a, b) => a._order - b._order);
318
- blockData.forEach((b) => {
319
- delete b._order;
320
- delete b._parentId;
321
- });
322
- let current = docs[docIdx];
323
- for (let i = 0;i < parts.length - 1; i++) {
324
- if (!current[parts[i]])
325
- current[parts[i]] = {};
326
- current = current[parts[i]];
327
- }
328
- current[parts[parts.length - 1]] = blockData;
329
- }
330
- }
331
- }
332
- }
333
- const totalPages = Math.ceil(total / limit);
334
- const hasNextPage = page * limit < total;
335
- return {
336
- docs: docs.filter(Boolean),
337
- totalDocs: total,
338
- limit,
339
- totalPages,
340
- page,
341
- pagingCounter: offset + 1,
342
- hasNextPage,
343
- hasPrevPage: page > 1 || !!options?.after || !!options?.before,
344
- prevPage: page > 1 ? page - 1 : null,
345
- nextPage: page < totalPages ? page + 1 : null,
346
- nextCursor: hasNextPage && docs.length > 0 ? docs[docs.length - 1][cursorColumn] : null,
347
- prevCursor: docs.length > 0 && (page > 1 || !!options?.after || !!options?.before) ? docs[0][cursorColumn] : null
348
- };
349
- }
350
- async update(collection, query, data) {
351
- const tableName = toSnakeCase(collection);
352
- return this.db.transaction().execute(async (tx) => {
353
- let normalizedQuery = query;
354
- if (typeof query !== "object" || query === null) {
355
- normalizedQuery = { id: query };
356
- }
357
- const current = await this.findOne(collection, normalizedQuery, tx);
358
- if (!current)
359
- throw new Error("Document not found");
360
- const store = requestContext.getStore();
361
- if (store)
362
- store.previousData = current;
363
- const colDef = this._collections.find((c) => c.slug === collection);
364
- const jsonFields = colDef?.fields.filter((f) => ["richtext", "json", "file"].includes(f.type)).map((f) => f.name) || [];
365
- const flatData = flattenPayload(data, "", jsonFields);
366
- for (const field of jsonFields) {
367
- if (flatData[field] && typeof flatData[field] === "object") {
368
- flatData[field] = JSON.stringify(flatData[field]);
369
- }
370
- }
371
- const hasManyData = {};
372
- const blocksData = {};
373
- for (const key in flatData) {
374
- if (Array.isArray(flatData[key])) {
375
- const isHasMany = colDef?.fields.some((f) => f.type === "relationship" && ("hasMany" in f) && f.hasMany && f.name === key);
376
- if (isHasMany) {
377
- hasManyData[key] = flatData[key];
378
- } else {
379
- blocksData[key] = flatData[key];
380
- }
381
- delete flatData[key];
382
- }
383
- }
384
- if (Object.keys(flatData).length > 0) {
385
- await tx.updateTable(tableName).set(flatData).where("id", "=", current.id).execute();
386
- }
387
- for (const [key, values] of Object.entries(hasManyData)) {
388
- const joinTableName = `${tableName}_${toSnakeCase(key)}_relations`.toLowerCase();
389
- await tx.deleteFrom(joinTableName).where("source_id", "=", current.id).execute();
390
- if (values.length > 0) {
391
- const joinData = values.map((val, idx) => {
392
- const tId = typeof val === "object" ? val.id : val;
393
- return { id: crypto.randomUUID(), source_id: current.id, target_id: tId, order: idx };
394
- });
395
- await tx.insertInto(joinTableName).values(joinData).execute();
396
- }
397
- }
398
- for (const [key, blocks] of Object.entries(blocksData)) {
399
- const fieldDef = colDef?.fields.find((f) => f.name === key);
400
- if (fieldDef?.type === "blocks" && fieldDef.blocks) {
401
- for (const b of fieldDef.blocks) {
402
- const blockTableName = `${tableName}_${toSnakeCase(key)}_${b.slug}`.toLowerCase();
403
- try {
404
- await tx.deleteFrom(blockTableName).where("_parent_id", "=", current.id).execute();
405
- } catch (e) {}
406
- }
407
- }
408
- for (let i = 0;i < blocks.length; i++) {
409
- const block = blocks[i];
410
- if (!block.blockType)
411
- continue;
412
- const blockTableName = `${tableName}_${toSnakeCase(key)}_${block.blockType}`.toLowerCase();
413
- const bId = block.id || crypto.randomUUID();
414
- const blockConfig = fieldDef?.blocks?.find((b) => b.slug === block.blockType);
415
- const blockJsonFields = blockConfig?.fields.filter((f) => ["richtext", "json", "file"].includes(f.type)).map((f) => f.name) || [];
416
- const blockFlatData = flattenPayload({ ...block, id: bId }, "", blockJsonFields);
417
- for (const f of blockJsonFields) {
418
- if (blockFlatData[f] && typeof blockFlatData[f] === "object") {
419
- blockFlatData[f] = JSON.stringify(blockFlatData[f]);
420
- }
421
- }
422
- delete blockFlatData.blockType;
423
- const blockData = {
424
- ...blockFlatData,
425
- _parent_id: current.id,
426
- _order: i,
427
- block_type: block.blockType
428
- };
429
- await tx.insertInto(blockTableName).values(blockData).execute();
430
- }
431
- }
432
- return this.findOne(collection, { id: current.id }, tx);
433
- });
434
- }
435
- async delete(collection, query) {
436
- const tableName = toSnakeCase(collection);
437
- let normalizedQuery = query;
438
- if (typeof query !== "object" || query === null) {
439
- normalizedQuery = { id: query };
440
- }
441
- const current = await this.findOne(collection, normalizedQuery);
442
- if (!current)
443
- return false;
444
- await this.db.transaction().execute(async (tx) => {
445
- const colDef = this._collections.find((c) => c.slug === collection);
446
- if (colDef) {
447
- for (const field of colDef.fields) {
448
- const snakeName = toSnakeCase(field.name);
449
- if (field.type === "relationship" && "hasMany" in field && field.hasMany) {
450
- const joinTableName = `${tableName}_${snakeName}_relations`.toLowerCase();
451
- try {
452
- await tx.deleteFrom(joinTableName).where("source_id", "=", current.id).execute();
453
- } catch (e) {}
454
- } else if (field.type === "blocks" && field.blocks) {
455
- for (const b of field.blocks) {
456
- const blockTableName = `${tableName}_${snakeName}_${b.slug}`.toLowerCase();
457
- try {
458
- await tx.deleteFrom(blockTableName).where("_parent_id", "=", current.id).execute();
459
- } catch (e) {}
460
- }
461
- }
462
- }
463
- }
464
- await tx.deleteFrom(tableName).where("id", "=", current.id).execute();
465
- });
466
- return true;
467
- }
468
- async updateMany(collection, query, data) {
469
- const tableName = toSnakeCase(collection);
470
- return this.db.transaction().execute(async (tx) => {
471
- let qb = tx.updateTable(tableName);
472
- if (query && Object.keys(query).length > 0) {
473
- qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
474
- }
475
- const colDef = this._collections.find((c) => c.slug === collection);
476
- const jsonFields = colDef?.fields.filter((f) => ["richtext", "json", "file"].includes(f.type)).map((f) => f.name) || [];
477
- const flatData = flattenPayload(data, "", jsonFields);
478
- for (const field of jsonFields) {
479
- if (flatData[field] && typeof flatData[field] === "object") {
480
- flatData[field] = JSON.stringify(flatData[field]);
481
- }
482
- }
483
- for (const key in flatData) {
484
- if (Array.isArray(flatData[key])) {
485
- delete flatData[key];
486
- }
487
- }
488
- if (Object.keys(flatData).length > 0) {
489
- const result = await qb.set(flatData).executeTakeFirst();
490
- return Number(result.numUpdatedRows || 0);
491
- }
492
- return 0;
493
- });
494
- }
495
- async deleteMany(collection, query) {
496
- const tableName = toSnakeCase(collection);
497
- return this.db.transaction().execute(async (tx) => {
498
- let selectQb = tx.selectFrom(tableName).select("id");
499
- if (query && Object.keys(query).length > 0) {
500
- selectQb = selectQb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
501
- }
502
- const docs = await selectQb.execute();
503
- if (docs.length === 0)
504
- return 0;
505
- const ids = docs.map((d) => d.id);
506
- const colDef = this._collections.find((c) => c.slug === collection);
507
- if (colDef) {
508
- for (const field of colDef.fields) {
509
- const snakeName = toSnakeCase(field.name);
510
- if (field.type === "relationship" && "hasMany" in field && field.hasMany) {
511
- const joinTableName = `${tableName}_${snakeName}_relations`.toLowerCase();
512
- try {
513
- await tx.deleteFrom(joinTableName).where("source_id", "in", ids).execute();
514
- } catch (e) {}
515
- } else if (field.type === "blocks" && field.blocks) {
516
- for (const b of field.blocks) {
517
- const blockTableName = `${tableName}_${snakeName}_${b.slug}`.toLowerCase();
518
- try {
519
- await tx.deleteFrom(blockTableName).where("_parent_id", "in", ids).execute();
520
- } catch (e) {}
521
- }
522
- }
523
- }
524
- }
525
- const result = await tx.deleteFrom(tableName).where("id", "in", ids).executeTakeFirst();
526
- return Number(result.numDeletedRows || 0);
527
- });
528
- }
529
- async findGlobal(slug) {
530
- const tableName = toSnakeCase(slug);
531
- const row = await this.db.selectFrom(tableName).selectAll().limit(1).executeTakeFirst();
532
- return row ? unflattenRow(row) : null;
533
- }
534
- async updateGlobal(slug, data) {
535
- const tableName = toSnakeCase(slug);
536
- const existing = await this.findGlobal(slug);
537
- const flatData = flattenPayload(data);
538
- const globalDef = this._globals.find((g) => g.slug === slug);
539
- const now = new Date().toISOString();
540
- flatData[toSnakeCase("updatedAt")] = now;
541
- if (!existing) {
542
- if (!flatData.id)
543
- flatData.id = "global";
544
- flatData[toSnakeCase("createdAt")] = now;
545
- await this.db.insertInto(tableName).values(flatData).execute();
546
- } else {
547
- await this.db.updateTable(tableName).set(flatData).where("id", "=", existing.id).execute();
548
- }
549
- return this.findGlobal(slug);
550
- }
551
- async runMigrations() {
552
- const migrator = new Migrator({
553
- db: this.db,
554
- provider: new FileMigrationProvider({
555
- fs,
556
- path,
557
- migrationFolder: pathToFileURL(path.resolve(process.cwd(), this.migrationDir)).href
558
- })
559
- });
560
- const { error, results } = await migrator.migrateToLatest();
561
- results?.forEach((it) => {
562
- if (it.status === "Success") {
563
- logger.success(`\uD83D\uDE80 Migration "${it.migrationName}" was executed successfully`);
564
- } else if (it.status === "Error") {
565
- logger.error(`❌ Migration "${it.migrationName}" failed`);
566
- }
567
- });
568
- if (error) {
569
- throw error;
570
- }
571
- }
572
- async migrate(collections, globals = []) {
573
- this._collections = collections;
574
- this._globals = globals;
575
- if (this.push) {
576
- await pushSchema(this.db, "sqlite", collections, globals, {
577
- pushDestructive: this.pushDestructive
578
- });
579
- }
580
- }
581
- }
582
- function createBetterSQLiteAdapter(path2, options) {
583
- return new BetterSQLiteAdapter(path2, options);
584
- }
585
-
586
- export { BetterSQLiteAdapter, createBetterSQLiteAdapter };