@antelopejs/dms-database 0.0.14 → 0.1.1
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/README.md +30 -5
- package/dist/db/models/query_history.model.d.ts +1 -0
- package/dist/db/models/query_history.model.js +6 -0
- package/dist/db/models/query_history.model.js.map +1 -1
- package/dist/db/tables/query_history.table.d.ts +3 -0
- package/dist/db/tables/query_history.table.js +12 -0
- package/dist/db/tables/query_history.table.js.map +1 -1
- package/dist/db/tables/saved_queries.table.d.ts +1 -0
- package/dist/db/tables/saved_queries.table.js +4 -0
- package/dist/db/tables/saved_queries.table.js.map +1 -1
- package/dist/i18n/messages.d.ts +39 -0
- package/dist/i18n/messages.js +64 -0
- package/dist/i18n/messages.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -7
- package/dist/index.js.map +1 -1
- package/dist/module.d.ts +11 -0
- package/dist/module.js +55 -0
- package/dist/module.js.map +1 -0
- package/dist/pages/data.d.ts +1 -1
- package/dist/pages/data.js +9 -6
- package/dist/pages/data.js.map +1 -1
- package/dist/pages/diagram.d.ts +9 -0
- package/dist/pages/diagram.js +45 -0
- package/dist/pages/diagram.js.map +1 -0
- package/dist/pages/index.d.ts +1 -0
- package/dist/pages/index.js +1 -0
- package/dist/pages/index.js.map +1 -1
- package/dist/pages/overview.d.ts +4 -1
- package/dist/pages/overview.js +113 -6
- package/dist/pages/overview.js.map +1 -1
- package/dist/pages/query.d.ts +1 -1
- package/dist/pages/query.js +22 -6
- package/dist/pages/query.js.map +1 -1
- package/dist/pages/schemas.d.ts +2 -1
- package/dist/pages/schemas.js +143 -6
- package/dist/pages/schemas.js.map +1 -1
- package/dist/routes/data.d.ts +8 -0
- package/dist/routes/data.js +84 -21
- package/dist/routes/data.js.map +1 -1
- package/dist/routes/index.d.ts +1 -0
- package/dist/routes/index.js +1 -0
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/overview.d.ts +12 -0
- package/dist/routes/overview.js +55 -0
- package/dist/routes/overview.js.map +1 -0
- package/dist/routes/query.d.ts +5 -1
- package/dist/routes/query.js +162 -27
- package/dist/routes/query.js.map +1 -1
- package/dist/routes/tables.d.ts +15 -12
- package/dist/routes/tables.js +95 -55
- package/dist/routes/tables.js.map +1 -1
- package/dist/service/catalog.d.ts +3 -0
- package/dist/service/catalog.js +26 -0
- package/dist/service/catalog.js.map +1 -0
- package/dist/service/health.d.ts +3 -3
- package/dist/service/health.js +17 -14
- package/dist/service/health.js.map +1 -1
- package/dist/service/introspect.d.ts +3 -1
- package/dist/service/introspect.js +131 -43
- package/dist/service/introspect.js.map +1 -1
- package/dist/service/overview.d.ts +9 -0
- package/dist/service/overview.js +113 -0
- package/dist/service/overview.js.map +1 -0
- package/dist/service/queryInspection.d.ts +15 -0
- package/dist/service/queryInspection.js +107 -0
- package/dist/service/queryInspection.js.map +1 -0
- package/dist/service/references.d.ts +9 -0
- package/dist/service/references.js +52 -0
- package/dist/service/references.js.map +1 -0
- package/dist/service/schemaFilters.d.ts +26 -0
- package/dist/service/schemaFilters.js +42 -0
- package/dist/service/schemaFilters.js.map +1 -0
- package/dist/service/stagedSerialization.d.ts +2 -0
- package/dist/service/stagedSerialization.js +38 -10
- package/dist/service/stagedSerialization.js.map +1 -1
- package/dist/service/types.d.ts +11 -1
- package/dist/types/constants.d.ts +2 -0
- package/dist/types/constants.js +3 -1
- package/dist/types/constants.js.map +1 -1
- package/dist/utils/query.d.ts +0 -2
- package/dist/utils/query.js +0 -20
- package/dist/utils/query.js.map +1 -1
- package/frontend-vue/app/{composables → build/composables}/useDataBrowserGrid.ts +65 -50
- package/frontend-vue/app/build/composables/useDataBrowserTabs.ts +366 -0
- package/frontend-vue/app/build/composables/useDatabaseHealth.ts +50 -0
- package/frontend-vue/app/build/composables/useDatabaseSchemas.ts +140 -0
- package/frontend-vue/app/{composables → build/composables}/useDiagramPersistence.ts +47 -39
- package/frontend-vue/app/build/composables/useQueryRuntime.ts +217 -0
- package/frontend-vue/app/build/composables/useQueryStore.ts +162 -0
- package/frontend-vue/app/build/data/cellValues.ts +132 -0
- package/frontend-vue/app/build/data/instanceOptions.ts +36 -0
- package/frontend-vue/app/build/data/pickerMenus.ts +175 -0
- package/frontend-vue/app/build/data/recentTables.ts +48 -0
- package/frontend-vue/app/build/data/stagedEdits.ts +117 -0
- package/frontend-vue/app/build/data/stagedWrites.ts +64 -0
- package/frontend-vue/app/build/data/useStagedSave.ts +298 -0
- package/frontend-vue/app/build/diagram/autosave.ts +72 -0
- package/frontend-vue/app/build/diagram/graph.ts +585 -0
- package/frontend-vue/app/build/diagram/history.ts +178 -0
- package/frontend-vue/app/build/diagram/shortcuts.ts +62 -0
- package/frontend-vue/app/build/diagram/sync.ts +137 -0
- package/frontend-vue/app/build/query/completion.ts +100 -0
- package/frontend-vue/app/build/query/csv.ts +32 -0
- package/frontend-vue/app/build/query/examples.ts +38 -0
- package/frontend-vue/app/build/query/runs.ts +168 -0
- package/frontend-vue/app/build/query/tableColumns.ts +35 -0
- package/frontend-vue/app/build/query/target.ts +143 -0
- package/frontend-vue/app/build/schemas/filterState.ts +128 -0
- package/frontend-vue/app/build/schemas/useSchemasListing.ts +62 -0
- package/frontend-vue/app/build/utils/databaseLinks.ts +98 -0
- package/frontend-vue/app/build/utils/fieldTypes.ts +198 -0
- package/frontend-vue/app/build/utils/relativeTime.ts +19 -0
- package/frontend-vue/app/{utils → build/utils}/stagedSerialization.ts +7 -1
- package/frontend-vue/app/components/ConnectionStatus.vue +122 -0
- package/frontend-vue/app/components/DataBrowser.vue +126 -0
- package/frontend-vue/app/components/DataBrowserSidebar.vue +293 -210
- package/frontend-vue/app/components/DataBrowserTabBar.vue +185 -93
- package/frontend-vue/app/components/DataFilterBar.vue +163 -0
- package/frontend-vue/app/components/DataGrid.vue +737 -499
- package/frontend-vue/app/components/DataGridCell.vue +125 -77
- package/frontend-vue/app/components/DataGridHeaderCell.vue +119 -81
- package/frontend-vue/app/components/DiagramNoteNode.vue +81 -63
- package/frontend-vue/app/components/DiagramRelationEdge.vue +57 -27
- package/frontend-vue/app/components/DiagramStubNode.vue +16 -17
- package/frontend-vue/app/components/DiagramTableNode.vue +106 -68
- package/frontend-vue/app/components/InstancePicker.vue +195 -0
- package/frontend-vue/app/components/JsonCellPanel.vue +55 -41
- package/frontend-vue/app/components/QueryBuilderPanel.vue +290 -238
- package/frontend-vue/app/components/QueryConsole.vue +726 -0
- package/frontend-vue/app/components/QueryLibrary.vue +314 -0
- package/frontend-vue/app/components/QueryResultPanel.vue +556 -126
- package/frontend-vue/app/components/RowDrawer.vue +520 -0
- package/frontend-vue/app/components/SchemaDiagram.vue +1016 -1051
- package/frontend-vue/app/components/SchemaPicker.vue +86 -0
- package/frontend-vue/app/components/SchemasFilterBar.vue +201 -0
- package/frontend-vue/app/components/TableInspector.vue +741 -0
- package/frontend-vue/app/config/shortcuts-registry.ts +65 -0
- package/frontend-vue/dms.frontend.ts +5 -14
- package/frontend-vue/i18n/locales/database-en-GB.json +527 -193
- package/frontend-vue/i18n/locales/database-fr-FR.json +529 -195
- package/frontend-vue/package.json +2 -1
- package/frontend-vue/pnpm-lock.yaml +2601 -858
- package/frontend-vue/pnpm-workspace.yaml +1 -1
- package/frontend-vue/tests/dataBrowser.test.ts +206 -0
- package/frontend-vue/tests/diagram.test.ts +516 -0
- package/frontend-vue/tests/helpers.test.ts +205 -0
- package/frontend-vue/tests/instanceOptions.test.ts +53 -0
- package/frontend-vue/tests/locales.test.ts +56 -0
- package/frontend-vue/tests/persistence.test.ts +106 -5
- package/frontend-vue/tests/pickerMenus.test.ts +254 -0
- package/frontend-vue/tests/queryConsole.test.ts +282 -0
- package/frontend-vue/tests/queryRuntime.test.ts +2 -2
- package/frontend-vue/tests/registration.test.ts +36 -25
- package/frontend-vue/tests/schemasFilters.test.ts +115 -0
- package/package.json +7 -7
- package/frontend-vue/app/components/QueryFavoritesPanel.vue +0 -127
- package/frontend-vue/app/components/QueryHistoryPanel.vue +0 -134
- package/frontend-vue/app/components/SchemaTableInspector.vue +0 -278
- package/frontend-vue/app/composables/useDataBrowserTabs.ts +0 -255
- package/frontend-vue/app/composables/useDatabaseHealth.ts +0 -50
- package/frontend-vue/app/composables/useDatabaseSchemas.ts +0 -92
- package/frontend-vue/app/composables/useQueryRuntime.ts +0 -118
- package/frontend-vue/app/composables/useQueryStore.ts +0 -117
- package/frontend-vue/app/composables/useTableViewRowClick.ts +0 -22
- package/frontend-vue/app/custom-pages/database/data.vue +0 -41
- package/frontend-vue/app/custom-pages/database/overview.vue +0 -367
- package/frontend-vue/app/custom-pages/database/query.vue +0 -436
- package/frontend-vue/app/custom-pages/database/schemas.vue +0 -218
- package/frontend-vue/app/utils/databaseFieldModifiers.ts +0 -33
- package/frontend-vue/app/utils/databaseFieldTypeIcons.ts +0 -224
- package/frontend-vue/app/utils/dmsTableView.ts +0 -83
- package/frontend-vue/app/utils/relativeTime.ts +0 -18
package/dist/routes/tables.js
CHANGED
|
@@ -14,80 +14,120 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.DatabaseTablesController = void 0;
|
|
16
16
|
const interface_api_1 = require("@antelopejs/interface-api");
|
|
17
|
+
const interface_api_util_1 = require("@antelopejs/interface-api-util");
|
|
17
18
|
const auth_1 = require("@antelopejs/interface-dms/auth");
|
|
19
|
+
const messages_1 = require("../i18n/messages");
|
|
18
20
|
const introspect_1 = require("../service/introspect");
|
|
21
|
+
const schemaFilters_1 = require("../service/schemaFilters");
|
|
22
|
+
const schemaRegistry_1 = require("../service/schemaRegistry");
|
|
19
23
|
const query_1 = require("../utils/query");
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
|
|
24
|
+
const INSTANCE_LIMIT_DEFAULT = 100;
|
|
25
|
+
const INSTANCE_LIMIT_MAX = 500;
|
|
26
|
+
const instanceCollator = new Intl.Collator(undefined, { numeric: true });
|
|
27
|
+
function relationTargets(schemaId, table) {
|
|
28
|
+
const targets = table.relations.map((relation) => relation.toSchema === schemaId
|
|
29
|
+
? relation.toTable
|
|
30
|
+
: `${relation.toSchema}.${relation.toTable}`);
|
|
31
|
+
return [...new Set(targets)];
|
|
32
|
+
}
|
|
33
|
+
function modifierNames(table, locale) {
|
|
34
|
+
const ids = new Set(Object.values(table.modifiers).flat());
|
|
35
|
+
return [...ids].map((id) => (0, messages_1.formatModifier)(locale, id));
|
|
36
|
+
}
|
|
37
|
+
function matchesSearch(table, needle) {
|
|
38
|
+
if (table.name.toLowerCase().includes(needle))
|
|
39
|
+
return true;
|
|
40
|
+
return Object.keys(table.fields).some((field) => field.toLowerCase().includes(needle));
|
|
41
|
+
}
|
|
42
|
+
function needleOf(text) {
|
|
43
|
+
const needle = text?.trim().toLowerCase();
|
|
44
|
+
return needle || undefined;
|
|
45
|
+
}
|
|
46
|
+
function matchesStructure({ schemaId, table }, filters, needle) {
|
|
47
|
+
if (filters.scope && schemaId !== filters.scope)
|
|
48
|
+
return false;
|
|
49
|
+
if (needle && !matchesSearch(table, needle))
|
|
50
|
+
return false;
|
|
51
|
+
if (filters.has.includes("relations") && table.relations.length === 0)
|
|
52
|
+
return false;
|
|
53
|
+
if (filters.has.includes("modifiers") &&
|
|
54
|
+
Object.values(table.modifiers).every((ids) => ids.length === 0))
|
|
55
|
+
return false;
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
function countRows(schemaId, tableName, instance) {
|
|
59
|
+
if (instance.kind === "all")
|
|
60
|
+
return (0, introspect_1.getTableTotalCount)(schemaId, tableName);
|
|
61
|
+
if (instance.kind === "default")
|
|
62
|
+
return (0, introspect_1.getTableElementCount)(schemaId, tableName);
|
|
63
|
+
return (0, introspect_1.getTableElementCount)(schemaId, tableName, instance.id);
|
|
64
|
+
}
|
|
65
|
+
async function listTableSourceRows(locale, filters) {
|
|
66
|
+
const needle = needleOf(filters.q);
|
|
23
67
|
const summaries = await (0, introspect_1.listSchemaSummaries)();
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
68
|
+
const registered = summaries.flatMap((summary) => summary.tables.map((table) => ({ schemaId: summary.id, table })));
|
|
69
|
+
const tables = registered.filter((listed) => matchesStructure(listed, filters, needle));
|
|
70
|
+
const counts = await Promise.all(tables.map(({ schemaId, table }) => countRows(schemaId, table.name, filters.instance)));
|
|
71
|
+
const rows = tables.map(({ schemaId, table }, index) => ({
|
|
72
|
+
id: `${schemaId}::${table.name}`,
|
|
73
|
+
schema: schemaId,
|
|
74
|
+
name: table.name,
|
|
75
|
+
elementCount: counts[index] ?? 0,
|
|
76
|
+
columnCount: Object.keys(table.fields).length,
|
|
77
|
+
indexCount: Object.keys(table.indexes ?? {}).length,
|
|
78
|
+
relations: relationTargets(schemaId, table),
|
|
79
|
+
modifiers: modifierNames(table, locale),
|
|
80
|
+
}));
|
|
81
|
+
return {
|
|
82
|
+
rows: filters.has.includes("empty")
|
|
83
|
+
? rows.filter((row) => row.elementCount === 0)
|
|
84
|
+
: rows,
|
|
85
|
+
all: registered.length,
|
|
86
|
+
};
|
|
40
87
|
}
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
|
|
88
|
+
function matchNamedInstances(instances, search, limit) {
|
|
89
|
+
const needle = needleOf(search);
|
|
90
|
+
const matches = instances
|
|
91
|
+
.filter((id) => !needle || id.toLowerCase().includes(needle))
|
|
92
|
+
.sort((left, right) => instanceCollator.compare(left, right));
|
|
93
|
+
return { instances: matches.slice(0, limit), total: matches.length };
|
|
45
94
|
}
|
|
46
95
|
let DatabaseTablesController = class DatabaseTablesController extends (0, interface_api_1.Controller)("/api/database/tables") {
|
|
47
|
-
async
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
const offset = Math.max(0, (0, query_1.parseInteger)(offsetRaw, 0));
|
|
51
|
-
const limit = (0, query_1.clamp)((0, query_1.parseInteger)(limitRaw, DEFAULT_LIMIT), 1, MAX_LIMIT);
|
|
52
|
-
return {
|
|
53
|
-
results: sorted.slice(offset, offset + limit),
|
|
54
|
-
total: sorted.length,
|
|
55
|
-
offset,
|
|
56
|
-
limit,
|
|
57
|
-
};
|
|
96
|
+
async source(user, scope, instance, q, has) {
|
|
97
|
+
const { rows, all } = await listTableSourceRows((0, messages_1.localeOf)(user), (0, schemaFilters_1.readSchemaFilters)({ scope, instance, q, has }));
|
|
98
|
+
return { results: rows, total: rows.length, all };
|
|
58
99
|
}
|
|
59
|
-
async
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
};
|
|
100
|
+
async instances(schemaRaw, search, limitRaw) {
|
|
101
|
+
const schema = (0, query_1.asNonEmptyString)(schemaRaw);
|
|
102
|
+
(0, interface_api_util_1.assert)(schema, 400, "Missing 'schema'");
|
|
103
|
+
const registered = (0, schemaRegistry_1.getRegistry)().get(schema);
|
|
104
|
+
(0, interface_api_util_1.assert)(registered, 404, `Unknown schema ${schema}`);
|
|
105
|
+
const named = await (0, introspect_1.listSchemaInstances)(registered);
|
|
106
|
+
const limit = (0, query_1.clamp)((0, query_1.parseInteger)(limitRaw, INSTANCE_LIMIT_DEFAULT), 1, INSTANCE_LIMIT_MAX);
|
|
107
|
+
return matchNamedInstances(named, (0, query_1.asNonEmptyString)(search), limit);
|
|
64
108
|
}
|
|
65
109
|
};
|
|
66
110
|
exports.DatabaseTablesController = DatabaseTablesController;
|
|
67
111
|
__decorate([
|
|
68
|
-
(0, interface_api_1.Get)("/
|
|
112
|
+
(0, interface_api_1.Get)("/source"),
|
|
69
113
|
__param(0, (0, auth_1.AuthRawUser)()),
|
|
70
|
-
__param(1, (0, interface_api_1.Parameter)("
|
|
114
|
+
__param(1, (0, interface_api_1.Parameter)("filter_scope", "query")),
|
|
71
115
|
__param(2, (0, interface_api_1.Parameter)("filter_instance", "query")),
|
|
72
|
-
__param(3, (0, interface_api_1.Parameter)("
|
|
73
|
-
__param(4, (0, interface_api_1.Parameter)("
|
|
74
|
-
__param(5, (0, interface_api_1.Parameter)("limit", "query")),
|
|
75
|
-
__param(6, (0, interface_api_1.Parameter)("sortKey", "query")),
|
|
76
|
-
__param(7, (0, interface_api_1.Parameter)("sortDirection", "query")),
|
|
116
|
+
__param(3, (0, interface_api_1.Parameter)("filter_q", "query")),
|
|
117
|
+
__param(4, (0, interface_api_1.Parameter)("filter_has", "query")),
|
|
77
118
|
__metadata("design:type", Function),
|
|
78
|
-
__metadata("design:paramtypes", [Function, Object, Object, Object, Object
|
|
119
|
+
__metadata("design:paramtypes", [Function, Object, Object, Object, Object]),
|
|
79
120
|
__metadata("design:returntype", Promise)
|
|
80
|
-
], DatabaseTablesController.prototype, "
|
|
121
|
+
], DatabaseTablesController.prototype, "source", null);
|
|
81
122
|
__decorate([
|
|
82
|
-
(0, interface_api_1.Get)("/
|
|
83
|
-
__param(0, (0,
|
|
84
|
-
__param(1, (0, interface_api_1.Parameter)("
|
|
85
|
-
__param(2, (0, interface_api_1.Parameter)("
|
|
86
|
-
__param(3, (0, interface_api_1.Parameter)("search", "query")),
|
|
123
|
+
(0, interface_api_1.Get)("/instances"),
|
|
124
|
+
__param(0, (0, interface_api_1.Parameter)("schema", "query")),
|
|
125
|
+
__param(1, (0, interface_api_1.Parameter)("search", "query")),
|
|
126
|
+
__param(2, (0, interface_api_1.Parameter)("limit", "query")),
|
|
87
127
|
__metadata("design:type", Function),
|
|
88
|
-
__metadata("design:paramtypes", [
|
|
128
|
+
__metadata("design:paramtypes", [Object, Object, Object]),
|
|
89
129
|
__metadata("design:returntype", Promise)
|
|
90
|
-
], DatabaseTablesController.prototype, "
|
|
130
|
+
], DatabaseTablesController.prototype, "instances", null);
|
|
91
131
|
exports.DatabaseTablesController = DatabaseTablesController = __decorate([
|
|
92
132
|
(0, auth_1.AuthOwnerOnly)()
|
|
93
133
|
], DatabaseTablesController);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tables.js","sourceRoot":"","sources":["../../src/routes/tables.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,6DAAuE;
|
|
1
|
+
{"version":3,"file":"tables.js","sourceRoot":"","sources":["../../src/routes/tables.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readCatalogReadout = readCatalogReadout;
|
|
4
|
+
const messages_1 = require("../i18n/messages");
|
|
5
|
+
const health_1 = require("./health");
|
|
6
|
+
const SEPARATOR = " · ";
|
|
7
|
+
async function readCatalogReadout(user) {
|
|
8
|
+
const locale = (0, messages_1.localeOf)(user);
|
|
9
|
+
const health = await (0, health_1.getOverviewHealth)();
|
|
10
|
+
if (health.status === "down") {
|
|
11
|
+
return [{ text: (0, messages_1.formatMessage)(locale, "connectionDown"), tone: "error" }];
|
|
12
|
+
}
|
|
13
|
+
const contents = [
|
|
14
|
+
(0, messages_1.formatCount)(locale, "tables", health.tableCount),
|
|
15
|
+
(0, messages_1.formatCount)(locale, "rows", health.totalRows),
|
|
16
|
+
].join(SEPARATOR);
|
|
17
|
+
const connection = [(0, messages_1.formatCount)(locale, "schemas", health.schemaCount)];
|
|
18
|
+
if (health.latencyMs !== null) {
|
|
19
|
+
connection.push((0, messages_1.formatMessage)(locale, "latency", { value: String(health.latencyMs) }));
|
|
20
|
+
}
|
|
21
|
+
return [
|
|
22
|
+
{ text: contents, tone: "success" },
|
|
23
|
+
{ text: connection.join(SEPARATOR), tone: "info" },
|
|
24
|
+
];
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/service/catalog.ts"],"names":[],"mappings":";;AAeA,gDAsBC;AApCD,+CAK0B;AAC1B,qCAA6C;AAE7C,MAAM,SAAS,GAAG,KAAK,CAAC;AAMjB,KAAK,UAAU,kBAAkB,CACtC,IAA+B;IAE/B,MAAM,MAAM,GAAG,IAAA,mBAAQ,EAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,MAAM,GAAG,MAAM,IAAA,0BAAiB,GAAE,CAAC;IACzC,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC7B,OAAO,CAAC,EAAE,IAAI,EAAE,IAAA,wBAAa,EAAC,MAAM,EAAE,gBAAgB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,MAAM,QAAQ,GAAG;QACf,IAAA,sBAAW,EAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC;QAChD,IAAA,sBAAW,EAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC;KAC9C,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAClB,MAAM,UAAU,GAAG,CAAC,IAAA,sBAAW,EAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;IACxE,IAAI,MAAM,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;QAC9B,UAAU,CAAC,IAAI,CACb,IAAA,wBAAa,EAAC,MAAM,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CACtE,CAAC;IACJ,CAAC;IACD,OAAO;QACL,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE;QACnC,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE;KACnD,CAAC;AACJ,CAAC"}
|
package/dist/service/health.d.ts
CHANGED
|
@@ -8,13 +8,13 @@ export interface OverviewHealth {
|
|
|
8
8
|
status: ConnectionStatus;
|
|
9
9
|
latencyMs: number | null;
|
|
10
10
|
driver: string | null;
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
checkedAt: string;
|
|
12
|
+
error: string | null;
|
|
13
13
|
schemaCount: number;
|
|
14
14
|
tableCount: number;
|
|
15
|
+
relationCount: number;
|
|
15
16
|
indexCount: number;
|
|
16
17
|
totalRows: number;
|
|
17
|
-
sizeBytes: number | null;
|
|
18
18
|
storage: StorageEntry[];
|
|
19
19
|
}
|
|
20
20
|
export declare function getOverviewHealth(): Promise<OverviewHealth>;
|
package/dist/service/health.js
CHANGED
|
@@ -9,19 +9,24 @@ async function probeConnection() {
|
|
|
9
9
|
const schemaIds = Array.from(registry.keys());
|
|
10
10
|
const probeSchema = schemaIds[0] ? registry.get(schemaIds[0]) : undefined;
|
|
11
11
|
if (!probeSchema)
|
|
12
|
-
return { status: "ok", latencyMs: null };
|
|
12
|
+
return { status: "ok", latencyMs: null, error: null };
|
|
13
13
|
const startedAt = Date.now();
|
|
14
14
|
try {
|
|
15
15
|
await probeSchema.listInstances().run();
|
|
16
|
-
return { status: "ok", latencyMs: Date.now() - startedAt };
|
|
16
|
+
return { status: "ok", latencyMs: Date.now() - startedAt, error: null };
|
|
17
17
|
}
|
|
18
|
-
catch {
|
|
19
|
-
return {
|
|
18
|
+
catch (error) {
|
|
19
|
+
return {
|
|
20
|
+
status: "down",
|
|
21
|
+
latencyMs: null,
|
|
22
|
+
error: error instanceof Error ? error.message : String(error),
|
|
23
|
+
};
|
|
20
24
|
}
|
|
21
25
|
}
|
|
22
26
|
async function aggregateStorage(summaries) {
|
|
23
27
|
let tableCount = 0;
|
|
24
28
|
let indexCount = 0;
|
|
29
|
+
let relationCount = 0;
|
|
25
30
|
let totalRows = 0;
|
|
26
31
|
const storage = [];
|
|
27
32
|
for (const summary of summaries) {
|
|
@@ -31,28 +36,26 @@ async function aggregateStorage(summaries) {
|
|
|
31
36
|
const rows = counts[idx] ?? 0;
|
|
32
37
|
totalRows += rows;
|
|
33
38
|
indexCount += Object.keys(table.indexes ?? {}).length;
|
|
39
|
+
relationCount += table.relations.length;
|
|
34
40
|
storage.push({ schema: summary.id, table: table.name, rows });
|
|
35
41
|
});
|
|
36
42
|
}
|
|
37
43
|
storage.sort((a, b) => b.rows - a.rows);
|
|
38
|
-
return { tableCount, indexCount, totalRows, storage };
|
|
44
|
+
return { tableCount, relationCount, indexCount, totalRows, storage };
|
|
39
45
|
}
|
|
40
46
|
async function getOverviewHealth() {
|
|
41
|
-
const
|
|
47
|
+
const checkedAt = new Date().toISOString();
|
|
48
|
+
const { status, latencyMs, error } = await probeConnection();
|
|
42
49
|
const summaries = await (0, introspect_1.listSchemaSummaries)();
|
|
43
|
-
const
|
|
50
|
+
const aggregate = await aggregateStorage(summaries);
|
|
44
51
|
return {
|
|
45
52
|
status,
|
|
46
53
|
latencyMs,
|
|
47
54
|
driver: (0, config_1.getModuleConfig)().driverLabel ?? null,
|
|
48
|
-
|
|
49
|
-
|
|
55
|
+
checkedAt,
|
|
56
|
+
error,
|
|
50
57
|
schemaCount: summaries.length,
|
|
51
|
-
|
|
52
|
-
indexCount,
|
|
53
|
-
totalRows,
|
|
54
|
-
sizeBytes: null,
|
|
55
|
-
storage,
|
|
58
|
+
...aggregate,
|
|
56
59
|
};
|
|
57
60
|
}
|
|
58
61
|
//# sourceMappingURL=health.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/service/health.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/service/health.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type InstanceId, type Schema } from "@antelopejs/interface-database";
|
|
2
2
|
import type { SchemaSummary, SchemaSummaryWithStats } from "./types";
|
|
3
3
|
export declare function listSchemaSummaries(): Promise<SchemaSummary[]>;
|
|
4
|
+
export declare function listSchemaInstances(schema: Schema): Promise<string[]>;
|
|
4
5
|
export declare function getTableElementCount(schemaId: string, tableName: string, instance?: InstanceId): Promise<number>;
|
|
6
|
+
export declare function getTableTotalCount(schemaId: string, tableName: string): Promise<number>;
|
|
5
7
|
export declare function listSchemaSummariesWithStats(): Promise<SchemaSummaryWithStats[]>;
|
|
6
8
|
export declare function getTablePrimaryKey(schemaId: string, tableName: string): string | undefined;
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.listSchemaSummaries = listSchemaSummaries;
|
|
4
|
+
exports.listSchemaInstances = listSchemaInstances;
|
|
4
5
|
exports.getTableElementCount = getTableElementCount;
|
|
6
|
+
exports.getTableTotalCount = getTableTotalCount;
|
|
5
7
|
exports.listSchemaSummariesWithStats = listSchemaSummariesWithStats;
|
|
6
8
|
exports.getTablePrimaryKey = getTablePrimaryKey;
|
|
7
9
|
const logging_1 = require("@antelopejs/interface-core/logging");
|
|
10
|
+
const interface_database_1 = require("@antelopejs/interface-database");
|
|
8
11
|
const interface_database_decorators_1 = require("@antelopejs/interface-database-decorators");
|
|
9
12
|
const config_1 = require("../config");
|
|
10
13
|
const fieldDescriptor_1 = require("./fieldDescriptor");
|
|
@@ -14,6 +17,7 @@ const STATS_TTL_MS = 30_000;
|
|
|
14
17
|
const FIELDS_TTL_MS = 30_000;
|
|
15
18
|
const FIELD_INFERENCE_SAMPLE_SIZE = 5;
|
|
16
19
|
const UNKNOWN_DESCRIPTOR = { kind: "unknown" };
|
|
20
|
+
const NULL_DESCRIPTOR = { kind: "null" };
|
|
17
21
|
const warnedRelations = new Set();
|
|
18
22
|
function warnOnce(key, message) {
|
|
19
23
|
if (warnedRelations.has(key))
|
|
@@ -66,13 +70,39 @@ function resolveModifiers(TableClass) {
|
|
|
66
70
|
return out;
|
|
67
71
|
}
|
|
68
72
|
const fieldsCache = new Map();
|
|
73
|
+
function inferArrayType(items) {
|
|
74
|
+
const members = [];
|
|
75
|
+
for (const item of items) {
|
|
76
|
+
const type = inferFieldType(item);
|
|
77
|
+
if (!type)
|
|
78
|
+
continue;
|
|
79
|
+
const key = JSON.stringify(type);
|
|
80
|
+
if (!members.some((member) => JSON.stringify(member) === key))
|
|
81
|
+
members.push(type);
|
|
82
|
+
}
|
|
83
|
+
if (members.length === 0)
|
|
84
|
+
return { kind: "array" };
|
|
85
|
+
const [only] = members;
|
|
86
|
+
return {
|
|
87
|
+
kind: "array",
|
|
88
|
+
element: members.length === 1 && only ? only : { kind: "union", members },
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function arrayOf(descriptor) {
|
|
92
|
+
const members = descriptor?.kind === "union" ? descriptor.members : [descriptor];
|
|
93
|
+
return members.find((member) => member?.kind === "array");
|
|
94
|
+
}
|
|
95
|
+
function refineSampled(seen, next) {
|
|
96
|
+
const untyped = seen?.kind === "array" && !seen.element;
|
|
97
|
+
return untyped && arrayOf(next)?.element ? next : (seen ?? next);
|
|
98
|
+
}
|
|
69
99
|
function inferFieldType(value) {
|
|
70
100
|
if (value === null || value === undefined)
|
|
71
101
|
return undefined;
|
|
72
102
|
if (value instanceof Date)
|
|
73
103
|
return { kind: "date" };
|
|
74
104
|
if (Array.isArray(value))
|
|
75
|
-
return
|
|
105
|
+
return inferArrayType(value);
|
|
76
106
|
if (typeof value === "object")
|
|
77
107
|
return { kind: "object", fields: {} };
|
|
78
108
|
if (typeof value === "string")
|
|
@@ -83,32 +113,80 @@ function inferFieldType(value) {
|
|
|
83
113
|
return { kind: "boolean" };
|
|
84
114
|
return undefined;
|
|
85
115
|
}
|
|
86
|
-
async function
|
|
87
|
-
const cacheKey = `${schemaId}::${tableName}`;
|
|
88
|
-
const cached = fieldsCache.get(cacheKey);
|
|
89
|
-
const now = Date.now();
|
|
90
|
-
if (cached && cached.expiresAt > now)
|
|
91
|
-
return cached.value;
|
|
92
|
-
const inferred = {};
|
|
116
|
+
async function sampleRows(schema, tableName, instance) {
|
|
93
117
|
try {
|
|
94
|
-
|
|
95
|
-
.instance()
|
|
118
|
+
return (await schema
|
|
119
|
+
.instance(instance)
|
|
96
120
|
.table(tableName)
|
|
97
|
-
.slice(0, FIELD_INFERENCE_SAMPLE_SIZE);
|
|
98
|
-
|
|
99
|
-
|
|
121
|
+
.slice(0, FIELD_INFERENCE_SAMPLE_SIZE));
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async function sampleAnyInstance(schema, tableName) {
|
|
128
|
+
const rows = await sampleRows(schema, tableName);
|
|
129
|
+
if (rows.length > 0)
|
|
130
|
+
return rows;
|
|
131
|
+
for (const instance of await listSchemaInstances(schema)) {
|
|
132
|
+
const named = await sampleRows(schema, tableName, instance);
|
|
133
|
+
if (named.length > 0)
|
|
134
|
+
return named;
|
|
135
|
+
}
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
const INSTANCE_TAG_FIELD = "_instance";
|
|
139
|
+
const NULLISH_KINDS = new Set([
|
|
140
|
+
"null",
|
|
141
|
+
"undefined",
|
|
142
|
+
"any",
|
|
143
|
+
"unknown",
|
|
144
|
+
]);
|
|
145
|
+
function admitsNull(descriptor) {
|
|
146
|
+
if (NULLISH_KINDS.has(descriptor.kind))
|
|
147
|
+
return true;
|
|
148
|
+
return (descriptor.kind === "union" &&
|
|
149
|
+
descriptor.members.some((member) => NULLISH_KINDS.has(member.kind)));
|
|
150
|
+
}
|
|
151
|
+
function withNull(descriptor) {
|
|
152
|
+
if (admitsNull(descriptor))
|
|
153
|
+
return descriptor;
|
|
154
|
+
if (descriptor.kind === "union")
|
|
155
|
+
return { kind: "union", members: [...descriptor.members, NULL_DESCRIPTOR] };
|
|
156
|
+
return { kind: "union", members: [descriptor, NULL_DESCRIPTOR] };
|
|
157
|
+
}
|
|
158
|
+
function inferFromRows(rows) {
|
|
159
|
+
const observed = new Map();
|
|
160
|
+
for (const row of rows) {
|
|
161
|
+
if (!row || typeof row !== "object")
|
|
162
|
+
continue;
|
|
163
|
+
for (const [key, value] of Object.entries(row)) {
|
|
164
|
+
if (key === INSTANCE_TAG_FIELD)
|
|
100
165
|
continue;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
166
|
+
const field = observed.get(key) ?? { nullable: false };
|
|
167
|
+
if (value === null)
|
|
168
|
+
field.nullable = true;
|
|
169
|
+
else
|
|
170
|
+
field.type = refineSampled(field.type, inferFieldType(value));
|
|
171
|
+
observed.set(key, field);
|
|
108
172
|
}
|
|
109
173
|
}
|
|
110
|
-
|
|
174
|
+
const inferred = {};
|
|
175
|
+
for (const [key, { type, nullable }] of observed) {
|
|
176
|
+
if (type)
|
|
177
|
+
inferred[key] = nullable ? withNull(type) : type;
|
|
178
|
+
else if (nullable)
|
|
179
|
+
inferred[key] = NULL_DESCRIPTOR;
|
|
111
180
|
}
|
|
181
|
+
return inferred;
|
|
182
|
+
}
|
|
183
|
+
async function inferTableFields(schemaId, schema, tableName) {
|
|
184
|
+
const cacheKey = `${schemaId}::${tableName}`;
|
|
185
|
+
const cached = fieldsCache.get(cacheKey);
|
|
186
|
+
const now = Date.now();
|
|
187
|
+
if (cached && cached.expiresAt > now)
|
|
188
|
+
return cached.value;
|
|
189
|
+
const inferred = inferFromRows(await sampleAnyInstance(schema, tableName));
|
|
112
190
|
fieldsCache.set(cacheKey, {
|
|
113
191
|
value: inferred,
|
|
114
192
|
expiresAt: now + FIELDS_TTL_MS,
|
|
@@ -183,17 +261,24 @@ async function summarizeTable(id, schema, tableName, def, tableClasses) {
|
|
|
183
261
|
for (const [name, value] of Object.entries(definitionFields)) {
|
|
184
262
|
fromDefinition[name] = (0, fieldDescriptor_1.toFieldDescriptor)(value);
|
|
185
263
|
}
|
|
264
|
+
const withSampled = (name, descriptor) => {
|
|
265
|
+
const seen = sampled[name];
|
|
266
|
+
const element = arrayOf(seen)?.element;
|
|
267
|
+
const typed = descriptor.kind === "array" && !descriptor.element && element
|
|
268
|
+
? { kind: "array", element }
|
|
269
|
+
: descriptor;
|
|
270
|
+
return seen && admitsNull(seen) ? withNull(typed) : typed;
|
|
271
|
+
};
|
|
186
272
|
const fields = {};
|
|
187
273
|
for (const name of declared.ordered) {
|
|
188
|
-
fields[name] =
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
UNKNOWN_DESCRIPTOR;
|
|
274
|
+
fields[name] = withSampled(name, fromDefinition[name] ??
|
|
275
|
+
declared.types[name] ??
|
|
276
|
+
sampled[name] ??
|
|
277
|
+
UNKNOWN_DESCRIPTOR);
|
|
193
278
|
}
|
|
194
279
|
for (const [name, descriptor] of Object.entries(fromDefinition)) {
|
|
195
280
|
if (!(name in fields))
|
|
196
|
-
fields[name] = descriptor;
|
|
281
|
+
fields[name] = withSampled(name, descriptor);
|
|
197
282
|
}
|
|
198
283
|
for (const [name, descriptor] of Object.entries(sampled)) {
|
|
199
284
|
if (!(name in fields))
|
|
@@ -225,14 +310,18 @@ function tableCountKey(schemaId, tableName, instance) {
|
|
|
225
310
|
return `${schemaId}::${String(instance ?? "")}::${tableName}`;
|
|
226
311
|
}
|
|
227
312
|
async function countTableRows(schema, tableName, instance) {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
313
|
+
const table = schema.instance(instance).table(tableName);
|
|
314
|
+
const total = await table.count();
|
|
315
|
+
return typeof total === "number" && Number.isFinite(total) ? total : 0;
|
|
316
|
+
}
|
|
317
|
+
async function cachedCount(key, count) {
|
|
318
|
+
const cached = tableCountCache.get(key);
|
|
319
|
+
const now = Date.now();
|
|
320
|
+
if (cached && cached.expiresAt > now)
|
|
321
|
+
return cached.value;
|
|
322
|
+
const value = await count();
|
|
323
|
+
tableCountCache.set(key, { value, expiresAt: now + STATS_TTL_MS });
|
|
324
|
+
return value;
|
|
236
325
|
}
|
|
237
326
|
async function listSchemaInstances(schema) {
|
|
238
327
|
try {
|
|
@@ -246,17 +335,16 @@ async function listSchemaInstances(schema) {
|
|
|
246
335
|
}
|
|
247
336
|
}
|
|
248
337
|
async function getTableElementCount(schemaId, tableName, instance) {
|
|
249
|
-
const key = tableCountKey(schemaId, tableName, instance);
|
|
250
|
-
const cached = tableCountCache.get(key);
|
|
251
|
-
const now = Date.now();
|
|
252
|
-
if (cached && cached.expiresAt > now)
|
|
253
|
-
return cached.value;
|
|
254
338
|
const schema = (0, schemaRegistry_1.getRegistry)().get(schemaId);
|
|
255
339
|
if (!schema)
|
|
256
340
|
return 0;
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
341
|
+
return cachedCount(tableCountKey(schemaId, tableName, instance), () => countTableRows(schema, tableName, instance).catch(() => 0));
|
|
342
|
+
}
|
|
343
|
+
async function getTableTotalCount(schemaId, tableName) {
|
|
344
|
+
const schema = (0, schemaRegistry_1.getRegistry)().get(schemaId);
|
|
345
|
+
if (!schema)
|
|
346
|
+
return 0;
|
|
347
|
+
return cachedCount(tableCountKey(schemaId, tableName, interface_database_1.CROSS_INSTANCE), () => countTableRows(schema, tableName, interface_database_1.CROSS_INSTANCE).catch(() => 0));
|
|
260
348
|
}
|
|
261
349
|
async function computeInsights(id, schema) {
|
|
262
350
|
const tableNames = Object.keys(schema.definition);
|