@antelopejs/interface-dms-builder 0.2.3 → 0.2.5
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/analysis.d.ts +4 -1
- package/dist/analysis.js.map +1 -1
- package/dist/catalog.d.ts +6 -0
- package/dist/project.d.ts +16 -2
- package/dist/project.js.map +1 -1
- package/dist/queries.js.map +1 -1
- package/dist/results.d.ts +1 -1
- package/docs/11.external-databases.md +58 -13
- package/docs/3.catalog.md +1 -0
- package/docs/8.results-and-errors.md +1 -1
- package/docs/tsconfig.json +5 -1
- package/package.json +1 -1
package/dist/analysis.d.ts
CHANGED
|
@@ -59,13 +59,15 @@ export interface ProposedResource {
|
|
|
59
59
|
fields: ProposedField[];
|
|
60
60
|
leftOut: ProposedLeftOut[];
|
|
61
61
|
writes: ProposedWrites;
|
|
62
|
+
rows?: number;
|
|
63
|
+
profiledRows?: number;
|
|
62
64
|
}
|
|
63
65
|
export interface ProposedExclusion {
|
|
64
66
|
relation: string;
|
|
65
67
|
reason: string;
|
|
66
68
|
rule: string;
|
|
67
69
|
}
|
|
68
|
-
export type OpenItemKind = "schemas" | "purpose" | "label" | "reference";
|
|
70
|
+
export type OpenItemKind = "schemas" | "purpose" | "label" | "reference" | "field-type";
|
|
69
71
|
export interface OpenItemOption {
|
|
70
72
|
value: unknown;
|
|
71
73
|
title: string;
|
|
@@ -79,6 +81,7 @@ export interface OpenItem {
|
|
|
79
81
|
options: OpenItemOption[];
|
|
80
82
|
proposed: unknown;
|
|
81
83
|
resource?: ProposedResource;
|
|
84
|
+
open?: OpenItem[];
|
|
82
85
|
}
|
|
83
86
|
export interface ProposalDatabase {
|
|
84
87
|
engine: string;
|
package/dist/analysis.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analysis.js","sourceRoot":"","sources":["../src/analysis.ts"],"names":[],"mappings":";;;AAAA,+DAA+D;
|
|
1
|
+
{"version":3,"file":"analysis.js","sourceRoot":"","sources":["../src/analysis.ts"],"names":[],"mappings":";;;AAAA,+DAA+D;AAyMlD,QAAA,eAAe,GAC1B,IAAA,kCAAiB,GAEd,CAAC;AAMO,QAAA,WAAW,GACtB,IAAA,kCAAiB,GAAoD,CAAC;AAc3D,QAAA,UAAU,GACrB,IAAA,kCAAiB,GAEd,CAAC"}
|
package/dist/catalog.d.ts
CHANGED
|
@@ -81,6 +81,12 @@ export interface BlockTypeDescriptor {
|
|
|
81
81
|
shapeSource: ShapeSource;
|
|
82
82
|
description?: string;
|
|
83
83
|
controllerArg?: boolean;
|
|
84
|
+
initialChildren?: BlockInitialChild[];
|
|
85
|
+
}
|
|
86
|
+
export interface BlockInitialChild {
|
|
87
|
+
id: string;
|
|
88
|
+
type: string;
|
|
89
|
+
options: Record<string, unknown>;
|
|
84
90
|
}
|
|
85
91
|
export interface DataTypeDescriptor {
|
|
86
92
|
id: string;
|
package/dist/project.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export interface ModuleEntryInput {
|
|
|
10
10
|
env?: Record<string, string>;
|
|
11
11
|
importOverrides?: ImportOverrideInput[];
|
|
12
12
|
exportPriority?: Record<string, number>;
|
|
13
|
+
disabledExports?: string[];
|
|
13
14
|
}
|
|
14
15
|
export interface AddModuleStep {
|
|
15
16
|
op: "AddModule";
|
|
@@ -26,15 +27,28 @@ export interface CreateLocalModuleStep {
|
|
|
26
27
|
id: string;
|
|
27
28
|
path: string;
|
|
28
29
|
entry?: ModuleEntryInput;
|
|
30
|
+
connection?: string;
|
|
29
31
|
}
|
|
30
|
-
export
|
|
32
|
+
export interface RemoveModuleStep {
|
|
33
|
+
op: "RemoveModule";
|
|
34
|
+
id: string;
|
|
35
|
+
}
|
|
36
|
+
export interface RemoveConnectionStep {
|
|
37
|
+
op: "RemoveConnection";
|
|
38
|
+
interface: string;
|
|
39
|
+
id: string;
|
|
40
|
+
}
|
|
41
|
+
export type ProjectConfigStep = AddModuleStep | ConfigureModuleStep | CreateLocalModuleStep | RemoveModuleStep | RemoveConnectionStep;
|
|
31
42
|
export interface ProjectConfigOpts {
|
|
32
43
|
dryRun?: boolean;
|
|
33
44
|
}
|
|
45
|
+
export interface CreateLocalModuleOpts extends ProjectConfigOpts {
|
|
46
|
+
connection?: string;
|
|
47
|
+
}
|
|
34
48
|
export interface ProjectConfigResult {
|
|
35
49
|
files: string[];
|
|
36
50
|
}
|
|
37
51
|
export declare const ConfigureProject: (steps: ProjectConfigStep[], opts?: ProjectConfigOpts | undefined) => Promise<OpResult<ProjectConfigResult>>;
|
|
38
52
|
export declare const AddModule: (id: string, entry: ModuleEntryInput, opts?: ProjectConfigOpts | undefined) => Promise<OpResult<ProjectConfigResult>>;
|
|
39
53
|
export declare const ConfigureModule: (id: string, entry: ModuleEntryInput, opts?: ProjectConfigOpts | undefined) => Promise<OpResult<ProjectConfigResult>>;
|
|
40
|
-
export declare const CreateLocalModule: (id: string, path: string, entry?: ModuleEntryInput | undefined, opts?:
|
|
54
|
+
export declare const CreateLocalModule: (id: string, path: string, entry?: ModuleEntryInput | undefined, opts?: CreateLocalModuleOpts | undefined) => Promise<OpResult<ProjectConfigResult>>;
|
package/dist/project.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project.js","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":";;;AAAA,+DAA+D;
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":";;;AAAA,+DAA+D;AA6GlD,QAAA,gBAAgB,GAC3B,IAAA,kCAAiB,GAKd,CAAC;AAGO,QAAA,SAAS,GACpB,IAAA,kCAAiB,GAMd,CAAC;AAGO,QAAA,eAAe,GAC1B,IAAA,kCAAiB,GAMd,CAAC;AAGO,QAAA,iBAAiB,GAC5B,IAAA,kCAAiB,GAOd,CAAC"}
|
package/dist/queries.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../src/queries.ts"],"names":[],"mappings":";;;AAAA,+DAA+D;
|
|
1
|
+
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../src/queries.ts"],"names":[],"mappings":";;;AAAA,+DAA+D;AA2MlD,QAAA,kBAAkB,GAC7B,IAAA,kCAAiB,GAEd,CAAC;AAEO,QAAA,QAAQ,GACnB,IAAA,kCAAiB,GAMd,CAAC;AAEO,QAAA,cAAc,GACzB,IAAA,kCAAiB,GAMd,CAAC;AAEO,QAAA,WAAW,GACtB,IAAA,kCAAiB,GAEd,CAAC"}
|
package/dist/results.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export interface TypecheckError {
|
|
|
14
14
|
message: string;
|
|
15
15
|
}
|
|
16
16
|
export interface OpWarning {
|
|
17
|
-
code: "query_opaque" | "query_kept" | "index_clamped" | "datatype_fallback" | "data_not_dropped" | "route_changed" | "data_kept" | "page_not_written" | "relation_missing";
|
|
17
|
+
code: "query_opaque" | "query_kept" | "index_clamped" | "datatype_fallback" | "data_not_dropped" | "route_changed" | "data_kept" | "page_not_written" | "relation_missing" | "module_not_loaded";
|
|
18
18
|
message: string;
|
|
19
19
|
}
|
|
20
20
|
export type DuplicateScope = "page" | "siblings" | "category" | "resource" | "query" | "module";
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
A DMS project can show pages over a database it does not own: a client's PostgreSQL, read and written live through
|
|
5
|
+
A DMS project can show pages over a database it does not own: a client's PostgreSQL, MongoDB or RethinkDB, read and written live through that engine's module (`@antelopejs/postgres`, `@antelopejs/mongodb`, `@antelopejs/rethinkdb`) in external mode. The builder takes such a database in four moves, each an operation:
|
|
6
6
|
|
|
7
|
-
1. **Wire it** into `antelope.config.ts` with `ConfigureProject`: the provider module, a local module for its tables,
|
|
7
|
+
1. **Wire it** into `antelope.config.ts` with `ConfigureProject`: the provider module, a local module for its tables, the builder's catalog connection, and the DMS module's pin to the project's own database.
|
|
8
8
|
2. **Analyse it** with `AnalyseDatabase`, which reads the catalog and proposes a mapping by fixed rules. It writes nothing.
|
|
9
9
|
3. **Decide** the proposal: a person in the builder's *Database* workspace, or an assistant through these operations.
|
|
10
10
|
4. **Map it** with `MapResources`, which writes table classes, controllers and TableView pages into the module bound to the database.
|
|
@@ -18,11 +18,23 @@ The builder reaches the database through `@antelopejs/interface-database-catalog
|
|
|
18
18
|
| Step | Writes |
|
|
19
19
|
| --- | --- |
|
|
20
20
|
| `AddModule` | a module entry, refusing an id that exists |
|
|
21
|
-
| `ConfigureModule` | merges config, `importOverrides` (pins and connection ids), `exportPriority` and env variable names into an entry |
|
|
22
|
-
| `CreateLocalModule` | scaffolds a local module and adds its entry |
|
|
21
|
+
| `ConfigureModule` | merges config, `importOverrides` (pins and connection ids), `exportPriority`, `disabledExports` and env variable names into an entry |
|
|
22
|
+
| `CreateLocalModule` | scaffolds a local module and adds its entry; with `connection`, its record names that connection |
|
|
23
|
+
| `RemoveModule` | removes an entry and the `envOverrides` entries supplying its config, refusing one another module still reads through; its files stay |
|
|
24
|
+
| `RemoveConnection` | removes a named connection to an interface from every module's `importOverrides` |
|
|
23
25
|
|
|
24
26
|
`env` takes variable names, never values: each is added to `envOverrides`, and to `.env.example` when the project has one.
|
|
25
27
|
|
|
28
|
+
The provider's entry depends on its engine:
|
|
29
|
+
|
|
30
|
+
| Engine | Package | `env` | `disabledExports` |
|
|
31
|
+
| --- | --- | --- | --- |
|
|
32
|
+
| PostgreSQL | `@antelopejs/postgres` | `url` | none |
|
|
33
|
+
| MongoDB | `@antelopejs/mongodb` | `url` and `database` | `@antelopejs/interface-mongodb` |
|
|
34
|
+
| RethinkDB | `@antelopejs/rethinkdb` | `url`, the database as its path | `@antelopejs/interface-rethinkdb` |
|
|
35
|
+
|
|
36
|
+
`disabledExports` keeps core from ever offering the external instance's raw client, so a module that needs the DMS's own MongoDB or RethinkDB client never gets the client's database instead.
|
|
37
|
+
|
|
26
38
|
```typescript
|
|
27
39
|
import { ConfigureProject } from "@antelopejs/interface-dms-builder";
|
|
28
40
|
|
|
@@ -36,20 +48,22 @@ const result = await ConfigureProject([
|
|
|
36
48
|
source: { type: "package", package: "@antelopejs/postgres", version: "^0.2.0" },
|
|
37
49
|
config: { mode: "external", statementTimeoutMs: 30000 },
|
|
38
50
|
env: { url: "ERP_DATABASE_URL" },
|
|
51
|
+
exportPriority: { "@antelopejs/interface-database": -1 },
|
|
39
52
|
},
|
|
40
53
|
},
|
|
41
54
|
{
|
|
42
55
|
op: "CreateLocalModule",
|
|
43
56
|
id: "erp-tables",
|
|
44
57
|
path: "modules/erp-tables",
|
|
58
|
+
connection: "erp",
|
|
45
59
|
entry: {
|
|
46
60
|
importOverrides: [{ interface: "@antelopejs/interface-database", source: "postgres-erp" }],
|
|
47
61
|
},
|
|
48
62
|
},
|
|
49
63
|
{
|
|
50
64
|
op: "ConfigureModule",
|
|
51
|
-
id: "
|
|
52
|
-
entry: {
|
|
65
|
+
id: "dms",
|
|
66
|
+
entry: { importOverrides: [{ interface: "@antelopejs/interface-database", source: "mongodb" }] },
|
|
53
67
|
},
|
|
54
68
|
{
|
|
55
69
|
op: "ConfigureModule",
|
|
@@ -59,8 +73,21 @@ const result = await ConfigureProject([
|
|
|
59
73
|
]);
|
|
60
74
|
```
|
|
61
75
|
|
|
76
|
+
- The provider's `exportPriority` of `-1` keeps the project's own database the default for every module that does not pin `interface-database`.
|
|
77
|
+
- The tables module pins `interface-database` to the provider, and uses the DMS. Core passes that pin on to the DMS, which every other module reaches with the default, so the DMS pins the project's own database to settle it. A DMS that already pins `interface-database` needs nothing more.
|
|
78
|
+
|
|
62
79
|
The connection exists once the project restarts with the variable set.
|
|
63
80
|
|
|
81
|
+
### Remove a Connection
|
|
82
|
+
|
|
83
|
+
Removing a connection takes its catalog connections and its tables module out of the configuration, with `RemoveConnection` and `RemoveModule`. The tables module's folder is deleted with it. The database itself is untouched.
|
|
84
|
+
|
|
85
|
+
The tables module is the one whose `dmsBuilder.database` record names the connection, which `CreateLocalModule` writes with `connection` (the single-step `CreateLocalModule` takes it in its options). Another module that reads through the provider is never removed or deleted.
|
|
86
|
+
|
|
87
|
+
The provider goes too, with the variables that supply its configuration in `envOverrides`, `.env` and `.env.example`, only when it was added for this connection alone: its `exportPriority` for `@antelopejs/interface-database` is below the project's own database, and no module or connection the removal leaves names it. Otherwise it stays, since it may be the project's own database.
|
|
88
|
+
|
|
89
|
+
A removal is all or nothing: the folders are moved aside and `.env` is edited first, and both are put back when the configuration cannot be written.
|
|
90
|
+
|
|
64
91
|
## Analyse a Database
|
|
65
92
|
|
|
66
93
|
`AnalyseDatabase({ connection, module, schemas? })` starts a job and answers it at once: profiling a database takes a while. `GetAnalysis(id)` answers the job's `progress` while it runs, then its `proposal`, or its `error`.
|
|
@@ -100,18 +127,27 @@ A **fact** follows from the catalog with no judgement. A **default** is a judgem
|
|
|
100
127
|
| R2 | no key | stats only: table class and model, no page |
|
|
101
128
|
| R3 | no rows | excluded |
|
|
102
129
|
| R4 | a framework's or a migration tool's table | excluded |
|
|
103
|
-
| R5 | keyed by its two
|
|
130
|
+
| R5 | keyed by its two references | stats only |
|
|
104
131
|
| R6 | keyed, with rows and a label | TableView |
|
|
105
132
|
| R7 | keyed, no label, referenced | TableView labelled by its key, and a `label` question |
|
|
106
133
|
| R8 | keyed, no label, not referenced, with a time axis | stats only |
|
|
107
134
|
| R9 | anything else | a `purpose` question, nothing proposed |
|
|
108
135
|
| L1, L2 | the label by name, then by order; titles from short comments, else from names | |
|
|
109
|
-
| F1–F5 | columns no type reads and secrets left out; the first declaration;
|
|
136
|
+
| F1–F5 | columns no type reads and secrets left out; the first declaration; references the database declares, and references found whole, as relation columns | |
|
|
110
137
|
| W1 | every TableView | read-only |
|
|
111
138
|
|
|
112
139
|
Each field also carries the declarations its column `accepts`, and its profile's aggregates: traits, nulls, distinct values, range and categories. Never a row.
|
|
113
140
|
|
|
114
|
-
|
|
141
|
+
Each resource also carries its `rows`, counted by the profile or estimated, when either is known.
|
|
142
|
+
|
|
143
|
+
What the rules could not decide is in `open`, each item with its options and what the proposal holds meanwhile:
|
|
144
|
+
|
|
145
|
+
- A `label` item offers every column a field reads, the key among them.
|
|
146
|
+
- A `reference` item offers a plain column, the target its values were found in, and every TableView whose single-column key accepts the column.
|
|
147
|
+
- A `purpose` item carries the `resource` it would map, should the answer be to map it, and in its own `open` the questions that resource leaves: they are asked only once the answer maps it.
|
|
148
|
+
- A `field-type` item asks which declaration reads a field of several native types.
|
|
149
|
+
|
|
150
|
+
A document database declares no field types, so its catalog reads them from a sample. When no type covers enough of a field's values (`int 60% | string 40%`), the field is left out and a `field-type` item asks which declaration reads it: its options are a declaration per type seen, and leaving it out. The `_id` of a collection without a key is never declared, so it is left out and asks nothing. `MapResources` accepts the declaration it answers. MongoDB and RethinkDB declare no references either, so F5 finds them all.
|
|
115
151
|
|
|
116
152
|
## Map Relations
|
|
117
153
|
|
|
@@ -133,14 +169,23 @@ const result = await MapResources({
|
|
|
133
169
|
fields: [{ column: "name", searchable: true }, { column: "segment", filterable: true }],
|
|
134
170
|
},
|
|
135
171
|
],
|
|
136
|
-
excluded: [{ relation: "erp.
|
|
172
|
+
excluded: [{ relation: "erp.schema_migrations", reason: "a framework's or a migration tool's table" }],
|
|
137
173
|
});
|
|
138
174
|
```
|
|
139
175
|
|
|
140
|
-
- **Names are the database's own.** `_id` is declared only where the relation has a key, and nothing creates or alters a table.
|
|
176
|
+
- **Names are the database's own.** `_id` is declared only where the relation has a key, and nothing creates or alters a table. A MongoDB collection's key is `_id` itself, which is declared once.
|
|
141
177
|
- **Relation columns** point at a relation of the batch, or one the module mapped before, by its single-column key.
|
|
142
|
-
- **Mapping again** a relation already mapped rewrites it from the new choices. Its page is created, kept or removed as `tableView` says
|
|
143
|
-
-
|
|
178
|
+
- **Mapping again** a relation already mapped rewrites it from the new choices. Its page is created, kept or removed as `tableView` says, and takes the new `title`. The module's relation columns pointing at it take its new `label`.
|
|
179
|
+
- **The module's `package.json`** records the connection and the `excluded` tables with their reasons, so the next analysis does not propose those tables. Mapping one later removes it from the record:
|
|
180
|
+
|
|
181
|
+
```json
|
|
182
|
+
"dmsBuilder": {
|
|
183
|
+
"database": {
|
|
184
|
+
"connection": "erp",
|
|
185
|
+
"excludedTables": { "erp.schema_migrations": "a framework's or a migration tool's table" }
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
144
189
|
- **In a mapped module**, `CreateResource` and `AddField` are refused, since its tables are the database's. `DeleteResource` keeps the client's rows and warns `data_kept`.
|
|
145
190
|
|
|
146
191
|
## Next Steps
|
package/docs/3.catalog.md
CHANGED
|
@@ -42,6 +42,7 @@ The catalog is cached. `RefreshSourceIndex` with no scope drops that cache; see
|
|
|
42
42
|
| `shapeSource` | `ShapeSource` | How the emit shape was determined. |
|
|
43
43
|
| `description` | `string` | A human-readable description of the block. |
|
|
44
44
|
| `controllerArg` | `boolean` | `true` when the factory takes a leading controller-class argument before its options object. |
|
|
45
|
+
| `initialChildren` | `BlockInitialChild[]` | The children a new block of this type starts with, as the DMS's own helper places them in code (a `PageToolbar`'s `LiveToggle` and `PeriodSelector`, with the options of `pageToolbar()`). Each has an `id` (the child id roles name it by), a `type` (a catalog key) and its `options`. Absent for most types. |
|
|
45
46
|
|
|
46
47
|
Only a `container` block can hold children, so it is the check to make before passing a block's path as `AddBlockInput.parent`.
|
|
47
48
|
|
|
@@ -39,7 +39,7 @@ Reads that use the envelope — `GetPageStructure`, `GetResourceStructure` — r
|
|
|
39
39
|
| --- | --- | --- |
|
|
40
40
|
| `path` | `string` | The file's absolute path. |
|
|
41
41
|
| `kind` | `"create" \| "modify" \| "delete"` | What happened to the file. |
|
|
42
|
-
| `diff` | `string` |
|
|
42
|
+
| `diff` | `string` | The change as unified diff hunks (`@@ -a,b +c,d @@`, then lines prefixed with a space, `-` or `+`), with no file headers. Empty for a deletion. |
|
|
43
43
|
|
|
44
44
|
A single operation usually touches more than one file — creating a page writes the page file and rewrites the barrel that exports it; creating a resource writes three files and rewrites a barrel.
|
|
45
45
|
|
package/docs/tsconfig.json
CHANGED
|
@@ -4,7 +4,11 @@
|
|
|
4
4
|
"rootDir": "..",
|
|
5
5
|
"composite": false,
|
|
6
6
|
"incremental": false,
|
|
7
|
-
"noEmit": true
|
|
7
|
+
"noEmit": true,
|
|
8
|
+
"paths": {
|
|
9
|
+
"@antelopejs/interface-dms-builder": ["../src/index.ts"],
|
|
10
|
+
"@antelopejs/interface-dms-builder/*": ["../src/*"]
|
|
11
|
+
}
|
|
8
12
|
},
|
|
9
13
|
"include": ["../src/**/*.ts", "**/*.ts"]
|
|
10
14
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antelopejs/interface-dms-builder",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "AntelopeJS interface for the DMS builder: create and edit pages, blocks, resources and queries in a DMS project from another module.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"antelopejs",
|