@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 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.
@@ -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
+ }