-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathexternal-datasource-service.ts
More file actions
159 lines (144 loc) · 5.63 KB
/
Copy pathexternal-datasource-service.ts
File metadata and controls
159 lines (144 loc) · 5.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
/**
* IExternalDatasourceService — External Datasource Federation contract
* (ADR-0015 §4.5, §6).
*
* The service that turns a federated datasource (`schemaMode !== 'managed'`)
* into something the rest of ObjectStack can use: it lists remote tables,
* drafts `Object` definitions from them, and validates declared objects
* against the live remote schema. Implemented in
* `@objectstack/service-external-datasource` on top of the driver's
* introspection capability; consumed by the CLI, the boot-validation plugin
* (Gate 2), and the REST layer.
*/
import type { SchemaDiffEntry } from '../shared/external-errors';
import type { ExternalCatalog } from '../data/external-catalog.zod';
/**
* A remote table discovered via introspection, filtered by the datasource's
* `external.allowedSchemas`.
*/
export interface RemoteTable {
/** Remote schema/database qualifier, when the dialect has one. */
schema?: string;
/** Remote table/view name. */
name: string;
/** Number of columns. */
columnCount: number;
/** Approximate row count, when the driver can supply it cheaply. */
rowCountEstimate?: number;
}
/**
* Options controlling how a remote table is turned into an `Object` draft.
*/
export interface GenerateDraftOpts {
/** Restrict to a single remote schema. */
remoteSchema?: string;
/** Remote column → local field name overrides. */
rename?: Record<string, string>;
/** Override primary-key detection. */
primaryKey?: string[];
/** Only include these remote columns. */
includeColumns?: string[];
/** Exclude these remote columns. */
excludeColumns?: string[];
}
/**
* A generated `Object` draft: both the structured definition and a ready-to-
* write `*.object.ts` source string (with `// REVIEW:` markers on lossy
* column mappings).
*/
export interface ObjectDraft {
/** Suggested object name (snake_case), derived from the remote table. */
name: string;
/** The datasource this object is bound to. */
datasource: string;
/** The structured object definition (parseable by `ObjectSchema`). */
definition: Record<string, unknown>;
/** Rendered TypeScript source for an `*.object.ts` file. */
source: string;
/** Columns whose mapping is lossy or unknown, surfaced for human review. */
review: Array<{ column: string; remoteType: string; note: string }>;
}
/**
* Options for {@link IExternalDatasourceService.importObject}: a superset of
* the draft options, plus the runtime-persona choices the Studio "Import as
* Object" action exposes.
*/
export interface ImportObjectOpts extends GenerateDraftOpts {
/** Override the auto-derived object name (snake_case). */
name?: string;
/**
* Mark the imported object writable (`object.external.writable`). Default
* `false` — federated objects are read-only unless explicitly opted in (and
* the datasource must also set `external.allowWrites`, ADR-0015 Gate 3).
*/
writable?: boolean;
}
/** Outcome of importing a remote table as a live federated object. */
export interface ImportObjectResult {
/** The object name as persisted. */
name: string;
/** The persisted object definition (parseable by `ObjectSchema`). */
definition: Record<string, unknown>;
/** Review notes carried over from the draft (lossy/unknown column mappings). */
review: ObjectDraft['review'];
}
/** Per-object validation outcome. */
export interface SchemaValidationResult {
ok: boolean;
datasource: string;
object: string;
diffs: SchemaDiffEntry[];
}
/** Aggregate validation outcome across many federated objects. */
export interface SchemaValidationReport {
ok: boolean;
results: SchemaValidationResult[];
}
/**
* External datasource service contract.
*
* All methods are keyed by ObjectStack identifiers (`datasource` / object
* `name`), never by live connections — credential resolution and driver
* acquisition are the implementation's concern.
*/
export interface IExternalDatasourceService {
/**
* List remote tables on a federated datasource, filtered by
* `external.allowedSchemas`.
*/
listRemoteTables(datasource: string, opts?: { schema?: string }): Promise<RemoteTable[]>;
/**
* Generate an `Object` draft (structured + `*.object.ts` source) from a
* remote table, using the type-compat matrix to map columns to field types.
*/
generateObjectDraft(
datasource: string,
remoteName: string,
opts?: GenerateDraftOpts,
): Promise<ObjectDraft>;
/**
* Persist a remote table as a live, runtime-origin federated `Object` so it
* is immediately queryable — the backend of the Studio "Import as Object"
* action (ADR-0015 §6.4, Addendum runtime persona). Builds the draft via
* {@link generateObjectDraft}, applies the import overrides, and writes it
* through the metadata store. Requires a writable metadata store: throws when
* none is wired (e.g. a GitOps-only / read-only deployment).
*/
importObject(
datasource: string,
remoteName: string,
opts?: ImportObjectOpts,
): Promise<ImportObjectResult>;
/**
* Refresh and persist the cached remote schema snapshot as an
* `external_catalog` metadata record (conventionally `<datasource>_catalog`).
* Returns the snapshot. Persistence is best-effort: when no catalog store is
* wired the snapshot is still returned, just not cached.
*/
refreshCatalog(datasource: string): Promise<ExternalCatalog>;
/** Validate one federated object against the live remote table. */
validateObject(objectName: string): Promise<SchemaValidationResult>;
/** Validate every federated object, parallelised per datasource. */
validateAll(): Promise<SchemaValidationReport>;
}