@tablecraft-app/plugin-api 0.0.0-stage → 1.2.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/LICENSE +21 -0
- package/README.md +46 -2
- package/dist/catalog.d.ts +112 -0
- package/dist/catalog.js +5 -0
- package/dist/completion.d.ts +109 -0
- package/dist/completion.js +12 -0
- package/dist/errors.d.ts +67 -0
- package/dist/errors.js +124 -0
- package/dist/explain.d.ts +58 -0
- package/dist/explain.js +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +16 -0
- package/dist/inspection.d.ts +38 -0
- package/dist/inspection.js +21 -0
- package/dist/keyspace.d.ts +180 -0
- package/dist/keyspace.js +2 -0
- package/dist/manifest.d.ts +200 -0
- package/dist/manifest.js +238 -0
- package/dist/objects.d.ts +140 -0
- package/dist/objects.js +2 -0
- package/dist/plugin.d.ts +565 -0
- package/dist/plugin.js +58 -0
- package/dist/sessions.d.ts +59 -0
- package/dist/sessions.js +2 -0
- package/dist/sql/classify.d.ts +19 -0
- package/dist/sql/classify.js +95 -0
- package/dist/sql/complete.d.ts +23 -0
- package/dist/sql/complete.js +480 -0
- package/dist/sql/explain.d.ts +42 -0
- package/dist/sql/explain.js +108 -0
- package/dist/sql/format.d.ts +26 -0
- package/dist/sql/format.js +117 -0
- package/dist/sql/functions.d.ts +47 -0
- package/dist/sql/functions.js +159 -0
- package/dist/sql/generate.d.ts +22 -0
- package/dist/sql/generate.js +64 -0
- package/dist/sql/index.d.ts +16 -0
- package/dist/sql/index.js +16 -0
- package/dist/sql/inspect.d.ts +10 -0
- package/dist/sql/inspect.js +134 -0
- package/dist/sql/inspectContext.d.ts +78 -0
- package/dist/sql/inspectContext.js +251 -0
- package/dist/sql/inspectResolve.d.ts +6 -0
- package/dist/sql/inspectResolve.js +391 -0
- package/dist/sql/inspectStyle.d.ts +3 -0
- package/dist/sql/inspectStyle.js +384 -0
- package/dist/sql/inspectSyntax.d.ts +10 -0
- package/dist/sql/inspectSyntax.js +179 -0
- package/dist/sql/layout.d.ts +8 -0
- package/dist/sql/layout.js +114 -0
- package/dist/sql/layoutNodes.d.ts +46 -0
- package/dist/sql/layoutNodes.js +317 -0
- package/dist/sql/layoutPrint.d.ts +60 -0
- package/dist/sql/layoutPrint.js +806 -0
- package/dist/sql/layoutWriter.d.ts +21 -0
- package/dist/sql/layoutWriter.js +77 -0
- package/dist/sql/literals.d.ts +28 -0
- package/dist/sql/literals.js +78 -0
- package/dist/sql/namespace.d.ts +41 -0
- package/dist/sql/namespace.js +220 -0
- package/dist/sql/objects.d.ts +42 -0
- package/dist/sql/objects.js +222 -0
- package/dist/sql/parameters.d.ts +20 -0
- package/dist/sql/parameters.js +88 -0
- package/dist/sql/resolution.d.ts +73 -0
- package/dist/sql/resolution.js +192 -0
- package/dist/sql/routines.d.ts +27 -0
- package/dist/sql/routines.js +42 -0
- package/dist/sql/scope.d.ts +117 -0
- package/dist/sql/scope.js +540 -0
- package/dist/sql/select.d.ts +41 -0
- package/dist/sql/select.js +287 -0
- package/dist/sql/signature.d.ts +18 -0
- package/dist/sql/signature.js +137 -0
- package/dist/sql/splitter.d.ts +15 -0
- package/dist/sql/splitter.js +217 -0
- package/dist/sql/suggest.d.ts +6 -0
- package/dist/sql/suggest.js +36 -0
- package/dist/sql/tokens.d.ts +62 -0
- package/dist/sql/tokens.js +227 -0
- package/dist/sql/words.d.ts +23 -0
- package/dist/sql/words.js +72 -0
- package/dist/testing/index.d.ts +274 -0
- package/dist/testing/index.js +2398 -0
- package/dist/tls.d.ts +33 -0
- package/dist/tls.js +118 -0
- package/dist/url.d.ts +54 -0
- package/dist/url.js +228 -0
- package/dist/values.d.ts +44 -0
- package/dist/values.js +44 -0
- package/dist/version.d.ts +22 -0
- package/dist/version.js +29 -0
- package/package.json +42 -4
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import type { Introspector, Namespace, Relation, Routine } from "./catalog.js";
|
|
3
|
+
import type { CompletionCatalog, CompletionRequest, CompletionResult, Declaration, ResolveRequest, SignatureHelp } from "./completion.js";
|
|
4
|
+
import type { ExplainedPlan, Explainability, ExplainOptions } from "./explain.js";
|
|
5
|
+
import type { InspectionRequest, Problem } from "./inspection.js";
|
|
6
|
+
import type { Keyspace } from "./keyspace.js";
|
|
7
|
+
import type { ObjectEditor } from "./objects.js";
|
|
8
|
+
import type { SessionMonitor } from "./sessions.js";
|
|
9
|
+
import type { TypeClass, WireValue } from "./values.js";
|
|
10
|
+
/**
|
|
11
|
+
* What a plugin can do. The UI branches on these, never on a plugin id (decision 007), and a
|
|
12
|
+
* capability without contract-suite coverage cannot be declared (decision 013).
|
|
13
|
+
*/
|
|
14
|
+
export declare const CAPABILITIES: readonly ["sql", "cancel", "schemaTree", "transactions", "ddl", "explain", "explainAnalyze", "currentNamespace", "keepAlive", "bulkInsert", "objects", "serverMessages", "sessions", "routineCall", "commands", "keyValue", "nodes", "serverInfo"];
|
|
15
|
+
export type Capability = (typeof CAPABILITIES)[number];
|
|
16
|
+
/** Statements `SqlLanguage.generate` writes from a catalog relation (plan 010). */
|
|
17
|
+
export declare const GENERATED_STATEMENTS: readonly ["drop", "select", "insert", "update"];
|
|
18
|
+
export type GeneratedStatement = (typeof GENERATED_STATEMENTS)[number];
|
|
19
|
+
export interface Column {
|
|
20
|
+
readonly name: string;
|
|
21
|
+
/** The type the database reports, verbatim; null when it reports none. */
|
|
22
|
+
readonly type: string | null;
|
|
23
|
+
/**
|
|
24
|
+
* What the values are, when the type name alone does not say: Oracle's `NUMBER` is an integer
|
|
25
|
+
* at scale 0 and a decimal otherwise. Absent, the host reads the class from `type` (decision 101).
|
|
26
|
+
*/
|
|
27
|
+
readonly typeClass?: TypeClass;
|
|
28
|
+
/**
|
|
29
|
+
* The base-table column the driver says the value is read from (plan 026): null for an
|
|
30
|
+
* expression, absent when the driver does not say. A console result is editable only where the
|
|
31
|
+
* plugin's `selectSource` and this agree.
|
|
32
|
+
*/
|
|
33
|
+
readonly origin?: ColumnOrigin | null;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Where the driver says a result column comes from, in its own terms: a table id or qualified
|
|
37
|
+
* name, and a column number or name. Stable within one result; compared, never shown or parsed.
|
|
38
|
+
*/
|
|
39
|
+
export interface ColumnOrigin {
|
|
40
|
+
readonly table: string;
|
|
41
|
+
readonly column: string;
|
|
42
|
+
}
|
|
43
|
+
export type Row = readonly WireValue[];
|
|
44
|
+
export interface ExecuteResult {
|
|
45
|
+
/** Empty for a statement that returns no rows. */
|
|
46
|
+
readonly columns: readonly Column[];
|
|
47
|
+
/** Pulled lazily, so the host decides how many rows to fetch. */
|
|
48
|
+
readonly rows: AsyncIterable<Row>;
|
|
49
|
+
/** Null when the database does not report it, or the statement returns rows. */
|
|
50
|
+
readonly rowsAffected: number | null;
|
|
51
|
+
/**
|
|
52
|
+
* What the server said about the statement besides its rows, such as MySQL's warnings or
|
|
53
|
+
* PostgreSQL's notices (decision 066), in the order it said them, at most `SERVER_MESSAGE_LIMIT`
|
|
54
|
+
* of them and one more saying how many were left out. Complete once `rows` is exhausted; empty
|
|
55
|
+
* before that, and when the statement was cancelled or its rows abandoned. Present exactly when
|
|
56
|
+
* the plugin declares `serverMessages`.
|
|
57
|
+
*/
|
|
58
|
+
readonly messages?: readonly ServerMessage[];
|
|
59
|
+
/**
|
|
60
|
+
* A command's one-value answer, such as a status, a number or a string (decision 112): the
|
|
61
|
+
* console shows it in Output and opens no result. Only a `commands` plugin sets it, and then
|
|
62
|
+
* `columns` and `rows` are empty.
|
|
63
|
+
*/
|
|
64
|
+
readonly reply?: CommandReply;
|
|
65
|
+
}
|
|
66
|
+
/** A scalar reply to a command (decision 112). */
|
|
67
|
+
export interface CommandReply {
|
|
68
|
+
readonly value: WireValue;
|
|
69
|
+
/** The reply as the server's own client prints it: `"Ann"`, `(integer) 5`, `(nil)`, `OK`. */
|
|
70
|
+
readonly text: string;
|
|
71
|
+
}
|
|
72
|
+
/** How serious a `ServerMessage` is, from the server's own word for it. */
|
|
73
|
+
export declare const SERVER_MESSAGE_LEVELS: readonly ["error", "warning", "notice", "info"];
|
|
74
|
+
export type ServerMessageLevel = (typeof SERVER_MESSAGE_LEVELS)[number];
|
|
75
|
+
/** One thing the server said about a statement that succeeded (decision 066). */
|
|
76
|
+
export interface ServerMessage {
|
|
77
|
+
readonly level: ServerMessageLevel;
|
|
78
|
+
/** The server's code for it, such as `1815` or `01000`; null when it gives none. */
|
|
79
|
+
readonly code: string | null;
|
|
80
|
+
readonly text: string;
|
|
81
|
+
}
|
|
82
|
+
/** The most messages a plugin reports for one statement; past it, one more message says how many it left out. */
|
|
83
|
+
export declare const SERVER_MESSAGE_LIMIT = 100;
|
|
84
|
+
/** The message that stands for the ones past `SERVER_MESSAGE_LIMIT`. */
|
|
85
|
+
export declare function omittedMessages(count: number): ServerMessage;
|
|
86
|
+
/** A value bound to a placeholder: text the server casts, or SQL NULL (decision 043). */
|
|
87
|
+
export type ParameterValue = string | null;
|
|
88
|
+
/** What one routine parameter is given: a value, or its declared default (decision 090). */
|
|
89
|
+
export type RoutineArgument = {
|
|
90
|
+
readonly kind: "value";
|
|
91
|
+
readonly value: ParameterValue;
|
|
92
|
+
} | {
|
|
93
|
+
readonly kind: "default";
|
|
94
|
+
};
|
|
95
|
+
/** The console text that calls a routine, and the value for each `:marker` in it (decision 090). */
|
|
96
|
+
export interface RoutineCall {
|
|
97
|
+
/** One statement per line; every value is a named placeholder, never a literal. */
|
|
98
|
+
readonly sql: string;
|
|
99
|
+
/** Keyed by marker with its colon, `:amount`: the record `bind` takes. */
|
|
100
|
+
readonly params: Readonly<Record<string, ParameterValue>>;
|
|
101
|
+
}
|
|
102
|
+
export interface ExecuteOptions {
|
|
103
|
+
/**
|
|
104
|
+
* Ship every byte of a binary value (`BytesValue.preview` holds all of it) instead of the
|
|
105
|
+
* preview. For an export, which writes values whole (decision 040); a grid never asks.
|
|
106
|
+
*/
|
|
107
|
+
readonly fullBytes?: boolean;
|
|
108
|
+
/**
|
|
109
|
+
* Where a command runs, for a plugin that declares `nodes` (decision 114): `NODE_AUTO` (absent
|
|
110
|
+
* means the same) lets the plugin route it, `NODE_ALL_PRIMARIES` runs it on every primary and
|
|
111
|
+
* leads each row with a `node` column, and anything else is a `ServerNode.id`.
|
|
112
|
+
*/
|
|
113
|
+
readonly node?: string;
|
|
114
|
+
}
|
|
115
|
+
/** `ExecuteOptions.node`: the plugin routes the command by its keys (decision 114). */
|
|
116
|
+
export declare const NODE_AUTO = "auto";
|
|
117
|
+
/** `ExecuteOptions.node`: the command runs once on every primary (decision 114). */
|
|
118
|
+
export declare const NODE_ALL_PRIMARIES = "allPrimaries";
|
|
119
|
+
export declare const NODE_ROLES: readonly ["primary", "replica"];
|
|
120
|
+
export type NodeRole = (typeof NODE_ROLES)[number];
|
|
121
|
+
/** One server of the datasource (decision 114); a standalone server is one primary. */
|
|
122
|
+
export interface ServerNode {
|
|
123
|
+
/** Stable while the cluster is: Redis' node id, or the address of a standalone server. */
|
|
124
|
+
readonly id: string;
|
|
125
|
+
/** `host:port`, as the client reaches it. */
|
|
126
|
+
readonly address: string;
|
|
127
|
+
readonly role: NodeRole;
|
|
128
|
+
/** Inclusive hash-slot ranges a primary serves; empty for a replica and a standalone server. */
|
|
129
|
+
readonly slots: readonly (readonly [number, number])[];
|
|
130
|
+
/** The primary a replica follows; null for a primary. */
|
|
131
|
+
readonly primaryId: string | null;
|
|
132
|
+
/** The server's word for its health, such as `connected` or `fail`. */
|
|
133
|
+
readonly state: string;
|
|
134
|
+
}
|
|
135
|
+
/** A titled group of a server's figures, such as Redis' `# Memory` section of `INFO` (decision 114). */
|
|
136
|
+
export interface ServerInfoSection {
|
|
137
|
+
readonly title: string;
|
|
138
|
+
readonly entries: readonly {
|
|
139
|
+
readonly name: string;
|
|
140
|
+
readonly value: string;
|
|
141
|
+
}[];
|
|
142
|
+
}
|
|
143
|
+
/** One slow-log entry: when, for how long, what ran, and from where. */
|
|
144
|
+
export interface SlowCommand {
|
|
145
|
+
readonly id: number;
|
|
146
|
+
/** ISO-8601. */
|
|
147
|
+
readonly at: string;
|
|
148
|
+
readonly durationMicros: number;
|
|
149
|
+
readonly command: string;
|
|
150
|
+
readonly client: string | null;
|
|
151
|
+
readonly node: string | null;
|
|
152
|
+
}
|
|
153
|
+
/** What `Session.serverInfo` reads about one node. */
|
|
154
|
+
export interface ServerInfo {
|
|
155
|
+
/** The node, or null for a standalone server. */
|
|
156
|
+
readonly node: string | null;
|
|
157
|
+
readonly sections: readonly ServerInfoSection[];
|
|
158
|
+
}
|
|
159
|
+
/** Kinds a file importer infers from a column's text, narrowest first within each family (plan 021). */
|
|
160
|
+
export declare const IMPORT_KINDS: readonly ["boolean", "integer", "bigint", "decimal", "double", "date", "timestamp", "text"];
|
|
161
|
+
export type ImportKind = (typeof IMPORT_KINDS)[number];
|
|
162
|
+
/** What a sample of one column's text looks like; `integerDigits` and `scale` are the widest `decimal` seen. */
|
|
163
|
+
export interface InferredColumn {
|
|
164
|
+
readonly kind: ImportKind;
|
|
165
|
+
readonly integerDigits: number;
|
|
166
|
+
readonly scale: number;
|
|
167
|
+
}
|
|
168
|
+
/** A column of a table an import creates, typed in the dialect. */
|
|
169
|
+
export interface NewColumn {
|
|
170
|
+
readonly name: string;
|
|
171
|
+
readonly type: string;
|
|
172
|
+
}
|
|
173
|
+
/** Where `Session.insertRows` writes: `table` as the introspector qualifies it, `columns` as it describes them. */
|
|
174
|
+
export interface InsertTarget {
|
|
175
|
+
readonly table: string;
|
|
176
|
+
readonly columns: readonly Column[];
|
|
177
|
+
}
|
|
178
|
+
/** One row for `Session.insertRows`, a value per target column: text as a file holds it, or SQL NULL. */
|
|
179
|
+
export type InsertRow = readonly ParameterValue[];
|
|
180
|
+
export interface Session {
|
|
181
|
+
/**
|
|
182
|
+
* Rejects with a `PluginError`: `cancelled` when `cancel` interrupted it, `connectionLost` when
|
|
183
|
+
* the connection was gone before the statement was sent, `sessionBusy` when an earlier statement
|
|
184
|
+
* or its result has not finished closing, `statementFailed` otherwise. A session runs one
|
|
185
|
+
* statement at a time. `params` are bound by the driver to the
|
|
186
|
+
* dialect's native placeholders in `sql`, as `SqlLanguage.bind` wrote them; never spliced.
|
|
187
|
+
*/
|
|
188
|
+
execute(sql: string, params?: readonly ParameterValue[], options?: ExecuteOptions): Promise<ExecuteResult>;
|
|
189
|
+
/**
|
|
190
|
+
* Present exactly when the plugin declares `cancel`. Interrupts the running statement, which
|
|
191
|
+
* then rejects with `cancelled`, and leaves the session usable; a no-op when nothing runs.
|
|
192
|
+
*/
|
|
193
|
+
cancel?(): Promise<void>;
|
|
194
|
+
/** Present exactly when the plugin declares `schemaTree`. */
|
|
195
|
+
readonly introspector?: Introspector;
|
|
196
|
+
/** Present exactly when the plugin declares `transactions`. A new session starts in `auto`. */
|
|
197
|
+
readonly transactions?: Transactions;
|
|
198
|
+
/**
|
|
199
|
+
* Present exactly when the plugin declares `explain` (decision 031). Checks `sql` with
|
|
200
|
+
* `SqlLanguage.explainable` and rejects with `explainUnsupported` and its reason when refused;
|
|
201
|
+
* otherwise sends the dialect's EXPLAIN on this session, like `execute`, and reads the whole plan.
|
|
202
|
+
* With `analyze`, which needs `explainAnalyze`, the statement runs, in this session's transaction.
|
|
203
|
+
* `cancel` interrupts it as it does `execute`.
|
|
204
|
+
*/
|
|
205
|
+
explain?(sql: string, options: ExplainOptions): Promise<ExplainedPlan>;
|
|
206
|
+
/**
|
|
207
|
+
* Present exactly when the plugin declares `currentNamespace` (decision 048). Asks the server
|
|
208
|
+
* which namespace unqualified names resolve against now, as an introspector namespace path; null
|
|
209
|
+
* when none does. Never opens a transaction, and the host calls it only while nothing runs.
|
|
210
|
+
*/
|
|
211
|
+
currentNamespace?(): Promise<readonly string[] | null>;
|
|
212
|
+
/**
|
|
213
|
+
* Present exactly when the plugin declares `keepAlive` (decision 054). One round trip to the
|
|
214
|
+
* server; rejects with `connectionLost` when the connection is gone. The host calls it only while
|
|
215
|
+
* nothing runs, and bounds how long it waits.
|
|
216
|
+
*/
|
|
217
|
+
ping?(): Promise<void>;
|
|
218
|
+
/**
|
|
219
|
+
* Present exactly when the plugin declares `bulkInsert` (decision 046). Writes `rows` into
|
|
220
|
+
* `target` by the dialect's fastest safe path, values never spliced into SQL. Atomic: when the
|
|
221
|
+
* database refuses any row it rejects with `statementFailed`, none of `rows` is kept, and an open
|
|
222
|
+
* transaction stays usable; a lost connection rejects with `connectionFailed`. Text is converted
|
|
223
|
+
* where the column needs it, so what TableCraft's CSV export writes inserts back the same: `0x…`
|
|
224
|
+
* hex into a binary column, `true`/`false` into a boolean stored as a number.
|
|
225
|
+
*/
|
|
226
|
+
insertRows?(target: InsertTarget, rows: readonly InsertRow[]): Promise<void>;
|
|
227
|
+
/** Present exactly when the plugin declares `sessions` (decision 088). */
|
|
228
|
+
readonly sessions?: SessionMonitor;
|
|
229
|
+
/**
|
|
230
|
+
* Present exactly when the plugin declares `sessions`: the server's id for this connection, as
|
|
231
|
+
* `ServerSession.id` lists it, so the host can tell its own sessions apart.
|
|
232
|
+
*/
|
|
233
|
+
readonly serverSessionId?: string;
|
|
234
|
+
/**
|
|
235
|
+
* The `ServerSession.instance` this connection is listed under, where an id names a session on one
|
|
236
|
+
* server of a cluster only (TiDB before Global Kill); absent elsewhere, or when the server would
|
|
237
|
+
* not say, and the host then matches by id alone.
|
|
238
|
+
*/
|
|
239
|
+
readonly serverInstance?: string;
|
|
240
|
+
/** Present exactly when the plugin declares `keyValue` (decision 113). */
|
|
241
|
+
readonly keyspace?: Keyspace;
|
|
242
|
+
/**
|
|
243
|
+
* Present exactly when the plugin declares `nodes` (decision 114): every server of the
|
|
244
|
+
* datasource, primaries first; one entry for a single server.
|
|
245
|
+
*/
|
|
246
|
+
nodes?(): Promise<readonly ServerNode[]>;
|
|
247
|
+
/**
|
|
248
|
+
* Present exactly when the plugin declares `serverInfo`: what `node` (a `ServerNode.id`, or null
|
|
249
|
+
* for the one server or a primary of the plugin's choice) reports about itself.
|
|
250
|
+
*/
|
|
251
|
+
serverInfo?(node: string | null): Promise<ServerInfo>;
|
|
252
|
+
/** Present exactly when the plugin declares `serverInfo`: the newest `limit` slow commands, of every primary for a null `node`. */
|
|
253
|
+
slowLog?(node: string | null, limit: number): Promise<readonly SlowCommand[]>;
|
|
254
|
+
/**
|
|
255
|
+
* Settles in bounded time even when the network is gone: a graceful goodbye that does not
|
|
256
|
+
* answer within a few seconds gives way to dropping the socket (decision 040).
|
|
257
|
+
*/
|
|
258
|
+
close(): Promise<void>;
|
|
259
|
+
/** What the server reports about itself, such as `17.4`; null when it reports nothing. */
|
|
260
|
+
readonly serverVersion: string | null;
|
|
261
|
+
/**
|
|
262
|
+
* True when another session on the same configuration sees a different database, as with
|
|
263
|
+
* SQLite's `:memory:`; the engine then never re-runs this session's statements elsewhere.
|
|
264
|
+
*/
|
|
265
|
+
readonly privateDatabase?: boolean;
|
|
266
|
+
/**
|
|
267
|
+
* The TLS the connection settled on, read once after connect; null or absent when it is plain
|
|
268
|
+
* (decision 072).
|
|
269
|
+
*/
|
|
270
|
+
readonly tls?: TlsInfo | null;
|
|
271
|
+
}
|
|
272
|
+
/** What a TLS handshake agreed, as Node's socket names it: `TLSv1.3`, `TLS_AES_256_GCM_SHA384`. */
|
|
273
|
+
export interface TlsInfo {
|
|
274
|
+
readonly protocol: string;
|
|
275
|
+
readonly cipher: string;
|
|
276
|
+
}
|
|
277
|
+
export interface ConnectOptions {
|
|
278
|
+
/**
|
|
279
|
+
* Ask the database to refuse writes for the whole session (decision 011). A guard against
|
|
280
|
+
* accidents, not a security boundary: a statement can switch it back off.
|
|
281
|
+
*/
|
|
282
|
+
readonly readOnly: boolean;
|
|
283
|
+
/**
|
|
284
|
+
* Turn on TCP keepalive, first probe after this many idle milliseconds, so a peer that vanished
|
|
285
|
+
* without a goodbye is noticed by the OS (decisions 040, 054). Absent: the driver's default. A
|
|
286
|
+
* plugin declaring `keepAlive` honours it; one without a socket ignores it.
|
|
287
|
+
*/
|
|
288
|
+
readonly keepAliveInitialDelayMs?: number;
|
|
289
|
+
/**
|
|
290
|
+
* The host name the server certificate must carry when the plugin dials another address, as
|
|
291
|
+
* through an SSH tunnel to `127.0.0.1` (decision 073). Absent: the configured host itself.
|
|
292
|
+
*/
|
|
293
|
+
readonly serverName?: string;
|
|
294
|
+
}
|
|
295
|
+
/** One statement of a script, in UTF-16 offsets into the text `split` received (decision 023). */
|
|
296
|
+
export interface StatementSpan {
|
|
297
|
+
readonly from: number;
|
|
298
|
+
readonly to: number;
|
|
299
|
+
/** `text.slice(from, to)`: the statement without its delimiter. */
|
|
300
|
+
readonly sql: string;
|
|
301
|
+
/**
|
|
302
|
+
* How many times the script asks for the statement to run: SQL Server's `GO 3` after it
|
|
303
|
+
* (decision 100). Absent means once. The host never repeats a statement; a plugin may.
|
|
304
|
+
*/
|
|
305
|
+
readonly repeat?: number;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* A statement of a streamed script (decision 081): offsets count UTF-16 units from the start of
|
|
309
|
+
* everything pushed, and `line` and `column` (both from 1) say where it starts.
|
|
310
|
+
*/
|
|
311
|
+
export interface StreamedStatement extends StatementSpan {
|
|
312
|
+
readonly line: number;
|
|
313
|
+
readonly column: number;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* `split` over text that arrives in pieces, so a script never has to be held whole (decision 081).
|
|
317
|
+
* `push` returns the statements the text so far completes; `end` returns the rest.
|
|
318
|
+
*/
|
|
319
|
+
export interface StatementStream {
|
|
320
|
+
push(text: string): readonly StreamedStatement[];
|
|
321
|
+
end(): readonly StreamedStatement[];
|
|
322
|
+
}
|
|
323
|
+
export declare const STATEMENT_KINDS: readonly ["read", "write", "ddl", "transaction", "other"];
|
|
324
|
+
export type StatementKind = (typeof STATEMENT_KINDS)[number];
|
|
325
|
+
export interface StatementClass {
|
|
326
|
+
readonly kind: StatementKind;
|
|
327
|
+
/** Why the statement needs confirmation before it runs (decision 011), such as `DELETE without WHERE`; null when it does not. */
|
|
328
|
+
readonly destructive: string | null;
|
|
329
|
+
/**
|
|
330
|
+
* The statement may move the session's current namespace, such as `USE db` or
|
|
331
|
+
* `SET search_path` (plan 022); the host then asks `Session.currentNamespace` again.
|
|
332
|
+
*/
|
|
333
|
+
readonly setsNamespace?: boolean;
|
|
334
|
+
/**
|
|
335
|
+
* Why the statement may be slow or heavy for the server, such as `KEYS walks every key`; the
|
|
336
|
+
* editor marks it and never blocks the run (decision 112). Null or absent when it is not.
|
|
337
|
+
*/
|
|
338
|
+
readonly costly?: string | null;
|
|
339
|
+
/** With `destructive`: confirming it asks for the datasource's name, not just OK (decision 112). */
|
|
340
|
+
readonly confirmByName?: boolean;
|
|
341
|
+
}
|
|
342
|
+
export declare const KEYWORD_CASES: readonly ["upper", "lower", "preserve"];
|
|
343
|
+
export type KeywordCase = (typeof KEYWORD_CASES)[number];
|
|
344
|
+
/** `aligned` is the DataGrip-like layout (decision 061); `standard` is `sql-formatter`'s own (decision 042). */
|
|
345
|
+
export declare const FORMAT_STYLES: readonly ["aligned", "standard"];
|
|
346
|
+
export type FormatStyle = (typeof FORMAT_STYLES)[number];
|
|
347
|
+
/** How `SqlLanguage.format` lays text out (decisions 042, 061). */
|
|
348
|
+
export interface FormatOptions {
|
|
349
|
+
readonly style: FormatStyle;
|
|
350
|
+
readonly keywordCase: KeywordCase;
|
|
351
|
+
readonly indentWidth: number;
|
|
352
|
+
/** Blank lines between two statements. */
|
|
353
|
+
readonly linesBetweenStatements: number;
|
|
354
|
+
/** In the aligned style, `AS` in a select list and `=` in a `SET` line up in a column. */
|
|
355
|
+
readonly alignAliases: boolean;
|
|
356
|
+
}
|
|
357
|
+
export declare const PARAMETER_STYLES: readonly ["named", "numbered", "positional"];
|
|
358
|
+
/** `:name`, `$1`, or a bare `?` (decision 043). */
|
|
359
|
+
export type ParameterStyle = (typeof PARAMETER_STYLES)[number];
|
|
360
|
+
/** One placeholder in a statement, in UTF-16 offsets into the text `parameters` received. */
|
|
361
|
+
export interface SqlParameter {
|
|
362
|
+
/** As written for `:name` and `$1`; the n-th bare `?` is `?n`. Occurrences sharing a name share a value. */
|
|
363
|
+
readonly name: string;
|
|
364
|
+
readonly from: number;
|
|
365
|
+
readonly to: number;
|
|
366
|
+
readonly style: ParameterStyle;
|
|
367
|
+
}
|
|
368
|
+
/** A statement rewritten to the dialect's native placeholders, and the values for them in order. */
|
|
369
|
+
export interface BoundStatement {
|
|
370
|
+
readonly sql: string;
|
|
371
|
+
readonly params: readonly ParameterValue[];
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* What a console `SELECT` reads, for editing its result in place (plan 026, decision 056): the
|
|
375
|
+
* one base table, and per select-list column the table column it is (`*` expanded from the
|
|
376
|
+
* catalog), or null for anything else. `readOnly` says, for the toolbar, why the statement is not
|
|
377
|
+
* that simple.
|
|
378
|
+
*/
|
|
379
|
+
export type SelectSource = {
|
|
380
|
+
readonly kind: "table";
|
|
381
|
+
readonly path: readonly string[];
|
|
382
|
+
readonly relation: string;
|
|
383
|
+
readonly columns: readonly (string | null)[];
|
|
384
|
+
} | {
|
|
385
|
+
readonly kind: "readOnly";
|
|
386
|
+
readonly reason: string;
|
|
387
|
+
};
|
|
388
|
+
/** The statements that set, roll back to and release a savepoint called `name` (plan 026). */
|
|
389
|
+
export interface SavepointStatements {
|
|
390
|
+
readonly set: string;
|
|
391
|
+
readonly rollback: string;
|
|
392
|
+
readonly release: string;
|
|
393
|
+
}
|
|
394
|
+
/** What the console asks the plugin about its dialect (decision 008); the host never parses SQL. */
|
|
395
|
+
export interface SqlLanguage {
|
|
396
|
+
/** Every non-empty statement in `text`, in order. Comments and blanks between statements belong to none. */
|
|
397
|
+
split(text: string): readonly StatementSpan[];
|
|
398
|
+
/**
|
|
399
|
+
* A fresh stream that splits exactly as `split` would, for scripts too large to hold (decision
|
|
400
|
+
* 081). Absent: the host splits the whole file with `split`, up to a size it can hold.
|
|
401
|
+
*/
|
|
402
|
+
splitStream?(): StatementStream;
|
|
403
|
+
classify(sql: string): StatementClass;
|
|
404
|
+
/** `name` quoted as an identifier, whatever characters it holds. */
|
|
405
|
+
quoteIdentifier(name: string): string;
|
|
406
|
+
/**
|
|
407
|
+
* `value` as a literal a statement can insert into a column of `columnType`. A bytes value
|
|
408
|
+
* carries only its preview, so a longer one is written clipped with a comment saying so.
|
|
409
|
+
*/
|
|
410
|
+
literal(value: WireValue, columnType: string | null): string;
|
|
411
|
+
/** An `INSERT` into `qualifiedTable` where every column takes its default (decision 026). */
|
|
412
|
+
emptyInsert(qualifiedTable: string): string;
|
|
413
|
+
/**
|
|
414
|
+
* What `UPDATE … SET column = …` writes to give a column its default: `DEFAULT` where the dialect
|
|
415
|
+
* accepts it, else the catalog's `defaultExpression` (`ColumnMeta.default`), or `NULL` without one.
|
|
416
|
+
*/
|
|
417
|
+
updateDefault(defaultExpression: string | null): string;
|
|
418
|
+
/**
|
|
419
|
+
* What fits at the caret, read from `catalog` (decision 028). Never rejects for SQL it cannot
|
|
420
|
+
* read: it offers less. `sqlCompleter` in `@tablecraft-app/plugin-api/sql` implements it.
|
|
421
|
+
*/
|
|
422
|
+
complete(request: CompletionRequest, catalog: CompletionCatalog): Promise<CompletionResult>;
|
|
423
|
+
/** Where the name at the caret was declared; null when it names nothing the scope or catalog knows. */
|
|
424
|
+
resolve(request: ResolveRequest, catalog: CompletionCatalog): Promise<Declaration | null>;
|
|
425
|
+
/**
|
|
426
|
+
* The built-in function call the caret is inside and the argument it is at, for the parameter
|
|
427
|
+
* hint (decision 098); null outside a call or in one the dialect does not document.
|
|
428
|
+
*/
|
|
429
|
+
signatureAt?(request: CompletionRequest, catalog: CompletionCatalog): Promise<SignatureHelp | null>;
|
|
430
|
+
/**
|
|
431
|
+
* Every problem in `request.text` found without running it, each with its quick fixes (plan 108).
|
|
432
|
+
* Never rejects for SQL it cannot read: it reports less. A name the catalog cannot answer for (an
|
|
433
|
+
* empty or undescribed namespace) is not reported unresolved. `sqlInspector` implements it.
|
|
434
|
+
*/
|
|
435
|
+
inspect?(request: InspectionRequest, catalog: CompletionCatalog): Promise<readonly Problem[]>;
|
|
436
|
+
/**
|
|
437
|
+
* A `statement` over `relation` for the SQL Generator (decision 029): one clause per line, columns
|
|
438
|
+
* in table order, names quoted only where needed; `qualifiedName` is what the introspector names
|
|
439
|
+
* the relation. A generated UPDATE matches no row until its `NULL`s are edited. `sqlGenerator` in
|
|
440
|
+
* `@tablecraft-app/plugin-api/sql` implements it.
|
|
441
|
+
*/
|
|
442
|
+
generate(statement: GeneratedStatement, relation: Relation, qualifiedName: string): string;
|
|
443
|
+
/**
|
|
444
|
+
* Present exactly when the plugin declares `explain` (decision 031): whether `sql`, one statement
|
|
445
|
+
* without its delimiter, can be explained (with `analyze`, analysed) in this dialect, and whether it
|
|
446
|
+
* writes. Pure; `sqlExplainable` in `@tablecraft-app/plugin-api/sql` implements it.
|
|
447
|
+
*/
|
|
448
|
+
explainable?(sql: string, options: ExplainOptions): Explainability;
|
|
449
|
+
/**
|
|
450
|
+
* `text` laid out by `options` (decision 042), comments and literals untouched. Throws an `Error`
|
|
451
|
+
* whose message says why when the text cannot be read; the host then leaves the text as it was.
|
|
452
|
+
* `sqlFormatter` in `@tablecraft-app/plugin-api/sql` implements it.
|
|
453
|
+
*/
|
|
454
|
+
format(text: string, options: FormatOptions): string;
|
|
455
|
+
/**
|
|
456
|
+
* Every placeholder in `statement`, one statement without its delimiter, in order (decision 043).
|
|
457
|
+
* Nothing inside a literal, quoted identifier or comment is one. `sqlParameters` implements it.
|
|
458
|
+
*/
|
|
459
|
+
parameters(statement: string): readonly SqlParameter[];
|
|
460
|
+
/**
|
|
461
|
+
* `statement` with each placeholder `parameters` finds rewritten to the driver's native form, and
|
|
462
|
+
* the values in the order `Session.execute` binds them. Throws a `PluginError` coded
|
|
463
|
+
* `statementFailed` naming a placeholder `values` has no entry for.
|
|
464
|
+
*/
|
|
465
|
+
bind(statement: string, values: Readonly<Record<string, ParameterValue>>): BoundStatement;
|
|
466
|
+
/**
|
|
467
|
+
* Present exactly when the plugin declares `bulkInsert`: the column type an import proposes for
|
|
468
|
+
* text that looks like `column` (decision 046). Every value of the sample inserts into it.
|
|
469
|
+
*/
|
|
470
|
+
importType?(column: InferredColumn): string;
|
|
471
|
+
/** Present exactly when the plugin declares `bulkInsert`: the `CREATE TABLE` for a new import target. */
|
|
472
|
+
createTable?(qualifiedName: string, columns: readonly NewColumn[]): string;
|
|
473
|
+
/** Present exactly when the plugin declares `objects`: the DDL for creating, altering, renaming and dropping (decision 052). */
|
|
474
|
+
readonly objects?: ObjectEditor;
|
|
475
|
+
/**
|
|
476
|
+
* The base table `sql`, one statement without its delimiter, reads, when it is a single-table
|
|
477
|
+
* `SELECT` with no join, grouping, aggregate, window, set operation, `DISTINCT` or `WITH`
|
|
478
|
+
* (plan 026). Never rejects: what it cannot read is `readOnly`. Absent: console results stay
|
|
479
|
+
* read-only. `sqlCompleter` in `@tablecraft-app/plugin-api/sql` implements it.
|
|
480
|
+
*/
|
|
481
|
+
selectSource?(sql: string, catalog: CompletionCatalog): Promise<SelectSource>;
|
|
482
|
+
/**
|
|
483
|
+
* Present with `selectSource`: the savepoint statements that let edits joining an open
|
|
484
|
+
* transaction undo only themselves when one is refused. `sqlSavepoints` implements it.
|
|
485
|
+
*/
|
|
486
|
+
savepoint?(name: string): SavepointStatements;
|
|
487
|
+
/** Present exactly when the plugin declares `currentNamespace`: how the console switches namespace (decision 060). */
|
|
488
|
+
readonly namespaceSwitch?: NamespaceSwitch;
|
|
489
|
+
/**
|
|
490
|
+
* Present exactly when the plugin declares `routineCall` (decision 090): the console text that
|
|
491
|
+
* calls `routine`, named `qualifiedName` by the introspector, and returns its result, OUT values
|
|
492
|
+
* included. `args` has one entry per parameter in order; an `out` entry is ignored. Throws a
|
|
493
|
+
* `PluginError` coded `statementFailed` saying what to change when the arguments do not fit.
|
|
494
|
+
*/
|
|
495
|
+
routineCall?(routine: Routine, qualifiedName: string, args: readonly RoutineArgument[]): RoutineCall;
|
|
496
|
+
}
|
|
497
|
+
/** How a session moves to another namespace from the console's switcher (decision 060). */
|
|
498
|
+
export interface NamespaceSwitch {
|
|
499
|
+
/**
|
|
500
|
+
* Which catalog namespaces a switch can name: `topLevel` the ones with a one-part path (MySQL's
|
|
501
|
+
* databases), `schema` those of kind `schema` (PostgreSQL's schemas).
|
|
502
|
+
*/
|
|
503
|
+
readonly targets: "topLevel" | "schema";
|
|
504
|
+
/** Whether a rollback undoes the switch inside an open transaction. */
|
|
505
|
+
readonly transactional: boolean;
|
|
506
|
+
/**
|
|
507
|
+
* The one statement that makes `path` the session's current namespace, the name always quoted.
|
|
508
|
+
* Throws a `PluginError` coded `statementFailed` for a path it cannot name.
|
|
509
|
+
*/
|
|
510
|
+
statement(path: readonly string[]): string;
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Whether a switch over `targets` can name `namespace`. Not by `Namespace.kind` alone: MySQL lists
|
|
514
|
+
* its databases as top-level schemas, so a `USE` picks a top-level namespace whatever its kind.
|
|
515
|
+
*/
|
|
516
|
+
export declare function switchableTo(targets: NamespaceSwitch["targets"], namespace: Namespace): boolean;
|
|
517
|
+
export declare const TRANSACTION_MODES: readonly ["auto", "manual"];
|
|
518
|
+
export type TransactionMode = (typeof TRANSACTION_MODES)[number];
|
|
519
|
+
/**
|
|
520
|
+
* Transaction control for one session (decision 011). In `manual` the plugin opens a transaction
|
|
521
|
+
* before the first statement; in `auto` it tracks the ones a statement opens or ends explicitly.
|
|
522
|
+
*/
|
|
523
|
+
export interface Transactions {
|
|
524
|
+
/** Rejects with `statementFailed` when leaving `manual` while a transaction is open: commit or roll back first. */
|
|
525
|
+
setMode(mode: TransactionMode): Promise<void>;
|
|
526
|
+
/** A no-op when no transaction is open. */
|
|
527
|
+
commit(): Promise<void>;
|
|
528
|
+
/** A no-op when no transaction is open. */
|
|
529
|
+
rollback(): Promise<void>;
|
|
530
|
+
readonly mode: TransactionMode;
|
|
531
|
+
/** Whether a transaction is open after the last statement, commit or rollback. */
|
|
532
|
+
readonly open: boolean;
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* The console language of a datasource that speaks commands, not SQL (decision 112): one command
|
|
536
|
+
* per line, as the server's own client reads them.
|
|
537
|
+
*/
|
|
538
|
+
export interface CommandLanguage {
|
|
539
|
+
/** Every command in `text`, in order; comments and blank lines belong to none. */
|
|
540
|
+
split(text: string): readonly StatementSpan[];
|
|
541
|
+
classify(command: string): StatementClass;
|
|
542
|
+
/**
|
|
543
|
+
* What fits at the caret. `session` is a connection the host keeps for such questions, null
|
|
544
|
+
* when it cannot open one; the plugin then completes from what it knows offline. Never rejects
|
|
545
|
+
* for text it cannot read.
|
|
546
|
+
*/
|
|
547
|
+
complete(request: CompletionRequest, session: Session | null): Promise<CompletionResult>;
|
|
548
|
+
/** The command the caret is in and the argument it is at, for the parameter hint (decision 098). */
|
|
549
|
+
signatureAt?(request: CompletionRequest, session: Session | null): Promise<SignatureHelp | null>;
|
|
550
|
+
/** Problems in `request.text` found without running it, such as a costly command, with quick fixes. */
|
|
551
|
+
inspect?(request: InspectionRequest): Promise<readonly Problem[]>;
|
|
552
|
+
}
|
|
553
|
+
/** The default export of a plugin's entry module (decision 005). */
|
|
554
|
+
export interface DatasourcePlugin {
|
|
555
|
+
readonly id: string;
|
|
556
|
+
readonly capabilities: readonly Capability[];
|
|
557
|
+
/** Present exactly when the plugin declares `sql`. */
|
|
558
|
+
readonly language?: SqlLanguage;
|
|
559
|
+
/** Present exactly when the plugin declares `commands` (decision 112). */
|
|
560
|
+
readonly commandLanguage?: CommandLanguage;
|
|
561
|
+
/** Validates the configuration `connect` receives; the host parses before it calls. */
|
|
562
|
+
readonly connectionSchema: z.ZodType;
|
|
563
|
+
/** Rejects with a `PluginError` coded `connectionFailed` when the database cannot be reached. */
|
|
564
|
+
connect(config: unknown, options: ConnectOptions): Promise<Session>;
|
|
565
|
+
}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a plugin can do. The UI branches on these, never on a plugin id (decision 007), and a
|
|
3
|
+
* capability without contract-suite coverage cannot be declared (decision 013).
|
|
4
|
+
*/
|
|
5
|
+
export const CAPABILITIES = [
|
|
6
|
+
"sql",
|
|
7
|
+
"cancel",
|
|
8
|
+
"schemaTree",
|
|
9
|
+
"transactions",
|
|
10
|
+
"ddl",
|
|
11
|
+
"explain",
|
|
12
|
+
"explainAnalyze",
|
|
13
|
+
"currentNamespace",
|
|
14
|
+
"keepAlive",
|
|
15
|
+
"bulkInsert",
|
|
16
|
+
"objects",
|
|
17
|
+
"serverMessages",
|
|
18
|
+
"sessions",
|
|
19
|
+
"routineCall",
|
|
20
|
+
"commands",
|
|
21
|
+
"keyValue",
|
|
22
|
+
"nodes",
|
|
23
|
+
"serverInfo",
|
|
24
|
+
];
|
|
25
|
+
/** Statements `SqlLanguage.generate` writes from a catalog relation (plan 010). */
|
|
26
|
+
export const GENERATED_STATEMENTS = ["drop", "select", "insert", "update"];
|
|
27
|
+
/** How serious a `ServerMessage` is, from the server's own word for it. */
|
|
28
|
+
export const SERVER_MESSAGE_LEVELS = ["error", "warning", "notice", "info"];
|
|
29
|
+
/** The most messages a plugin reports for one statement; past it, one more message says how many it left out. */
|
|
30
|
+
export const SERVER_MESSAGE_LIMIT = 100;
|
|
31
|
+
/** The message that stands for the ones past `SERVER_MESSAGE_LIMIT`. */
|
|
32
|
+
export function omittedMessages(count) {
|
|
33
|
+
return {
|
|
34
|
+
level: "info",
|
|
35
|
+
code: null,
|
|
36
|
+
text: `${String(count)} more server ${count === 1 ? "message is" : "messages are"} not shown.`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/** `ExecuteOptions.node`: the plugin routes the command by its keys (decision 114). */
|
|
40
|
+
export const NODE_AUTO = "auto";
|
|
41
|
+
/** `ExecuteOptions.node`: the command runs once on every primary (decision 114). */
|
|
42
|
+
export const NODE_ALL_PRIMARIES = "allPrimaries";
|
|
43
|
+
export const NODE_ROLES = ["primary", "replica"];
|
|
44
|
+
/** Kinds a file importer infers from a column's text, narrowest first within each family (plan 021). */
|
|
45
|
+
export const IMPORT_KINDS = ["boolean", "integer", "bigint", "decimal", "double", "date", "timestamp", "text"];
|
|
46
|
+
export const STATEMENT_KINDS = ["read", "write", "ddl", "transaction", "other"];
|
|
47
|
+
export const KEYWORD_CASES = ["upper", "lower", "preserve"];
|
|
48
|
+
/** `aligned` is the DataGrip-like layout (decision 061); `standard` is `sql-formatter`'s own (decision 042). */
|
|
49
|
+
export const FORMAT_STYLES = ["aligned", "standard"];
|
|
50
|
+
export const PARAMETER_STYLES = ["named", "numbered", "positional"];
|
|
51
|
+
/**
|
|
52
|
+
* Whether a switch over `targets` can name `namespace`. Not by `Namespace.kind` alone: MySQL lists
|
|
53
|
+
* its databases as top-level schemas, so a `USE` picks a top-level namespace whatever its kind.
|
|
54
|
+
*/
|
|
55
|
+
export function switchableTo(targets, namespace) {
|
|
56
|
+
return targets === "topLevel" ? namespace.path.length === 1 : namespace.kind === "schema";
|
|
57
|
+
}
|
|
58
|
+
export const TRANSACTION_MODES = ["auto", "manual"];
|