@api-client/core 0.18.6 → 0.18.7
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/build/src/modeling/importers/CsvImporter.d.ts +40 -6
- package/build/src/modeling/importers/CsvImporter.d.ts.map +1 -1
- package/build/src/modeling/importers/CsvImporter.js +75 -2
- package/build/src/modeling/importers/CsvImporter.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/data/models/example-generator-api.json +23 -23
- package/package.json +1 -1
- package/src/modeling/importers/CsvImporter.ts +115 -5
- package/tests/unit/modeling/importers/csv_importer.spec.ts +351 -0
|
@@ -1,8 +1,35 @@
|
|
|
1
|
-
import { type CSVOptions, type ParseResult } from '@pawel-up/csv';
|
|
1
|
+
import { type CSVOptions, type ParseResult as ParseResult_ } from '@pawel-up/csv';
|
|
2
2
|
import type { DataDomain } from '../DataDomain.js';
|
|
3
3
|
import type { DomainEntity } from '../DomainEntity.js';
|
|
4
4
|
import type { DomainModel } from '../DomainModel.js';
|
|
5
|
-
|
|
5
|
+
interface ParseResult extends ParseResult_ {
|
|
6
|
+
/**
|
|
7
|
+
* The file name of the CSV that was parsed.
|
|
8
|
+
* If the CSV is provided as a string, it will be named `inline_csv_0`, `inline_csv_1`, etc.
|
|
9
|
+
*/
|
|
10
|
+
file: string;
|
|
11
|
+
}
|
|
12
|
+
interface ImportResult {
|
|
13
|
+
/**
|
|
14
|
+
* The DomainEntity created from the CSV data.
|
|
15
|
+
*/
|
|
16
|
+
entity: DomainEntity;
|
|
17
|
+
/**
|
|
18
|
+
* The DomainModel that contains the imported entity.
|
|
19
|
+
*/
|
|
20
|
+
model: DomainModel;
|
|
21
|
+
}
|
|
22
|
+
interface ImportManyResult {
|
|
23
|
+
/**
|
|
24
|
+
* An array of DomainEntity instances created from the CSV data.
|
|
25
|
+
*/
|
|
26
|
+
entities: DomainEntity[];
|
|
27
|
+
/**
|
|
28
|
+
* The DomainModel that contains all imported entities.
|
|
29
|
+
*/
|
|
30
|
+
model: DomainModel;
|
|
31
|
+
}
|
|
32
|
+
export type { CSVOptions, ParseResult, ImportResult, ImportManyResult };
|
|
6
33
|
/**
|
|
7
34
|
* Imports CSV data into a DataDomain.
|
|
8
35
|
*
|
|
@@ -25,6 +52,7 @@ export declare class CsvImporter {
|
|
|
25
52
|
* @returns A promise that resolves with the parsed result.
|
|
26
53
|
*/
|
|
27
54
|
parse(csv: File | string): Promise<ParseResult>;
|
|
55
|
+
private removeExtension;
|
|
28
56
|
/**
|
|
29
57
|
* Imports the parsed CSV data structure into the domain as a new model and entity.
|
|
30
58
|
* It creates a `DomainEntity` where each column from the CSV is represented as a `DomainProperty`.
|
|
@@ -33,9 +61,15 @@ export declare class CsvImporter {
|
|
|
33
61
|
* @param modelName The name to be used for the created `DomainModel` and `DomainEntity`.
|
|
34
62
|
* @returns A promise that resolves when the import is complete.
|
|
35
63
|
*/
|
|
36
|
-
import(data: ParseResult, modelName: string): Promise<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
64
|
+
import(data: ParseResult, modelName: string): Promise<ImportResult>;
|
|
65
|
+
/**
|
|
66
|
+
* Imports multiple parsed CSV data structures into the same data model.
|
|
67
|
+
* Creates a single `DomainModel` with multiple `DomainEntity` instances, one for each CSV data structure.
|
|
68
|
+
* Each entity represents the structure of its corresponding CSV file.
|
|
69
|
+
* @param data Array of objects containing parsed CSV data and entity names.
|
|
70
|
+
* @param modelName The name to be used for the created `DomainModel`.
|
|
71
|
+
* @returns A promise that resolves with the created model and all entities.
|
|
72
|
+
*/
|
|
73
|
+
importMany(data: ParseResult[], modelName: string): Promise<ImportManyResult>;
|
|
40
74
|
}
|
|
41
75
|
//# sourceMappingURL=CsvImporter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CsvImporter.d.ts","sourceRoot":"","sources":["../../../../src/modeling/importers/CsvImporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAa,KAAK,WAAW,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"CsvImporter.d.ts","sourceRoot":"","sources":["../../../../src/modeling/importers/CsvImporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAa,KAAK,WAAW,IAAI,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAGlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpD,UAAU,WAAY,SAAQ,YAAY;IACxC;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAA;CACb;AAID,UAAU,YAAY;IACpB;;OAEG;IACH,MAAM,EAAE,YAAY,CAAA;IACpB;;OAEG;IACH,KAAK,EAAE,WAAW,CAAA;CACnB;AAED,UAAU,gBAAgB;IACxB;;OAEG;IACH,QAAQ,EAAE,YAAY,EAAE,CAAA;IACxB;;OAEG;IACH,KAAK,EAAE,WAAW,CAAA;CACnB;AAED,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB,EAAE,CAAA;AAEvE;;;;;GAKG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,MAAM,CAAY;IAE1B;;;;OAIG;gBACS,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,UAAU;IAKpD;;;;;OAKG;IACU,KAAK,CAAC,GAAG,EAAE,IAAI,GAAG,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAQ5D,OAAO,CAAC,eAAe;IAOvB;;;;;;;OAOG;IACU,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IA6ChF;;;;;;;OAOG;IACU,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAyD3F"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CSVParser } from '@pawel-up/csv';
|
|
2
2
|
import { sanitizeInput, toDatabaseColumnName, toDatabaseTableName } from '../helpers/database.js';
|
|
3
|
+
let increment = 0;
|
|
3
4
|
/**
|
|
4
5
|
* Imports CSV data into a DataDomain.
|
|
5
6
|
*
|
|
@@ -24,8 +25,18 @@ export class CsvImporter {
|
|
|
24
25
|
* @param csv The CSV content to parse, as a File object or a string.
|
|
25
26
|
* @returns A promise that resolves with the parsed result.
|
|
26
27
|
*/
|
|
27
|
-
parse(csv) {
|
|
28
|
-
|
|
28
|
+
async parse(csv) {
|
|
29
|
+
const result = await this.parser.parse(csv);
|
|
30
|
+
return {
|
|
31
|
+
...result,
|
|
32
|
+
file: typeof csv === 'string' ? 'inline_csv_' + increment++ : csv.name,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
removeExtension(name) {
|
|
36
|
+
if (name.endsWith('.csv')) {
|
|
37
|
+
name = name.slice(0, -4); // Remove .csv extension if present
|
|
38
|
+
}
|
|
39
|
+
return name;
|
|
29
40
|
}
|
|
30
41
|
/**
|
|
31
42
|
* Imports the parsed CSV data structure into the domain as a new model and entity.
|
|
@@ -36,6 +47,7 @@ export class CsvImporter {
|
|
|
36
47
|
* @returns A promise that resolves when the import is complete.
|
|
37
48
|
*/
|
|
38
49
|
async import(data, modelName) {
|
|
50
|
+
modelName = this.removeExtension(modelName);
|
|
39
51
|
const name = toDatabaseTableName(modelName, 'imported_cvs_data');
|
|
40
52
|
const model = this.domain.addModel({ info: { name } });
|
|
41
53
|
const entity = model.addEntity({ info: { name } });
|
|
@@ -78,5 +90,66 @@ export class CsvImporter {
|
|
|
78
90
|
}
|
|
79
91
|
return { entity, model };
|
|
80
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Imports multiple parsed CSV data structures into the same data model.
|
|
95
|
+
* Creates a single `DomainModel` with multiple `DomainEntity` instances, one for each CSV data structure.
|
|
96
|
+
* Each entity represents the structure of its corresponding CSV file.
|
|
97
|
+
* @param data Array of objects containing parsed CSV data and entity names.
|
|
98
|
+
* @param modelName The name to be used for the created `DomainModel`.
|
|
99
|
+
* @returns A promise that resolves with the created model and all entities.
|
|
100
|
+
*/
|
|
101
|
+
async importMany(data, modelName) {
|
|
102
|
+
modelName = this.removeExtension(modelName);
|
|
103
|
+
const name = toDatabaseTableName(modelName, 'imported_cvs_data');
|
|
104
|
+
const model = this.domain.addModel({ info: { name } });
|
|
105
|
+
const sanitizedModelName = sanitizeInput(modelName);
|
|
106
|
+
if (name !== sanitizedModelName) {
|
|
107
|
+
model.info.displayName = sanitizedModelName;
|
|
108
|
+
}
|
|
109
|
+
const entities = [];
|
|
110
|
+
for (const { format, values, file } of data) {
|
|
111
|
+
const cleanFile = this.removeExtension(file);
|
|
112
|
+
const entityDbName = toDatabaseTableName(cleanFile, `entity_${entities.length}`);
|
|
113
|
+
const entity = model.addEntity({ info: { name: entityDbName } });
|
|
114
|
+
const sanitizedEntityName = sanitizeInput(cleanFile);
|
|
115
|
+
if (entityDbName !== sanitizedEntityName) {
|
|
116
|
+
entity.info.displayName = sanitizedEntityName;
|
|
117
|
+
}
|
|
118
|
+
const exampleRow = values[0];
|
|
119
|
+
for (const row of format) {
|
|
120
|
+
const { index, name, type, format } = row;
|
|
121
|
+
const columnName = toDatabaseColumnName(name, `column_${index}`);
|
|
122
|
+
const schema = {
|
|
123
|
+
info: { name: columnName },
|
|
124
|
+
type,
|
|
125
|
+
};
|
|
126
|
+
if (format) {
|
|
127
|
+
schema.bindings = [
|
|
128
|
+
{
|
|
129
|
+
type: 'web',
|
|
130
|
+
schema: {
|
|
131
|
+
format: format === 'integer' ? 'int64' : 'double',
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
];
|
|
135
|
+
}
|
|
136
|
+
if (Array.isArray(exampleRow) && exampleRow[index]) {
|
|
137
|
+
const value = exampleRow[index];
|
|
138
|
+
if (value !== undefined && value !== null) {
|
|
139
|
+
schema.schema = {
|
|
140
|
+
examples: [sanitizeInput(String(value))],
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const prop = entity.addProperty(schema);
|
|
145
|
+
const sn = sanitizeInput(name);
|
|
146
|
+
if (sn !== columnName) {
|
|
147
|
+
prop.info.displayName = sn;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
entities.push(entity);
|
|
151
|
+
}
|
|
152
|
+
return { entities, model };
|
|
153
|
+
}
|
|
81
154
|
}
|
|
82
155
|
//# sourceMappingURL=CsvImporter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CsvImporter.js","sourceRoot":"","sources":["../../../../src/modeling/importers/CsvImporter.ts"],"names":[],"mappings":"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","sourcesContent":["import { type CSVOptions, CSVParser, type ParseResult } from '@pawel-up/csv'\nimport type { DataDomain } from '../DataDomain.js'\nimport { sanitizeInput, toDatabaseColumnName, toDatabaseTableName } from '../helpers/database.js'\nimport type { DomainPropertySchema } from '../DomainProperty.js'\nimport type { DomainEntity } from '../DomainEntity.js'\nimport type { DomainModel } from '../DomainModel.js'\n\nexport type { CSVOptions, ParseResult }\n\n/**\n * Imports CSV data into a DataDomain.\n *\n * This class parses CSV files and translates the column definitions into DomainProperty instances\n * within a specified DomainModel and DomainEntity.\n */\nexport class CsvImporter {\n private parser: CSVParser\n private domain: DataDomain\n\n /**\n * Creates an instance of CsvImporter.\n * @param domain The DataDomain to which the imported data will be added.\n * @param options Optional CSV parsing options.\n */\n constructor(domain: DataDomain, options?: CSVOptions) {\n this.parser = new CSVParser(options)\n this.domain = domain\n }\n\n /**\n * Parses a CSV file or string to extract its structure and data.\n * This is a wrapper around the underlying CSV parser.\n * @param csv The CSV content to parse, as a File object or a string.\n * @returns A promise that resolves with the parsed result.\n */\n public parse(csv: File | string): Promise<ParseResult> {\n return this.parser.parse(csv)\n }\n\n /**\n * Imports the parsed CSV data structure into the domain as a new model and entity.\n * It creates a `DomainEntity` where each column from the CSV is represented as a `DomainProperty`.\n * The first row of data is used to provide an example value for each property.\n * @param data The result from the `parse` method, containing the CSV structure and values.\n * @param modelName The name to be used for the created `DomainModel` and `DomainEntity`.\n * @returns A promise that resolves when the import is complete.\n */\n public async import(data: ParseResult, modelName: string): Promise<{ entity: DomainEntity; model: DomainModel }> {\n const name = toDatabaseTableName(modelName, 'imported_cvs_data')\n const model = this.domain.addModel({ info: { name } })\n const entity = model.addEntity({ info: { name } })\n const sanitizedInputName = sanitizeInput(modelName)\n if (name !== sanitizedInputName) {\n model.info.displayName = sanitizedInputName\n entity.info.displayName = sanitizedInputName\n }\n for (const row of data.format) {\n const { index, name, type, format } = row\n const columnName = toDatabaseColumnName(name, `column_${index}`)\n const schema: Partial<DomainPropertySchema> = {\n info: { name: columnName },\n type,\n }\n if (format) {\n schema.bindings = [\n {\n type: 'web',\n schema: {\n format: format === 'integer' ? 'int64' : 'double',\n },\n },\n ]\n }\n const exampleRow = data.values[0]\n if (Array.isArray(exampleRow) && exampleRow[index]) {\n const value = exampleRow[index]\n if (value !== undefined && value !== null) {\n schema.schema = {\n examples: [sanitizeInput(String(value))],\n }\n }\n }\n const prop = entity.addProperty(schema)\n const sn = sanitizeInput(name)\n if (sn !== columnName) {\n prop.info.displayName = sn\n }\n }\n return { entity, model }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"CsvImporter.js","sourceRoot":"","sources":["../../../../src/modeling/importers/CsvImporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,SAAS,EAAoC,MAAM,eAAe,CAAA;AAE5F,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAajG,IAAI,SAAS,GAAG,CAAC,CAAA;AA0BjB;;;;;GAKG;AACH,MAAM,OAAO,WAAW;IACd,MAAM,CAAW;IACjB,MAAM,CAAY;IAE1B;;;;OAIG;IACH,YAAY,MAAkB,EAAE,OAAoB;QAClD,IAAI,CAAC,MAAM,GAAG,IAAI,SAAS,CAAC,OAAO,CAAC,CAAA;QACpC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,KAAK,CAAC,GAAkB;QACnC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC3C,OAAO;YACL,GAAG,MAAM;YACT,IAAI,EAAE,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,GAAG,SAAS,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI;SACvE,CAAA;IACH,CAAC;IAEO,eAAe,CAAC,IAAY;QAClC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA,CAAC,mCAAmC;QAC9D,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,MAAM,CAAC,IAAiB,EAAE,SAAiB;QACtD,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,CAAA;QAC3C,MAAM,IAAI,GAAG,mBAAmB,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAA;QAChE,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAA;QACtD,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAA;QAClD,MAAM,kBAAkB,GAAG,aAAa,CAAC,SAAS,CAAC,CAAA;QACnD,IAAI,IAAI,KAAK,kBAAkB,EAAE,CAAC;YAChC,KAAK,CAAC,IAAI,CAAC,WAAW,GAAG,kBAAkB,CAAA;YAC3C,MAAM,CAAC,IAAI,CAAC,WAAW,GAAG,kBAAkB,CAAA;QAC9C,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAC9B,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAA;YACzC,MAAM,UAAU,GAAG,oBAAoB,CAAC,IAAI,EAAE,UAAU,KAAK,EAAE,CAAC,CAAA;YAChE,MAAM,MAAM,GAAkC;gBAC5C,IAAI,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE;gBAC1B,IAAI;aACL,CAAA;YACD,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,QAAQ,GAAG;oBAChB;wBACE,IAAI,EAAE,KAAK;wBACX,MAAM,EAAE;4BACN,MAAM,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ;yBAClD;qBACF;iBACF,CAAA;YACH,CAAC;YACD,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;YACjC,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;gBACnD,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAA;gBAC/B,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;oBAC1C,MAAM,CAAC,MAAM,GAAG;wBACd,QAAQ,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;qBACzC,CAAA;gBACH,CAAC;YACH,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;YACvC,MAAM,EAAE,GAAG,aAAa,CAAC,IAAI,CAAC,CAAA;YAC9B,IAAI,EAAE,KAAK,UAAU,EAAE,CAAC;gBACtB,IAAI,CAAC,IAAI,CAAC,WAAW,GAAG,EAAE,CAAA;YAC5B,CAAC;QACH,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAA;IAC1B,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,UAAU,CAAC,IAAmB,EAAE,SAAiB;QAC5D,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,CAAA;QAC3C,MAAM,IAAI,GAAG,mBAAmB,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAA;QAChE,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAA;QACtD,MAAM,kBAAkB,GAAG,aAAa,CAAC,SAAS,CAAC,CAAA;QACnD,IAAI,IAAI,KAAK,kBAAkB,EAAE,CAAC;YAChC,KAAK,CAAC,IAAI,CAAC,WAAW,GAAG,kBAAkB,CAAA;QAC7C,CAAC;QAED,MAAM,QAAQ,GAAmB,EAAE,CAAA;QAEnC,KAAK,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC;YAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAA;YAC5C,MAAM,YAAY,GAAG,mBAAmB,CAAC,SAAS,EAAE,UAAU,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAA;YAChF,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,CAAC,CAAA;YAChE,MAAM,mBAAmB,GAAG,aAAa,CAAC,SAAS,CAAC,CAAA;YACpD,IAAI,YAAY,KAAK,mBAAmB,EAAE,CAAC;gBACzC,MAAM,CAAC,IAAI,CAAC,WAAW,GAAG,mBAAmB,CAAA;YAC/C,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;YAC5B,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;gBACzB,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAA;gBACzC,MAAM,UAAU,GAAG,oBAAoB,CAAC,IAAI,EAAE,UAAU,KAAK,EAAE,CAAC,CAAA;gBAChE,MAAM,MAAM,GAAkC;oBAC5C,IAAI,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE;oBAC1B,IAAI;iBACL,CAAA;gBACD,IAAI,MAAM,EAAE,CAAC;oBACX,MAAM,CAAC,QAAQ,GAAG;wBAChB;4BACE,IAAI,EAAE,KAAK;4BACX,MAAM,EAAE;gCACN,MAAM,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ;6BAClD;yBACF;qBACF,CAAA;gBACH,CAAC;gBACD,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;oBACnD,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAA;oBAC/B,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;wBAC1C,MAAM,CAAC,MAAM,GAAG;4BACd,QAAQ,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;yBACzC,CAAA;oBACH,CAAC;gBACH,CAAC;gBACD,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;gBACvC,MAAM,EAAE,GAAG,aAAa,CAAC,IAAI,CAAC,CAAA;gBAC9B,IAAI,EAAE,KAAK,UAAU,EAAE,CAAC;oBACtB,IAAI,CAAC,IAAI,CAAC,WAAW,GAAG,EAAE,CAAA;gBAC5B,CAAC;YACH,CAAC;YACD,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACvB,CAAC;QAED,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;IAC5B,CAAC;CACF","sourcesContent":["import { type CSVOptions, CSVParser, type ParseResult as ParseResult_ } from '@pawel-up/csv'\nimport type { DataDomain } from '../DataDomain.js'\nimport { sanitizeInput, toDatabaseColumnName, toDatabaseTableName } from '../helpers/database.js'\nimport type { DomainPropertySchema } from '../DomainProperty.js'\nimport type { DomainEntity } from '../DomainEntity.js'\nimport type { DomainModel } from '../DomainModel.js'\n\ninterface ParseResult extends ParseResult_ {\n /**\n * The file name of the CSV that was parsed.\n * If the CSV is provided as a string, it will be named `inline_csv_0`, `inline_csv_1`, etc.\n */\n file: string\n}\n\nlet increment = 0\n\ninterface ImportResult {\n /**\n * The DomainEntity created from the CSV data.\n */\n entity: DomainEntity\n /**\n * The DomainModel that contains the imported entity.\n */\n model: DomainModel\n}\n\ninterface ImportManyResult {\n /**\n * An array of DomainEntity instances created from the CSV data.\n */\n entities: DomainEntity[]\n /**\n * The DomainModel that contains all imported entities.\n */\n model: DomainModel\n}\n\nexport type { CSVOptions, ParseResult, ImportResult, ImportManyResult }\n\n/**\n * Imports CSV data into a DataDomain.\n *\n * This class parses CSV files and translates the column definitions into DomainProperty instances\n * within a specified DomainModel and DomainEntity.\n */\nexport class CsvImporter {\n private parser: CSVParser\n private domain: DataDomain\n\n /**\n * Creates an instance of CsvImporter.\n * @param domain The DataDomain to which the imported data will be added.\n * @param options Optional CSV parsing options.\n */\n constructor(domain: DataDomain, options?: CSVOptions) {\n this.parser = new CSVParser(options)\n this.domain = domain\n }\n\n /**\n * Parses a CSV file or string to extract its structure and data.\n * This is a wrapper around the underlying CSV parser.\n * @param csv The CSV content to parse, as a File object or a string.\n * @returns A promise that resolves with the parsed result.\n */\n public async parse(csv: File | string): Promise<ParseResult> {\n const result = await this.parser.parse(csv)\n return {\n ...result,\n file: typeof csv === 'string' ? 'inline_csv_' + increment++ : csv.name,\n }\n }\n\n private removeExtension(name: string): string {\n if (name.endsWith('.csv')) {\n name = name.slice(0, -4) // Remove .csv extension if present\n }\n return name\n }\n\n /**\n * Imports the parsed CSV data structure into the domain as a new model and entity.\n * It creates a `DomainEntity` where each column from the CSV is represented as a `DomainProperty`.\n * The first row of data is used to provide an example value for each property.\n * @param data The result from the `parse` method, containing the CSV structure and values.\n * @param modelName The name to be used for the created `DomainModel` and `DomainEntity`.\n * @returns A promise that resolves when the import is complete.\n */\n public async import(data: ParseResult, modelName: string): Promise<ImportResult> {\n modelName = this.removeExtension(modelName)\n const name = toDatabaseTableName(modelName, 'imported_cvs_data')\n const model = this.domain.addModel({ info: { name } })\n const entity = model.addEntity({ info: { name } })\n const sanitizedInputName = sanitizeInput(modelName)\n if (name !== sanitizedInputName) {\n model.info.displayName = sanitizedInputName\n entity.info.displayName = sanitizedInputName\n }\n for (const row of data.format) {\n const { index, name, type, format } = row\n const columnName = toDatabaseColumnName(name, `column_${index}`)\n const schema: Partial<DomainPropertySchema> = {\n info: { name: columnName },\n type,\n }\n if (format) {\n schema.bindings = [\n {\n type: 'web',\n schema: {\n format: format === 'integer' ? 'int64' : 'double',\n },\n },\n ]\n }\n const exampleRow = data.values[0]\n if (Array.isArray(exampleRow) && exampleRow[index]) {\n const value = exampleRow[index]\n if (value !== undefined && value !== null) {\n schema.schema = {\n examples: [sanitizeInput(String(value))],\n }\n }\n }\n const prop = entity.addProperty(schema)\n const sn = sanitizeInput(name)\n if (sn !== columnName) {\n prop.info.displayName = sn\n }\n }\n return { entity, model }\n }\n\n /**\n * Imports multiple parsed CSV data structures into the same data model.\n * Creates a single `DomainModel` with multiple `DomainEntity` instances, one for each CSV data structure.\n * Each entity represents the structure of its corresponding CSV file.\n * @param data Array of objects containing parsed CSV data and entity names.\n * @param modelName The name to be used for the created `DomainModel`.\n * @returns A promise that resolves with the created model and all entities.\n */\n public async importMany(data: ParseResult[], modelName: string): Promise<ImportManyResult> {\n modelName = this.removeExtension(modelName)\n const name = toDatabaseTableName(modelName, 'imported_cvs_data')\n const model = this.domain.addModel({ info: { name } })\n const sanitizedModelName = sanitizeInput(modelName)\n if (name !== sanitizedModelName) {\n model.info.displayName = sanitizedModelName\n }\n\n const entities: DomainEntity[] = []\n\n for (const { format, values, file } of data) {\n const cleanFile = this.removeExtension(file)\n const entityDbName = toDatabaseTableName(cleanFile, `entity_${entities.length}`)\n const entity = model.addEntity({ info: { name: entityDbName } })\n const sanitizedEntityName = sanitizeInput(cleanFile)\n if (entityDbName !== sanitizedEntityName) {\n entity.info.displayName = sanitizedEntityName\n }\n\n const exampleRow = values[0]\n for (const row of format) {\n const { index, name, type, format } = row\n const columnName = toDatabaseColumnName(name, `column_${index}`)\n const schema: Partial<DomainPropertySchema> = {\n info: { name: columnName },\n type,\n }\n if (format) {\n schema.bindings = [\n {\n type: 'web',\n schema: {\n format: format === 'integer' ? 'int64' : 'double',\n },\n },\n ]\n }\n if (Array.isArray(exampleRow) && exampleRow[index]) {\n const value = exampleRow[index]\n if (value !== undefined && value !== null) {\n schema.schema = {\n examples: [sanitizeInput(String(value))],\n }\n }\n }\n const prop = entity.addProperty(schema)\n const sn = sanitizeInput(name)\n if (sn !== columnName) {\n prop.info.displayName = sn\n }\n }\n entities.push(entity)\n }\n\n return { entities, model }\n }\n}\n"]}
|