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