@adminiumjs/adapter-sqlite 0.1.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/dist/errors.d.ts +13 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +71 -0
- package/dist/errors.js.map +1 -0
- package/dist/file.d.ts +21 -0
- package/dist/file.d.ts.map +1 -0
- package/dist/file.js +48 -0
- package/dist/file.js.map +1 -0
- package/dist/index.d.ts +58 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +278 -0
- package/dist/index.js.map +1 -0
- package/dist/introspect.d.ts +74 -0
- package/dist/introspect.d.ts.map +1 -0
- package/dist/introspect.js +641 -0
- package/dist/introspect.js.map +1 -0
- package/dist/query-engine.d.ts +32 -0
- package/dist/query-engine.d.ts.map +1 -0
- package/dist/query-engine.js +82 -0
- package/dist/query-engine.js.map +1 -0
- package/dist/serialization.d.ts +35 -0
- package/dist/serialization.d.ts.map +1 -0
- package/dist/serialization.js +56 -0
- package/dist/serialization.js.map +1 -0
- package/dist/stats.d.ts +19 -0
- package/dist/stats.d.ts.map +1 -0
- package/dist/stats.js +124 -0
- package/dist/stats.js.map +1 -0
- package/dist/type-map.d.ts +47 -0
- package/dist/type-map.d.ts.map +1 -0
- package/dist/type-map.js +141 -0
- package/dist/type-map.js.map +1 -0
- package/package.json +30 -0
package/dist/errors.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Driver error → typed `AdapterError` mapping — 05-introspection-engine.md §3.
|
|
3
|
+
* better-sqlite3 errors carry a `code` like `SQLITE_CANTOPEN`; filesystem
|
|
4
|
+
* failures carry Node errnos (`ENOENT`, `EACCES`). The Studio wizard and the
|
|
5
|
+
* `diagnostics-readout` widget map `code` to remediation copy, so the
|
|
6
|
+
* mapping here is the whole UX for failure states. SQLite has no network,
|
|
7
|
+
* credentials, or TLS — `HOST_UNREACHABLE` doubles as "file not found /
|
|
8
|
+
* not openable" and `AUTH`/`TLS` never occur.
|
|
9
|
+
*/
|
|
10
|
+
import { AdapterError } from '@adminium/engine/adapter';
|
|
11
|
+
const UNREACHABLE_CODES = new Set([
|
|
12
|
+
'SQLITE_CANTOPEN',
|
|
13
|
+
'SQLITE_CANTOPEN_ISDIR',
|
|
14
|
+
'SQLITE_CANTOPEN_FULLPATH',
|
|
15
|
+
'SQLITE_NOTADB',
|
|
16
|
+
'ENOENT',
|
|
17
|
+
'ENOTDIR',
|
|
18
|
+
]);
|
|
19
|
+
const PERMISSION_CODES = new Set([
|
|
20
|
+
'SQLITE_READONLY',
|
|
21
|
+
'SQLITE_READONLY_DBMOVED',
|
|
22
|
+
'SQLITE_READONLY_CANTINIT',
|
|
23
|
+
'SQLITE_READONLY_DIRECTORY',
|
|
24
|
+
'SQLITE_AUTH',
|
|
25
|
+
'SQLITE_PERM',
|
|
26
|
+
'EACCES',
|
|
27
|
+
'EPERM',
|
|
28
|
+
]);
|
|
29
|
+
const TIMEOUT_CODES = new Set(['SQLITE_BUSY', 'SQLITE_BUSY_SNAPSHOT', 'SQLITE_LOCKED', 'SQLITE_PROTOCOL']);
|
|
30
|
+
const HINTS = {
|
|
31
|
+
HOST_UNREACHABLE: 'check the database file path — the file must exist and be a valid SQLite database',
|
|
32
|
+
PERMISSION: 'the process cannot write to the database file (or it was opened read-only) — check file permissions',
|
|
33
|
+
TIMEOUT: 'the database file is locked by another process; retry once the writer finishes',
|
|
34
|
+
};
|
|
35
|
+
const DRIFT_MESSAGE = /no such (table|column)/i;
|
|
36
|
+
function messageOf(error) {
|
|
37
|
+
return error instanceof Error ? error.message : String(error);
|
|
38
|
+
}
|
|
39
|
+
/** Coerce any driver/filesystem failure into the one allowed error type. */
|
|
40
|
+
export function toAdapterError(error, context) {
|
|
41
|
+
if (error instanceof AdapterError)
|
|
42
|
+
return error;
|
|
43
|
+
const message = messageOf(error);
|
|
44
|
+
const code = typeof error === 'object' && error !== null && 'code' in error
|
|
45
|
+
? String(error.code)
|
|
46
|
+
: '';
|
|
47
|
+
let mapped = 'UNKNOWN';
|
|
48
|
+
if (UNREACHABLE_CODES.has(code))
|
|
49
|
+
mapped = 'HOST_UNREACHABLE';
|
|
50
|
+
else if (PERMISSION_CODES.has(code))
|
|
51
|
+
mapped = 'PERMISSION';
|
|
52
|
+
else if (TIMEOUT_CODES.has(code))
|
|
53
|
+
mapped = 'TIMEOUT';
|
|
54
|
+
else if (code === 'SQLITE_ERROR' && DRIFT_MESSAGE.test(message))
|
|
55
|
+
mapped = 'SCHEMA_DRIFT';
|
|
56
|
+
else if (DRIFT_MESSAGE.test(message))
|
|
57
|
+
mapped = 'SCHEMA_DRIFT';
|
|
58
|
+
// better-sqlite3 throws plain TypeErrors for unopenable paths pre-driver.
|
|
59
|
+
else if (/(unable to open|not a database|does not exist)/i.test(message)) {
|
|
60
|
+
mapped = 'HOST_UNREACHABLE';
|
|
61
|
+
}
|
|
62
|
+
const options = {
|
|
63
|
+
detail: code.length > 0 ? `${code}: ${message}` : message,
|
|
64
|
+
cause: error,
|
|
65
|
+
};
|
|
66
|
+
const hint = HINTS[mapped];
|
|
67
|
+
if (hint !== undefined)
|
|
68
|
+
options.hint = hint;
|
|
69
|
+
return new AdapterError(mapped, `${context}: ${message}`, options);
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,YAAY,EAAyB,MAAM,0BAA0B,CAAC;AAE/E,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IAChC,iBAAiB;IACjB,uBAAuB;IACvB,0BAA0B;IAC1B,eAAe;IACf,QAAQ;IACR,SAAS;CACV,CAAC,CAAC;AACH,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IAC/B,iBAAiB;IACjB,yBAAyB;IACzB,0BAA0B;IAC1B,2BAA2B;IAC3B,aAAa;IACb,aAAa;IACb,QAAQ;IACR,OAAO;CACR,CAAC,CAAC;AACH,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,aAAa,EAAE,sBAAsB,EAAE,eAAe,EAAE,iBAAiB,CAAC,CAAC,CAAC;AAE3G,MAAM,KAAK,GAA8C;IACvD,gBAAgB,EACd,mFAAmF;IACrF,UAAU,EACR,qGAAqG;IACvG,OAAO,EAAE,gFAAgF;CAC1F,CAAC;AAEF,MAAM,aAAa,GAAG,yBAAyB,CAAC;AAEhD,SAAS,SAAS,CAAC,KAAc;IAC/B,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,cAAc,CAAC,KAAc,EAAE,OAAe;IAC5D,IAAI,KAAK,YAAY,YAAY;QAAE,OAAO,KAAK,CAAC;IAEhD,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IACjC,MAAM,IAAI,GACR,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK;QAC5D,CAAC,CAAC,MAAM,CAAE,KAA2B,CAAC,IAAI,CAAC;QAC3C,CAAC,CAAC,EAAE,CAAC;IAET,IAAI,MAAM,GAAqB,SAAS,CAAC;IACzC,IAAI,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,MAAM,GAAG,kBAAkB,CAAC;SACxD,IAAI,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,MAAM,GAAG,YAAY,CAAC;SACtD,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,MAAM,GAAG,SAAS,CAAC;SAChD,IAAI,IAAI,KAAK,cAAc,IAAI,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,MAAM,GAAG,cAAc,CAAC;SACpF,IAAI,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,MAAM,GAAG,cAAc,CAAC;IAC9D,0EAA0E;SACrE,IAAI,iDAAiD,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACzE,MAAM,GAAG,kBAAkB,CAAC;IAC9B,CAAC;IAED,MAAM,OAAO,GAAsD;QACjE,MAAM,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO;QACzD,KAAK,EAAE,KAAK;KACb,CAAC;IACF,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3B,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAC5C,OAAO,IAAI,YAAY,CAAC,MAAM,EAAE,GAAG,OAAO,KAAK,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;AACrE,CAAC"}
|
package/dist/file.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connection-config → database file path normalization — 05 §4.3: the SQLite
|
|
3
|
+
* connection config is a FILE PATH, not a DSN, but the engine accepts the
|
|
4
|
+
* common DSN spellings and normalizes them here:
|
|
5
|
+
*
|
|
6
|
+
* { file: '/abs/path/app.db' } → '/abs/path/app.db'
|
|
7
|
+
* { file: ':memory:' } → ':memory:' (demo/test)
|
|
8
|
+
* 'sqlite:///abs/path.db' → '/abs/path.db'
|
|
9
|
+
* 'sqlite::memory:' → ':memory:'
|
|
10
|
+
* 'file:abs/path.db' / 'file:///…' → 'abs/path.db' / '/…'
|
|
11
|
+
* plain path → unchanged
|
|
12
|
+
*
|
|
13
|
+
* Pure module so the spellings are unit-testable offline.
|
|
14
|
+
*/
|
|
15
|
+
export interface SqliteFileConfig {
|
|
16
|
+
readonly file?: string;
|
|
17
|
+
readonly dsn?: string;
|
|
18
|
+
}
|
|
19
|
+
/** Resolve the database file path from a role-branded config. */
|
|
20
|
+
export declare function normalizeSqliteFile(config: SqliteFileConfig): string | null;
|
|
21
|
+
//# sourceMappingURL=file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../src/file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,iEAAiE;AACjE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,GAAG,IAAI,CA2B3E"}
|
package/dist/file.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connection-config → database file path normalization — 05 §4.3: the SQLite
|
|
3
|
+
* connection config is a FILE PATH, not a DSN, but the engine accepts the
|
|
4
|
+
* common DSN spellings and normalizes them here:
|
|
5
|
+
*
|
|
6
|
+
* { file: '/abs/path/app.db' } → '/abs/path/app.db'
|
|
7
|
+
* { file: ':memory:' } → ':memory:' (demo/test)
|
|
8
|
+
* 'sqlite:///abs/path.db' → '/abs/path.db'
|
|
9
|
+
* 'sqlite::memory:' → ':memory:'
|
|
10
|
+
* 'file:abs/path.db' / 'file:///…' → 'abs/path.db' / '/…'
|
|
11
|
+
* plain path → unchanged
|
|
12
|
+
*
|
|
13
|
+
* Pure module so the spellings are unit-testable offline.
|
|
14
|
+
*/
|
|
15
|
+
/** Resolve the database file path from a role-branded config. */
|
|
16
|
+
export function normalizeSqliteFile(config) {
|
|
17
|
+
const raw = config.file ?? config.dsn;
|
|
18
|
+
if (raw === undefined || raw.length === 0)
|
|
19
|
+
return null;
|
|
20
|
+
let text = raw.trim();
|
|
21
|
+
if (text === ':memory:')
|
|
22
|
+
return ':memory:';
|
|
23
|
+
if (text.toLowerCase().startsWith('sqlite:')) {
|
|
24
|
+
text = text.slice('sqlite:'.length);
|
|
25
|
+
if (text === ':memory:' || text === '')
|
|
26
|
+
return ':memory:';
|
|
27
|
+
// sqlite:///abs/path.db → ///abs/path.db → /abs/path.db
|
|
28
|
+
if (text.startsWith('///'))
|
|
29
|
+
return text.slice(2);
|
|
30
|
+
if (text.startsWith('//'))
|
|
31
|
+
return text.slice(2);
|
|
32
|
+
return text;
|
|
33
|
+
}
|
|
34
|
+
if (text.toLowerCase().startsWith('file:')) {
|
|
35
|
+
text = text.slice('file:'.length);
|
|
36
|
+
// file:///abs/path.db → /abs/path.db; strip query params (?mode=…)
|
|
37
|
+
const query = text.indexOf('?');
|
|
38
|
+
if (query !== -1)
|
|
39
|
+
text = text.slice(0, query);
|
|
40
|
+
if (text.startsWith('///'))
|
|
41
|
+
return text.slice(2);
|
|
42
|
+
if (text.startsWith('//'))
|
|
43
|
+
return text.slice(2);
|
|
44
|
+
return text;
|
|
45
|
+
}
|
|
46
|
+
return text;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=file.js.map
|
package/dist/file.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file.js","sourceRoot":"","sources":["../src/file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAOH,iEAAiE;AACjE,MAAM,UAAU,mBAAmB,CAAC,MAAwB;IAC1D,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,GAAG,CAAC;IACtC,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACvD,IAAI,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAEtB,IAAI,IAAI,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IAE3C,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7C,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACpC,IAAI,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,EAAE;YAAE,OAAO,UAAU,CAAC;QAC1D,wDAAwD;QACxD,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjD,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAChD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3C,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAClC,mEAAmE;QACnE,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,KAAK,KAAK,CAAC,CAAC;YAAE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QAC9C,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjD,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAChD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type AdapterProvider, type AdapterRegistry, type CapabilityProbeResult, type CollectStatsOptions, type ColumnSampleOptions, type ConnectionConfig, type ConnectionRole, type DatabaseAdapter, type DatabaseModel, type Dialect, type FilterSpec, type IntrospectOptions, type MutationResult, type MutationSpec, type QueryResult, type QuerySpec, type Row, type SampleOptions, type StatsResult, type TableRef, type TestResult } from '@adminium/engine/adapter';
|
|
2
|
+
export declare class SqliteAdapter<Role extends ConnectionRole = ConnectionRole> implements DatabaseAdapter<Role> {
|
|
3
|
+
#private;
|
|
4
|
+
readonly dialect: Dialect;
|
|
5
|
+
readonly capabilities: {
|
|
6
|
+
hasEnums: boolean;
|
|
7
|
+
hasFKs: boolean;
|
|
8
|
+
hasSchemas: boolean;
|
|
9
|
+
hasComments: boolean;
|
|
10
|
+
hasChecks: boolean;
|
|
11
|
+
hasRLS: boolean;
|
|
12
|
+
hasMaterializedViews: boolean;
|
|
13
|
+
hasRowEstimates: boolean;
|
|
14
|
+
supportsStatementTimeout: boolean;
|
|
15
|
+
supportsReturning: boolean;
|
|
16
|
+
maxIdentifierLength: number;
|
|
17
|
+
};
|
|
18
|
+
readonly role: Role;
|
|
19
|
+
constructor(role: Role);
|
|
20
|
+
/** Lazy handle — the file is not opened until the first statement. */
|
|
21
|
+
connect(config: ConnectionConfig<Role>): Promise<void>;
|
|
22
|
+
test(): Promise<TestResult>;
|
|
23
|
+
/** Runs on every connect/test; results persist on the connection row. */
|
|
24
|
+
probeCapabilities(): Promise<CapabilityProbeResult>;
|
|
25
|
+
/** SCHEMA ONLY — pragma/sqlite_master (+ §4.3 small-file COUNT exception). */
|
|
26
|
+
introspect(this: DatabaseAdapter<'introspect'>, opts?: IntrospectOptions): Promise<DatabaseModel>;
|
|
27
|
+
count(this: DatabaseAdapter<'data'>, _table: TableRef, _filter?: FilterSpec, _opts?: {
|
|
28
|
+
cap?: number;
|
|
29
|
+
}): Promise<{
|
|
30
|
+
value: number;
|
|
31
|
+
capped: boolean;
|
|
32
|
+
}>;
|
|
33
|
+
sample(this: DatabaseAdapter<'data'>, _table: TableRef, _opts: SampleOptions): Promise<Row[]>;
|
|
34
|
+
sampleColumn(this: DatabaseAdapter<'data'>, _table: TableRef, _column: string, _opts: ColumnSampleOptions): Promise<unknown[]>;
|
|
35
|
+
query(this: DatabaseAdapter<'data'>, _spec: QuerySpec): Promise<QueryResult>;
|
|
36
|
+
mutate(this: DatabaseAdapter<'data'>, _spec: MutationSpec): Promise<MutationResult>;
|
|
37
|
+
/** Aggregate statistics for LLM enrichment (06 §4.2); sample-free by default. */
|
|
38
|
+
collectTableStats(this: DatabaseAdapter<'data'>, table: TableRef, opts?: CollectStatsOptions): Promise<StatsResult>;
|
|
39
|
+
/** Close the handle; idempotent. */
|
|
40
|
+
close(): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
/** What the server registers at boot (01-architecture.md §2.3.1). */
|
|
43
|
+
export declare const sqliteAdapter: AdapterProvider;
|
|
44
|
+
/**
|
|
45
|
+
* Boot registration helper — `@adminium/server` calls `register()` once at
|
|
46
|
+
* startup; tests may pass their own registry instance.
|
|
47
|
+
*/
|
|
48
|
+
export declare function register(registry?: AdapterRegistry<AdapterProvider>): void;
|
|
49
|
+
export { applyDataPragmas, createQueryEngine, type InjectableDatabase, type SqliteQueryEngineOptions, } from './query-engine.js';
|
|
50
|
+
export { normalizeSqliteFile, type SqliteFileConfig } from './file.js';
|
|
51
|
+
export { collectSqliteStats, type StatsExecutor } from './stats.js';
|
|
52
|
+
export { COLUMNS_SQL, EXACT_COUNT_MAX_FILE_BYTES, exactCountsSql, FOREIGN_KEYS_SQL, INDEX_COLUMNS_SQL, INDEX_LIST_SQL, introspectSqlite, MASTER_SQL, parseCheckEnum, scanCheckConstraints, SQLITE_CAPABILITIES, STAT1_SQL, TABLE_LIST_SQL, type CatalogExecutor, type CatalogRow, type IntrospectContext, } from './introspect.js';
|
|
53
|
+
export { classifyDefault, mapSqliteType, sqliteAffinity, type MappedType, type SqliteAffinity, } from './type-map.js';
|
|
54
|
+
export { SQLITE_MAX_IDENTIFIER_LENGTH, quoteIdentifier, sqliteSerializers, } from './serialization.js';
|
|
55
|
+
export { toAdapterError } from './errors.js';
|
|
56
|
+
/** @deprecated M0 scaffold export; kept so early imports keep compiling. */
|
|
57
|
+
export declare const PACKAGE_NAME = "@adminium/adapter-sqlite";
|
|
58
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adminium/adapter-sqlite — the `better-sqlite3` implementation of the
|
|
3
|
+
* `DatabaseAdapter` contract (05-introspection-engine.md §3/§4.3, M9/05-T14).
|
|
4
|
+
*
|
|
5
|
+
* Mirrors the postgres reference adapter: connect/test/probeCapabilities,
|
|
6
|
+
* `introspect()` (schema only — pragma/sqlite_master, plus the documented
|
|
7
|
+
* §4.3 small-file COUNT exception), the Kysely query-engine factory with
|
|
8
|
+
* better-sqlite3 instance injection, and the boot registration helper. The
|
|
9
|
+
* data-role methods (`query`/`mutate`/`sample`/`count`) follow the same
|
|
10
|
+
* 05-T05 pattern and currently reject with a typed `UNSUPPORTED` error after
|
|
11
|
+
* their role guard runs — CRUD goes through `createQueryEngine()`.
|
|
12
|
+
*
|
|
13
|
+
* The connection config is a FILE PATH (`{ file }`, `:memory:` allowed) —
|
|
14
|
+
* this is the Electron/offline engine (11-electron.md). The introspect
|
|
15
|
+
* instance opens `{ readonly: true, fileMustExist: true }`; the data
|
|
16
|
+
* instance opens read-write with WAL/foreign_keys/busy_timeout pragmas.
|
|
17
|
+
*
|
|
18
|
+
* NOTE (05 §4.3): the worker-thread pool that keeps the synchronous driver
|
|
19
|
+
* off the Fastify event loop is an integration follow-up — the adapter
|
|
20
|
+
* facade is already Promise-based, so the pool slots in behind `#exec`
|
|
21
|
+
* without any contract change.
|
|
22
|
+
*/
|
|
23
|
+
import { accessSync, constants, statSync } from 'node:fs';
|
|
24
|
+
import { basename } from 'node:path';
|
|
25
|
+
import Database from 'better-sqlite3';
|
|
26
|
+
import { AdapterError, adapterRegistry, registerAdapter, } from '@adminium/engine/adapter';
|
|
27
|
+
import { toAdapterError } from './errors.js';
|
|
28
|
+
import { normalizeSqliteFile } from './file.js';
|
|
29
|
+
import { introspectSqlite, SQLITE_CAPABILITIES, } from './introspect.js';
|
|
30
|
+
import { applyDataPragmas, createQueryEngine } from './query-engine.js';
|
|
31
|
+
import { collectSqliteStats } from './stats.js';
|
|
32
|
+
export class SqliteAdapter {
|
|
33
|
+
dialect = 'sqlite';
|
|
34
|
+
capabilities = { ...SQLITE_CAPABILITIES };
|
|
35
|
+
role;
|
|
36
|
+
#file = null;
|
|
37
|
+
/** How this role's handle is actually opened (introspect is forced readonly). */
|
|
38
|
+
#mode = 'readwrite';
|
|
39
|
+
/** What the config asked for — the read-only DETECTION signal (see connect). */
|
|
40
|
+
#requestedMode = 'readwrite';
|
|
41
|
+
#db = null;
|
|
42
|
+
#closed = false;
|
|
43
|
+
constructor(role) {
|
|
44
|
+
this.role = role;
|
|
45
|
+
}
|
|
46
|
+
/** Lazy handle — the file is not opened until the first statement. */
|
|
47
|
+
async connect(config) {
|
|
48
|
+
if (config.role !== this.role) {
|
|
49
|
+
throw new AdapterError('PERMISSION', `connection config is branded "${config.role}" but this adapter instance is "${this.role}"`, { hint: 'the three logical connections are never interchangeable (01-architecture.md §3)' });
|
|
50
|
+
}
|
|
51
|
+
const file = normalizeSqliteFile(config);
|
|
52
|
+
if (file === null) {
|
|
53
|
+
throw new AdapterError('UNKNOWN', 'sqlite connections require a file path', {
|
|
54
|
+
hint: "pass { file: '/abs/path.db' } (or ':memory:' for demo/test)",
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
this.#file = file;
|
|
58
|
+
// The introspect handle ALWAYS opens readonly (05 §4.3) — a safety measure
|
|
59
|
+
// so introspection can never write, NOT a statement about whether the
|
|
60
|
+
// underlying database is writable. Keep the config-requested mode separately
|
|
61
|
+
// so read-only DETECTION reflects the CONNECTION, not the forced open mode:
|
|
62
|
+
// otherwise every introspect probe would report the whole connection
|
|
63
|
+
// read-only and block all CRUD (the data role opens readwrite).
|
|
64
|
+
this.#requestedMode = config.mode ?? 'readwrite';
|
|
65
|
+
this.#mode = this.role === 'introspect' ? 'readonly' : this.#requestedMode;
|
|
66
|
+
this.#closed = false;
|
|
67
|
+
}
|
|
68
|
+
#requireDb() {
|
|
69
|
+
if (this.#closed || this.#file === null) {
|
|
70
|
+
throw new AdapterError('UNKNOWN', 'adapter is not connected — call connect() first');
|
|
71
|
+
}
|
|
72
|
+
if (this.#db !== null)
|
|
73
|
+
return this.#db;
|
|
74
|
+
const file = this.#file;
|
|
75
|
+
try {
|
|
76
|
+
if (this.#mode === 'readonly' && file !== ':memory:') {
|
|
77
|
+
this.#db = new Database(file, { readonly: true, fileMustExist: true });
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
this.#db = new Database(file, { fileMustExist: file !== ':memory:' });
|
|
81
|
+
if (this.role === 'data')
|
|
82
|
+
applyDataPragmas(this.#db, file);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
throw toAdapterError(error, 'sqlite open failed');
|
|
87
|
+
}
|
|
88
|
+
return this.#db;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The Promise-based executor facade over the synchronous driver — the
|
|
92
|
+
* 05 §4.3 worker pool slots in behind this method without contract change.
|
|
93
|
+
*/
|
|
94
|
+
async #exec(sql) {
|
|
95
|
+
const db = this.#requireDb();
|
|
96
|
+
try {
|
|
97
|
+
return db.prepare(sql).all();
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
throw toAdapterError(error, 'sqlite query failed');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Read-only detection — 05 §4.3. Reflects whether the CONNECTION (the
|
|
105
|
+
* underlying database file) is writable, NOT how this role opened its handle:
|
|
106
|
+
* the introspect handle always opens readonly for safety, yet the connection
|
|
107
|
+
* may be fully writable via the data role. Genuine read-only signals are an
|
|
108
|
+
* explicit `mode: 'readonly'` config, a file the process cannot write
|
|
109
|
+
* (`W_OK`), or `PRAGMA query_only = 1`.
|
|
110
|
+
*/
|
|
111
|
+
#detectReadOnly() {
|
|
112
|
+
if (this.#requestedMode === 'readonly')
|
|
113
|
+
return true;
|
|
114
|
+
const file = this.#file;
|
|
115
|
+
if (file !== null && file !== ':memory:') {
|
|
116
|
+
try {
|
|
117
|
+
accessSync(file, constants.W_OK);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
const queryOnly = this.#requireDb().pragma('query_only', { simple: true });
|
|
125
|
+
if (queryOnly === 1 || queryOnly === '1')
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// pragma failure never blocks detection
|
|
130
|
+
}
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
#serverVersion() {
|
|
134
|
+
const row = this.#requireDb()
|
|
135
|
+
.prepare('SELECT sqlite_version() AS version')
|
|
136
|
+
.get();
|
|
137
|
+
return String(row?.version ?? '');
|
|
138
|
+
}
|
|
139
|
+
async test() {
|
|
140
|
+
const startedAt = Date.now();
|
|
141
|
+
try {
|
|
142
|
+
const version = this.#serverVersion();
|
|
143
|
+
return {
|
|
144
|
+
ok: true,
|
|
145
|
+
latencyMs: Date.now() - startedAt,
|
|
146
|
+
serverVersion: version,
|
|
147
|
+
currentUser: null, // SQLite has no users
|
|
148
|
+
canWrite: !this.#detectReadOnly(),
|
|
149
|
+
ssl: false, // local file — no transport
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
return {
|
|
154
|
+
ok: false,
|
|
155
|
+
latencyMs: Date.now() - startedAt,
|
|
156
|
+
serverVersion: null,
|
|
157
|
+
currentUser: null,
|
|
158
|
+
canWrite: false,
|
|
159
|
+
ssl: false,
|
|
160
|
+
error: toAdapterError(error, 'connection test failed'),
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/** Runs on every connect/test; results persist on the connection row. */
|
|
165
|
+
async probeCapabilities() {
|
|
166
|
+
const version = this.#serverVersion();
|
|
167
|
+
const readOnly = this.#detectReadOnly();
|
|
168
|
+
return {
|
|
169
|
+
capabilities: { ...SQLITE_CAPABILITIES },
|
|
170
|
+
privileges: {
|
|
171
|
+
canReadSchema: true,
|
|
172
|
+
canRead: true,
|
|
173
|
+
canWrite: !readOnly,
|
|
174
|
+
canDDL: !readOnly,
|
|
175
|
+
},
|
|
176
|
+
serverVersion: version,
|
|
177
|
+
currentRole: { name: 'local', readOnly },
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/** SCHEMA ONLY — pragma/sqlite_master (+ §4.3 small-file COUNT exception). */
|
|
181
|
+
async introspect(opts) {
|
|
182
|
+
const self = this;
|
|
183
|
+
// Runtime guard behind the compile-time role brand (05 §3).
|
|
184
|
+
if (self.role !== 'introspect') {
|
|
185
|
+
throw new AdapterError('PERMISSION', 'introspect() is only available on the introspect-role instance');
|
|
186
|
+
}
|
|
187
|
+
const file = self.#file ?? ':memory:';
|
|
188
|
+
let fileSizeBytes = null;
|
|
189
|
+
if (file === ':memory:') {
|
|
190
|
+
fileSizeBytes = 0; // in-memory databases always qualify for exact counts
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
try {
|
|
194
|
+
fileSizeBytes = statSync(file).size;
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
fileSizeBytes = null;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const databaseName = file === ':memory:' ? 'memory' : basename(file).replace(/\.[^.]+$/, '');
|
|
201
|
+
return introspectSqlite(async (sql) => self.#exec(sql), { connectionId: databaseName, databaseName, fileSizeBytes }, opts);
|
|
202
|
+
}
|
|
203
|
+
#guardDataRole(method) {
|
|
204
|
+
if (this.role !== 'data') {
|
|
205
|
+
throw new AdapterError('PERMISSION', `${method}() is only available on the data-role instance`, { hint: 'row-touching methods never run on the introspect connection (05 §10)' });
|
|
206
|
+
}
|
|
207
|
+
throw new AdapterError('UNSUPPORTED', `${method}() lands with 05-T05 (dynamic Kysely CRUD)`, {
|
|
208
|
+
hint: 'use createQueryEngine() for the CRUD query port in the meantime',
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
/* eslint-disable @typescript-eslint/no-unused-vars -- 05-T05 stubs: the
|
|
212
|
+
parameter lists must match the DatabaseAdapter contract exactly. */
|
|
213
|
+
async count(_table, _filter, _opts) {
|
|
214
|
+
return this.#guardDataRole('count');
|
|
215
|
+
}
|
|
216
|
+
async sample(_table, _opts) {
|
|
217
|
+
return this.#guardDataRole('sample');
|
|
218
|
+
}
|
|
219
|
+
async sampleColumn(_table, _column, _opts) {
|
|
220
|
+
return this.#guardDataRole('sampleColumn');
|
|
221
|
+
}
|
|
222
|
+
async query(_spec) {
|
|
223
|
+
return this.#guardDataRole('query');
|
|
224
|
+
}
|
|
225
|
+
async mutate(_spec) {
|
|
226
|
+
return this.#guardDataRole('mutate');
|
|
227
|
+
}
|
|
228
|
+
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
229
|
+
/** Aggregate statistics for LLM enrichment (06 §4.2); sample-free by default. */
|
|
230
|
+
async collectTableStats(table, opts) {
|
|
231
|
+
const self = this;
|
|
232
|
+
if (self.role !== 'data') {
|
|
233
|
+
throw new AdapterError('PERMISSION', 'collectTableStats() is only available on the data-role instance', { hint: 'statistics touch user rows and never run on the introspect connection (05 §10)' });
|
|
234
|
+
}
|
|
235
|
+
return collectSqliteStats((sql) => self.#exec(sql), table, opts);
|
|
236
|
+
}
|
|
237
|
+
/** Close the handle; idempotent. */
|
|
238
|
+
async close() {
|
|
239
|
+
if (this.#closed)
|
|
240
|
+
return;
|
|
241
|
+
this.#closed = true;
|
|
242
|
+
const db = this.#db;
|
|
243
|
+
this.#db = null;
|
|
244
|
+
if (db !== null)
|
|
245
|
+
db.close();
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/** What the server registers at boot (01-architecture.md §2.3.1). */
|
|
249
|
+
export const sqliteAdapter = {
|
|
250
|
+
dialect: 'sqlite',
|
|
251
|
+
async create(config) {
|
|
252
|
+
const adapter = new SqliteAdapter(config.role);
|
|
253
|
+
await adapter.connect(config);
|
|
254
|
+
return adapter;
|
|
255
|
+
},
|
|
256
|
+
createQueryEngine,
|
|
257
|
+
};
|
|
258
|
+
/**
|
|
259
|
+
* Boot registration helper — `@adminium/server` calls `register()` once at
|
|
260
|
+
* startup; tests may pass their own registry instance.
|
|
261
|
+
*/
|
|
262
|
+
export function register(registry = adapterRegistry) {
|
|
263
|
+
if (registry === adapterRegistry) {
|
|
264
|
+
registerAdapter(sqliteAdapter);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
registry.register(sqliteAdapter);
|
|
268
|
+
}
|
|
269
|
+
export { applyDataPragmas, createQueryEngine, } from './query-engine.js';
|
|
270
|
+
export { normalizeSqliteFile } from './file.js';
|
|
271
|
+
export { collectSqliteStats } from './stats.js';
|
|
272
|
+
export { COLUMNS_SQL, EXACT_COUNT_MAX_FILE_BYTES, exactCountsSql, FOREIGN_KEYS_SQL, INDEX_COLUMNS_SQL, INDEX_LIST_SQL, introspectSqlite, MASTER_SQL, parseCheckEnum, scanCheckConstraints, SQLITE_CAPABILITIES, STAT1_SQL, TABLE_LIST_SQL, } from './introspect.js';
|
|
273
|
+
export { classifyDefault, mapSqliteType, sqliteAffinity, } from './type-map.js';
|
|
274
|
+
export { SQLITE_MAX_IDENTIFIER_LENGTH, quoteIdentifier, sqliteSerializers, } from './serialization.js';
|
|
275
|
+
export { toAdapterError } from './errors.js';
|
|
276
|
+
/** @deprecated M0 scaffold export; kept so early imports keep compiling. */
|
|
277
|
+
export const PACKAGE_NAME = '@adminium/adapter-sqlite';
|
|
278
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite introspection — 05-introspection-engine.md §4.3.
|
|
3
|
+
*
|
|
4
|
+
* Reads pragma table-valued functions joined against `sqlite_master`, so the
|
|
5
|
+
* statement set stays FIXED regardless of table count (the per-table pragma
|
|
6
|
+
* loop happens inside SQLite, not over the executor). This module is
|
|
7
|
+
* executor-agnostic — `introspectSqlite` takes a `CatalogExecutor` (any
|
|
8
|
+
* `sql → rows` function) so the assembly logic is testable without the
|
|
9
|
+
* `better-sqlite3` driver; `src/index.ts` wires it to the database handle.
|
|
10
|
+
* Mirrors the postgres reference adapter file for file.
|
|
11
|
+
*
|
|
12
|
+
* THE "SCHEMA ONLY" INVARIANT (05 §10): every statement here references
|
|
13
|
+
* `sqlite_master` / `pragma_*` / `sqlite_stat1` exclusively — with the one
|
|
14
|
+
* documented exception of §4.3: exact `COUNT(*)` per table on files
|
|
15
|
+
* < 100 MB, which touches no column values.
|
|
16
|
+
*/
|
|
17
|
+
import { type AdapterCapabilities, type DatabaseModel, type IntrospectOptions } from '@adminium/engine/adapter';
|
|
18
|
+
export type CatalogRow = Record<string, unknown>;
|
|
19
|
+
/** Any `sql → rows` runner (better-sqlite3 in production, canned rows in tests). */
|
|
20
|
+
export type CatalogExecutor = (sql: string) => Promise<CatalogRow[]>;
|
|
21
|
+
export interface IntrospectContext {
|
|
22
|
+
/** `adminium_connections` row id; falls back to the file stem. */
|
|
23
|
+
connectionId: string;
|
|
24
|
+
/** File stem (or 'memory') — becomes `model.name`; the schema is 'main'. */
|
|
25
|
+
databaseName: string;
|
|
26
|
+
/** Database file size; null = unknown. Gates the exact-count exception. */
|
|
27
|
+
fileSizeBytes: number | null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Static dialect capabilities — 05 §2.1/§4.3 (probe refines per-connection).
|
|
31
|
+
* Canonical values live in the engine's capability matrix (M9-T04) so the
|
|
32
|
+
* wizard's degradation copy and the adapter never disagree.
|
|
33
|
+
*/
|
|
34
|
+
export declare const SQLITE_CAPABILITIES: AdapterCapabilities;
|
|
35
|
+
/** §4.3: exact per-table `COUNT(*)` only when the file is under 100 MB. */
|
|
36
|
+
export declare const EXACT_COUNT_MAX_FILE_BYTES: number;
|
|
37
|
+
/** SQLite ≥ 3.37 — guarded with a sqlite_master fallback (05 §4.3). */
|
|
38
|
+
export declare const TABLE_LIST_SQL = "\nSELECT name, type, wr, strict\nFROM pragma_table_list\nWHERE schema = 'main' AND name NOT LIKE 'sqlite_%'\nORDER BY name";
|
|
39
|
+
/** DDL source — CHECK extraction, AUTOINCREMENT, WITHOUT ROWID fallback. */
|
|
40
|
+
export declare const MASTER_SQL = "\nSELECT name, type, sql\nFROM sqlite_master\nWHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%'\nORDER BY name";
|
|
41
|
+
/** table_xinfo includes hidden/generated columns (05 §4.3). */
|
|
42
|
+
export declare const COLUMNS_SQL = "\nSELECT m.name AS table_name,\n ti.cid AS ordinal,\n ti.name AS column_name,\n ti.type AS declared_type,\n ti.\"notnull\" AS not_null,\n ti.dflt_value AS default_text,\n ti.pk AS pk_ordinal,\n ti.hidden AS hidden\nFROM sqlite_master m\nJOIN pragma_table_xinfo(m.name) ti\nWHERE m.type IN ('table', 'view') AND m.name NOT LIKE 'sqlite_%'\nORDER BY m.name, ti.cid";
|
|
43
|
+
export declare const FOREIGN_KEYS_SQL = "\nSELECT m.name AS table_name,\n fk.id AS fk_id,\n fk.seq AS seq,\n fk.\"table\" AS ref_table,\n fk.\"from\" AS from_column,\n fk.\"to\" AS to_column,\n fk.on_update AS on_update,\n fk.on_delete AS on_delete\nFROM sqlite_master m\nJOIN pragma_foreign_key_list(m.name) fk\nWHERE m.type = 'table' AND m.name NOT LIKE 'sqlite_%'\nORDER BY m.name, fk.id, fk.seq";
|
|
44
|
+
export declare const INDEX_LIST_SQL = "\nSELECT m.name AS table_name,\n il.name AS index_name,\n il.\"unique\" AS is_unique,\n il.origin AS origin,\n il.partial AS partial\nFROM sqlite_master m\nJOIN pragma_index_list(m.name) il\nWHERE m.type = 'table' AND m.name NOT LIKE 'sqlite_%'\nORDER BY m.name, il.name";
|
|
45
|
+
export declare const INDEX_COLUMNS_SQL = "\nSELECT m.name AS table_name,\n il.name AS index_name,\n ii.seqno AS seqno,\n ii.name AS column_name\nFROM sqlite_master m\nJOIN pragma_index_list(m.name) il\nJOIN pragma_index_info(il.name) ii\nWHERE m.type = 'table' AND m.name NOT LIKE 'sqlite_%'\nORDER BY m.name, il.name, ii.seqno";
|
|
46
|
+
/** Guarded: only present after ANALYZE has run (05 §4.3). */
|
|
47
|
+
export declare const STAT1_SQL = "\nSELECT tbl AS table_name, idx AS index_name, stat AS stat\nFROM sqlite_stat1";
|
|
48
|
+
/**
|
|
49
|
+
* One UNION ALL statement counting every included table — the §4.3 small-file
|
|
50
|
+
* exception. COUNT(*) touches no column values; `rowCountExact: true`.
|
|
51
|
+
*/
|
|
52
|
+
export declare function exactCountsSql(tableNames: readonly string[]): string;
|
|
53
|
+
/**
|
|
54
|
+
* Scan a CREATE TABLE statement for CHECK constraints (column-level and
|
|
55
|
+
* table-level), respecting strings/quoted identifiers. Returns the balanced
|
|
56
|
+
* inner expression of each `CHECK (…)` plus the `CONSTRAINT <name>` when
|
|
57
|
+
* present.
|
|
58
|
+
*/
|
|
59
|
+
export declare function scanCheckConstraints(ddl: string): {
|
|
60
|
+
name: string | null;
|
|
61
|
+
expression: string;
|
|
62
|
+
}[];
|
|
63
|
+
/** Parse a `col IN ('a','b')` check shape into a synthesized enum (05 §4.3). */
|
|
64
|
+
export declare function parseCheckEnum(expression: string): {
|
|
65
|
+
column: string;
|
|
66
|
+
values: string[];
|
|
67
|
+
} | null;
|
|
68
|
+
/**
|
|
69
|
+
* Run the fixed catalog query set through `exec` and assemble the
|
|
70
|
+
* `DatabaseModel`. Schema only — never touches user rows (except the §4.3
|
|
71
|
+
* small-file COUNT exception, which reads no column values).
|
|
72
|
+
*/
|
|
73
|
+
export declare function introspectSqlite(exec: CatalogExecutor, ctx: IntrospectContext, opts?: IntrospectOptions): Promise<DatabaseModel>;
|
|
74
|
+
//# sourceMappingURL=introspect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"introspect.d.ts","sourceRoot":"","sources":["../src/introspect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAGL,KAAK,mBAAmB,EAExB,KAAK,aAAa,EAGlB,KAAK,iBAAiB,EAIvB,MAAM,0BAA0B,CAAC;AASlC,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEjD,oFAAoF;AACpF,MAAM,MAAM,eAAe,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;AAErE,MAAM,WAAW,iBAAiB;IAChC,kEAAkE;IAClE,YAAY,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,YAAY,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,mBAEjC,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,0BAA0B,QAAoB,CAAC;AAa5D,uEAAuE;AACvE,eAAO,MAAM,cAAc,+HAIb,CAAC;AAEf,4EAA4E;AAC5E,eAAO,MAAM,UAAU,8HAIT,CAAC;AAEf,+DAA+D;AAC/D,eAAO,MAAM,WAAW,yZAYA,CAAC;AAEzB,eAAO,MAAM,gBAAgB,oZAYE,CAAC;AAEhC,eAAO,MAAM,cAAc,2SASF,CAAC;AAE1B,eAAO,MAAM,iBAAiB,oTASK,CAAC;AAEpC,6DAA6D;AAC7D,eAAO,MAAM,SAAS,mFAEJ,CAAC;AAMnB;;;GAGG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAOpE;AA0CD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,GACV;IAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,EAAE,CA4D/C;AAID,gFAAgF;AAChF,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,GACjB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAQ7C;AAoCD;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,eAAe,EACrB,GAAG,EAAE,iBAAiB,EACtB,IAAI,GAAE,iBAAsB,GAC3B,OAAO,CAAC,aAAa,CAAC,CAmYxB"}
|