|
| 1 | +import { Connection } from "duckdb-async"; |
| 2 | + |
1 | 3 | import { DbBaseCommand } from "./_base.js"; |
2 | 4 | import getConfig from "../../utils/config.js"; |
| 5 | +import path from "path"; |
| 6 | +import { removeFile, writeFile } from "../../utils/fs.js"; |
| 7 | + |
| 8 | +export interface DbTransformation { |
| 9 | + getSourceTable: () => string; |
| 10 | + getSourceColumns: () => string[]; |
| 11 | + transform: (data: object) => object; |
| 12 | + getDestinationTable: () => string; |
| 13 | +} |
| 14 | + |
| 15 | +export interface DuckDBConnection extends Connection {} |
3 | 16 |
|
4 | 17 | export default class TransformDb extends DbBaseCommand<typeof DbBaseCommand> { |
5 | 18 | static override summary = "Build new tables from existing or transformed data"; |
6 | 19 |
|
7 | 20 | static override examples = ["<%= config.bin %> <%= command.id %>"]; |
8 | 21 |
|
9 | 22 | public async run(): Promise<void> { |
10 | | - const { transformations } = getConfig(); |
| 23 | + const { transformations, dbOutputDir } = getConfig(); |
11 | 24 |
|
12 | 25 | if (!transformations.length) { |
13 | | - throw new Error("No trasformations to run."); |
| 26 | + throw new Error("No transformations to run."); |
14 | 27 | } |
15 | 28 |
|
16 | 29 | for (const transformation of transformations) { |
17 | | - console.log(transformation); |
| 30 | + const sourceTable = transformation.getSourceTable(); |
| 31 | + const sourceCols = transformation.getSourceColumns(); |
| 32 | + const results = await this.dbConn.all(` |
| 33 | + SELECT ${sourceCols.join(", ")} |
| 34 | + FROM '${sourceTable}' |
| 35 | + `); |
| 36 | + const transformed = transformation.transform(results); |
| 37 | + const destinationTable = transformation.getDestinationTable(); |
| 38 | + |
| 39 | + // DuckDB does not support reading from a stringified JSON object |
| 40 | + // https://github.com/duckdb/duckdb/discussions/9558 |
| 41 | + const jsonTmpFile = path.join(dbOutputDir, `${destinationTable}.json`); |
| 42 | + writeFile(jsonTmpFile, JSON.stringify(transformed)); |
| 43 | + |
| 44 | + await this.dbConn.all(` |
| 45 | + DROP TABLE IF EXISTS "${destinationTable}" |
| 46 | + `); |
| 47 | + |
| 48 | + await this.dbConn.all(` |
| 49 | + CREATE TABLE "${destinationTable}" AS |
| 50 | + SELECT * |
| 51 | + FROM read_json('${jsonTmpFile}') |
| 52 | + `); |
| 53 | + |
| 54 | + removeFile(jsonTmpFile); |
| 55 | + console.log( |
| 56 | + `Created table ${destinationTable} from ${sourceTable} with ${results.length} rows` |
| 57 | + ); |
18 | 58 | } |
19 | 59 | } |
20 | 60 | } |
0 commit comments