wn-turso 0.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/dist/adapters/adapter.d.ts +53 -0
- package/dist/adapters/adapter.d.ts.map +1 -0
- package/dist/adapters/adapter.js +4 -0
- package/dist/adapters/embedded-adapter.d.ts +24 -0
- package/dist/adapters/embedded-adapter.d.ts.map +1 -0
- package/dist/adapters/embedded-adapter.js +78 -0
- package/dist/adapters/index.d.ts +7 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +5 -0
- package/dist/adapters/remote-adapter.d.ts +21 -0
- package/dist/adapters/remote-adapter.d.ts.map +1 -0
- package/dist/adapters/remote-adapter.js +49 -0
- package/dist/cli/index.d.ts +6 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +61 -0
- package/dist/config.d.ts +77 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +37 -0
- package/dist/database/index.d.ts +10 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +8 -0
- package/dist/database/kysely-query-service.d.ts +32 -0
- package/dist/database/kysely-query-service.d.ts.map +1 -0
- package/dist/database/kysely-query-service.js +39 -0
- package/dist/database/turso-connection.d.ts +15 -0
- package/dist/database/turso-connection.d.ts.map +1 -0
- package/dist/database/turso-connection.js +29 -0
- package/dist/database/turso-database.d.ts +49 -0
- package/dist/database/turso-database.d.ts.map +1 -0
- package/dist/database/turso-database.js +124 -0
- package/dist/database/turso-dialect.d.ts +16 -0
- package/dist/database/turso-dialect.d.ts.map +1 -0
- package/dist/database/turso-dialect.js +25 -0
- package/dist/database/turso-driver.d.ts +25 -0
- package/dist/database/turso-driver.d.ts.map +1 -0
- package/dist/database/turso-driver.js +43 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/pipeline/index.d.ts +10 -0
- package/dist/pipeline/index.d.ts.map +1 -0
- package/dist/pipeline/index.js +13 -0
- package/dist/pipeline/operators.d.ts +65 -0
- package/dist/pipeline/operators.d.ts.map +1 -0
- package/dist/pipeline/operators.js +174 -0
- package/dist/pipeline/pipeline-builder.d.ts +107 -0
- package/dist/pipeline/pipeline-builder.d.ts.map +1 -0
- package/dist/pipeline/pipeline-builder.js +181 -0
- package/dist/pipeline/sink.d.ts +22 -0
- package/dist/pipeline/sink.d.ts.map +1 -0
- package/dist/pipeline/sink.js +63 -0
- package/dist/pipeline/source.d.ts +20 -0
- package/dist/pipeline/source.d.ts.map +1 -0
- package/dist/pipeline/source.js +66 -0
- package/dist/pipeline/streams.d.ts +18 -0
- package/dist/pipeline/streams.d.ts.map +1 -0
- package/dist/pipeline/streams.js +115 -0
- package/dist/pipeline/types.d.ts +86 -0
- package/dist/pipeline/types.d.ts.map +1 -0
- package/dist/pipeline/types.js +4 -0
- package/dist/wordnet/index.d.ts +5 -0
- package/dist/wordnet/index.d.ts.map +1 -0
- package/dist/wordnet/index.js +4 -0
- package/dist/wordnet/turso-wordnet.d.ts +85 -0
- package/dist/wordnet/turso-wordnet.d.ts.map +1 -0
- package/dist/wordnet/turso-wordnet.js +107 -0
- package/package.json +80 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fluent Pipeline builder API
|
|
3
|
+
*/
|
|
4
|
+
import type { PipelineSource, PipelineSink, PipelineResult } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Fluent pipeline builder for data transfer operations
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const result = await Pipeline
|
|
11
|
+
* .from(tursoSource(sourceConfig, 'synsets'))
|
|
12
|
+
* .filter(row => row.language === 'en')
|
|
13
|
+
* .extend(row => ({
|
|
14
|
+
* cached_count: 0,
|
|
15
|
+
* custom_score: computeScore(row),
|
|
16
|
+
* }))
|
|
17
|
+
* .to(tursoSink(destConfig, 'synsets_working'));
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare class Pipeline<T> {
|
|
21
|
+
private source;
|
|
22
|
+
private operations;
|
|
23
|
+
private constructor();
|
|
24
|
+
/**
|
|
25
|
+
* Create a new pipeline from a source
|
|
26
|
+
*/
|
|
27
|
+
static from<T>(source: PipelineSource<T>): Pipeline<T>;
|
|
28
|
+
/**
|
|
29
|
+
* Filter rows based on a predicate
|
|
30
|
+
*/
|
|
31
|
+
filter(predicate: (row: T) => boolean): Pipeline<T>;
|
|
32
|
+
/**
|
|
33
|
+
* Map rows to a new shape
|
|
34
|
+
*/
|
|
35
|
+
map<U>(fn: (row: T) => U): Pipeline<U>;
|
|
36
|
+
/**
|
|
37
|
+
* Transform rows, returning null to skip a row
|
|
38
|
+
*/
|
|
39
|
+
transform<U>(fn: (row: T) => U | null | undefined): Pipeline<U>;
|
|
40
|
+
/**
|
|
41
|
+
* Async transform for operations that need to await
|
|
42
|
+
*/
|
|
43
|
+
transformAsync<U>(fn: (row: T) => Promise<U | null | undefined>): Pipeline<U>;
|
|
44
|
+
/**
|
|
45
|
+
* Extend rows with additional properties
|
|
46
|
+
* Useful for adding columns to a "working DB" schema
|
|
47
|
+
*/
|
|
48
|
+
extend<Ext extends Record<string, any>>(fn: (row: T) => Ext): Pipeline<T & Ext>;
|
|
49
|
+
/**
|
|
50
|
+
* Async extend for operations that need to await
|
|
51
|
+
*/
|
|
52
|
+
extendAsync<Ext extends Record<string, any>>(fn: (row: T) => Promise<Ext>): Pipeline<T & Ext>;
|
|
53
|
+
/**
|
|
54
|
+
* Batch rows into arrays
|
|
55
|
+
*/
|
|
56
|
+
batch(size: number): Pipeline<T[]>;
|
|
57
|
+
/**
|
|
58
|
+
* Side effect for each row (logging, metrics)
|
|
59
|
+
*/
|
|
60
|
+
tap(fn: (row: T) => void): Pipeline<T>;
|
|
61
|
+
/**
|
|
62
|
+
* Async side effect
|
|
63
|
+
*/
|
|
64
|
+
tapAsync(fn: (row: T) => Promise<void>): Pipeline<T>;
|
|
65
|
+
/**
|
|
66
|
+
* Take first n rows
|
|
67
|
+
*/
|
|
68
|
+
take(n: number): Pipeline<T>;
|
|
69
|
+
/**
|
|
70
|
+
* Skip first n rows
|
|
71
|
+
*/
|
|
72
|
+
skip(n: number): Pipeline<T>;
|
|
73
|
+
/**
|
|
74
|
+
* Deduplicate rows by key
|
|
75
|
+
*/
|
|
76
|
+
distinct<K>(keyFn: (row: T) => K): Pipeline<T>;
|
|
77
|
+
/**
|
|
78
|
+
* Build the pipeline as an async iterable
|
|
79
|
+
* Useful for manual iteration or custom sinks
|
|
80
|
+
*/
|
|
81
|
+
build(): AsyncIterable<T>;
|
|
82
|
+
/**
|
|
83
|
+
* Execute the pipeline and write to a sink
|
|
84
|
+
*/
|
|
85
|
+
to(sink: PipelineSink<T>): Promise<PipelineResult>;
|
|
86
|
+
/**
|
|
87
|
+
* Execute the pipeline and collect results into an array
|
|
88
|
+
*/
|
|
89
|
+
toArray(): Promise<T[]>;
|
|
90
|
+
/**
|
|
91
|
+
* Count the rows that pass through the pipeline
|
|
92
|
+
*/
|
|
93
|
+
count(): Promise<number>;
|
|
94
|
+
/**
|
|
95
|
+
* Execute a function for each row
|
|
96
|
+
*/
|
|
97
|
+
forEach(fn: (row: T) => void): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* Execute an async function for each row
|
|
100
|
+
*/
|
|
101
|
+
forEachAsync(fn: (row: T) => Promise<void>): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Get the source count (if available)
|
|
104
|
+
*/
|
|
105
|
+
sourceCount(): Promise<number | undefined>;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=pipeline-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-builder.d.ts","sourceRoot":"","sources":["../../src/pipeline/pipeline-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fluent Pipeline builder API
|
|
3
|
+
*/
|
|
4
|
+
import * as operators from './operators.js';
|
|
5
|
+
/**
|
|
6
|
+
* Fluent pipeline builder for data transfer operations
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const result = await Pipeline
|
|
11
|
+
* .from(tursoSource(sourceConfig, 'synsets'))
|
|
12
|
+
* .filter(row => row.language === 'en')
|
|
13
|
+
* .extend(row => ({
|
|
14
|
+
* cached_count: 0,
|
|
15
|
+
* custom_score: computeScore(row),
|
|
16
|
+
* }))
|
|
17
|
+
* .to(tursoSink(destConfig, 'synsets_working'));
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export class Pipeline {
|
|
21
|
+
source;
|
|
22
|
+
operations = [];
|
|
23
|
+
constructor(source) {
|
|
24
|
+
this.source = source;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create a new pipeline from a source
|
|
28
|
+
*/
|
|
29
|
+
static from(source) {
|
|
30
|
+
return new Pipeline(source);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Filter rows based on a predicate
|
|
34
|
+
*/
|
|
35
|
+
filter(predicate) {
|
|
36
|
+
this.operations.push(operators.filter(predicate));
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Map rows to a new shape
|
|
41
|
+
*/
|
|
42
|
+
map(fn) {
|
|
43
|
+
this.operations.push(operators.map(fn));
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Transform rows, returning null to skip a row
|
|
48
|
+
*/
|
|
49
|
+
transform(fn) {
|
|
50
|
+
this.operations.push(operators.transform(fn));
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Async transform for operations that need to await
|
|
55
|
+
*/
|
|
56
|
+
transformAsync(fn) {
|
|
57
|
+
this.operations.push(operators.transformAsync(fn));
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Extend rows with additional properties
|
|
62
|
+
* Useful for adding columns to a "working DB" schema
|
|
63
|
+
*/
|
|
64
|
+
extend(fn) {
|
|
65
|
+
this.operations.push(operators.extend(fn));
|
|
66
|
+
return this;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Async extend for operations that need to await
|
|
70
|
+
*/
|
|
71
|
+
extendAsync(fn) {
|
|
72
|
+
this.operations.push(operators.extendAsync(fn));
|
|
73
|
+
return this;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Batch rows into arrays
|
|
77
|
+
*/
|
|
78
|
+
batch(size) {
|
|
79
|
+
this.operations.push(operators.batch(size));
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Side effect for each row (logging, metrics)
|
|
84
|
+
*/
|
|
85
|
+
tap(fn) {
|
|
86
|
+
this.operations.push(operators.tap(fn));
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Async side effect
|
|
91
|
+
*/
|
|
92
|
+
tapAsync(fn) {
|
|
93
|
+
this.operations.push(operators.tapAsync(fn));
|
|
94
|
+
return this;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Take first n rows
|
|
98
|
+
*/
|
|
99
|
+
take(n) {
|
|
100
|
+
this.operations.push(operators.take(n));
|
|
101
|
+
return this;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Skip first n rows
|
|
105
|
+
*/
|
|
106
|
+
skip(n) {
|
|
107
|
+
this.operations.push(operators.skip(n));
|
|
108
|
+
return this;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Deduplicate rows by key
|
|
112
|
+
*/
|
|
113
|
+
distinct(keyFn) {
|
|
114
|
+
this.operations.push(operators.distinct(keyFn));
|
|
115
|
+
return this;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Build the pipeline as an async iterable
|
|
119
|
+
* Useful for manual iteration or custom sinks
|
|
120
|
+
*/
|
|
121
|
+
build() {
|
|
122
|
+
let stream = this.source.read();
|
|
123
|
+
for (const op of this.operations) {
|
|
124
|
+
stream = op(stream);
|
|
125
|
+
}
|
|
126
|
+
return stream;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Execute the pipeline and write to a sink
|
|
130
|
+
*/
|
|
131
|
+
async to(sink) {
|
|
132
|
+
const stream = this.build();
|
|
133
|
+
return sink.write(stream);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Execute the pipeline and collect results into an array
|
|
137
|
+
*/
|
|
138
|
+
async toArray() {
|
|
139
|
+
const results = [];
|
|
140
|
+
const stream = this.build();
|
|
141
|
+
for await (const row of stream) {
|
|
142
|
+
results.push(row);
|
|
143
|
+
}
|
|
144
|
+
return results;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Count the rows that pass through the pipeline
|
|
148
|
+
*/
|
|
149
|
+
async count() {
|
|
150
|
+
let count = 0;
|
|
151
|
+
const stream = this.build();
|
|
152
|
+
for await (const _row of stream) {
|
|
153
|
+
count++;
|
|
154
|
+
}
|
|
155
|
+
return count;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Execute a function for each row
|
|
159
|
+
*/
|
|
160
|
+
async forEach(fn) {
|
|
161
|
+
const stream = this.build();
|
|
162
|
+
for await (const row of stream) {
|
|
163
|
+
fn(row);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Execute an async function for each row
|
|
168
|
+
*/
|
|
169
|
+
async forEachAsync(fn) {
|
|
170
|
+
const stream = this.build();
|
|
171
|
+
for await (const row of stream) {
|
|
172
|
+
await fn(row);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Get the source count (if available)
|
|
177
|
+
*/
|
|
178
|
+
async sourceCount() {
|
|
179
|
+
return this.source.count?.();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline sinks for writing data
|
|
3
|
+
*/
|
|
4
|
+
import type { Kysely } from 'kysely';
|
|
5
|
+
import type { TursoDatabaseConfig } from '../config.js';
|
|
6
|
+
import type { PipelineSink, SinkOptions } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Create a pipeline sink for a Turso database
|
|
9
|
+
*/
|
|
10
|
+
export declare function tursoSink<T extends Record<string, any>>(config: TursoDatabaseConfig, table: string, options?: SinkOptions): PipelineSink<T>;
|
|
11
|
+
/**
|
|
12
|
+
* Create a pipeline sink from a Kysely database instance
|
|
13
|
+
* (for use with existing connections)
|
|
14
|
+
*/
|
|
15
|
+
export declare function kyselySink<T extends Record<string, any>>(db: Kysely<any>, table: string, options?: SinkOptions): PipelineSink<T>;
|
|
16
|
+
/**
|
|
17
|
+
* Create a sink that collects items into an array (for testing)
|
|
18
|
+
*/
|
|
19
|
+
export declare function arraySink<T>(): PipelineSink<T> & {
|
|
20
|
+
items: T[];
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=sink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sink.d.ts","sourceRoot":"","sources":["../../src/pipeline/sink.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAkB,MAAM,YAAY,CAAC;AAG5E;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACrD,MAAM,EAAE,mBAAmB,EAC3B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,WAAgB,GACxB,YAAY,CAAC,CAAC,CAAC,CAkBjB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACtD,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EACf,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,WAAgB,GACxB,YAAY,CAAC,CAAC,CAAC,CAQjB;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC,CAAC,GAAG;IAAE,KAAK,EAAE,CAAC,EAAE,CAAA;CAAE,CAyB/D"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline sinks for writing data
|
|
3
|
+
*/
|
|
4
|
+
import { TursoDatabase } from '../database/turso-database.js';
|
|
5
|
+
import { writeBatches } from './streams.js';
|
|
6
|
+
/**
|
|
7
|
+
* Create a pipeline sink for a Turso database
|
|
8
|
+
*/
|
|
9
|
+
export function tursoSink(config, table, options = {}) {
|
|
10
|
+
return {
|
|
11
|
+
name: `turso:${config.url}/${table}`,
|
|
12
|
+
async write(data) {
|
|
13
|
+
const db = new TursoDatabase({
|
|
14
|
+
...config,
|
|
15
|
+
readonly: false, // Ensure we can write
|
|
16
|
+
});
|
|
17
|
+
await db.initialize();
|
|
18
|
+
try {
|
|
19
|
+
return await writeBatches(db.getDatabase(), table, data, options);
|
|
20
|
+
}
|
|
21
|
+
finally {
|
|
22
|
+
await db.close();
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Create a pipeline sink from a Kysely database instance
|
|
29
|
+
* (for use with existing connections)
|
|
30
|
+
*/
|
|
31
|
+
export function kyselySink(db, table, options = {}) {
|
|
32
|
+
return {
|
|
33
|
+
name: `kysely:${table}`,
|
|
34
|
+
async write(data) {
|
|
35
|
+
return writeBatches(db, table, data, options);
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Create a sink that collects items into an array (for testing)
|
|
41
|
+
*/
|
|
42
|
+
export function arraySink() {
|
|
43
|
+
const items = [];
|
|
44
|
+
const startTime = Date.now();
|
|
45
|
+
return {
|
|
46
|
+
name: 'array',
|
|
47
|
+
items,
|
|
48
|
+
async write(data) {
|
|
49
|
+
let processed = 0;
|
|
50
|
+
for await (const item of data) {
|
|
51
|
+
items.push(item);
|
|
52
|
+
processed++;
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
processed,
|
|
56
|
+
inserted: processed,
|
|
57
|
+
skipped: 0,
|
|
58
|
+
errors: 0,
|
|
59
|
+
duration: Date.now() - startTime,
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline sources for reading data
|
|
3
|
+
*/
|
|
4
|
+
import type { Kysely } from 'kysely';
|
|
5
|
+
import type { TursoDatabaseConfig } from '../config.js';
|
|
6
|
+
import type { PipelineSource, SourceOptions } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Create a pipeline source from a Turso database
|
|
9
|
+
*/
|
|
10
|
+
export declare function tursoSource<T extends Record<string, any>>(config: TursoDatabaseConfig, table: string, options?: SourceOptions<T>): PipelineSource<T>;
|
|
11
|
+
/**
|
|
12
|
+
* Create a pipeline source from a Kysely database instance
|
|
13
|
+
* (for use with existing connections)
|
|
14
|
+
*/
|
|
15
|
+
export declare function kyselySource<T extends Record<string, any>>(db: Kysely<any>, table: string, options?: SourceOptions<T>): PipelineSource<T>;
|
|
16
|
+
/**
|
|
17
|
+
* Create a source from an array (for testing)
|
|
18
|
+
*/
|
|
19
|
+
export declare function arraySource<T>(items: T[], name?: string): PipelineSource<T>;
|
|
20
|
+
//# sourceMappingURL=source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/pipeline/source.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhE;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACvD,MAAM,EAAE,mBAAmB,EAC3B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAa,CAAC,CAAC,CAAM,GAC7B,cAAc,CAAC,CAAC,CAAC,CA6BnB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACxD,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EACf,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAa,CAAC,CAAC,CAAM,GAC7B,cAAc,CAAC,CAAC,CAAC,CAYnB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,KAAK,EAAE,CAAC,EAAE,EACV,IAAI,GAAE,MAAgB,GACrB,cAAc,CAAC,CAAC,CAAC,CAcnB"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline sources for reading data
|
|
3
|
+
*/
|
|
4
|
+
import { TursoDatabase } from '../database/turso-database.js';
|
|
5
|
+
import { streamTable, countRows } from './streams.js';
|
|
6
|
+
/**
|
|
7
|
+
* Create a pipeline source from a Turso database
|
|
8
|
+
*/
|
|
9
|
+
export function tursoSource(config, table, options = {}) {
|
|
10
|
+
let db = null;
|
|
11
|
+
return {
|
|
12
|
+
name: `turso:${config.url}/${table}`,
|
|
13
|
+
async *read() {
|
|
14
|
+
db = new TursoDatabase(config);
|
|
15
|
+
await db.initialize();
|
|
16
|
+
try {
|
|
17
|
+
yield* streamTable(db.getDatabase(), table, options);
|
|
18
|
+
}
|
|
19
|
+
finally {
|
|
20
|
+
await db.close();
|
|
21
|
+
db = null;
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
async count() {
|
|
25
|
+
const tempDb = new TursoDatabase(config);
|
|
26
|
+
await tempDb.initialize();
|
|
27
|
+
try {
|
|
28
|
+
return await countRows(tempDb.getDatabase(), table, options);
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
await tempDb.close();
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create a pipeline source from a Kysely database instance
|
|
38
|
+
* (for use with existing connections)
|
|
39
|
+
*/
|
|
40
|
+
export function kyselySource(db, table, options = {}) {
|
|
41
|
+
return {
|
|
42
|
+
name: `kysely:${table}`,
|
|
43
|
+
async *read() {
|
|
44
|
+
yield* streamTable(db, table, options);
|
|
45
|
+
},
|
|
46
|
+
async count() {
|
|
47
|
+
return countRows(db, table, options);
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Create a source from an array (for testing)
|
|
53
|
+
*/
|
|
54
|
+
export function arraySource(items, name = 'array') {
|
|
55
|
+
return {
|
|
56
|
+
name,
|
|
57
|
+
async *read() {
|
|
58
|
+
for (const item of items) {
|
|
59
|
+
yield item;
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
async count() {
|
|
63
|
+
return items.length;
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Low-level streaming utilities for pipeline operations
|
|
3
|
+
*/
|
|
4
|
+
import type { Kysely } from 'kysely';
|
|
5
|
+
import type { SourceOptions, SinkOptions, PipelineResult } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Stream rows from a table as an async generator
|
|
8
|
+
*/
|
|
9
|
+
export declare function streamTable<T>(db: Kysely<any>, table: string, options?: SourceOptions<T>): AsyncGenerator<T>;
|
|
10
|
+
/**
|
|
11
|
+
* Write rows in batches to a table
|
|
12
|
+
*/
|
|
13
|
+
export declare function writeBatches<T extends Record<string, any>>(db: Kysely<any>, table: string, rows: AsyncIterable<T>, options?: SinkOptions): Promise<PipelineResult>;
|
|
14
|
+
/**
|
|
15
|
+
* Count rows in a table with optional filter
|
|
16
|
+
*/
|
|
17
|
+
export declare function countRows<T>(db: Kysely<any>, table: string, options?: SourceOptions<T>): Promise<number>;
|
|
18
|
+
//# sourceMappingURL=streams.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streams.d.ts","sourceRoot":"","sources":["../../src/pipeline/streams.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE7E;;GAEG;AACH,wBAAuB,WAAW,CAAC,CAAC,EAClC,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EACf,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAa,CAAC,CAAC,CAAM,GAC7B,cAAc,CAAC,CAAC,CAAC,CA8CnB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC9D,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EACf,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,EACtB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,cAAc,CAAC,CAiEzB;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EACf,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAa,CAAC,CAAC,CAAM,GAC7B,OAAO,CAAC,MAAM,CAAC,CAWjB"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Low-level streaming utilities for pipeline operations
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Stream rows from a table as an async generator
|
|
6
|
+
*/
|
|
7
|
+
export async function* streamTable(db, table, options = {}) {
|
|
8
|
+
const { batchSize = 1000, where, orderBy, limit, offset = 0 } = options;
|
|
9
|
+
let currentOffset = offset;
|
|
10
|
+
let hasMore = true;
|
|
11
|
+
let totalFetched = 0;
|
|
12
|
+
while (hasMore) {
|
|
13
|
+
let query = db.selectFrom(table).selectAll();
|
|
14
|
+
if (where) {
|
|
15
|
+
query = where(query);
|
|
16
|
+
}
|
|
17
|
+
if (orderBy) {
|
|
18
|
+
query = query.orderBy(orderBy);
|
|
19
|
+
}
|
|
20
|
+
// Apply pagination
|
|
21
|
+
query = query.limit(batchSize).offset(currentOffset);
|
|
22
|
+
const rows = await query.execute();
|
|
23
|
+
if (rows.length === 0) {
|
|
24
|
+
hasMore = false;
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
for (const row of rows) {
|
|
28
|
+
yield row;
|
|
29
|
+
totalFetched++;
|
|
30
|
+
// Check if we've hit the limit
|
|
31
|
+
if (limit !== undefined && totalFetched >= limit) {
|
|
32
|
+
hasMore = false;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// If we got fewer rows than batch size, we're done
|
|
37
|
+
if (rows.length < batchSize) {
|
|
38
|
+
hasMore = false;
|
|
39
|
+
}
|
|
40
|
+
currentOffset += batchSize;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Write rows in batches to a table
|
|
45
|
+
*/
|
|
46
|
+
export async function writeBatches(db, table, rows, options = {}) {
|
|
47
|
+
const { batchSize = 100, onConflict = 'error', onProgress } = options;
|
|
48
|
+
const startTime = Date.now();
|
|
49
|
+
let processed = 0;
|
|
50
|
+
let inserted = 0;
|
|
51
|
+
let skipped = 0;
|
|
52
|
+
let errors = 0;
|
|
53
|
+
let batch = [];
|
|
54
|
+
const flushBatch = async () => {
|
|
55
|
+
if (batch.length === 0)
|
|
56
|
+
return;
|
|
57
|
+
try {
|
|
58
|
+
let query = db.insertInto(table).values(batch);
|
|
59
|
+
if (onConflict === 'ignore') {
|
|
60
|
+
query = query.onConflict((oc) => oc.doNothing());
|
|
61
|
+
}
|
|
62
|
+
else if (onConflict === 'replace') {
|
|
63
|
+
// For replace, we need to know the primary key columns
|
|
64
|
+
// This is a simplified version - full implementation would need schema introspection
|
|
65
|
+
query = query.onConflict((oc) => oc.doNothing());
|
|
66
|
+
}
|
|
67
|
+
const result = await query.execute();
|
|
68
|
+
inserted += batch.length;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
if (onConflict === 'error') {
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
// For ignore/replace, count as errors
|
|
75
|
+
errors += batch.length;
|
|
76
|
+
}
|
|
77
|
+
batch = [];
|
|
78
|
+
};
|
|
79
|
+
for await (const row of rows) {
|
|
80
|
+
batch.push(row);
|
|
81
|
+
processed++;
|
|
82
|
+
if (batch.length >= batchSize) {
|
|
83
|
+
await flushBatch();
|
|
84
|
+
if (onProgress) {
|
|
85
|
+
onProgress({
|
|
86
|
+
current: processed,
|
|
87
|
+
processed,
|
|
88
|
+
skipped,
|
|
89
|
+
errors,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Flush remaining rows
|
|
95
|
+
await flushBatch();
|
|
96
|
+
return {
|
|
97
|
+
processed,
|
|
98
|
+
inserted,
|
|
99
|
+
skipped,
|
|
100
|
+
errors,
|
|
101
|
+
duration: Date.now() - startTime,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Count rows in a table with optional filter
|
|
106
|
+
*/
|
|
107
|
+
export async function countRows(db, table, options = {}) {
|
|
108
|
+
const { where } = options;
|
|
109
|
+
let query = db.selectFrom(table).select((eb) => eb.fn.count('*').as('count'));
|
|
110
|
+
if (where) {
|
|
111
|
+
query = where(query);
|
|
112
|
+
}
|
|
113
|
+
const result = await query.executeTakeFirst();
|
|
114
|
+
return Number(result?.count ?? 0);
|
|
115
|
+
}
|