@manablox/db 0.2.0 → 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/index-Cyf_N5K3.d.ts +658 -0
- package/dist/index-rZ24t-Ln.d.ts +4338 -0
- package/dist/index.d.ts +123 -0
- package/dist/index.js +60 -0
- package/dist/repositories-DYjzuuF6.js +1533 -0
- package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
- package/dist/schema-Bb4p16Yz.js +539 -0
- package/dist/schema.d.ts +2 -0
- package/dist/schema.js +2 -0
- package/dist/testing.d.ts +77 -0
- package/dist/testing.js +217 -0
- package/package.json +18 -10
- package/drizzle.config.ts +0 -11
- package/src/bootstrap.ts +0 -13
- package/src/cli/create-db.ts +0 -30
- package/src/cli/migrate.ts +0 -17
- package/src/client.ts +0 -44
- package/src/columns.ts +0 -39
- package/src/errors.ts +0 -50
- package/src/index.ts +0 -19
- package/src/migrate.ts +0 -21
- package/src/pagination.ts +0 -52
- package/src/query.ts +0 -213
- package/src/repositories/asset-usage.ts +0 -166
- package/src/repositories/asset.ts +0 -181
- package/src/repositories/content-type.ts +0 -116
- package/src/repositories/content.ts +0 -811
- package/src/repositories/index.ts +0 -40
- package/src/repositories/menu.ts +0 -235
- package/src/repositories/role.ts +0 -85
- package/src/repositories/space.ts +0 -83
- package/src/repositories/user.ts +0 -280
- package/src/repositories/webhook.ts +0 -46
- package/src/repositories/workflow.ts +0 -306
- package/src/schema/assets.ts +0 -108
- package/src/schema/auth.ts +0 -166
- package/src/schema/content-types.ts +0 -31
- package/src/schema/content.ts +0 -133
- package/src/schema/index.ts +0 -38
- package/src/schema/menus.ts +0 -61
- package/src/schema/relations.ts +0 -64
- package/src/schema/spaces.ts +0 -20
- package/src/schema/webhooks.ts +0 -46
- package/src/schema/workflows.ts +0 -92
- package/src/testing-fixtures.ts +0 -139
- package/src/testing.ts +0 -105
- package/test/asset-usage.test.ts +0 -101
- package/test/menu.test.ts +0 -126
- package/test/publish.test.ts +0 -130
- package/test/query.test.ts +0 -170
- package/test/role.test.ts +0 -81
- package/test/tree.test.ts +0 -188
- package/test/user.test.ts +0 -126
- package/test/webhook.test.ts +0 -48
- package/tsconfig.json +0 -4
- package/vitest.config.ts +0 -10
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { ContentTypeRegistry } from '@manablox/core';
|
|
2
|
-
import type { Database } from '../client.js';
|
|
3
|
-
import { AssetRepository } from './asset.js';
|
|
4
|
-
import { AssetUsageRepository } from './asset-usage.js';
|
|
5
|
-
import { ContentRepository } from './content.js';
|
|
6
|
-
import { ContentTypeRepository } from './content-type.js';
|
|
7
|
-
import { MenuRepository } from './menu.js';
|
|
8
|
-
import { RoleRepository } from './role.js';
|
|
9
|
-
import { SpaceRepository } from './space.js';
|
|
10
|
-
import { UserRepository } from './user.js';
|
|
11
|
-
import { WebhookRepository } from './webhook.js';
|
|
12
|
-
import { WorkflowRepository } from './workflow.js';
|
|
13
|
-
|
|
14
|
-
export interface Repositories {
|
|
15
|
-
content: ContentRepository;
|
|
16
|
-
contentTypes: ContentTypeRepository;
|
|
17
|
-
spaces: SpaceRepository;
|
|
18
|
-
assets: AssetRepository;
|
|
19
|
-
assetUsages: AssetUsageRepository;
|
|
20
|
-
users: UserRepository;
|
|
21
|
-
menus: MenuRepository;
|
|
22
|
-
roles: RoleRepository;
|
|
23
|
-
workflows: WorkflowRepository;
|
|
24
|
-
webhooks: WebhookRepository;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function createRepositories(db: Database, registry: ContentTypeRegistry): Repositories {
|
|
28
|
-
return {
|
|
29
|
-
content: new ContentRepository(db, registry),
|
|
30
|
-
contentTypes: new ContentTypeRepository(db),
|
|
31
|
-
spaces: new SpaceRepository(db),
|
|
32
|
-
assets: new AssetRepository(db),
|
|
33
|
-
assetUsages: new AssetUsageRepository(db),
|
|
34
|
-
users: new UserRepository(db),
|
|
35
|
-
menus: new MenuRepository(db),
|
|
36
|
-
roles: new RoleRepository(db),
|
|
37
|
-
workflows: new WorkflowRepository(db),
|
|
38
|
-
webhooks: new WebhookRepository(db),
|
|
39
|
-
};
|
|
40
|
-
}
|
package/src/repositories/menu.ts
DELETED
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import { type Loose, ManabloxError } from '@manablox/core';
|
|
3
|
-
import { and, asc, eq, inArray } from 'drizzle-orm';
|
|
4
|
-
import type { Database } from '../client.js';
|
|
5
|
-
import {
|
|
6
|
-
type ContentRow,
|
|
7
|
-
contents,
|
|
8
|
-
type MenuItemRow,
|
|
9
|
-
type MenuRow,
|
|
10
|
-
menuItems,
|
|
11
|
-
menus,
|
|
12
|
-
publishedContents,
|
|
13
|
-
} from '../schema/index.js';
|
|
14
|
-
|
|
15
|
-
export interface MenuWriteData {
|
|
16
|
-
id?: string | undefined;
|
|
17
|
-
spaceId: string;
|
|
18
|
-
name: string;
|
|
19
|
-
machineName: string;
|
|
20
|
-
description?: string | null | undefined;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* One entry as the admin hands over the whole menu: a content entry names a
|
|
25
|
-
* `localizationId`, a link entry a `url`; either may carry a label. `id` is kept when
|
|
26
|
-
* given, so an unchanged entry keeps its identity across saves.
|
|
27
|
-
*/
|
|
28
|
-
export interface MenuItemInput {
|
|
29
|
-
id?: string | undefined;
|
|
30
|
-
localizationId?: string | null | undefined;
|
|
31
|
-
label?: string | null | undefined;
|
|
32
|
-
url?: string | null | undefined;
|
|
33
|
-
children?: MenuItemInput[] | undefined;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface MenuItemNode {
|
|
37
|
-
item: MenuItemRow;
|
|
38
|
-
children: MenuItemNode[];
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/** An entry with its document looked up for one locale; `content` is null for a link. */
|
|
42
|
-
export interface ResolvedMenuItem {
|
|
43
|
-
id: string;
|
|
44
|
-
label: string | null;
|
|
45
|
-
url: string | null;
|
|
46
|
-
localizationId: string | null;
|
|
47
|
-
content: ContentRow | null;
|
|
48
|
-
children: ResolvedMenuItem[];
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export class MenuRepository {
|
|
52
|
-
constructor(private readonly db: Database) {}
|
|
53
|
-
|
|
54
|
-
async listBySpace(spaceId: string): Promise<MenuRow[]> {
|
|
55
|
-
return this.db.select().from(menus).where(eq(menus.spaceId, spaceId)).orderBy(menus.name);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async findById(id: string): Promise<MenuRow | null> {
|
|
59
|
-
const rows = await this.db.select().from(menus).where(eq(menus.id, id)).limit(1);
|
|
60
|
-
return rows[0] ?? null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async findByMachineName(spaceId: string, machineName: string): Promise<MenuRow | null> {
|
|
64
|
-
const rows = await this.db
|
|
65
|
-
.select()
|
|
66
|
-
.from(menus)
|
|
67
|
-
.where(and(eq(menus.spaceId, spaceId), eq(menus.machineName, machineName)))
|
|
68
|
-
.limit(1);
|
|
69
|
-
return rows[0] ?? null;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
async create(data: MenuWriteData): Promise<MenuRow> {
|
|
73
|
-
const [row] = await this.db
|
|
74
|
-
.insert(menus)
|
|
75
|
-
.values({
|
|
76
|
-
...(data.id ? { id: data.id } : {}),
|
|
77
|
-
spaceId: data.spaceId,
|
|
78
|
-
name: data.name,
|
|
79
|
-
machineName: data.machineName,
|
|
80
|
-
description: data.description ?? null,
|
|
81
|
-
})
|
|
82
|
-
.returning();
|
|
83
|
-
if (!row) throw new ManabloxError('menu.create.failed');
|
|
84
|
-
return row;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async update(id: string, data: Loose<Omit<MenuWriteData, 'spaceId'>>): Promise<MenuRow> {
|
|
88
|
-
const [row] = await this.db
|
|
89
|
-
.update(menus)
|
|
90
|
-
.set({
|
|
91
|
-
...(data.name !== undefined ? { name: data.name } : {}),
|
|
92
|
-
...(data.machineName !== undefined ? { machineName: data.machineName } : {}),
|
|
93
|
-
...(data.description !== undefined ? { description: data.description } : {}),
|
|
94
|
-
updatedAt: new Date(),
|
|
95
|
-
})
|
|
96
|
-
.where(eq(menus.id, id))
|
|
97
|
-
.returning();
|
|
98
|
-
if (!row) throw ManabloxError.notFound('menu.notFound', { id });
|
|
99
|
-
return row;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
async delete(id: string): Promise<void> {
|
|
103
|
-
await this.db.delete(menus).where(eq(menus.id, id));
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/** Every entry of a menu, flat, in tree order within each level. */
|
|
107
|
-
async items(menuId: string): Promise<MenuItemRow[]> {
|
|
108
|
-
return this.db
|
|
109
|
-
.select()
|
|
110
|
-
.from(menuItems)
|
|
111
|
-
.where(eq(menuItems.menuId, menuId))
|
|
112
|
-
.orderBy(asc(menuItems.position), asc(menuItems.id));
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
async tree(menuId: string): Promise<MenuItemNode[]> {
|
|
116
|
-
return buildTree(await this.items(menuId));
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Replaces the whole entry tree in one transaction.
|
|
121
|
-
*
|
|
122
|
-
* A menu is edited as one document and saved as one, so this is simpler and safer than
|
|
123
|
-
* a per-entry API whose partial failures would leave a half-reordered menu behind.
|
|
124
|
-
*/
|
|
125
|
-
async setItems(menuId: string, tree: MenuItemInput[]): Promise<MenuItemNode[]> {
|
|
126
|
-
const rows: (typeof menuItems.$inferInsert)[] = [];
|
|
127
|
-
const flatten = (nodes: MenuItemInput[], parentId: string | null) => {
|
|
128
|
-
nodes.forEach((node, position) => {
|
|
129
|
-
const id = node.id ?? randomUUID();
|
|
130
|
-
rows.push({
|
|
131
|
-
id,
|
|
132
|
-
menuId,
|
|
133
|
-
parentId,
|
|
134
|
-
position,
|
|
135
|
-
localizationId: node.localizationId ?? null,
|
|
136
|
-
label: node.label ?? null,
|
|
137
|
-
url: node.url ?? null,
|
|
138
|
-
});
|
|
139
|
-
flatten(node.children ?? [], id);
|
|
140
|
-
});
|
|
141
|
-
};
|
|
142
|
-
flatten(tree, null);
|
|
143
|
-
|
|
144
|
-
return this.db.transaction(async (tx) => {
|
|
145
|
-
await tx.delete(menuItems).where(eq(menuItems.menuId, menuId));
|
|
146
|
-
if (rows.length) await tx.insert(menuItems).values(rows);
|
|
147
|
-
await tx.update(menus).set({ updatedAt: new Date() }).where(eq(menus.id, menuId));
|
|
148
|
-
return buildTree(rows.map((row) => ({ ...row, position: row.position ?? 0 }) as MenuItemRow));
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/** Menus that carry the document, for the editor's "used in" hint. */
|
|
153
|
-
async menusReferencing(spaceId: string, localizationId: string): Promise<MenuRow[]> {
|
|
154
|
-
return this.db
|
|
155
|
-
.selectDistinct({
|
|
156
|
-
id: menus.id,
|
|
157
|
-
spaceId: menus.spaceId,
|
|
158
|
-
name: menus.name,
|
|
159
|
-
machineName: menus.machineName,
|
|
160
|
-
description: menus.description,
|
|
161
|
-
createdAt: menus.createdAt,
|
|
162
|
-
updatedAt: menus.updatedAt,
|
|
163
|
-
})
|
|
164
|
-
.from(menuItems)
|
|
165
|
-
.innerJoin(menus, eq(menuItems.menuId, menus.id))
|
|
166
|
-
.where(and(eq(menus.spaceId, spaceId), eq(menuItems.localizationId, localizationId)))
|
|
167
|
-
.orderBy(menus.name);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/** Drops every entry pointing at a document, in every menu; sub-entries cascade. */
|
|
171
|
-
async removeContent(localizationId: string): Promise<number> {
|
|
172
|
-
const removed = await this.db
|
|
173
|
-
.delete(menuItems)
|
|
174
|
-
.where(eq(menuItems.localizationId, localizationId))
|
|
175
|
-
.returning({ id: menuItems.id });
|
|
176
|
-
return removed.length;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* The tree with each content entry's document for one locale. A content entry whose
|
|
181
|
-
* document has no row in that locale — or, on the published table, no published one —
|
|
182
|
-
* comes back with `content: null`; the caller decides whether to show or drop it.
|
|
183
|
-
*/
|
|
184
|
-
async resolve(menu: MenuRow, locale: string, published = false): Promise<ResolvedMenuItem[]> {
|
|
185
|
-
const items = await this.items(menu.id);
|
|
186
|
-
const localizationIds = [
|
|
187
|
-
...new Set(items.flatMap((item) => (item.localizationId ? [item.localizationId] : []))),
|
|
188
|
-
];
|
|
189
|
-
|
|
190
|
-
const table = published ? publishedContents : contents;
|
|
191
|
-
const rows = localizationIds.length
|
|
192
|
-
? await this.db
|
|
193
|
-
.select()
|
|
194
|
-
.from(table)
|
|
195
|
-
.where(
|
|
196
|
-
and(
|
|
197
|
-
eq(table.spaceId, menu.spaceId),
|
|
198
|
-
eq(table.locale, locale),
|
|
199
|
-
inArray(table.localizationId, localizationIds),
|
|
200
|
-
),
|
|
201
|
-
)
|
|
202
|
-
: [];
|
|
203
|
-
const byLocalization = new Map(rows.map((row) => [row.localizationId, row]));
|
|
204
|
-
|
|
205
|
-
const toResolved = (node: MenuItemNode): ResolvedMenuItem => ({
|
|
206
|
-
id: node.item.id,
|
|
207
|
-
label: node.item.label,
|
|
208
|
-
url: node.item.url,
|
|
209
|
-
localizationId: node.item.localizationId,
|
|
210
|
-
content: node.item.localizationId
|
|
211
|
-
? (byLocalization.get(node.item.localizationId) ?? null)
|
|
212
|
-
: null,
|
|
213
|
-
children: node.children.map(toResolved),
|
|
214
|
-
});
|
|
215
|
-
return buildTree(items).map(toResolved);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function buildTree(rows: MenuItemRow[]): MenuItemNode[] {
|
|
220
|
-
const nodes = new Map<string, MenuItemNode>();
|
|
221
|
-
for (const row of rows) nodes.set(row.id, { item: row, children: [] });
|
|
222
|
-
|
|
223
|
-
const roots: MenuItemNode[] = [];
|
|
224
|
-
for (const node of nodes.values()) {
|
|
225
|
-
const parent = node.item.parentId ? nodes.get(node.item.parentId) : undefined;
|
|
226
|
-
(parent ? parent.children : roots).push(node);
|
|
227
|
-
}
|
|
228
|
-
const byPosition = (a: MenuItemNode, b: MenuItemNode) => a.item.position - b.item.position;
|
|
229
|
-
const sort = (list: MenuItemNode[]) => {
|
|
230
|
-
list.sort(byPosition);
|
|
231
|
-
for (const node of list) sort(node.children);
|
|
232
|
-
};
|
|
233
|
-
sort(roots);
|
|
234
|
-
return roots;
|
|
235
|
-
}
|
package/src/repositories/role.ts
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { ManabloxError } from '@manablox/core';
|
|
2
|
-
import { and, eq, sql } from 'drizzle-orm';
|
|
3
|
-
import type { Database } from '../client.js';
|
|
4
|
-
import { memberships, type RoleRow, roles } from '../schema/index.js';
|
|
5
|
-
|
|
6
|
-
export interface RoleWriteData {
|
|
7
|
-
name: string;
|
|
8
|
-
machineName: string;
|
|
9
|
-
description?: string | null;
|
|
10
|
-
permissions: string[];
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export class RoleRepository {
|
|
14
|
-
constructor(private readonly db: Database) {}
|
|
15
|
-
|
|
16
|
-
async listBySpace(spaceId: string): Promise<RoleRow[]> {
|
|
17
|
-
return this.db.select().from(roles).where(eq(roles.spaceId, spaceId)).orderBy(roles.name);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async findById(id: string): Promise<RoleRow | null> {
|
|
21
|
-
const rows = await this.db.select().from(roles).where(eq(roles.id, id)).limit(1);
|
|
22
|
-
return rows[0] ?? null;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
async findByMachineName(spaceId: string, machineName: string): Promise<RoleRow | null> {
|
|
26
|
-
const rows = await this.db
|
|
27
|
-
.select()
|
|
28
|
-
.from(roles)
|
|
29
|
-
.where(and(eq(roles.spaceId, spaceId), eq(roles.machineName, machineName)))
|
|
30
|
-
.limit(1);
|
|
31
|
-
return rows[0] ?? null;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async create(spaceId: string, data: RoleWriteData): Promise<RoleRow> {
|
|
35
|
-
const [row] = await this.db
|
|
36
|
-
.insert(roles)
|
|
37
|
-
.values({ spaceId, ...data })
|
|
38
|
-
.returning();
|
|
39
|
-
if (!row) throw new ManabloxError('role.create.failed');
|
|
40
|
-
return row;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async update(id: string, data: Partial<RoleWriteData>): Promise<RoleRow> {
|
|
44
|
-
const [row] = await this.db
|
|
45
|
-
.update(roles)
|
|
46
|
-
.set({ ...data, updatedAt: new Date() })
|
|
47
|
-
.where(eq(roles.id, id))
|
|
48
|
-
.returning();
|
|
49
|
-
if (!row) throw ManabloxError.notFound('role.notFound', { id });
|
|
50
|
-
return row;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async delete(id: string): Promise<void> {
|
|
54
|
-
await this.db.delete(roles).where(eq(roles.id, id));
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/** How many members of the role's space hold it, by name. */
|
|
58
|
-
async countMembers(spaceId: string, machineName: string): Promise<number> {
|
|
59
|
-
const rows = await this.db
|
|
60
|
-
.select({ count: sql<number>`count(*)::int` })
|
|
61
|
-
.from(memberships)
|
|
62
|
-
.where(and(eq(memberships.spaceId, spaceId), eq(memberships.role, machineName)));
|
|
63
|
-
return rows[0]?.count ?? 0;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Drops every grant narrowed to a content type from every role, once the type is
|
|
68
|
-
* gone. Grants are a JSON array, so this is one statement across the roles that carry
|
|
69
|
-
* such a grant rather than a read-modify-write per role.
|
|
70
|
-
*/
|
|
71
|
-
async pruneContentType(typeId: string): Promise<void> {
|
|
72
|
-
const suffix = `:${typeId}`;
|
|
73
|
-
await this.db
|
|
74
|
-
.update(roles)
|
|
75
|
-
.set({
|
|
76
|
-
permissions: sql`(
|
|
77
|
-
select coalesce(jsonb_agg(value), '[]'::jsonb)
|
|
78
|
-
from jsonb_array_elements_text(${roles.permissions}) as value
|
|
79
|
-
where value not like ${`%${suffix}`}
|
|
80
|
-
)`,
|
|
81
|
-
updatedAt: new Date(),
|
|
82
|
-
})
|
|
83
|
-
.where(sql`${roles.permissions}::text like ${`%${suffix}%`}`);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { type Loose, ManabloxError } from '@manablox/core';
|
|
2
|
-
import { eq, inArray } from 'drizzle-orm';
|
|
3
|
-
import type { Database } from '../client.js';
|
|
4
|
-
import { type SpaceRow, spaces } from '../schema/index.js';
|
|
5
|
-
|
|
6
|
-
export interface SpaceWriteData {
|
|
7
|
-
id?: string | undefined;
|
|
8
|
-
name: string;
|
|
9
|
-
machineName: string;
|
|
10
|
-
description?: string | null | undefined;
|
|
11
|
-
url: string;
|
|
12
|
-
defaultLocale?: string | undefined;
|
|
13
|
-
locales?: string[] | undefined;
|
|
14
|
-
settings?: Record<string, unknown> | undefined;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export class SpaceRepository {
|
|
18
|
-
constructor(private readonly db: Database) {}
|
|
19
|
-
|
|
20
|
-
async all(): Promise<SpaceRow[]> {
|
|
21
|
-
return this.db.select().from(spaces).orderBy(spaces.name);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
async findManyByIds(ids: string[]): Promise<SpaceRow[]> {
|
|
25
|
-
if (ids.length === 0) return [];
|
|
26
|
-
return this.db.select().from(spaces).where(inArray(spaces.id, ids)).orderBy(spaces.name);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async findById(id: string): Promise<SpaceRow | null> {
|
|
30
|
-
const rows = await this.db.select().from(spaces).where(eq(spaces.id, id)).limit(1);
|
|
31
|
-
return rows[0] ?? null;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async findByMachineName(machineName: string): Promise<SpaceRow | null> {
|
|
35
|
-
const rows = await this.db
|
|
36
|
-
.select()
|
|
37
|
-
.from(spaces)
|
|
38
|
-
.where(eq(spaces.machineName, machineName))
|
|
39
|
-
.limit(1);
|
|
40
|
-
return rows[0] ?? null;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async create(data: SpaceWriteData): Promise<SpaceRow> {
|
|
44
|
-
const [row] = await this.db
|
|
45
|
-
.insert(spaces)
|
|
46
|
-
.values({
|
|
47
|
-
...(data.id ? { id: data.id } : {}),
|
|
48
|
-
name: data.name,
|
|
49
|
-
machineName: data.machineName,
|
|
50
|
-
description: data.description ?? null,
|
|
51
|
-
url: data.url,
|
|
52
|
-
defaultLocale: data.defaultLocale ?? 'en',
|
|
53
|
-
locales: data.locales ?? [data.defaultLocale ?? 'en'],
|
|
54
|
-
settings: data.settings ?? {},
|
|
55
|
-
})
|
|
56
|
-
.returning();
|
|
57
|
-
if (!row) throw new ManabloxError('space.create.failed');
|
|
58
|
-
return row;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async update(id: string, data: Loose<SpaceWriteData>): Promise<SpaceRow> {
|
|
62
|
-
const [row] = await this.db
|
|
63
|
-
.update(spaces)
|
|
64
|
-
.set({
|
|
65
|
-
...(data.name !== undefined ? { name: data.name } : {}),
|
|
66
|
-
...(data.machineName !== undefined ? { machineName: data.machineName } : {}),
|
|
67
|
-
...(data.description !== undefined ? { description: data.description } : {}),
|
|
68
|
-
...(data.url !== undefined ? { url: data.url } : {}),
|
|
69
|
-
...(data.defaultLocale !== undefined ? { defaultLocale: data.defaultLocale } : {}),
|
|
70
|
-
...(data.locales !== undefined ? { locales: data.locales } : {}),
|
|
71
|
-
...(data.settings !== undefined ? { settings: data.settings } : {}),
|
|
72
|
-
updatedAt: new Date(),
|
|
73
|
-
})
|
|
74
|
-
.where(eq(spaces.id, id))
|
|
75
|
-
.returning();
|
|
76
|
-
if (!row) throw ManabloxError.notFound('space.notFound', { id });
|
|
77
|
-
return row;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
async delete(id: string): Promise<void> {
|
|
81
|
-
await this.db.delete(spaces).where(eq(spaces.id, id));
|
|
82
|
-
}
|
|
83
|
-
}
|