@fougere/adapter-duckdb 0.2.0-alpha.2
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/dist/index.d.ts +84 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +155 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Fougere contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read across an app's sources — one SQL query over what can be attached.
|
|
3
|
+
*
|
|
4
|
+
* The by-key path (`findByKeys` and its dual) ENRICHES a page: it answers "I hold
|
|
5
|
+
* these rows, give me the related ones". It cannot SELECT one — filtering, sorting,
|
|
6
|
+
* paginating or counting on the other side collapses into reading that side whole.
|
|
7
|
+
* That is the hole this closes, and it is not a reporting nicety: "my loans, newest
|
|
8
|
+
* book first" crosses.
|
|
9
|
+
*
|
|
10
|
+
* What it is NOT is a query builder. A cross-source builder would be a Calcite in
|
|
11
|
+
* TypeScript, and it would promise a composability the sources have not got. The query
|
|
12
|
+
* stays SQL; what Fougere contributes is the three derivations a hand-written one would
|
|
13
|
+
* duplicate — where each entity lives, what its table and columns are called, and the
|
|
14
|
+
* shape of the answer.
|
|
15
|
+
*
|
|
16
|
+
* Measured before writing any of it (2026-08-15):
|
|
17
|
+
*
|
|
18
|
+
* - attaching Postgres pushes the filter down — `Filters: lang='fr'` reaches it over
|
|
19
|
+
* 100 000 rows, so a real database is queried where it is and never copied;
|
|
20
|
+
* - at PAGE size DuckDB is ~100× slower than two indexed reads (7 ms of floor per
|
|
21
|
+
* query), so this must never sit on the ordinary read path;
|
|
22
|
+
* - SQL Server cannot be attached at all — no `sqlserver` extension exists.
|
|
23
|
+
*/
|
|
24
|
+
import { type DuckDBConnection } from '@duckdb/node-api';
|
|
25
|
+
type ShapeClass = abstract new (...args: any[]) => any;
|
|
26
|
+
/** The engines DuckDB can attach — and the reason the list is short. */
|
|
27
|
+
export type Attachable = 'sqlite' | 'postgres' | 'mysql';
|
|
28
|
+
export interface SourceDeclaration {
|
|
29
|
+
/** A file, for sqlite. */
|
|
30
|
+
path?: string;
|
|
31
|
+
/** A connection string, for an engine reached over the network. */
|
|
32
|
+
attach?: string;
|
|
33
|
+
/** Defaults to sqlite, the engine `db:` resolves from a name. */
|
|
34
|
+
type?: Attachable;
|
|
35
|
+
/** Registration names of the entities whose rows live here. */
|
|
36
|
+
entities: string[];
|
|
37
|
+
}
|
|
38
|
+
export interface ConnectOptions {
|
|
39
|
+
/** The default source — where an entity no declaration names lives. */
|
|
40
|
+
db: {
|
|
41
|
+
path?: string;
|
|
42
|
+
attach?: string;
|
|
43
|
+
type?: Attachable;
|
|
44
|
+
};
|
|
45
|
+
/** The other places, exactly as `fougere.config.ts` states them. */
|
|
46
|
+
sources?: Record<string, SourceDeclaration>;
|
|
47
|
+
/**
|
|
48
|
+
* What this scope may read — and therefore what gets attached at all.
|
|
49
|
+
*
|
|
50
|
+
* Not a check performed after the fact: a source holding none of these is never
|
|
51
|
+
* attached, so its tables do not exist in this connection. `facadeFor` excludes an
|
|
52
|
+
* entity with no door on purpose ("it would publish the auth tables to anyone who
|
|
53
|
+
* asks"), and a SQL door at app scope would hand them over — this is what stops it.
|
|
54
|
+
*/
|
|
55
|
+
reads: readonly ShapeClass[];
|
|
56
|
+
/** Same resolver the storage uses, when an app renames tables. */
|
|
57
|
+
tableName?: (name: string) => string;
|
|
58
|
+
}
|
|
59
|
+
/** A query's answer: the rows, projected onto the shape that was named. */
|
|
60
|
+
export interface Sources {
|
|
61
|
+
/**
|
|
62
|
+
* Name the shape the answer takes, then write the query.
|
|
63
|
+
*
|
|
64
|
+
* The tag is only reachable THROUGH the shape, so "no query without a declared
|
|
65
|
+
* output" is held by the types rather than asked for. It matters: a raw `select *`
|
|
66
|
+
* would return the fields `boundary.out: 'closed'` promises never leave — the one
|
|
67
|
+
* strong guarantee the framework makes, walked around. The projection is the fence.
|
|
68
|
+
*/
|
|
69
|
+
read<E extends ShapeClass>(shape: E): (sql: TemplateStringsArray, ...refs: unknown[]) => Promise<InstanceType<E>[]>;
|
|
70
|
+
/** The attached sources, by alias — what the scope actually opened. */
|
|
71
|
+
attached: ReadonlyMap<string, string>;
|
|
72
|
+
close(): Promise<void>;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Open a read-only view of the app's sources.
|
|
76
|
+
*
|
|
77
|
+
* `READ_ONLY` on every attach, and it is the engine that enforces it rather than a rule
|
|
78
|
+
* anyone here remembers: this door reads across an app's whole storage, so it is
|
|
79
|
+
* strictly more reachable than `orm.client` — which at least keeps the scope of its
|
|
80
|
+
* entity — and a write through it would meet no judge at all.
|
|
81
|
+
*/
|
|
82
|
+
export declare function connectSources(options: ConnectOptions): Promise<Sources>;
|
|
83
|
+
export type { DuckDBConnection };
|
|
84
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAKzE,KAAK,UAAU,GAAG,QAAQ,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC;AAEvD,wEAAwE;AACxE,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;AAEzD,MAAM,WAAW,iBAAiB;IAChC,0BAA0B;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,EAAE,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,UAAU,CAAA;KAAE,CAAC;IAC1D,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC5C;;;;;;;OAOG;IACH,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;IAC7B,kEAAkE;IAClE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACtC;AAED,2EAA2E;AAC3E,MAAM,WAAW,OAAO;IACtB;;;;;;;OAOG;IACH,IAAI,CAAC,CAAC,SAAS,UAAU,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,oBAAoB,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACpH,uEAAuE;IACvE,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAmCD;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CA0D9E;AAuDD,YAAY,EAAE,gBAAgB,EAAE,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read across an app's sources — one SQL query over what can be attached.
|
|
3
|
+
*
|
|
4
|
+
* The by-key path (`findByKeys` and its dual) ENRICHES a page: it answers "I hold
|
|
5
|
+
* these rows, give me the related ones". It cannot SELECT one — filtering, sorting,
|
|
6
|
+
* paginating or counting on the other side collapses into reading that side whole.
|
|
7
|
+
* That is the hole this closes, and it is not a reporting nicety: "my loans, newest
|
|
8
|
+
* book first" crosses.
|
|
9
|
+
*
|
|
10
|
+
* What it is NOT is a query builder. A cross-source builder would be a Calcite in
|
|
11
|
+
* TypeScript, and it would promise a composability the sources have not got. The query
|
|
12
|
+
* stays SQL; what Fougere contributes is the three derivations a hand-written one would
|
|
13
|
+
* duplicate — where each entity lives, what its table and columns are called, and the
|
|
14
|
+
* shape of the answer.
|
|
15
|
+
*
|
|
16
|
+
* Measured before writing any of it (2026-08-15):
|
|
17
|
+
*
|
|
18
|
+
* - attaching Postgres pushes the filter down — `Filters: lang='fr'` reaches it over
|
|
19
|
+
* 100 000 rows, so a real database is queried where it is and never copied;
|
|
20
|
+
* - at PAGE size DuckDB is ~100× slower than two indexed reads (7 ms of floor per
|
|
21
|
+
* query), so this must never sit on the ordinary read path;
|
|
22
|
+
* - SQL Server cannot be attached at all — no `sqlserver` extension exists.
|
|
23
|
+
*/
|
|
24
|
+
import { DuckDBInstance } from '@duckdb/node-api';
|
|
25
|
+
import { fieldsOf } from '@fougere/schema';
|
|
26
|
+
import { toTable, toTableName, toSnakeCase, codecsOf } from '@fougere/adapter-sql';
|
|
27
|
+
const EXTENSION = {
|
|
28
|
+
sqlite: 'sqlite',
|
|
29
|
+
postgres: 'postgres',
|
|
30
|
+
mysql: 'mysql',
|
|
31
|
+
};
|
|
32
|
+
const TYPE_CLAUSE = {
|
|
33
|
+
sqlite: 'sqlite',
|
|
34
|
+
postgres: 'postgres',
|
|
35
|
+
mysql: 'mysql',
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* The default source's alias — the same word `fougere.config.ts` uses for it.
|
|
39
|
+
*
|
|
40
|
+
* Not `main`: DuckDB reserves it, and an attach under that name is refused outright.
|
|
41
|
+
*/
|
|
42
|
+
const DEFAULT_ALIAS = 'db';
|
|
43
|
+
/** 'Book' and 'book' name the same rows — the spelling `sources:` accepts either way. */
|
|
44
|
+
const keyOf = (name) => name.charAt(0).toLowerCase() + name.slice(1);
|
|
45
|
+
function targetOf(declaration, alias) {
|
|
46
|
+
const target = declaration.attach ?? declaration.path;
|
|
47
|
+
if (!target) {
|
|
48
|
+
throw new Error(`source '${alias}': neither \`path\` nor \`attach\` — DuckDB is told what to open, ` +
|
|
49
|
+
`and an in-memory database of its own would hold none of your rows.`);
|
|
50
|
+
}
|
|
51
|
+
return target;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Open a read-only view of the app's sources.
|
|
55
|
+
*
|
|
56
|
+
* `READ_ONLY` on every attach, and it is the engine that enforces it rather than a rule
|
|
57
|
+
* anyone here remembers: this door reads across an app's whole storage, so it is
|
|
58
|
+
* strictly more reachable than `orm.client` — which at least keeps the scope of its
|
|
59
|
+
* entity — and a write through it would meet no judge at all.
|
|
60
|
+
*/
|
|
61
|
+
export async function connectSources(options) {
|
|
62
|
+
const resolve = options.tableName ?? toTableName;
|
|
63
|
+
// Where each named entity lives; anything unnamed is in the default source.
|
|
64
|
+
const home = new Map();
|
|
65
|
+
for (const [alias, declaration] of Object.entries(options.sources ?? {})) {
|
|
66
|
+
for (const entity of declaration.entities)
|
|
67
|
+
home.set(keyOf(entity), alias);
|
|
68
|
+
}
|
|
69
|
+
// Only what this scope reads is attached — the declaration IS the environment.
|
|
70
|
+
const wanted = new Set();
|
|
71
|
+
const placed = new Map();
|
|
72
|
+
for (const shape of options.reads) {
|
|
73
|
+
const name = keyOf(shape.name ?? '');
|
|
74
|
+
const alias = home.get(name) ?? DEFAULT_ALIAS;
|
|
75
|
+
wanted.add(alias);
|
|
76
|
+
placed.set(shape, { alias, table: resolve(name) });
|
|
77
|
+
}
|
|
78
|
+
const instance = await DuckDBInstance.create(':memory:');
|
|
79
|
+
const db = await instance.connect();
|
|
80
|
+
const attached = new Map();
|
|
81
|
+
for (const alias of wanted) {
|
|
82
|
+
const declaration = alias === DEFAULT_ALIAS
|
|
83
|
+
? { ...options.db, entities: [] }
|
|
84
|
+
: options.sources?.[alias];
|
|
85
|
+
if (!declaration)
|
|
86
|
+
throw new Error(`source '${alias}' is read but never declared.`);
|
|
87
|
+
const type = declaration.type ?? 'sqlite';
|
|
88
|
+
if (!(type in EXTENSION)) {
|
|
89
|
+
throw new Error(`source '${alias}' is a ${type} database, which DuckDB cannot attach — there is no ` +
|
|
90
|
+
`such extension. Read it by key through its own ORM, or mirror it into one of ` +
|
|
91
|
+
`${Object.keys(EXTENSION).join(', ')}.`);
|
|
92
|
+
}
|
|
93
|
+
await db.run(`INSTALL ${EXTENSION[type]}; LOAD ${EXTENSION[type]};`);
|
|
94
|
+
await db.run(`ATTACH '${targetOf(declaration, alias)}' AS ${quote(alias)} (TYPE ${TYPE_CLAUSE[type]}, READ_ONLY);`);
|
|
95
|
+
attached.set(alias, targetOf(declaration, alias));
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
attached,
|
|
99
|
+
close: async () => { db.closeSync(); },
|
|
100
|
+
read(shape) {
|
|
101
|
+
const fields = fieldsOf(shape);
|
|
102
|
+
const codecs = codecsOf(toTable('x', shape).columns);
|
|
103
|
+
const names = Object.keys(fields);
|
|
104
|
+
return async (parts, ...refs) => {
|
|
105
|
+
const sql = parts.reduce((out, part, i) => out + part + (i < refs.length ? qualify(refs[i], placed) : ''), '');
|
|
106
|
+
const rows = (await db.runAndReadAll(sql)).getRowObjects();
|
|
107
|
+
if (rows.length > 0)
|
|
108
|
+
refuseMismatch(shape, names, rows[0], sql);
|
|
109
|
+
return rows.map((row) => project(names, codecs, row));
|
|
110
|
+
};
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/** `${Book}` becomes `archive.books` — the alias AND the table, from one declaration. */
|
|
115
|
+
function qualify(ref, placed) {
|
|
116
|
+
const found = placed.get(ref);
|
|
117
|
+
if (found)
|
|
118
|
+
return `${quote(found.alias)}.${quote(found.table)}`;
|
|
119
|
+
const name = ref?.name;
|
|
120
|
+
if (name) {
|
|
121
|
+
throw new Error(`${name} is named in a query but not in \`reads\` — its source is not attached, so its ` +
|
|
122
|
+
`table does not exist in this connection. Add it to \`reads\`, or stop naming it.`);
|
|
123
|
+
}
|
|
124
|
+
// A plain value interpolated into SQL is refused: this tag substitutes ENTITIES, and
|
|
125
|
+
// accepting a value would be a string-built query with no binding in sight.
|
|
126
|
+
throw new Error(`only an entity may be interpolated into a source query — pass a value through the ` +
|
|
127
|
+
`query text you write, or filter the result.`);
|
|
128
|
+
}
|
|
129
|
+
const quote = (identifier) => `"${identifier.replace(/"/g, '""')}"`;
|
|
130
|
+
/**
|
|
131
|
+
* The column set, checked ONCE against the shape.
|
|
132
|
+
*
|
|
133
|
+
* Not the JSON Schema judge per row: an aggregate is not a client's input, and the
|
|
134
|
+
* caller here is the query its own author wrote. What must not pass silently is the two
|
|
135
|
+
* disagreeing — a renamed alias yielding a column of nulls under the right type.
|
|
136
|
+
*/
|
|
137
|
+
function refuseMismatch(shape, names, row, sql) {
|
|
138
|
+
const missing = names.filter((name) => !(toSnakeCase(name) in row) && !(name in row));
|
|
139
|
+
if (missing.length === 0)
|
|
140
|
+
return;
|
|
141
|
+
throw new Error(`${shape.name ?? 'the shape'} declares ${missing.map((m) => `\`${m}\``).join(', ')}, ` +
|
|
142
|
+
`and the query answers ${Object.keys(row).map((c) => `\`${c}\``).join(', ')} — name the column with ` +
|
|
143
|
+
`\`as\`, or drop the field.\n${sql.trim()}`);
|
|
144
|
+
}
|
|
145
|
+
/** Keep what the shape declares, converted — a column it does not name never leaves. */
|
|
146
|
+
function project(names, codecs, row) {
|
|
147
|
+
const out = {};
|
|
148
|
+
for (const name of names) {
|
|
149
|
+
const column = toSnakeCase(name);
|
|
150
|
+
const raw = column in row ? row[column] : row[name];
|
|
151
|
+
out[name] = codecs.get(name)?.read(raw) ?? raw;
|
|
152
|
+
}
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fougere/adapter-duckdb",
|
|
3
|
+
"version": "0.2.0-alpha.2",
|
|
4
|
+
"description": "Read across an app's sources — one SQL query over what DuckDB can attach.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"fougere",
|
|
7
|
+
"typescript",
|
|
8
|
+
"duckdb",
|
|
9
|
+
"federation",
|
|
10
|
+
"analytics"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/chok/fougere.git",
|
|
16
|
+
"directory": "packages/adapter/duckdb"
|
|
17
|
+
},
|
|
18
|
+
"type": "module",
|
|
19
|
+
"main": "dist/index.js",
|
|
20
|
+
"types": "dist/index.d.ts",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"import": "./dist/index.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@fougere/schema": "0.2.0-alpha.2",
|
|
32
|
+
"@fougere/adapter-sql": "0.2.0-alpha.2"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@duckdb/node-api": ">=1.4.0-0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@duckdb/node-api": "^1.5.5-r.4",
|
|
39
|
+
"better-sqlite3": "^13.0.3",
|
|
40
|
+
"@types/better-sqlite3": "^7.6.13"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "rm -rf dist && tsc",
|
|
47
|
+
"test": "vitest run",
|
|
48
|
+
"test:watch": "vitest",
|
|
49
|
+
"typecheck": "tsc --noEmit -p tsconfig.test.json"
|
|
50
|
+
}
|
|
51
|
+
}
|