@cogenta/schema 0.1.2 → 0.3.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.
- package/dist/define-collection.d.ts.map +1 -1
- package/dist/define-collection.js +32 -0
- package/dist/define-collection.js.map +1 -1
- package/dist/define-taxonomy.d.ts +9 -0
- package/dist/define-taxonomy.d.ts.map +1 -0
- package/dist/define-taxonomy.js +144 -0
- package/dist/define-taxonomy.js.map +1 -0
- package/dist/fields.d.ts +20 -0
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js +14 -0
- package/dist/fields.js.map +1 -1
- package/dist/generate-schema-json.d.ts +28 -4
- package/dist/generate-schema-json.d.ts.map +1 -1
- package/dist/generate-schema-json.js +25 -4
- package/dist/generate-schema-json.js.map +1 -1
- package/dist/generate-types.js +1 -0
- package/dist/generate-types.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/links/check.d.ts +76 -0
- package/dist/links/check.d.ts.map +1 -0
- package/dist/links/check.js +169 -0
- package/dist/links/check.js.map +1 -0
- package/dist/links/extract.d.ts +36 -0
- package/dist/links/extract.d.ts.map +1 -0
- package/dist/links/extract.js +69 -0
- package/dist/links/extract.js.map +1 -0
- package/dist/links/index.d.ts +10 -0
- package/dist/links/index.d.ts.map +1 -0
- package/dist/links/index.js +8 -0
- package/dist/links/index.js.map +1 -0
- package/dist/store/columns.d.ts.map +1 -1
- package/dist/store/columns.js +5 -2
- package/dist/store/columns.js.map +1 -1
- package/dist/store/index.d.ts +16 -2
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +9 -1
- package/dist/store/index.js.map +1 -1
- package/dist/store/lifecycle-events.d.ts +72 -0
- package/dist/store/lifecycle-events.d.ts.map +1 -0
- package/dist/store/lifecycle-events.js +73 -0
- package/dist/store/lifecycle-events.js.map +1 -0
- package/dist/store/menu-store.d.ts +99 -0
- package/dist/store/menu-store.d.ts.map +1 -0
- package/dist/store/menu-store.js +418 -0
- package/dist/store/menu-store.js.map +1 -0
- package/dist/store/menu-tables.d.ts +26 -0
- package/dist/store/menu-tables.d.ts.map +1 -0
- package/dist/store/menu-tables.js +79 -0
- package/dist/store/menu-tables.js.map +1 -0
- package/dist/store/naming.d.ts +11 -2
- package/dist/store/naming.d.ts.map +1 -1
- package/dist/store/naming.js +13 -1
- package/dist/store/naming.js.map +1 -1
- package/dist/store/read-only.d.ts +9 -3
- package/dist/store/read-only.d.ts.map +1 -1
- package/dist/store/read-only.js +13 -3
- package/dist/store/read-only.js.map +1 -1
- package/dist/store/scheduled-publish-enqueue.d.ts +37 -0
- package/dist/store/scheduled-publish-enqueue.d.ts.map +1 -0
- package/dist/store/scheduled-publish-enqueue.js +51 -0
- package/dist/store/scheduled-publish-enqueue.js.map +1 -0
- package/dist/store/schema-2-migration.d.ts +32 -0
- package/dist/store/schema-2-migration.d.ts.map +1 -0
- package/dist/store/schema-2-migration.js +136 -0
- package/dist/store/schema-2-migration.js.map +1 -0
- package/dist/store/search-indexing.d.ts +34 -0
- package/dist/store/search-indexing.d.ts.map +1 -0
- package/dist/store/search-indexing.js +65 -0
- package/dist/store/search-indexing.js.map +1 -0
- package/dist/store/store.d.ts +45 -8
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +398 -59
- package/dist/store/store.js.map +1 -1
- package/dist/store/tables.d.ts +15 -3
- package/dist/store/tables.d.ts.map +1 -1
- package/dist/store/tables.js +98 -6
- package/dist/store/tables.js.map +1 -1
- package/dist/store/taxonomy-path.d.ts +25 -0
- package/dist/store/taxonomy-path.d.ts.map +1 -0
- package/dist/store/taxonomy-path.js +64 -0
- package/dist/store/taxonomy-path.js.map +1 -0
- package/dist/store/taxonomy-store.d.ts +62 -0
- package/dist/store/taxonomy-store.d.ts.map +1 -0
- package/dist/store/taxonomy-store.js +292 -0
- package/dist/store/taxonomy-store.js.map +1 -0
- package/dist/store/types.d.ts +42 -2
- package/dist/store/types.d.ts.map +1 -1
- package/dist/store/values.d.ts.map +1 -1
- package/dist/store/values.js +4 -1
- package/dist/store/values.js.map +1 -1
- package/dist/system-fields.d.ts +2 -1
- package/dist/system-fields.d.ts.map +1 -1
- package/dist/system-fields.js +4 -0
- package/dist/system-fields.js.map +1 -1
- package/dist/types.d.ts +86 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +12 -3
- package/dist/types.js.map +1 -1
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +5 -1
- package/dist/validation.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { buildPath } from '../routing/router.js';
|
|
2
|
+
function pathFor(collection, entry) {
|
|
3
|
+
if (collection.routing === undefined)
|
|
4
|
+
return null;
|
|
5
|
+
const params = {};
|
|
6
|
+
for (const [field, value] of Object.entries(entry.values)) {
|
|
7
|
+
if (typeof value === 'string')
|
|
8
|
+
params[field] = value;
|
|
9
|
+
}
|
|
10
|
+
try {
|
|
11
|
+
return buildPath(collection, params, entry.locale);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
// A route whose parameters are not all present yet. `null` is the honest
|
|
15
|
+
// answer — better than refusing the publish that just succeeded.
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function withLifecycleEvents(store, options) {
|
|
20
|
+
async function fire(event, entry) {
|
|
21
|
+
try {
|
|
22
|
+
await options.emit({
|
|
23
|
+
event,
|
|
24
|
+
collection: options.collection.name,
|
|
25
|
+
id: entry.id,
|
|
26
|
+
locale: entry.locale,
|
|
27
|
+
status: entry.status,
|
|
28
|
+
publishedAt: entry.publishedAt,
|
|
29
|
+
updatedAt: entry.updatedAt,
|
|
30
|
+
version: entry.version,
|
|
31
|
+
path: pathFor(options.collection, entry),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
options.onError?.(error);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
...store,
|
|
40
|
+
// `create({ status: 'published' })` is a real publication — it is how an
|
|
41
|
+
// import, an agent, or `POST /api/content/{collection}` with a published
|
|
42
|
+
// status puts a page online without ever calling `publish()`. Missing it
|
|
43
|
+
// would make the event depend on which door the content came through.
|
|
44
|
+
create: async (input) => {
|
|
45
|
+
const created = await store.create(input);
|
|
46
|
+
if (created.status === 'published')
|
|
47
|
+
await fire('content.publish', created);
|
|
48
|
+
return created;
|
|
49
|
+
},
|
|
50
|
+
publish: async (id, input) => {
|
|
51
|
+
const published = await store.publish(id, input);
|
|
52
|
+
await fire('content.publish', published);
|
|
53
|
+
return published;
|
|
54
|
+
},
|
|
55
|
+
unpublish: async (id, input) => {
|
|
56
|
+
const unpublished = await store.unpublish(id, input);
|
|
57
|
+
await fire('content.unpublish', unpublished);
|
|
58
|
+
return unpublished;
|
|
59
|
+
},
|
|
60
|
+
delete: async (id) => {
|
|
61
|
+
// Read before the delete: afterwards there is nothing left to describe,
|
|
62
|
+
// and a receiver told only "some id disappeared" cannot find the page to
|
|
63
|
+
// drop. The published face is asked for first — deleting an entry that
|
|
64
|
+
// was never public is not news to a public consumer.
|
|
65
|
+
const before = await store.read(id, { state: 'published' }).catch(() => null);
|
|
66
|
+
const removed = await store.delete(id);
|
|
67
|
+
if (removed && before !== null)
|
|
68
|
+
await fire('content.delete', before);
|
|
69
|
+
return removed;
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=lifecycle-events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle-events.js","sourceRoot":"","sources":["../../src/store/lifecycle-events.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { type DatabaseHandle } from '@cogenta/core';
|
|
2
|
+
/**
|
|
3
|
+
* The persistence layer of navigation menus.
|
|
4
|
+
*
|
|
5
|
+
* Structurally a menu is the same shape as a taxonomy — a named tree,
|
|
6
|
+
* maintained with a materialised path so that "everything under this item" is
|
|
7
|
+
* one `like`, portable across the three dialects (ADR-0006) — but it is not a
|
|
8
|
+
* `TaxonomyStore`: a menu is not declared in the site's schema, it is created
|
|
9
|
+
* and edited at runtime from the admin, so it gets one fixed pair of tables
|
|
10
|
+
* (`menu-tables.ts`) rather than a table per declared name.
|
|
11
|
+
*/
|
|
12
|
+
export type MenuItemKind = 'entry' | 'url' | 'submenu-placeholder';
|
|
13
|
+
/** Deep enough for any real navigation; the path column is bounded to match. */
|
|
14
|
+
export declare const MAX_MENU_DEPTH = 8;
|
|
15
|
+
export interface Menu {
|
|
16
|
+
readonly id: string;
|
|
17
|
+
readonly name: string;
|
|
18
|
+
readonly locale: string;
|
|
19
|
+
readonly label: string;
|
|
20
|
+
readonly createdAt: string;
|
|
21
|
+
readonly updatedAt: string;
|
|
22
|
+
}
|
|
23
|
+
export interface MenuItem {
|
|
24
|
+
readonly id: string;
|
|
25
|
+
readonly menuId: string;
|
|
26
|
+
readonly parent: string | null;
|
|
27
|
+
readonly label: string;
|
|
28
|
+
readonly kind: MenuItemKind;
|
|
29
|
+
readonly targetCollection: string | null;
|
|
30
|
+
readonly targetEntryId: string | null;
|
|
31
|
+
readonly url: string | null;
|
|
32
|
+
readonly position: number;
|
|
33
|
+
readonly depth: number;
|
|
34
|
+
readonly openInNewTab: boolean;
|
|
35
|
+
readonly createdAt: string;
|
|
36
|
+
readonly updatedAt: string;
|
|
37
|
+
}
|
|
38
|
+
export interface CreateMenuInput {
|
|
39
|
+
readonly id?: string;
|
|
40
|
+
readonly name: string;
|
|
41
|
+
readonly locale: string;
|
|
42
|
+
readonly label: string;
|
|
43
|
+
}
|
|
44
|
+
export interface UpdateMenuInput {
|
|
45
|
+
readonly label?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface ListMenusOptions {
|
|
48
|
+
readonly locale?: string;
|
|
49
|
+
}
|
|
50
|
+
export interface CreateMenuItemInput {
|
|
51
|
+
readonly id?: string;
|
|
52
|
+
readonly label: string;
|
|
53
|
+
readonly kind: MenuItemKind;
|
|
54
|
+
readonly parent?: string | null;
|
|
55
|
+
readonly targetCollection?: string | null;
|
|
56
|
+
readonly targetEntryId?: string | null;
|
|
57
|
+
readonly url?: string | null;
|
|
58
|
+
readonly position?: number;
|
|
59
|
+
readonly openInNewTab?: boolean;
|
|
60
|
+
}
|
|
61
|
+
export interface UpdateMenuItemInput {
|
|
62
|
+
readonly label?: string;
|
|
63
|
+
readonly kind?: MenuItemKind;
|
|
64
|
+
readonly targetCollection?: string | null;
|
|
65
|
+
readonly targetEntryId?: string | null;
|
|
66
|
+
readonly url?: string | null;
|
|
67
|
+
readonly openInNewTab?: boolean;
|
|
68
|
+
}
|
|
69
|
+
export interface MenuStoreOptions {
|
|
70
|
+
readonly db: DatabaseHandle;
|
|
71
|
+
/** Injectable so tests can pin time; nothing else should pass it. */
|
|
72
|
+
readonly now?: () => Date;
|
|
73
|
+
readonly newId?: () => string;
|
|
74
|
+
}
|
|
75
|
+
export interface MenuStore {
|
|
76
|
+
create(input: CreateMenuInput): Promise<Menu>;
|
|
77
|
+
read(id: string): Promise<Menu | null>;
|
|
78
|
+
byName(name: string, locale: string): Promise<Menu | null>;
|
|
79
|
+
update(id: string, input: UpdateMenuInput): Promise<Menu>;
|
|
80
|
+
/** Refuses while the menu still has items, unless `cascade` is asked for. */
|
|
81
|
+
delete(id: string, options?: {
|
|
82
|
+
readonly cascade?: boolean;
|
|
83
|
+
}): Promise<boolean>;
|
|
84
|
+
list(options?: ListMenusOptions): Promise<readonly Menu[]>;
|
|
85
|
+
createItem(menuId: string, input: CreateMenuItemInput): Promise<MenuItem>;
|
|
86
|
+
readItem(id: string): Promise<MenuItem | null>;
|
|
87
|
+
updateItem(id: string, input: UpdateMenuItemInput): Promise<MenuItem>;
|
|
88
|
+
/** Re-parents an item and rewrites the whole subtree's paths. */
|
|
89
|
+
moveItem(id: string, parent: string | null): Promise<MenuItem>;
|
|
90
|
+
/** Swaps this item's position with the sibling immediately before/after it. */
|
|
91
|
+
reorderItem(id: string, direction: 'up' | 'down'): Promise<MenuItem>;
|
|
92
|
+
deleteItem(id: string, options?: {
|
|
93
|
+
readonly cascade?: boolean;
|
|
94
|
+
}): Promise<boolean>;
|
|
95
|
+
/** Every item of the menu, in tree order. */
|
|
96
|
+
listItems(menuId: string): Promise<readonly MenuItem[]>;
|
|
97
|
+
}
|
|
98
|
+
export declare function createMenuStore(options: MenuStoreOptions): MenuStore;
|
|
99
|
+
//# sourceMappingURL=menu-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menu-store.d.ts","sourceRoot":"","sources":["../../src/store/menu-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
import { CogentaError, identifier, sql, } from '@cogenta/core';
|
|
2
|
+
import { newId as uuidv7 } from '../id.js';
|
|
3
|
+
import { joinFragments } from './fragments.js';
|
|
4
|
+
import { MENU_TABLES } from './menu-tables.js';
|
|
5
|
+
import { childPath, depthOf, isBelow, isWithin, rebasedPath } from './taxonomy-path.js';
|
|
6
|
+
/** Deep enough for any real navigation; the path column is bounded to match. */
|
|
7
|
+
export const MAX_MENU_DEPTH = 8;
|
|
8
|
+
function text(value) {
|
|
9
|
+
return typeof value === 'string' ? value : String(value);
|
|
10
|
+
}
|
|
11
|
+
function nullableText(value) {
|
|
12
|
+
return value === null || value === undefined ? null : text(value);
|
|
13
|
+
}
|
|
14
|
+
function invalid(message, hint, details) {
|
|
15
|
+
return new CogentaError({
|
|
16
|
+
code: 'MENU_ITEM_INVALID',
|
|
17
|
+
message,
|
|
18
|
+
hint,
|
|
19
|
+
...(details ? { details } : {}),
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export function createMenuStore(options) {
|
|
23
|
+
const { db } = options;
|
|
24
|
+
const dialect = db.dialect;
|
|
25
|
+
const now = options.now ?? (() => new Date());
|
|
26
|
+
const newId = options.newId ?? uuidv7;
|
|
27
|
+
const menus = identifier(MENU_TABLES.menus, dialect);
|
|
28
|
+
const items = identifier(MENU_TABLES.items, dialect);
|
|
29
|
+
const idColumn = identifier('id', dialect);
|
|
30
|
+
const parentColumn = identifier('parent_id', dialect);
|
|
31
|
+
const menuIdColumn = identifier('menu_id', dialect);
|
|
32
|
+
const nameColumn = identifier('name', dialect);
|
|
33
|
+
const localeColumn = identifier('locale', dialect);
|
|
34
|
+
const pathColumn = identifier('path', dialect);
|
|
35
|
+
const positionColumn = identifier('position', dialect);
|
|
36
|
+
const stamp = () => now().toISOString();
|
|
37
|
+
function menuNotFound(id) {
|
|
38
|
+
return new CogentaError({
|
|
39
|
+
code: 'MENU_UNKNOWN',
|
|
40
|
+
message: `No menu "${id}".`,
|
|
41
|
+
hint: 'Check the identifier — list the menus of this site to find the right one.',
|
|
42
|
+
details: { id },
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function itemNotFound(id) {
|
|
46
|
+
return new CogentaError({
|
|
47
|
+
code: 'MENU_ITEM_NOT_FOUND',
|
|
48
|
+
message: `No menu item "${id}".`,
|
|
49
|
+
hint: 'Check the identifier — it may already have been removed.',
|
|
50
|
+
details: { id },
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function toMenu(row) {
|
|
54
|
+
return {
|
|
55
|
+
id: text(row['id']),
|
|
56
|
+
name: text(row['name']),
|
|
57
|
+
locale: text(row['locale']),
|
|
58
|
+
label: text(row['label']),
|
|
59
|
+
createdAt: text(row['created_at']),
|
|
60
|
+
updatedAt: text(row['updated_at']),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function toItem(row) {
|
|
64
|
+
const path = text(row['path']);
|
|
65
|
+
return {
|
|
66
|
+
id: text(row['id']),
|
|
67
|
+
menuId: text(row['menu_id']),
|
|
68
|
+
parent: nullableText(row['parent_id']),
|
|
69
|
+
label: text(row['label']),
|
|
70
|
+
kind: text(row['kind']),
|
|
71
|
+
targetCollection: nullableText(row['target_collection']),
|
|
72
|
+
targetEntryId: nullableText(row['target_entry_id']),
|
|
73
|
+
url: nullableText(row['url']),
|
|
74
|
+
position: Number(row['position']),
|
|
75
|
+
depth: depthOf(path),
|
|
76
|
+
openInNewTab: text(row['open_in_new_tab']) === 'true',
|
|
77
|
+
createdAt: text(row['created_at']),
|
|
78
|
+
updatedAt: text(row['updated_at']),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
async function menuRowOf(tx, id) {
|
|
82
|
+
const found = await tx.query(sql `select * from ${menus} where ${idColumn} = ${id}`);
|
|
83
|
+
return found.rows[0] ?? null;
|
|
84
|
+
}
|
|
85
|
+
async function itemRowOf(tx, id) {
|
|
86
|
+
const found = await tx.query(sql `select * from ${items} where ${idColumn} = ${id}`);
|
|
87
|
+
return found.rows[0] ?? null;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* A path is id-based (`taxonomy-path.ts`'s scheme, reused as-is): two
|
|
91
|
+
* siblings' paths diverge at their own id, which sorts them by creation
|
|
92
|
+
* order, not by `position`. That is fine for "everything under this term"
|
|
93
|
+
* — a `like` — but wrong for a flat listing a reorder button has to
|
|
94
|
+
* respect. So the tree is walked in application code instead: group by
|
|
95
|
+
* parent, sort each group by `position`, then depth-first from the roots.
|
|
96
|
+
* A menu is small (navigation, not a content table), so this costs nothing
|
|
97
|
+
* a database index would meaningfully save.
|
|
98
|
+
*/
|
|
99
|
+
function orderAsTree(rows) {
|
|
100
|
+
const byParent = new Map();
|
|
101
|
+
for (const row of rows) {
|
|
102
|
+
const siblings = byParent.get(row.parent) ?? [];
|
|
103
|
+
siblings.push(row);
|
|
104
|
+
byParent.set(row.parent, siblings);
|
|
105
|
+
}
|
|
106
|
+
for (const siblings of byParent.values())
|
|
107
|
+
siblings.sort((a, b) => a.position - b.position);
|
|
108
|
+
const ordered = [];
|
|
109
|
+
const visit = (parent) => {
|
|
110
|
+
for (const item of byParent.get(parent) ?? []) {
|
|
111
|
+
ordered.push(item);
|
|
112
|
+
visit(item.id);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
visit(null);
|
|
116
|
+
return ordered;
|
|
117
|
+
}
|
|
118
|
+
async function assertNameFree(tx, name, locale, exceptId) {
|
|
119
|
+
const found = await tx.query(sql `select ${idColumn} from ${menus} where ${nameColumn} = ${name} and ${localeColumn} = ${locale}`);
|
|
120
|
+
const clash = found.rows.find((row) => text(row['id']) !== exceptId);
|
|
121
|
+
if (clash === undefined)
|
|
122
|
+
return;
|
|
123
|
+
throw new CogentaError({
|
|
124
|
+
code: 'MENU_NAME_TAKEN',
|
|
125
|
+
message: `A menu called "${name}" already exists for locale "${locale}".`,
|
|
126
|
+
hint: 'A menu name is unique per locale. Pick another name, or edit the existing menu.',
|
|
127
|
+
details: { name, locale },
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
function validateItemShape(kind, body) {
|
|
131
|
+
if (kind === 'url') {
|
|
132
|
+
if (typeof body.url !== 'string' || body.url.length === 0) {
|
|
133
|
+
throw invalid('A URL item needs a non-empty "url".', 'Send { "kind": "url", "url": "https://…" }.');
|
|
134
|
+
}
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (kind === 'entry') {
|
|
138
|
+
if (typeof body.targetCollection !== 'string' || body.targetCollection.length === 0) {
|
|
139
|
+
throw invalid('An entry item needs "targetCollection".', 'Send { "kind": "entry", "targetCollection": "page", "targetEntryId": "…" }.');
|
|
140
|
+
}
|
|
141
|
+
if (typeof body.targetEntryId !== 'string' || body.targetEntryId.length === 0) {
|
|
142
|
+
throw invalid('An entry item needs "targetEntryId".', 'Send { "kind": "entry", "targetCollection": "page", "targetEntryId": "…" }.');
|
|
143
|
+
}
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
// submenu-placeholder: a label to group children under, no target of its own.
|
|
147
|
+
}
|
|
148
|
+
async function nextPosition(tx, menuId, parent) {
|
|
149
|
+
const found = await tx.query(parent === null
|
|
150
|
+
? sql `select ${positionColumn} from ${items} where ${menuIdColumn} = ${menuId} and ${parentColumn} is null`
|
|
151
|
+
: sql `select ${positionColumn} from ${items} where ${menuIdColumn} = ${menuId} and ${parentColumn} = ${parent}`);
|
|
152
|
+
return found.rows.reduce((highest, row) => Math.max(highest, Number(row['position']) + 1), 0);
|
|
153
|
+
}
|
|
154
|
+
async function parentOf(tx, menuId, parent) {
|
|
155
|
+
if (parent === null)
|
|
156
|
+
return null;
|
|
157
|
+
const row = await itemRowOf(tx, parent);
|
|
158
|
+
if (row === null || text(row['menu_id']) !== menuId) {
|
|
159
|
+
throw invalid(`The parent "${parent}" is not an item of this menu.`, 'A submenu item can only nest under an item of the same menu.', { parent, menuId });
|
|
160
|
+
}
|
|
161
|
+
return row;
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
create: async (input) => db.transaction(async (tx) => {
|
|
165
|
+
await assertNameFree(tx, input.name, input.locale);
|
|
166
|
+
const id = input.id ?? newId();
|
|
167
|
+
const at = stamp();
|
|
168
|
+
await tx.query(sql `insert into ${menus} (${joinFragments([
|
|
169
|
+
idColumn,
|
|
170
|
+
nameColumn,
|
|
171
|
+
localeColumn,
|
|
172
|
+
identifier('label', dialect),
|
|
173
|
+
identifier('created_at', dialect),
|
|
174
|
+
identifier('updated_at', dialect),
|
|
175
|
+
], ', ')}) values (${id}, ${input.name}, ${input.locale}, ${input.label}, ${at}, ${at})`);
|
|
176
|
+
const row = await menuRowOf(tx, id);
|
|
177
|
+
if (row === null)
|
|
178
|
+
throw menuNotFound(id);
|
|
179
|
+
return toMenu(row);
|
|
180
|
+
}, { immediate: true }),
|
|
181
|
+
read: async (id) => {
|
|
182
|
+
const row = await menuRowOf(db, id);
|
|
183
|
+
return row === null ? null : toMenu(row);
|
|
184
|
+
},
|
|
185
|
+
byName: async (name, locale) => {
|
|
186
|
+
const found = await db.query(sql `select * from ${menus} where ${nameColumn} = ${name} and ${localeColumn} = ${locale}`);
|
|
187
|
+
const row = found.rows[0];
|
|
188
|
+
return row === undefined ? null : toMenu(row);
|
|
189
|
+
},
|
|
190
|
+
update: async (id, input) => db.transaction(async (tx) => {
|
|
191
|
+
const row = await menuRowOf(tx, id);
|
|
192
|
+
if (row === null)
|
|
193
|
+
throw menuNotFound(id);
|
|
194
|
+
const assignments = [
|
|
195
|
+
sql `${identifier('updated_at', dialect)} = ${stamp()}`,
|
|
196
|
+
];
|
|
197
|
+
if (input.label !== undefined) {
|
|
198
|
+
assignments.push(sql `${identifier('label', dialect)} = ${input.label}`);
|
|
199
|
+
}
|
|
200
|
+
await tx.query(sql `update ${menus} set ${joinFragments(assignments, ', ')} where ${idColumn} = ${id}`);
|
|
201
|
+
const after = await menuRowOf(tx, id);
|
|
202
|
+
if (after === null)
|
|
203
|
+
throw menuNotFound(id);
|
|
204
|
+
return toMenu(after);
|
|
205
|
+
}, { immediate: true }),
|
|
206
|
+
delete: async (id, deleteOptions) => db.transaction(async (tx) => {
|
|
207
|
+
const row = await menuRowOf(tx, id);
|
|
208
|
+
if (row === null)
|
|
209
|
+
return false;
|
|
210
|
+
const count = await tx.query(sql `select ${idColumn} from ${items} where ${menuIdColumn} = ${id}`);
|
|
211
|
+
if (count.rows.length > 0 && deleteOptions?.cascade !== true) {
|
|
212
|
+
throw new CogentaError({
|
|
213
|
+
code: 'MENU_ITEM_INVALID',
|
|
214
|
+
message: `The menu "${id}" still has ${count.rows.length} item(s).`,
|
|
215
|
+
hint: 'Remove them first, or pass { cascade: true } to delete the whole menu.',
|
|
216
|
+
details: { id, items: count.rows.length },
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
const removed = await tx.query(sql `delete from ${menus} where ${idColumn} = ${id}`);
|
|
220
|
+
return removed.rowsAffected > 0;
|
|
221
|
+
}, { immediate: true }),
|
|
222
|
+
list: async (listOptions = {}) => {
|
|
223
|
+
const found = await db.query(listOptions.locale === undefined
|
|
224
|
+
? sql `select * from ${menus} order by ${nameColumn} asc`
|
|
225
|
+
: sql `select * from ${menus} where ${localeColumn} = ${listOptions.locale} order by ${nameColumn} asc`);
|
|
226
|
+
return found.rows.map(toMenu);
|
|
227
|
+
},
|
|
228
|
+
createItem: async (menuId, input) => db.transaction(async (tx) => {
|
|
229
|
+
const menu = await menuRowOf(tx, menuId);
|
|
230
|
+
if (menu === null)
|
|
231
|
+
throw menuNotFound(menuId);
|
|
232
|
+
validateItemShape(input.kind, input);
|
|
233
|
+
const parent = input.parent ?? null;
|
|
234
|
+
const parentRow = await parentOf(tx, menuId, parent);
|
|
235
|
+
const parentPath = parentRow === null ? '' : text(parentRow['path']);
|
|
236
|
+
const id = input.id ?? newId();
|
|
237
|
+
const path = childPath(parentPath, id);
|
|
238
|
+
if (depthOf(path) >= MAX_MENU_DEPTH) {
|
|
239
|
+
throw invalid(`A menu item cannot be nested more than ${MAX_MENU_DEPTH} levels deep.`, 'Flatten this branch — a menu nobody can navigate is not a menu.', { depth: depthOf(path), max: MAX_MENU_DEPTH });
|
|
240
|
+
}
|
|
241
|
+
const position = input.position ?? (await nextPosition(tx, menuId, parent));
|
|
242
|
+
const at = stamp();
|
|
243
|
+
await tx.query(sql `insert into ${items} (${joinFragments([
|
|
244
|
+
idColumn,
|
|
245
|
+
menuIdColumn,
|
|
246
|
+
parentColumn,
|
|
247
|
+
identifier('label', dialect),
|
|
248
|
+
identifier('kind', dialect),
|
|
249
|
+
identifier('target_collection', dialect),
|
|
250
|
+
identifier('target_entry_id', dialect),
|
|
251
|
+
identifier('url', dialect),
|
|
252
|
+
positionColumn,
|
|
253
|
+
pathColumn,
|
|
254
|
+
identifier('open_in_new_tab', dialect),
|
|
255
|
+
identifier('created_at', dialect),
|
|
256
|
+
identifier('updated_at', dialect),
|
|
257
|
+
], ', ')}) values (
|
|
258
|
+
${id}, ${menuId}, ${parent}, ${input.label}, ${input.kind},
|
|
259
|
+
${input.targetCollection ?? null}, ${input.targetEntryId ?? null}, ${input.url ?? null},
|
|
260
|
+
${position}, ${path}, ${input.openInNewTab === true ? 'true' : 'false'}, ${at}, ${at}
|
|
261
|
+
)`);
|
|
262
|
+
const row = await itemRowOf(tx, id);
|
|
263
|
+
if (row === null)
|
|
264
|
+
throw itemNotFound(id);
|
|
265
|
+
return toItem(row);
|
|
266
|
+
}, { immediate: true }),
|
|
267
|
+
readItem: async (id) => {
|
|
268
|
+
const row = await itemRowOf(db, id);
|
|
269
|
+
return row === null ? null : toItem(row);
|
|
270
|
+
},
|
|
271
|
+
updateItem: async (id, input) => db.transaction(async (tx) => {
|
|
272
|
+
const row = await itemRowOf(tx, id);
|
|
273
|
+
if (row === null)
|
|
274
|
+
throw itemNotFound(id);
|
|
275
|
+
const kind = (input.kind ?? text(row['kind']));
|
|
276
|
+
if (input.kind !== undefined ||
|
|
277
|
+
input.url !== undefined ||
|
|
278
|
+
input.targetCollection !== undefined ||
|
|
279
|
+
input.targetEntryId !== undefined) {
|
|
280
|
+
validateItemShape(kind, {
|
|
281
|
+
url: input.url !== undefined ? input.url : nullableText(row['url']),
|
|
282
|
+
targetCollection: input.targetCollection !== undefined
|
|
283
|
+
? input.targetCollection
|
|
284
|
+
: nullableText(row['target_collection']),
|
|
285
|
+
targetEntryId: input.targetEntryId !== undefined
|
|
286
|
+
? input.targetEntryId
|
|
287
|
+
: nullableText(row['target_entry_id']),
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
const assignments = [
|
|
291
|
+
sql `${identifier('updated_at', dialect)} = ${stamp()}`,
|
|
292
|
+
];
|
|
293
|
+
if (input.label !== undefined)
|
|
294
|
+
assignments.push(sql `${identifier('label', dialect)} = ${input.label}`);
|
|
295
|
+
if (input.kind !== undefined)
|
|
296
|
+
assignments.push(sql `${identifier('kind', dialect)} = ${input.kind}`);
|
|
297
|
+
if (input.targetCollection !== undefined) {
|
|
298
|
+
assignments.push(sql `${identifier('target_collection', dialect)} = ${input.targetCollection}`);
|
|
299
|
+
}
|
|
300
|
+
if (input.targetEntryId !== undefined) {
|
|
301
|
+
assignments.push(sql `${identifier('target_entry_id', dialect)} = ${input.targetEntryId}`);
|
|
302
|
+
}
|
|
303
|
+
if (input.url !== undefined)
|
|
304
|
+
assignments.push(sql `${identifier('url', dialect)} = ${input.url}`);
|
|
305
|
+
if (input.openInNewTab !== undefined) {
|
|
306
|
+
assignments.push(sql `${identifier('open_in_new_tab', dialect)} = ${input.openInNewTab ? 'true' : 'false'}`);
|
|
307
|
+
}
|
|
308
|
+
await tx.query(sql `update ${items} set ${joinFragments(assignments, ', ')} where ${idColumn} = ${id}`);
|
|
309
|
+
const after = await itemRowOf(tx, id);
|
|
310
|
+
if (after === null)
|
|
311
|
+
throw itemNotFound(id);
|
|
312
|
+
return toItem(after);
|
|
313
|
+
}, { immediate: true }),
|
|
314
|
+
moveItem: async (id, parent) => db.transaction(async (tx) => {
|
|
315
|
+
const row = await itemRowOf(tx, id);
|
|
316
|
+
if (row === null)
|
|
317
|
+
throw itemNotFound(id);
|
|
318
|
+
const menuId = text(row['menu_id']);
|
|
319
|
+
const from = text(row['path']);
|
|
320
|
+
const parentRow = await parentOf(tx, menuId, parent);
|
|
321
|
+
const parentPath = parentRow === null ? '' : text(parentRow['path']);
|
|
322
|
+
if (parent !== null && isWithin(parentPath, from)) {
|
|
323
|
+
throw new CogentaError({
|
|
324
|
+
code: 'MENU_CYCLE',
|
|
325
|
+
message: `Moving "${id}" under "${parent}" would make it its own ancestor.`,
|
|
326
|
+
hint: 'Move the target out of this subtree first.',
|
|
327
|
+
details: { id, parent },
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
const to = childPath(parentPath, id);
|
|
331
|
+
if (to === from)
|
|
332
|
+
return toItem(row);
|
|
333
|
+
const subtree = await tx.query(sql `select * from ${items} where ${menuIdColumn} = ${menuId} and ${pathColumn} like ${`${from}%`}`);
|
|
334
|
+
for (const member of subtree.rows) {
|
|
335
|
+
const rebased = rebasedPath(text(member['path']), from, to);
|
|
336
|
+
if (depthOf(rebased) >= MAX_MENU_DEPTH) {
|
|
337
|
+
throw invalid(`Moving "${id}" would nest a descendant more than ${MAX_MENU_DEPTH} levels deep.`, 'Flatten the branch before moving it further down the tree.', { depth: depthOf(rebased), max: MAX_MENU_DEPTH });
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
const at = stamp();
|
|
341
|
+
for (const member of subtree.rows) {
|
|
342
|
+
const memberId = text(member['id']);
|
|
343
|
+
const rebased = rebasedPath(text(member['path']), from, to);
|
|
344
|
+
await tx.query(sql `update ${items}
|
|
345
|
+
set ${pathColumn} = ${rebased}, ${identifier('updated_at', dialect)} = ${at}
|
|
346
|
+
where ${idColumn} = ${memberId}`);
|
|
347
|
+
}
|
|
348
|
+
await tx.query(sql `update ${items}
|
|
349
|
+
set ${parentColumn} = ${parent}, ${positionColumn} = ${await nextPosition(tx, menuId, parent)}
|
|
350
|
+
where ${idColumn} = ${id}`);
|
|
351
|
+
const after = await itemRowOf(tx, id);
|
|
352
|
+
if (after === null)
|
|
353
|
+
throw itemNotFound(id);
|
|
354
|
+
return toItem(after);
|
|
355
|
+
}, { immediate: true }),
|
|
356
|
+
reorderItem: async (id, direction) => db.transaction(async (tx) => {
|
|
357
|
+
const row = await itemRowOf(tx, id);
|
|
358
|
+
if (row === null)
|
|
359
|
+
throw itemNotFound(id);
|
|
360
|
+
const menuId = text(row['menu_id']);
|
|
361
|
+
const parent = nullableText(row['parent_id']);
|
|
362
|
+
const siblings = await tx.query(parent === null
|
|
363
|
+
? sql `select * from ${items} where ${menuIdColumn} = ${menuId} and ${parentColumn} is null order by ${positionColumn} asc`
|
|
364
|
+
: sql `select * from ${items} where ${menuIdColumn} = ${menuId} and ${parentColumn} = ${parent} order by ${positionColumn} asc`);
|
|
365
|
+
const index = siblings.rows.findIndex((sibling) => text(sibling['id']) === id);
|
|
366
|
+
const swapIndex = direction === 'up' ? index - 1 : index + 1;
|
|
367
|
+
if (index === -1 || swapIndex < 0 || swapIndex >= siblings.rows.length) {
|
|
368
|
+
const after = await itemRowOf(tx, id);
|
|
369
|
+
if (after === null)
|
|
370
|
+
throw itemNotFound(id);
|
|
371
|
+
return toItem(after);
|
|
372
|
+
}
|
|
373
|
+
const neighbour = siblings.rows[swapIndex];
|
|
374
|
+
if (neighbour === undefined) {
|
|
375
|
+
const after = await itemRowOf(tx, id);
|
|
376
|
+
if (after === null)
|
|
377
|
+
throw itemNotFound(id);
|
|
378
|
+
return toItem(after);
|
|
379
|
+
}
|
|
380
|
+
const at = stamp();
|
|
381
|
+
const myPosition = row['position'];
|
|
382
|
+
const neighbourPosition = neighbour['position'];
|
|
383
|
+
await tx.query(sql `update ${items} set ${positionColumn} = ${neighbourPosition}, ${identifier('updated_at', dialect)} = ${at}
|
|
384
|
+
where ${idColumn} = ${id}`);
|
|
385
|
+
await tx.query(sql `update ${items} set ${positionColumn} = ${myPosition}, ${identifier('updated_at', dialect)} = ${at}
|
|
386
|
+
where ${idColumn} = ${text(neighbour['id'])}`);
|
|
387
|
+
const after = await itemRowOf(tx, id);
|
|
388
|
+
if (after === null)
|
|
389
|
+
throw itemNotFound(id);
|
|
390
|
+
return toItem(after);
|
|
391
|
+
}, { immediate: true }),
|
|
392
|
+
deleteItem: async (id, deleteOptions) => db.transaction(async (tx) => {
|
|
393
|
+
const row = await itemRowOf(tx, id);
|
|
394
|
+
if (row === null)
|
|
395
|
+
return false;
|
|
396
|
+
const path = text(row['path']);
|
|
397
|
+
const menuId = text(row['menu_id']);
|
|
398
|
+
const descendants = await tx.query(sql `select ${idColumn}, ${pathColumn} from ${items}
|
|
399
|
+
where ${menuIdColumn} = ${menuId} and ${pathColumn} like ${`${path}%`}`);
|
|
400
|
+
const children = descendants.rows.filter((member) => isBelow(text(member['path']), path));
|
|
401
|
+
if (children.length > 0 && deleteOptions?.cascade !== true) {
|
|
402
|
+
throw new CogentaError({
|
|
403
|
+
code: 'MENU_ITEM_INVALID',
|
|
404
|
+
message: `The menu item "${id}" still has ${children.length} child item(s).`,
|
|
405
|
+
hint: 'Move them elsewhere first, or pass { cascade: true } to delete the whole branch.',
|
|
406
|
+
details: { id, descendants: children.length },
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
const removed = await tx.query(sql `delete from ${items} where ${idColumn} = ${id}`);
|
|
410
|
+
return removed.rowsAffected > 0;
|
|
411
|
+
}, { immediate: true }),
|
|
412
|
+
listItems: async (menuId) => {
|
|
413
|
+
const found = await db.query(sql `select * from ${items} where ${menuIdColumn} = ${menuId}`);
|
|
414
|
+
return orderAsTree(found.rows.map(toItem));
|
|
415
|
+
},
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
//# sourceMappingURL=menu-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menu-store.js","sourceRoot":"","sources":["../../src/store/menu-store.ts"],"names":[],"mappings":"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"}
|