@jackchuka/gql-ingest 2.2.2 → 3.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/README.md +259 -32
- package/dist/cli/commands/add.d.ts +3 -0
- package/dist/cli/commands/add.d.ts.map +1 -0
- package/dist/cli/commands/init.d.ts +3 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +288 -0
- package/dist/cli/templates/index.d.ts +14 -0
- package/dist/cli/templates/index.d.ts.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15204 -0
- package/dist/index.js.map +7 -0
- package/dist/lib/config-schema.d.ts +103 -0
- package/dist/lib/config-schema.d.ts.map +1 -0
- package/dist/lib/config.d.ts +9 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/dependency-resolver.d.ts.map +1 -0
- package/dist/lib/events.d.ts +167 -0
- package/dist/lib/events.d.ts.map +1 -0
- package/dist/lib/gql-ingest.d.ts +155 -0
- package/dist/lib/gql-ingest.d.ts.map +1 -0
- package/dist/{graphql-client.d.ts → lib/graphql-client.d.ts} +8 -4
- package/dist/lib/graphql-client.d.ts.map +1 -0
- package/dist/lib/index.d.ts +8 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/logger.d.ts +29 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/mapper.d.ts +49 -0
- package/dist/lib/mapper.d.ts.map +1 -0
- package/dist/{metrics.d.ts → lib/metrics.d.ts} +22 -8
- package/dist/lib/metrics.d.ts.map +1 -0
- package/dist/readers/csv.d.ts +0 -4
- package/dist/readers/csv.d.ts.map +1 -1
- package/dist/readers/index.d.ts +1 -1
- package/dist/readers/index.d.ts.map +1 -1
- package/package.json +19 -7
- package/dist/cli.d.ts +0 -2
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -237
- package/dist/config.d.ts +0 -32
- package/dist/config.d.ts.map +0 -1
- package/dist/config.test.d.ts +0 -2
- package/dist/config.test.d.ts.map +0 -1
- package/dist/dependency-resolver.d.ts.map +0 -1
- package/dist/dependency-resolver.test.d.ts +0 -2
- package/dist/dependency-resolver.test.d.ts.map +0 -1
- package/dist/graphql-client.d.ts.map +0 -1
- package/dist/graphql-client.test.d.ts +0 -2
- package/dist/graphql-client.test.d.ts.map +0 -1
- package/dist/mapper.d.ts +0 -31
- package/dist/mapper.d.ts.map +0 -1
- package/dist/mapper.test.d.ts +0 -2
- package/dist/mapper.test.d.ts.map +0 -1
- package/dist/metrics.d.ts.map +0 -1
- package/dist/metrics.test.d.ts +0 -2
- package/dist/metrics.test.d.ts.map +0 -1
- package/dist/readers/csv.test.d.ts +0 -2
- package/dist/readers/csv.test.d.ts.map +0 -1
- package/dist/readers/data-reader.test.d.ts +0 -2
- package/dist/readers/data-reader.test.d.ts.map +0 -1
- package/dist/readers/json.test.d.ts +0 -2
- package/dist/readers/json.test.d.ts.map +0 -1
- package/dist/readers/jsonl.test.d.ts +0 -2
- package/dist/readers/jsonl.test.d.ts.map +0 -1
- package/dist/readers/yaml.test.d.ts +0 -2
- package/dist/readers/yaml.test.d.ts.map +0 -1
- /package/dist/{dependency-resolver.d.ts → lib/dependency-resolver.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://badge.fury.io/js/%40jackchuka%2Fgql-ingest)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
A TypeScript CLI tool that reads data from multiple formats (CSV, JSON, YAML, JSONL) and ingests it into GraphQL APIs through configurable mutations.
|
|
6
|
+
A TypeScript library and CLI tool that reads data from multiple formats (CSV, JSON, YAML, JSONL) and ingests it into GraphQL APIs through configurable mutations.
|
|
7
7
|
|
|
8
8
|
## Features
|
|
9
9
|
|
|
@@ -16,6 +16,8 @@ A TypeScript CLI tool that reads data from multiple formats (CSV, JSON, YAML, JS
|
|
|
16
16
|
- ✅ Entity-level and row-level concurrency control
|
|
17
17
|
- ✅ **Retry capabilities** with exponential backoff and configurable error handling
|
|
18
18
|
- ✅ Comprehensive metrics and progress tracking
|
|
19
|
+
- ✅ **Event-based progress monitoring** with real-time callbacks
|
|
20
|
+
- ✅ **Cancellation support** via AbortController pattern
|
|
19
21
|
|
|
20
22
|
## Installation
|
|
21
23
|
|
|
@@ -38,55 +40,280 @@ pnpm install
|
|
|
38
40
|
pnpm run build
|
|
39
41
|
```
|
|
40
42
|
|
|
43
|
+
## Quick Start
|
|
44
|
+
|
|
45
|
+
Initialize a new configuration and start ingesting data in minutes:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Create a new configuration directory
|
|
49
|
+
gql-ingest init ./my-config
|
|
50
|
+
|
|
51
|
+
# Add a new entity
|
|
52
|
+
gql-ingest add users -p ./my-config -f json --fields "id,name,email"
|
|
53
|
+
|
|
54
|
+
# Run ingestion
|
|
55
|
+
gql-ingest -e https://your-api.com/graphql -c ./my-config
|
|
56
|
+
```
|
|
57
|
+
|
|
41
58
|
## Usage
|
|
42
59
|
|
|
43
|
-
### CLI
|
|
60
|
+
### CLI Commands
|
|
61
|
+
|
|
62
|
+
#### Initialize Configuration
|
|
63
|
+
|
|
64
|
+
Create a new configuration directory with example files:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
gql-ingest init [path] [options]
|
|
68
|
+
|
|
69
|
+
Options:
|
|
70
|
+
--no-example Skip creating example entity files
|
|
71
|
+
--no-config Skip creating config.yaml
|
|
72
|
+
-f, --force Overwrite existing files
|
|
73
|
+
-q, --quiet Suppress output
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
This creates:
|
|
77
|
+
|
|
78
|
+
- `data/` - Data files directory
|
|
79
|
+
- `graphql/` - GraphQL mutation files
|
|
80
|
+
- `mappings/` - Mapping configuration files
|
|
81
|
+
- `config.yaml` - Processing configuration
|
|
82
|
+
- Example entity files (by default)
|
|
83
|
+
|
|
84
|
+
#### Add Entity
|
|
85
|
+
|
|
86
|
+
Add a new entity to an existing configuration:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
gql-ingest add <entity-name> [options]
|
|
90
|
+
|
|
91
|
+
Options:
|
|
92
|
+
-p, --path <path> Config directory path (default: current directory)
|
|
93
|
+
-f, --format <format> Data format (csv, json, yaml, jsonl)
|
|
94
|
+
--fields <fields> Comma-separated field names
|
|
95
|
+
--mutation <name> GraphQL mutation name
|
|
96
|
+
--no-interactive Skip prompts, use defaults only
|
|
97
|
+
-q, --quiet Suppress output
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Interactive mode prompts for format, fields, and mutation name. Use `--no-interactive` with flags for CI/CD.
|
|
101
|
+
|
|
102
|
+
#### Run Ingestion
|
|
103
|
+
|
|
104
|
+
Ingest data from configuration into GraphQL API:
|
|
44
105
|
|
|
45
106
|
```bash
|
|
46
107
|
gql-ingest [options]
|
|
47
108
|
|
|
48
109
|
Options:
|
|
49
|
-
-V, --version output the version number
|
|
50
110
|
-e, --endpoint <url> GraphQL endpoint URL (required)
|
|
51
111
|
-c, --config <path> Path to configuration directory (required)
|
|
52
|
-
-n, --entities <list> Comma-separated list of
|
|
53
|
-
-h, --headers <headers> JSON string of headers
|
|
54
|
-
-f, --format <format> Override data format detection
|
|
55
|
-
-
|
|
56
|
-
--help display help for command
|
|
112
|
+
-n, --entities <list> Comma-separated list of entities to process
|
|
113
|
+
-h, --headers <headers> JSON string of headers
|
|
114
|
+
-f, --format <format> Override data format detection
|
|
115
|
+
-q, --quiet Suppress output
|
|
57
116
|
```
|
|
58
117
|
|
|
59
|
-
### Examples
|
|
118
|
+
### CLI Examples
|
|
60
119
|
|
|
61
120
|
```bash
|
|
62
121
|
# Basic usage
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
122
|
+
gql-ingest \
|
|
123
|
+
-e https://your-graphql-api.com/graphql \
|
|
124
|
+
-c ./examples/demo
|
|
66
125
|
|
|
67
126
|
# With authentication headers
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
# With custom headers
|
|
74
|
-
npx @jackchuka/gql-ingest \
|
|
75
|
-
--endpoint https://api.example.com/graphql \
|
|
76
|
-
--config ./my-config \
|
|
77
|
-
--headers '{"X-API-Key": "your-api-key", "Content-Type": "application/json"}'
|
|
127
|
+
gql-ingest \
|
|
128
|
+
-e https://your-graphql-api.com/graphql \
|
|
129
|
+
-c ./examples/demo \
|
|
130
|
+
-h '{"Authorization": "Bearer YOUR_TOKEN"}'
|
|
78
131
|
|
|
79
132
|
# Process specific entities only
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
133
|
+
gql-ingest \
|
|
134
|
+
-e https://your-graphql-api.com/graphql \
|
|
135
|
+
-c ./examples/demo \
|
|
136
|
+
-n users,products
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Programmatic API
|
|
140
|
+
|
|
141
|
+
GQL Ingest provides a full programmatic API for integration into your Node.js applications.
|
|
142
|
+
|
|
143
|
+
#### Installation for API Usage
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
npm install @jackchuka/gql-ingest
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
#### Basic API Usage
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
import { GQLIngest, createConsoleLogger } from "@jackchuka/gql-ingest";
|
|
153
|
+
|
|
154
|
+
// Initialize the client
|
|
155
|
+
const client = new GQLIngest({
|
|
156
|
+
endpoint: "https://your-graphql-api.com/graphql",
|
|
157
|
+
headers: {
|
|
158
|
+
Authorization: "Bearer YOUR_TOKEN",
|
|
159
|
+
},
|
|
160
|
+
logger: createConsoleLogger({ prefix: "my-app" }), // Optional: enable logging with prefix
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Ingest all data from a configuration
|
|
164
|
+
const result = await client.ingest("./config");
|
|
165
|
+
|
|
166
|
+
// Check if ingestion was successful
|
|
167
|
+
if (result.success) {
|
|
168
|
+
console.log("Ingestion completed successfully");
|
|
169
|
+
console.log("Metrics:", result.metrics);
|
|
170
|
+
} else {
|
|
171
|
+
console.error("Ingestion failed:", result.errors);
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
#### Processing Specific Entities
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
// Process only specific entities
|
|
179
|
+
const result = await client.ingestEntities("./config", ["users", "products"]);
|
|
180
|
+
|
|
181
|
+
// Or using the ingest method with options
|
|
182
|
+
const result = await client.ingest("./config", {
|
|
183
|
+
entities: ["users", "products"],
|
|
184
|
+
format: "csv", // Optional: override format detection
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
#### Advanced API Usage
|
|
189
|
+
|
|
190
|
+
For more control, you can access the underlying components directly:
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
import {
|
|
194
|
+
GraphQLClientWrapper,
|
|
195
|
+
DataMapper,
|
|
196
|
+
DependencyResolver,
|
|
197
|
+
MetricsCollector,
|
|
198
|
+
loadConfig,
|
|
199
|
+
createConsoleLogger,
|
|
200
|
+
} from "@jackchuka/gql-ingest";
|
|
201
|
+
|
|
202
|
+
// Create your own custom workflow
|
|
203
|
+
const logger = createConsoleLogger();
|
|
204
|
+
const metrics = new MetricsCollector();
|
|
205
|
+
const client = new GraphQLClientWrapper(endpoint, headers, metrics, logger);
|
|
206
|
+
const mapper = new DataMapper(client, basePath, metrics, logger);
|
|
207
|
+
|
|
208
|
+
// Load configuration
|
|
209
|
+
const config = loadConfig("./config");
|
|
210
|
+
|
|
211
|
+
// Process entities with custom logic
|
|
212
|
+
// ... your custom implementation
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
#### API Methods
|
|
216
|
+
|
|
217
|
+
**GQLIngest Class Methods:**
|
|
218
|
+
|
|
219
|
+
- `constructor(options: GQLIngestOptions)` - Initialize the client
|
|
220
|
+
- `ingest(configPath: string, options?: IngestOptions)` - Ingest data from a configuration
|
|
221
|
+
- `ingestEntities(configPath: string, entities: string[])` - Process specific entities
|
|
222
|
+
- `getMetrics()` - Get current processing metrics
|
|
223
|
+
- `getMetricsSummary()` - Get formatted metrics summary
|
|
224
|
+
- `setLogger(logger: Logger)` - Set custom logger
|
|
225
|
+
- `setHeaders(headers: Record<string, string>)` - Update request headers
|
|
226
|
+
- `cancel(reason?: string)` - Cancel in-progress ingestion
|
|
227
|
+
- `processing` - Property indicating if ingestion is in progress
|
|
228
|
+
|
|
229
|
+
#### Event-Based Progress Monitoring
|
|
230
|
+
|
|
231
|
+
GQLIngest extends EventEmitter, enabling real-time progress tracking and cancellation:
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
import { GQLIngest } from "@jackchuka/gql-ingest";
|
|
235
|
+
|
|
236
|
+
const client = new GQLIngest({
|
|
237
|
+
endpoint: "https://your-api.com/graphql",
|
|
238
|
+
eventOptions: {
|
|
239
|
+
emitRowEvents: true, // Emit events for each row
|
|
240
|
+
emitProgressEvents: true, // Emit periodic progress
|
|
241
|
+
progressInterval: 1000, // Progress every 1 second
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// Listen for events
|
|
246
|
+
client.on("started", (p) => console.log(`Starting ${p.totalEntities} entities`));
|
|
247
|
+
client.on("progress", (p) => console.log(`${p.progressPercent.toFixed(1)}% complete`));
|
|
248
|
+
client.on("entityStart", (p) => console.log(`Processing ${p.entityName}`));
|
|
249
|
+
client.on("entityComplete", (p) =>
|
|
250
|
+
console.log(`${p.entityName}: ${p.metrics.successfulRows} rows`),
|
|
251
|
+
);
|
|
252
|
+
client.on("rowSuccess", (p) => console.log(`Row ${p.rowIndex} OK`));
|
|
253
|
+
client.on("rowFailure", (p) => console.error(`Row ${p.rowIndex} failed: ${p.error.message}`));
|
|
254
|
+
client.on("finished", (p) => console.log(`Done in ${p.durationMs}ms`));
|
|
255
|
+
client.on("errored", (p) => console.error(`Error: ${p.error.message}`));
|
|
256
|
+
client.on("cancelled", (p) => console.log(`Cancelled: ${p.reason}`));
|
|
257
|
+
|
|
258
|
+
// Handle graceful shutdown
|
|
259
|
+
process.on("SIGINT", () => client.cancel("User interrupted"));
|
|
260
|
+
|
|
261
|
+
await client.ingest("./config");
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
**Available Events:**
|
|
265
|
+
|
|
266
|
+
| Event | When Emitted | Key Payload Fields |
|
|
267
|
+
| ---------------- | ------------------------ | ------------------------------------------------- |
|
|
268
|
+
| `started` | Ingestion begins | `configPath`, `entityNames`, `totalWaves` |
|
|
269
|
+
| `progress` | Periodic interval | `progressPercent`, `successfulRows`, `failedRows` |
|
|
270
|
+
| `entityStart` | Entity processing begins | `entityName`, `totalRows`, `waveIndex` |
|
|
271
|
+
| `entityComplete` | Entity processing ends | `entityName`, `metrics`, `success` |
|
|
272
|
+
| `rowSuccess` | Row mutation succeeds | `entityName`, `rowIndex`, `row`, `result` |
|
|
273
|
+
| `rowFailure` | Row mutation fails | `entityName`, `rowIndex`, `error` |
|
|
274
|
+
| `cancelled` | Processing cancelled | `reason`, `metrics`, `elapsedMs` |
|
|
275
|
+
| `finished` | Processing completes | `metrics`, `durationMs`, `allSuccessful` |
|
|
276
|
+
| `errored` | Fatal error occurs | `error`, `metrics`, `elapsedMs` |
|
|
277
|
+
|
|
278
|
+
#### Cancellation Support
|
|
279
|
+
|
|
280
|
+
Cancel in-progress ingestion using the `cancel()` method or external AbortController:
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
// Method 1: Using cancel()
|
|
284
|
+
const client = new GQLIngest({ endpoint: "..." });
|
|
285
|
+
process.on("SIGINT", () => client.cancel("User interrupted"));
|
|
286
|
+
await client.ingest("./config");
|
|
287
|
+
|
|
288
|
+
// Method 2: Using external AbortController
|
|
289
|
+
const controller = new AbortController();
|
|
290
|
+
setTimeout(() => controller.abort("Timeout"), 60000);
|
|
291
|
+
await client.ingest("./config", { signal: controller.signal });
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
#### TypeScript Support
|
|
295
|
+
|
|
296
|
+
Full TypeScript support is included with comprehensive type definitions:
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
import type {
|
|
300
|
+
GQLIngestOptions,
|
|
301
|
+
IngestOptions,
|
|
302
|
+
IngestResult,
|
|
303
|
+
ProcessingMetrics,
|
|
304
|
+
EntityMetrics,
|
|
305
|
+
// Event types
|
|
306
|
+
EventOptions,
|
|
307
|
+
StartedEventPayload,
|
|
308
|
+
ProgressEventPayload,
|
|
309
|
+
EntityStartEventPayload,
|
|
310
|
+
EntityCompleteEventPayload,
|
|
311
|
+
RowSuccessEventPayload,
|
|
312
|
+
RowFailureEventPayload,
|
|
313
|
+
CancelledEventPayload,
|
|
314
|
+
FinishedEventPayload,
|
|
315
|
+
ErroredEventPayload,
|
|
316
|
+
} from "@jackchuka/gql-ingest";
|
|
90
317
|
```
|
|
91
318
|
|
|
92
319
|
## Parallel Processing 🚀
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAepC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkGzD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuC1D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
|