@coffer-org/server 2.5.2 → 2.6.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/collection-io.js +3 -4
- package/dist/extend-table.js +4 -5
- package/dist/global-search.js +3 -8
- package/dist/index.js +7 -2
- package/dist/mutate.js +4 -7
- package/dist/plugin-runtime.js +3 -5
- package/dist/read-rows.d.ts +8 -0
- package/dist/read-rows.js +11 -0
- package/dist/records-api.js +3 -3
- package/package.json +1 -1
package/dist/collection-io.js
CHANGED
|
@@ -2,6 +2,7 @@ import { serialize } from '@mikro-orm/core';
|
|
|
2
2
|
import { collectionGroups, fieldEntries, storageColumns } from '@coffer-org/sdk/shelf';
|
|
3
3
|
import { isGroup, isEmbeddedGroup, isJsonStored } from '@coffer-org/sdk/fields';
|
|
4
4
|
import { chunk } from "./batch.js";
|
|
5
|
+
import { selectRows } from "./read-rows.js";
|
|
5
6
|
function flattenLayout(fields) {
|
|
6
7
|
const out = [];
|
|
7
8
|
for (const f of fields) {
|
|
@@ -68,7 +69,7 @@ export async function readAt(em, prefix, fields, parentId) {
|
|
|
68
69
|
for (const c of collectionGroups(fields)) {
|
|
69
70
|
const table = `${prefix}__${c.key}`;
|
|
70
71
|
const childFields = c.group.fields;
|
|
71
|
-
const rows =
|
|
72
|
+
const rows = (await selectRows(em, table, { parent_id: parentId }, { orderBy: { position: 'asc' } }));
|
|
72
73
|
const acc = [];
|
|
73
74
|
for (const row of rows) {
|
|
74
75
|
const { id, parent_id: _pid, position: _pos, ...rest } = row;
|
|
@@ -90,9 +91,7 @@ export async function readAtMany(em, prefix, fields, parentIds) {
|
|
|
90
91
|
const childFields = c.group.fields;
|
|
91
92
|
const rows = [];
|
|
92
93
|
for (const ids of chunk(parentIds)) {
|
|
93
|
-
rows.push(...
|
|
94
|
-
orderBy: { position: 'asc' },
|
|
95
|
-
})));
|
|
94
|
+
rows.push(...(await selectRows(em, table, { parent_id: { $in: ids } }, { orderBy: { position: 'asc' } })));
|
|
96
95
|
}
|
|
97
96
|
const nestedByChild = await readAtMany(em, table, childFields, rows.map((r) => r.id));
|
|
98
97
|
for (const id of parentIds)
|
package/dist/extend-table.js
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
import { serialize } from '@mikro-orm/core';
|
|
2
1
|
import { getEm } from "./db.js";
|
|
3
2
|
import { splitAt, writeAt, readAt, readAtMany, deleteAt } from "./collection-io.js";
|
|
4
3
|
import { chunk } from "./batch.js";
|
|
4
|
+
import { selectRows } from "./read-rows.js";
|
|
5
5
|
export function extendEntityName(e) {
|
|
6
6
|
return `extend__${e.id}`;
|
|
7
7
|
}
|
|
8
8
|
export async function getExtendRecord(e, baseId, em) {
|
|
9
9
|
const fork = em ?? getEm().fork();
|
|
10
10
|
const name = extendEntityName(e);
|
|
11
|
-
const
|
|
12
|
-
if (!
|
|
11
|
+
const [flat] = (await selectRows(fork, name, { base_id: baseId }, { limit: 1 }));
|
|
12
|
+
if (!flat)
|
|
13
13
|
return undefined;
|
|
14
|
-
const flat = serialize(row);
|
|
15
14
|
const collections = await readAt(fork, name, e.fields, baseId);
|
|
16
15
|
return { ...flat, ...collections };
|
|
17
16
|
}
|
|
@@ -23,7 +22,7 @@ export async function getExtendRecords(e, baseIds, em) {
|
|
|
23
22
|
const name = extendEntityName(e);
|
|
24
23
|
const flats = [];
|
|
25
24
|
for (const ids of chunk(baseIds)) {
|
|
26
|
-
flats.push(...
|
|
25
|
+
flats.push(...(await selectRows(fork, name, { base_id: { $in: ids } })));
|
|
27
26
|
}
|
|
28
27
|
if (flats.length === 0)
|
|
29
28
|
return out;
|
package/dist/global-search.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { textSearchKeys, titleKey, recordTitle, storageColumnsFor } from '@coffer-org/sdk/shelf';
|
|
2
|
-
import { serialize } from '@mikro-orm/core';
|
|
3
2
|
import { tokenize } from '@coffer-org/core/search';
|
|
4
3
|
import { getLogger } from '@coffer-org/sdk/logger';
|
|
5
4
|
import { getEm } from "./db.js";
|
|
6
5
|
import { rowMatch } from "./records-api.js";
|
|
7
6
|
import { ftsAvailable, ftsCandidates, MIN_FTS_QUERY_LENGTH } from "./search-index.js";
|
|
7
|
+
import { selectRows } from "./read-rows.js";
|
|
8
8
|
const log = getLogger('search');
|
|
9
9
|
export const SEARCH_SCAN_LIMIT = 1000;
|
|
10
10
|
function matchCols(m) {
|
|
@@ -44,10 +44,7 @@ export async function globalSearchByScan(shelves, q, limit) {
|
|
|
44
44
|
continue;
|
|
45
45
|
if (!textSearchKeys(shelf.def).length)
|
|
46
46
|
continue;
|
|
47
|
-
const rows =
|
|
48
|
-
limit: SEARCH_SCAN_LIMIT,
|
|
49
|
-
fields: matchCols(shelf.def),
|
|
50
|
-
})).map((r) => serialize(r));
|
|
47
|
+
const rows = await selectRows(fork, shelf.table, {}, { limit: SEARCH_SCAN_LIMIT, fields: matchCols(shelf.def) });
|
|
51
48
|
if (rows.length === SEARCH_SCAN_LIMIT) {
|
|
52
49
|
log.warn('scan cap reached', { shelf: shelf.key, limit: SEARCH_SCAN_LIMIT });
|
|
53
50
|
}
|
|
@@ -77,9 +74,7 @@ export async function globalSearch(shelves, q, limit) {
|
|
|
77
74
|
continue;
|
|
78
75
|
if (!textSearchKeys(shelf.def).length)
|
|
79
76
|
continue;
|
|
80
|
-
const rows =
|
|
81
|
-
fields: matchCols(shelf.def),
|
|
82
|
-
})).map((r) => serialize(r));
|
|
77
|
+
const rows = await selectRows(fork, shelf.table, { id: { $in: ids } }, { fields: matchCols(shelf.def) });
|
|
83
78
|
scored.push(...scoreRows(shelf, rows, tokens));
|
|
84
79
|
}
|
|
85
80
|
scored.sort((a, b) => b.score - a.score || tieKey(a.result).localeCompare(tieKey(b.result)));
|
package/dist/index.js
CHANGED
|
@@ -365,6 +365,11 @@ function maskRecordRow(library, shelf, row) {
|
|
|
365
365
|
}
|
|
366
366
|
return out;
|
|
367
367
|
}
|
|
368
|
+
function listRow(library, shelf, row) {
|
|
369
|
+
const out = maskRecordRow(library, shelf, row);
|
|
370
|
+
const activity = out._activity;
|
|
371
|
+
return activity ? { ...out, _activity: { favorite: activity.favorite === true } } : out;
|
|
372
|
+
}
|
|
368
373
|
app.get('/api/trash', async (_req, reply) => {
|
|
369
374
|
const rows = await recordTrashList();
|
|
370
375
|
return rows.map((entry) => ({ ...entry, record: maskRecordRow(entry.library, entry.shelf, entry.record) }));
|
|
@@ -415,7 +420,7 @@ app.get('/api/:library/:shelf', async (req, reply) => {
|
|
|
415
420
|
let rows = await recordList(library, shelf, query, opts);
|
|
416
421
|
if (req.user && tracksRecordActivity(req.headers))
|
|
417
422
|
rows = await applySmartRanking(req.user.id, library, shelf, rows);
|
|
418
|
-
return rows.map((r) =>
|
|
423
|
+
return rows.map((r) => listRow(library, shelf, r));
|
|
419
424
|
}
|
|
420
425
|
const pageOpts = {
|
|
421
426
|
...opts,
|
|
@@ -431,7 +436,7 @@ app.get('/api/:library/:shelf', async (req, reply) => {
|
|
|
431
436
|
const pageOffset = Math.max(0, Number.isFinite(pageOpts.offset) ? Math.trunc(pageOpts.offset) : 0);
|
|
432
437
|
page = { rows: ranked.slice(pageOffset, pageOffset + pageLimit), total: ranked.length };
|
|
433
438
|
}
|
|
434
|
-
return { rows: page.rows.map((r) =>
|
|
439
|
+
return { rows: page.rows.map((r) => listRow(library, shelf, r)), total: page.total };
|
|
435
440
|
}
|
|
436
441
|
catch (e) {
|
|
437
442
|
if (e instanceof UnknownShelfError)
|
package/dist/mutate.js
CHANGED
|
@@ -3,6 +3,7 @@ import { buildZodObject, buildZodObjectPartial, fieldEntries } from '@coffer-org
|
|
|
3
3
|
import { isJsonStored, decodeVmsg } from '@coffer-org/sdk/fields';
|
|
4
4
|
import { resolveFlag } from '@coffer-org/sdk/condition';
|
|
5
5
|
import { getEm } from "./db.js";
|
|
6
|
+
import { selectRows } from "./read-rows.js";
|
|
6
7
|
import { normalizeFileFields, dropUnchangedFileFields, touchesFileFields } from "./file-fields.js";
|
|
7
8
|
import { notifyRecordsChanged } from "./index-signal.js";
|
|
8
9
|
import { encodeTemporal, decodeTemporal } from "./temporal.js";
|
|
@@ -54,18 +55,14 @@ export async function listRecords(entityName, opts = {}) {
|
|
|
54
55
|
const fork = getEm().fork();
|
|
55
56
|
const deleted = opts.deleted ?? 'active';
|
|
56
57
|
const where = deleted === 'active' ? { deleted_at: null } : deleted === 'deleted' ? { deleted_at: { $ne: null } } : {};
|
|
57
|
-
|
|
58
|
-
return serialize(rows);
|
|
58
|
+
return selectRows(fork, entityName, where, { orderBy: { id: 'asc' } });
|
|
59
59
|
}
|
|
60
60
|
export async function getRecord(m, entityName, id, opts = {}) {
|
|
61
61
|
const fork = getEm().fork();
|
|
62
|
-
const row = await fork
|
|
63
|
-
id,
|
|
64
|
-
...(opts.includeDeleted ? {} : { deleted_at: null }),
|
|
65
|
-
});
|
|
62
|
+
const [row] = await selectRows(fork, entityName, { id, ...(opts.includeDeleted ? {} : { deleted_at: null }) }, { limit: 1 });
|
|
66
63
|
if (!row)
|
|
67
64
|
return undefined;
|
|
68
|
-
const flat = decodeTemporal(m,
|
|
65
|
+
const flat = decodeTemporal(m, row);
|
|
69
66
|
const nested = nestEmbedded(m, flat);
|
|
70
67
|
const collections = await readCollections(fork, m, id);
|
|
71
68
|
return { ...nested, ...collections };
|
package/dist/plugin-runtime.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { serialize } from '@mikro-orm/core';
|
|
2
1
|
import { composeRegistry } from '@coffer-org/core/compose';
|
|
3
2
|
import { getLogger } from '@coffer-org/sdk/logger';
|
|
4
3
|
import { initDb, getOrm, getEm } from "./db.js";
|
|
@@ -6,6 +5,7 @@ import { syncSchema } from "./schema-sync.js";
|
|
|
6
5
|
import { systemEntities, buildPluginEntities, shelfTableName } from "./entity-schema.js";
|
|
7
6
|
import { pluginHooks, pluginCtx, HttpError } from "./plugin-hooks.js";
|
|
8
7
|
import { discoverPlugins, loadServerHooks } from "./plugin-discovery.js";
|
|
8
|
+
import { selectRows } from "./read-rows.js";
|
|
9
9
|
import { runMigrations, assertSafeRequired, renameSystemShelfKey } from "./migrations.js";
|
|
10
10
|
import { runSeeds } from "./seeds.js";
|
|
11
11
|
import { setActiveRegistry } from "./registry-context.js";
|
|
@@ -36,12 +36,10 @@ export function getDisabled() {
|
|
|
36
36
|
export async function getPluginSettings(pluginId) {
|
|
37
37
|
try {
|
|
38
38
|
const fork = getEm().fork();
|
|
39
|
-
const row = await fork
|
|
40
|
-
plugin_id: pluginId,
|
|
41
|
-
});
|
|
39
|
+
const [row] = await selectRows(fork, `_settings__${pluginId}`, { plugin_id: pluginId }, { limit: 1 });
|
|
42
40
|
if (!row)
|
|
43
41
|
return {};
|
|
44
|
-
return
|
|
42
|
+
return row;
|
|
45
43
|
}
|
|
46
44
|
catch {
|
|
47
45
|
return {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/core';
|
|
2
|
+
export type SelectOpts = {
|
|
3
|
+
fields?: string[];
|
|
4
|
+
orderBy?: Record<string, 'ASC' | 'DESC' | 'asc' | 'desc'>;
|
|
5
|
+
limit?: number;
|
|
6
|
+
offset?: number;
|
|
7
|
+
};
|
|
8
|
+
export declare function selectRows(em: EntityManager, entityName: string, where?: Record<string, unknown>, opts?: SelectOpts): Promise<Record<string, unknown>[]>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export async function selectRows(em, entityName, where = {}, opts = {}) {
|
|
2
|
+
const qb = em.createQueryBuilder(entityName);
|
|
3
|
+
qb.select(opts.fields ?? '*').where(where);
|
|
4
|
+
if (opts.orderBy)
|
|
5
|
+
qb.orderBy(opts.orderBy);
|
|
6
|
+
if (opts.limit !== undefined)
|
|
7
|
+
qb.limit(opts.limit, opts.offset);
|
|
8
|
+
else if (opts.offset !== undefined)
|
|
9
|
+
qb.offset(opts.offset);
|
|
10
|
+
return (await qb.execute('all', true));
|
|
11
|
+
}
|
package/dist/records-api.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { fieldMap, textSearchKeys, titleKey, recordTitle, listKeys, storageColumnsFor } from '@coffer-org/sdk/shelf';
|
|
2
2
|
import { tokenize, matchScoreFolded, foldText } from '@coffer-org/core/search';
|
|
3
|
-
import { serialize } from '@mikro-orm/core';
|
|
4
3
|
import { getActiveRegistry, getShelf, getExtendsFor } from "./registry-context.js";
|
|
4
|
+
import { selectRows } from "./read-rows.js";
|
|
5
5
|
import { shelfTableName } from "./entity-schema.js";
|
|
6
6
|
import { getExtendRecord, getExtendRecords } from "./extend-table.js";
|
|
7
7
|
import { getEm } from "./db.js";
|
|
@@ -15,7 +15,7 @@ export const MAX_PAGE = 500;
|
|
|
15
15
|
function pickCols(row, cols) {
|
|
16
16
|
const out = {};
|
|
17
17
|
for (const c of cols)
|
|
18
|
-
if (c in row)
|
|
18
|
+
if (c in row && row[c] !== null)
|
|
19
19
|
out[c] = row[c];
|
|
20
20
|
return out;
|
|
21
21
|
}
|
|
@@ -137,7 +137,7 @@ export async function recordList(library, shelf, query = {}, opts = {}) {
|
|
|
137
137
|
...(opts.orderBy ? { orderBy: opts.orderBy } : {}),
|
|
138
138
|
...(sqlSlice ? { limit: opts.limit, offset: Math.max(0, opts.offset ?? 0) } : {}),
|
|
139
139
|
};
|
|
140
|
-
let rows =
|
|
140
|
+
let rows = await selectRows(fork, ename, where, findOpts);
|
|
141
141
|
if (tokens.length > 0)
|
|
142
142
|
rows = rows.filter((row) => rowMatch(m, row, tokens) !== null);
|
|
143
143
|
if (projected)
|