@frictionless-ts/database 1.0.1
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.md +9 -0
- package/README.md +3 -0
- package/build/adapters/base.d.ts +20 -0
- package/build/adapters/base.js +66 -0
- package/build/adapters/create.d.ts +5 -0
- package/build/adapters/create.js +17 -0
- package/build/adapters/mysql.d.ts +10 -0
- package/build/adapters/mysql.js +90 -0
- package/build/adapters/mysql.spec.d.ts +1 -0
- package/build/adapters/mysql.spec.js +170 -0
- package/build/adapters/postgresql.d.ts +10 -0
- package/build/adapters/postgresql.js +100 -0
- package/build/adapters/postgresql.spec.d.ts +1 -0
- package/build/adapters/postgresql.spec.js +170 -0
- package/build/adapters/sqlite.bun.d.ts +2 -0
- package/build/adapters/sqlite.bun.js +7 -0
- package/build/adapters/sqlite.d.ts +11 -0
- package/build/adapters/sqlite.js +57 -0
- package/build/adapters/sqlite.node.d.ts +2 -0
- package/build/adapters/sqlite.node.js +43 -0
- package/build/adapters/sqlite.spec.d.ts +1 -0
- package/build/adapters/sqlite.spec.js +252 -0
- package/build/field/Field.d.ts +3 -0
- package/build/field/Field.js +2 -0
- package/build/field/Type.d.ts +2 -0
- package/build/field/Type.js +2 -0
- package/build/field/index.d.ts +2 -0
- package/build/field/index.js +2 -0
- package/build/index.d.ts +6 -0
- package/build/index.js +7 -0
- package/build/package/index.d.ts +2 -0
- package/build/package/index.js +3 -0
- package/build/package/load.d.ts +7 -0
- package/build/package/load.js +30 -0
- package/build/package/save.d.ts +10 -0
- package/build/package/save.js +28 -0
- package/build/plugin.d.ts +15 -0
- package/build/plugin.js +54 -0
- package/build/plugin.spec.d.ts +1 -0
- package/build/plugin.spec.js +328 -0
- package/build/resource/Format.d.ts +1 -0
- package/build/resource/Format.js +2 -0
- package/build/resource/index.d.ts +1 -0
- package/build/resource/index.js +2 -0
- package/build/schema/Schema.d.ts +4 -0
- package/build/schema/Schema.js +2 -0
- package/build/schema/index.d.ts +2 -0
- package/build/schema/index.js +2 -0
- package/build/schema/infer.d.ts +4 -0
- package/build/schema/infer.js +24 -0
- package/build/schema/infer.spec.d.ts +1 -0
- package/build/schema/infer.spec.js +25 -0
- package/build/table/index.d.ts +2 -0
- package/build/table/index.js +3 -0
- package/build/table/load.d.ts +6 -0
- package/build/table/load.js +29 -0
- package/build/table/load.spec.d.ts +1 -0
- package/build/table/load.spec.js +24 -0
- package/build/table/save.d.ts +4 -0
- package/build/table/save.js +57 -0
- package/build/table/save.spec.d.ts +1 -0
- package/build/table/save.spec.js +20 -0
- package/package.json +45 -0
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import * as pl from "nodejs-polars";
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import * as packageModule from "./package/index.js";
|
|
4
|
+
import { DatabasePlugin } from "./plugin.js";
|
|
5
|
+
import * as schemaModule from "./schema/index.js";
|
|
6
|
+
import * as tableModule from "./table/index.js";
|
|
7
|
+
vi.mock("./package/index.ts", () => ({
|
|
8
|
+
loadPackageFromDatabase: vi.fn(),
|
|
9
|
+
savePackageToDatabase: vi.fn(),
|
|
10
|
+
}));
|
|
11
|
+
vi.mock("./table/index.ts", () => ({
|
|
12
|
+
loadDatabaseTable: vi.fn(),
|
|
13
|
+
saveDatabaseTable: vi.fn(),
|
|
14
|
+
}));
|
|
15
|
+
vi.mock("./schema/index.ts", () => ({
|
|
16
|
+
inferDatabaseSchema: vi.fn(),
|
|
17
|
+
}));
|
|
18
|
+
describe("DatabasePlugin", () => {
|
|
19
|
+
let plugin;
|
|
20
|
+
let mockLoadPackageFromDatabase;
|
|
21
|
+
let mockSavePackageToDatabase;
|
|
22
|
+
let mockLoadDatabaseTable;
|
|
23
|
+
let mockSaveDatabaseTable;
|
|
24
|
+
let mockInferDatabaseSchema;
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
plugin = new DatabasePlugin();
|
|
27
|
+
mockLoadPackageFromDatabase = vi.mocked(packageModule.loadPackageFromDatabase);
|
|
28
|
+
mockSavePackageToDatabase = vi.mocked(packageModule.savePackageToDatabase);
|
|
29
|
+
mockLoadDatabaseTable = vi.mocked(tableModule.loadDatabaseTable);
|
|
30
|
+
mockSaveDatabaseTable = vi.mocked(tableModule.saveDatabaseTable);
|
|
31
|
+
mockInferDatabaseSchema = vi.mocked(schemaModule.inferDatabaseSchema);
|
|
32
|
+
vi.clearAllMocks();
|
|
33
|
+
});
|
|
34
|
+
describe("loadPackage", () => {
|
|
35
|
+
it("should load package from postgresql database", async () => {
|
|
36
|
+
const mockPackage = {
|
|
37
|
+
name: "test-package",
|
|
38
|
+
resources: [{ name: "test", data: [] }],
|
|
39
|
+
};
|
|
40
|
+
mockLoadPackageFromDatabase.mockResolvedValue(mockPackage);
|
|
41
|
+
const result = await plugin.loadPackage("postgresql://localhost/testdb");
|
|
42
|
+
expect(mockLoadPackageFromDatabase).toHaveBeenCalledWith("postgresql://localhost/testdb", { format: "postgresql" });
|
|
43
|
+
expect(result).toEqual(mockPackage);
|
|
44
|
+
});
|
|
45
|
+
it("should load package from mysql database", async () => {
|
|
46
|
+
const mockPackage = {
|
|
47
|
+
name: "test-package",
|
|
48
|
+
resources: [{ name: "test", data: [] }],
|
|
49
|
+
};
|
|
50
|
+
mockLoadPackageFromDatabase.mockResolvedValue(mockPackage);
|
|
51
|
+
const result = await plugin.loadPackage("mysql://localhost/testdb");
|
|
52
|
+
expect(mockLoadPackageFromDatabase).toHaveBeenCalledWith("mysql://localhost/testdb", { format: "mysql" });
|
|
53
|
+
expect(result).toEqual(mockPackage);
|
|
54
|
+
});
|
|
55
|
+
it("should load package from sqlite database", async () => {
|
|
56
|
+
const mockPackage = {
|
|
57
|
+
name: "test-package",
|
|
58
|
+
resources: [{ name: "test", data: [] }],
|
|
59
|
+
};
|
|
60
|
+
mockLoadPackageFromDatabase.mockResolvedValue(mockPackage);
|
|
61
|
+
const result = await plugin.loadPackage("sqlite://test.db");
|
|
62
|
+
expect(mockLoadPackageFromDatabase).toHaveBeenCalledWith("sqlite://test.db", {
|
|
63
|
+
format: "sqlite",
|
|
64
|
+
});
|
|
65
|
+
expect(result).toEqual(mockPackage);
|
|
66
|
+
});
|
|
67
|
+
it("should return undefined for non-database sources", async () => {
|
|
68
|
+
const result = await plugin.loadPackage("test.csv");
|
|
69
|
+
expect(mockLoadPackageFromDatabase).not.toHaveBeenCalled();
|
|
70
|
+
expect(result).toBeUndefined();
|
|
71
|
+
});
|
|
72
|
+
it("should return undefined for http urls", async () => {
|
|
73
|
+
const result = await plugin.loadPackage("https://example.com/data");
|
|
74
|
+
expect(mockLoadPackageFromDatabase).not.toHaveBeenCalled();
|
|
75
|
+
expect(result).toBeUndefined();
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
describe("savePackage", () => {
|
|
79
|
+
it("should save package to postgresql database", async () => {
|
|
80
|
+
const mockPackage = {
|
|
81
|
+
name: "test-package",
|
|
82
|
+
resources: [{ name: "test", data: [] }],
|
|
83
|
+
};
|
|
84
|
+
mockSavePackageToDatabase.mockResolvedValue(undefined);
|
|
85
|
+
await plugin.savePackage(mockPackage, {
|
|
86
|
+
target: "postgresql://localhost/testdb",
|
|
87
|
+
});
|
|
88
|
+
expect(mockSavePackageToDatabase).toHaveBeenCalledWith(mockPackage, {
|
|
89
|
+
target: "postgresql://localhost/testdb",
|
|
90
|
+
format: "postgresql",
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
it("should save package to mysql database", async () => {
|
|
94
|
+
const mockPackage = {
|
|
95
|
+
name: "test-package",
|
|
96
|
+
resources: [{ name: "test", data: [] }],
|
|
97
|
+
};
|
|
98
|
+
mockSavePackageToDatabase.mockResolvedValue(undefined);
|
|
99
|
+
await plugin.savePackage(mockPackage, {
|
|
100
|
+
target: "mysql://localhost/testdb",
|
|
101
|
+
});
|
|
102
|
+
expect(mockSavePackageToDatabase).toHaveBeenCalledWith(mockPackage, {
|
|
103
|
+
target: "mysql://localhost/testdb",
|
|
104
|
+
format: "mysql",
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
it("should save package to sqlite database", async () => {
|
|
108
|
+
const mockPackage = {
|
|
109
|
+
name: "test-package",
|
|
110
|
+
resources: [{ name: "test", data: [] }],
|
|
111
|
+
};
|
|
112
|
+
mockSavePackageToDatabase.mockResolvedValue(undefined);
|
|
113
|
+
await plugin.savePackage(mockPackage, { target: "sqlite://test.db" });
|
|
114
|
+
expect(mockSavePackageToDatabase).toHaveBeenCalledWith(mockPackage, {
|
|
115
|
+
target: "sqlite://test.db",
|
|
116
|
+
format: "sqlite",
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
it("should return undefined for non-database targets", async () => {
|
|
120
|
+
const mockPackage = {
|
|
121
|
+
name: "test-package",
|
|
122
|
+
resources: [{ name: "test", data: [] }],
|
|
123
|
+
};
|
|
124
|
+
const result = await plugin.savePackage(mockPackage, {
|
|
125
|
+
target: "test.csv",
|
|
126
|
+
});
|
|
127
|
+
expect(mockSavePackageToDatabase).not.toHaveBeenCalled();
|
|
128
|
+
expect(result).toBeUndefined();
|
|
129
|
+
});
|
|
130
|
+
it("should pass through plugins option", async () => {
|
|
131
|
+
const mockPackage = {
|
|
132
|
+
name: "test-package",
|
|
133
|
+
resources: [{ name: "test", data: [] }],
|
|
134
|
+
};
|
|
135
|
+
const mockPlugins = [];
|
|
136
|
+
mockSavePackageToDatabase.mockResolvedValue(undefined);
|
|
137
|
+
await plugin.savePackage(mockPackage, {
|
|
138
|
+
target: "sqlite://test.db",
|
|
139
|
+
plugins: mockPlugins,
|
|
140
|
+
});
|
|
141
|
+
expect(mockSavePackageToDatabase).toHaveBeenCalledWith(mockPackage, {
|
|
142
|
+
target: "sqlite://test.db",
|
|
143
|
+
format: "sqlite",
|
|
144
|
+
plugins: mockPlugins,
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
describe("loadTable", () => {
|
|
149
|
+
it("should load table from postgresql resource", async () => {
|
|
150
|
+
const resource = {
|
|
151
|
+
path: "postgresql://localhost/testdb",
|
|
152
|
+
};
|
|
153
|
+
const mockTable = pl.DataFrame().lazy();
|
|
154
|
+
mockLoadDatabaseTable.mockResolvedValue(mockTable);
|
|
155
|
+
const result = await plugin.loadTable(resource);
|
|
156
|
+
expect(mockLoadDatabaseTable).toHaveBeenCalledWith({
|
|
157
|
+
...resource,
|
|
158
|
+
format: "postgresql",
|
|
159
|
+
});
|
|
160
|
+
expect(result).toEqual(mockTable);
|
|
161
|
+
});
|
|
162
|
+
it("should load table from mysql resource", async () => {
|
|
163
|
+
const resource = {
|
|
164
|
+
path: "mysql://localhost/testdb",
|
|
165
|
+
};
|
|
166
|
+
const mockTable = pl.DataFrame().lazy();
|
|
167
|
+
mockLoadDatabaseTable.mockResolvedValue(mockTable);
|
|
168
|
+
const result = await plugin.loadTable(resource);
|
|
169
|
+
expect(mockLoadDatabaseTable).toHaveBeenCalledWith({
|
|
170
|
+
...resource,
|
|
171
|
+
format: "mysql",
|
|
172
|
+
});
|
|
173
|
+
expect(result).toEqual(mockTable);
|
|
174
|
+
});
|
|
175
|
+
it("should load table from sqlite resource", async () => {
|
|
176
|
+
const resource = {
|
|
177
|
+
path: "sqlite://test.db",
|
|
178
|
+
};
|
|
179
|
+
const mockTable = pl.DataFrame().lazy();
|
|
180
|
+
mockLoadDatabaseTable.mockResolvedValue(mockTable);
|
|
181
|
+
const result = await plugin.loadTable(resource);
|
|
182
|
+
expect(mockLoadDatabaseTable).toHaveBeenCalledWith({
|
|
183
|
+
...resource,
|
|
184
|
+
format: "sqlite",
|
|
185
|
+
});
|
|
186
|
+
expect(result).toEqual(mockTable);
|
|
187
|
+
});
|
|
188
|
+
it("should return undefined for non-database resources", async () => {
|
|
189
|
+
const resource = {
|
|
190
|
+
path: "test.csv",
|
|
191
|
+
};
|
|
192
|
+
const result = await plugin.loadTable(resource);
|
|
193
|
+
expect(mockLoadDatabaseTable).not.toHaveBeenCalled();
|
|
194
|
+
expect(result).toBeUndefined();
|
|
195
|
+
});
|
|
196
|
+
it("should handle explicit format specification", async () => {
|
|
197
|
+
const resource = {
|
|
198
|
+
path: "test.txt",
|
|
199
|
+
format: "sqlite",
|
|
200
|
+
};
|
|
201
|
+
const mockTable = pl.DataFrame().lazy();
|
|
202
|
+
mockLoadDatabaseTable.mockResolvedValue(mockTable);
|
|
203
|
+
const result = await plugin.loadTable(resource);
|
|
204
|
+
expect(mockLoadDatabaseTable).toHaveBeenCalledWith({
|
|
205
|
+
...resource,
|
|
206
|
+
format: "sqlite",
|
|
207
|
+
});
|
|
208
|
+
expect(result).toEqual(mockTable);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
describe("saveTable", () => {
|
|
212
|
+
it("should save table to postgresql database", async () => {
|
|
213
|
+
const table = pl.DataFrame().lazy();
|
|
214
|
+
const options = { path: "postgresql://localhost/testdb" };
|
|
215
|
+
mockSaveDatabaseTable.mockResolvedValue("postgresql://localhost/testdb");
|
|
216
|
+
const result = await plugin.saveTable(table, options);
|
|
217
|
+
expect(mockSaveDatabaseTable).toHaveBeenCalledWith(table, {
|
|
218
|
+
...options,
|
|
219
|
+
format: "postgresql",
|
|
220
|
+
});
|
|
221
|
+
expect(result).toBe("postgresql://localhost/testdb");
|
|
222
|
+
});
|
|
223
|
+
it("should save table to mysql database", async () => {
|
|
224
|
+
const table = pl.DataFrame().lazy();
|
|
225
|
+
const options = { path: "mysql://localhost/testdb" };
|
|
226
|
+
mockSaveDatabaseTable.mockResolvedValue("mysql://localhost/testdb");
|
|
227
|
+
const result = await plugin.saveTable(table, options);
|
|
228
|
+
expect(mockSaveDatabaseTable).toHaveBeenCalledWith(table, {
|
|
229
|
+
...options,
|
|
230
|
+
format: "mysql",
|
|
231
|
+
});
|
|
232
|
+
expect(result).toBe("mysql://localhost/testdb");
|
|
233
|
+
});
|
|
234
|
+
it("should save table to sqlite database", async () => {
|
|
235
|
+
const table = pl.DataFrame().lazy();
|
|
236
|
+
const options = { path: "sqlite://test.db" };
|
|
237
|
+
mockSaveDatabaseTable.mockResolvedValue("sqlite://test.db");
|
|
238
|
+
const result = await plugin.saveTable(table, options);
|
|
239
|
+
expect(mockSaveDatabaseTable).toHaveBeenCalledWith(table, {
|
|
240
|
+
...options,
|
|
241
|
+
format: "sqlite",
|
|
242
|
+
});
|
|
243
|
+
expect(result).toBe("sqlite://test.db");
|
|
244
|
+
});
|
|
245
|
+
it("should return undefined for non-database paths", async () => {
|
|
246
|
+
const table = pl.DataFrame().lazy();
|
|
247
|
+
const options = { path: "output.csv" };
|
|
248
|
+
const result = await plugin.saveTable(table, options);
|
|
249
|
+
expect(mockSaveDatabaseTable).not.toHaveBeenCalled();
|
|
250
|
+
expect(result).toBeUndefined();
|
|
251
|
+
});
|
|
252
|
+
it("should handle explicit format specification", async () => {
|
|
253
|
+
const table = pl.DataFrame().lazy();
|
|
254
|
+
const options = { path: "test.txt", format: "sqlite" };
|
|
255
|
+
mockSaveDatabaseTable.mockResolvedValue("test.txt");
|
|
256
|
+
const result = await plugin.saveTable(table, options);
|
|
257
|
+
expect(mockSaveDatabaseTable).toHaveBeenCalledWith(table, {
|
|
258
|
+
...options,
|
|
259
|
+
format: "sqlite",
|
|
260
|
+
});
|
|
261
|
+
expect(result).toBe("test.txt");
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
describe("inferSchema", () => {
|
|
265
|
+
it("should infer schema for postgresql resource", async () => {
|
|
266
|
+
const resource = {
|
|
267
|
+
path: "postgresql://localhost/testdb",
|
|
268
|
+
};
|
|
269
|
+
const mockSchema = { fields: [] };
|
|
270
|
+
mockInferDatabaseSchema.mockResolvedValue(mockSchema);
|
|
271
|
+
const result = await plugin.inferSchema(resource);
|
|
272
|
+
expect(mockInferDatabaseSchema).toHaveBeenCalledWith({
|
|
273
|
+
...resource,
|
|
274
|
+
format: "postgresql",
|
|
275
|
+
});
|
|
276
|
+
expect(result).toEqual(mockSchema);
|
|
277
|
+
});
|
|
278
|
+
it("should infer schema for mysql resource", async () => {
|
|
279
|
+
const resource = {
|
|
280
|
+
path: "mysql://localhost/testdb",
|
|
281
|
+
};
|
|
282
|
+
const mockSchema = { fields: [] };
|
|
283
|
+
mockInferDatabaseSchema.mockResolvedValue(mockSchema);
|
|
284
|
+
const result = await plugin.inferSchema(resource);
|
|
285
|
+
expect(mockInferDatabaseSchema).toHaveBeenCalledWith({
|
|
286
|
+
...resource,
|
|
287
|
+
format: "mysql",
|
|
288
|
+
});
|
|
289
|
+
expect(result).toEqual(mockSchema);
|
|
290
|
+
});
|
|
291
|
+
it("should infer schema for sqlite resource", async () => {
|
|
292
|
+
const resource = {
|
|
293
|
+
path: "sqlite://test.db",
|
|
294
|
+
};
|
|
295
|
+
const mockSchema = { fields: [] };
|
|
296
|
+
mockInferDatabaseSchema.mockResolvedValue(mockSchema);
|
|
297
|
+
const result = await plugin.inferSchema(resource);
|
|
298
|
+
expect(mockInferDatabaseSchema).toHaveBeenCalledWith({
|
|
299
|
+
...resource,
|
|
300
|
+
format: "sqlite",
|
|
301
|
+
});
|
|
302
|
+
expect(result).toEqual(mockSchema);
|
|
303
|
+
});
|
|
304
|
+
it("should return undefined for non-database resources", async () => {
|
|
305
|
+
const resource = {
|
|
306
|
+
path: "test.csv",
|
|
307
|
+
};
|
|
308
|
+
const result = await plugin.inferSchema(resource);
|
|
309
|
+
expect(mockInferDatabaseSchema).not.toHaveBeenCalled();
|
|
310
|
+
expect(result).toBeUndefined();
|
|
311
|
+
});
|
|
312
|
+
it("should handle explicit format specification", async () => {
|
|
313
|
+
const resource = {
|
|
314
|
+
path: "test.txt",
|
|
315
|
+
format: "sqlite",
|
|
316
|
+
};
|
|
317
|
+
const mockSchema = { fields: [] };
|
|
318
|
+
mockInferDatabaseSchema.mockResolvedValue(mockSchema);
|
|
319
|
+
const result = await plugin.inferSchema(resource);
|
|
320
|
+
expect(mockInferDatabaseSchema).toHaveBeenCalledWith({
|
|
321
|
+
...resource,
|
|
322
|
+
format: "sqlite",
|
|
323
|
+
});
|
|
324
|
+
expect(result).toEqual(mockSchema);
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLnNwZWMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9wbHVnaW4uc3BlYy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEtBQUssRUFBRSxNQUFNLGVBQWUsQ0FBQTtBQUNuQyxPQUFPLEVBQUUsVUFBVSxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxNQUFNLFFBQVEsQ0FBQTtBQUM3RCxPQUFPLEtBQUssYUFBYSxNQUFNLG9CQUFvQixDQUFBO0FBQ25ELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxhQUFhLENBQUE7QUFDNUMsT0FBTyxLQUFLLFlBQVksTUFBTSxtQkFBbUIsQ0FBQTtBQUNqRCxPQUFPLEtBQUssV0FBVyxNQUFNLGtCQUFrQixDQUFBO0FBRS9DLEVBQUUsQ0FBQyxJQUFJLENBQUMsb0JBQW9CLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztJQUNuQyx1QkFBdUIsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ2hDLHFCQUFxQixFQUFFLEVBQUUsQ0FBQyxFQUFFLEVBQUU7Q0FDL0IsQ0FBQyxDQUFDLENBQUE7QUFFSCxFQUFFLENBQUMsSUFBSSxDQUFDLGtCQUFrQixFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDakMsaUJBQWlCLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRTtJQUMxQixpQkFBaUIsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFO0NBQzNCLENBQUMsQ0FBQyxDQUFBO0FBRUgsRUFBRSxDQUFDLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDO0lBQ2xDLG1CQUFtQixFQUFFLEVBQUUsQ0FBQyxFQUFFLEVBQUU7Q0FDN0IsQ0FBQyxDQUFDLENBQUE7QUFFSCxRQUFRLENBQUMsZ0JBQWdCLEVBQUUsR0FBRyxFQUFFO0lBQzlCLElBQUksTUFBc0IsQ0FBQTtJQUMxQixJQUFJLDJCQUFxRCxDQUFBO0lBQ3pELElBQUkseUJB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QyxVQUFVLENBQUMsQ0FBQTtZQUVyRCxNQUFNLE1BQU0sR0FBRyxNQUFNLE1BQU0sQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLENBQUE7WUFFakQsTUFBTSxDQUFDLHVCQUF1QixDQUFDLENBQUMsb0JBQW9CLENBQUM7Z0JBQ25ELEdBQUcsUUFBUTtnQkFDWCxNQUFNLEVBQUUsUUFBUTthQUNqQixDQUFDLENBQUE7WUFDRixNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFBO1FBQ3BDLENBQUMsQ0FBQyxDQUFBO0lBQ0osQ0FBQyxDQUFDLENBQUE7QUFDSixDQUFDLENBQUMsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgUGFja2FnZSwgUmVzb3VyY2UgfSBmcm9tIFwiQGZyaWN0aW9ubGVzcy10cy9tZXRhZGF0YVwiXG5pbXBvcnQgKiBhcyBwbCBmcm9tIFwibm9kZWpzLXBvbGFyc1wiXG5pbXBvcnQgeyBiZWZvcmVFYWNoLCBkZXNjcmliZSwgZXhwZWN0LCBpdCwgdmkgfSBmcm9tIFwidml0ZXN0XCJcbmltcG9ydCAqIGFzIHBhY2thZ2VNb2R1bGUgZnJvbSBcIi4vcGFja2FnZS9pbmRleC50c1wiXG5pbXBvcnQgeyBEYXRhYmFzZVBsdWdpbiB9IGZyb20gXCIuL3BsdWdpbi50c1wiXG5pbXBvcnQgKiBhcyBzY2hlbWFNb2R1bGUgZnJvbSBcIi4vc2NoZW1hL2luZGV4LnRzXCJcbmltcG9ydCAqIGFzIHRhYmxlTW9kdWxlIGZyb20gXCIuL3RhYmxlL2luZGV4LnRzXCJcblxudmkubW9jayhcIi4vcGFja2FnZS9pbmRleC50c1wiLCAoKSA9PiAoe1xuICBsb2FkUGFja2FnZUZyb21EYXRhYmFzZTogdmkuZm4oKSxcbiAgc2F2ZVBhY2thZ2VUb0RhdGFiYXNlOiB2aS5mbigpLFxufSkpXG5cbnZpLm1vY2soXCIuL3RhYmxlL2luZGV4LnRzXCIsICgpID0+ICh7XG4gIGxvYWREYXRhYmFzZVRhYmxlOiB2aS5mbigpLFxuICBzYXZlRGF0YWJhc2VUYWJsZTogdmkuZm4oKSxcbn0pKVxuXG52aS5tb2NrKFwiLi9zY2hlbWEvaW5kZXgudHNcIiwgKCkgPT4gKHtcbiAgaW5mZXJEYXRhYmFzZVNjaGVtYTogdmkuZm4oKSxcbn0pKVxuXG5kZXNjcmliZShcIkRhdGFiYXNlUGx1Z2luXCIsICgpID0+IHtcbiAgbGV0IHBsdWdpbjogRGF0YWJhc2VQbHVnaW5cbiAgbGV0IG1vY2tMb2FkUGFja2FnZUZyb21EYXRhYmFzZTogUmV0dXJuVHlwZTx0eXBlb2YgdmkuZm4+XG4gIGxldCBtb2NrU2F2ZVBhY2thZ2VUb0RhdGFiYXNlOiBSZXR1cm5UeXBlPHR5cGVvZiB2aS5mbj5cbiAgbGV0IG1vY2tMb2FkRGF0YWJhc2VUYWJsZTogUmV0dXJuVHlwZTx0eXBlb2YgdmkuZm4+XG4gIGxldCBtb2NrU2F2ZURhdGFiYXNlVGFibGU6IFJldHVyblR5cGU8dHlwZW9mIHZpLmZuPlxuICBsZXQgbW9ja0luZmVyRGF0YWJhc2VTY2hlbWE6IFJldHVyblR5cGU8dHlwZW9mIHZpLmZuPlxuXG4gIGJlZm9yZUVhY2goKCkgPT4ge1xuICAgIHBsdWdpbiA9IG5ldyBEYXRhYmFzZVBsdWdpbigpXG4gICAgbW9ja0xvYWRQYWNrYWdlRnJvbURhdGFiYXNlID0gdmkubW9ja2VkKFxuICAgICAgcGFja2FnZU1vZHVsZS5sb2FkUGFja2FnZUZyb21EYXRhYmFzZSxcbiAgICApXG4gICAgbW9ja1NhdmVQYWNrYWdlVG9EYXRhYmFzZSA9IHZpLm1vY2tlZChwYWNrYWdlTW9kdWxlLnNhdmVQYWNrYWdlVG9EYXRhYmFzZSlcbiAgICBtb2NrTG9hZERhdGFiYXNlVGFibGUgPSB2aS5tb2NrZWQodGFibGVNb2R1bGUubG9hZERhdGFiYXNlVGFibGUpXG4gICAgbW9ja1NhdmVEYXRhYmFzZVRhYmxlID0gdmkubW9ja2VkKHRhYmxlTW9kdWxlLnNhdmVEYXRhYmFzZVRhYmxlKVxuICAgIG1vY2tJbmZlckRhdGFiYXNlU2NoZW1hID0gdmkubW9ja2VkKHNjaGVtYU1vZHVsZS5pbmZlckRhdGFiYXNlU2NoZW1hKVxuICAgIHZpLmNsZWFyQWxsTW9ja3MoKVxuICB9KVxuXG4gIGRlc2NyaWJlKFwibG9hZFBhY2thZ2VcIiwgKCkgPT4ge1xuICAgIGl0KFwic2hvdWxkIGxvYWQgcGFja2FnZSBmcm9tIHBvc3RncmVzcWwgZGF0YWJhc2VcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgbW9ja1BhY2thZ2U6IFBhY2thZ2UgPSB7XG4gICAgICAgIG5hbWU6IFwidGVzdC1wYWNrYWdlXCIsXG4gICAgICAgIHJlc291cmNlczogW3sgbmFtZTogXCJ0ZXN0XCIsIGRhdGE6IFtdIH1dLFxuICAgICAgfVxuICAgICAgbW9ja0xvYWRQYWNrYWdlRnJvbURhdGFiYXNlLm1vY2tSZXNvbHZlZFZhbHVlKG1vY2tQYWNrYWdlKVxuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwbHVnaW4ubG9hZFBhY2thZ2UoXCJwb3N0Z3Jlc3FsOi8vbG9jYWxob3N0L3Rlc3RkYlwiKVxuXG4gICAgICBleHBlY3QobW9ja0xvYWRQYWNrYWdlRnJvbURhdGFiYXNlKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICAgICAgXCJwb3N0Z3Jlc3FsOi8vbG9jYWxob3N0L3Rlc3RkYlwiLFxuICAgICAgICB7IGZvcm1hdDogXCJwb3N0Z3Jlc3FsXCIgfSxcbiAgICAgIClcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvRXF1YWwobW9ja1BhY2thZ2UpXG4gICAgfSlcblxuICAgIGl0KFwic2hvdWxkIGxvYWQgcGFja2FnZSBmcm9tIG15c3FsIGRhdGFiYXNlXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IG1vY2tQYWNrYWdlOiBQYWNrYWdlID0ge1xuICAgICAgICBuYW1lOiBcInRlc3QtcGFja2FnZVwiLFxuICAgICAgICByZXNvdXJjZXM6IFt7IG5hbWU6IFwidGVzdFwiLCBkYXRhOiBbXSB9XSxcbiAgICAgIH1cbiAgICAgIG1vY2tMb2FkUGFja2FnZUZyb21EYXRhYmFzZS5tb2NrUmVzb2x2ZWRWYWx1ZShtb2NrUGFja2FnZSlcblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcGx1Z2luLmxvYWRQYWNrYWdlKFwibXlzcWw6Ly9sb2NhbGhvc3QvdGVzdGRiXCIpXG5cbiAgICAgIGV4cGVjdChtb2NrTG9hZFBhY2thZ2VGcm9tRGF0YWJhc2UpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKFxuICAgICAgICBcIm15c3FsOi8vbG9jYWxob3N0L3Rlc3RkYlwiLFxuICAgICAgICB7IGZvcm1hdDogXCJteXNxbFwiIH0sXG4gICAgICApXG4gICAgICBleHBlY3QocmVzdWx0KS50b0VxdWFsKG1vY2tQYWNrYWdlKVxuICAgIH0pXG5cbiAgICBpdChcInNob3VsZCBsb2FkIHBhY2thZ2UgZnJvbSBzcWxpdGUgZGF0YWJhc2VcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgbW9ja1BhY2thZ2U6IFBhY2thZ2UgPSB7XG4gICAgICAgIG5hbWU6IFwidGVzdC1wYWNrYWdlXCIsXG4gICAgICAgIHJlc291cmNlczogW3sgbmFtZTogXCJ0ZXN0XCIsIGRhdGE6IFtdIH1dLFxuICAgICAgfVxuICAgICAgbW9ja0xvYWRQYWNrYWdlRnJvbURhdGFiYXNlLm1vY2tSZXNvbHZlZFZhbHVlKG1vY2tQYWNrYWdlKVxuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwbHVnaW4ubG9hZFBhY2thZ2UoXCJzcWxpdGU6Ly90ZXN0LmRiXCIpXG5cbiAgICAgIGV4cGVjdChtb2NrTG9hZFBhY2thZ2VGcm9tRGF0YWJhc2UpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKFxuICAgICAgICBcInNxbGl0ZTovL3Rlc3QuZGJcIixcbiAgICAgICAge1xuICAgICAgICAgIGZvcm1hdDogXCJzcWxpdGVcIixcbiAgICAgICAgfSxcbiAgICAgIClcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvRXF1YWwobW9ja1BhY2thZ2UpXG4gICAgfSlcblxuICAgIGl0KFwic2hvdWxkIHJldHVybiB1bmRlZmluZWQgZm9yIG5vbi1kYXRhYmFzZSBzb3VyY2VzXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBsdWdpbi5sb2FkUGFja2FnZShcInRlc3QuY3N2XCIpXG5cbiAgICAgIGV4cGVjdChtb2NrTG9hZFBhY2thZ2VGcm9tRGF0YWJhc2UpLm5vdC50b0hhdmVCZWVuQ2FsbGVkKClcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvQmVVbmRlZmluZWQoKVxuICAgIH0pXG5cbiAgICBpdChcInNob3VsZCByZXR1cm4gdW5kZWZpbmVkIGZvciBodHRwIHVybHNcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcGx1Z2luLmxvYWRQYWNrYWdlKFwiaHR0cHM6Ly9leGFtcGxlLmNvbS9kYXRhXCIpXG5cbiAgICAgIGV4cGVjdChtb2NrTG9hZFBhY2thZ2VGcm9tRGF0YWJhc2UpLm5vdC50b0hhdmVCZWVuQ2FsbGVkKClcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvQmVVbmRlZmluZWQoKVxuICAgIH0pXG4gIH0pXG5cbiAgZGVzY3JpYmUoXCJzYXZlUGFja2FnZVwiLCAoKSA9PiB7XG4gICAgaXQoXCJzaG91bGQgc2F2ZSBwYWNrYWdlIHRvIHBvc3RncmVzcWwgZGF0YWJhc2VcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgbW9ja1BhY2thZ2U6IFBhY2thZ2UgPSB7XG4gICAgICAgIG5hbWU6IFwidGVzdC1wYWNrYWdlXCIsXG4gICAgICAgIHJlc291cmNlczogW3sgbmFtZTogXCJ0ZXN0XCIsIGRhdGE6IFtdIH1dLFxuICAgICAgfVxuICAgICAgbW9ja1NhdmVQYWNrYWdlVG9EYXRhYmFzZS5tb2NrUmVzb2x2ZWRWYWx1ZSh1bmRlZmluZWQpXG5cbiAgICAgIGF3YWl0IHBsdWdpbi5zYXZlUGFja2FnZShtb2NrUGFja2FnZSwge1xuICAgICAgICB0YXJnZXQ6IFwicG9zdGdyZXNxbDovL2xvY2FsaG9zdC90ZXN0ZGJcIixcbiAgICAgIH0pXG5cbiAgICAgIGV4cGVjdChtb2NrU2F2ZVBhY2thZ2VUb0RhdGFiYXNlKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChtb2NrUGFja2FnZSwge1xuICAgICAgICB0YXJnZXQ6IFwicG9zdGdyZXNxbDovL2xvY2FsaG9zdC90ZXN0ZGJcIixcbiAgICAgICAgZm9ybWF0OiBcInBvc3RncmVzcWxcIixcbiAgICAgIH0pXG4gICAgfSlcblxuICAgIGl0KFwic2hvdWxkIHNhdmUgcGFja2FnZSB0byBteXNxbCBkYXRhYmFzZVwiLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBtb2NrUGFja2FnZTogUGFja2FnZSA9IHtcbiAgICAgICAgbmFtZTogXCJ0ZXN0LXBhY2thZ2VcIixcbiAgICAgICAgcmVzb3VyY2VzOiBbeyBuYW1lOiBcInRlc3RcIiwgZGF0YTogW10gfV0sXG4gICAgICB9XG4gICAgICBtb2NrU2F2ZVBhY2thZ2VUb0RhdGFiYXNlLm1vY2tSZXNvbHZlZFZhbHVlKHVuZGVmaW5lZClcblxuICAgICAgYXdhaXQgcGx1Z2luLnNhdmVQYWNrYWdlKG1vY2tQYWNrYWdlLCB7XG4gICAgICAgIHRhcmdldDogXCJteXNxbDovL2xvY2FsaG9zdC90ZXN0ZGJcIixcbiAgICAgIH0pXG5cbiAgICAgIGV4cGVjdChtb2NrU2F2ZVBhY2thZ2VUb0RhdGFiYXNlKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChtb2NrUGFja2FnZSwge1xuICAgICAgICB0YXJnZXQ6IFwibXlzcWw6Ly9sb2NhbGhvc3QvdGVzdGRiXCIsXG4gICAgICAgIGZvcm1hdDogXCJteXNxbFwiLFxuICAgICAgfSlcbiAgICB9KVxuXG4gICAgaXQoXCJzaG91bGQgc2F2ZSBwYWNrYWdlIHRvIHNxbGl0ZSBkYXRhYmFzZVwiLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBtb2NrUGFja2FnZTogUGFja2FnZSA9IHtcbiAgICAgICAgbmFtZTogXCJ0ZXN0LXBhY2thZ2VcIixcbiAgICAgICAgcmVzb3VyY2VzOiBbeyBuYW1lOiBcInRlc3RcIiwgZGF0YTogW10gfV0sXG4gICAgICB9XG4gICAgICBtb2NrU2F2ZVBhY2thZ2VUb0RhdGFiYXNlLm1vY2tSZXNvbHZlZFZhbHVlKHVuZGVmaW5lZClcblxuICAgICAgYXdhaXQgcGx1Z2luLnNhdmVQYWNrYWdlKG1vY2tQYWNrYWdlLCB7IHRhcmdldDogXCJzcWxpdGU6Ly90ZXN0LmRiXCIgfSlcblxuICAgICAgZXhwZWN0KG1vY2tTYXZlUGFja2FnZVRvRGF0YWJhc2UpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKG1vY2tQYWNrYWdlLCB7XG4gICAgICAgIHRhcmdldDogXCJzcWxpdGU6Ly90ZXN0LmRiXCIsXG4gICAgICAgIGZvcm1hdDogXCJzcWxpdGVcIixcbiAgICAgIH0pXG4gICAgfSlcblxuICAgIGl0KFwic2hvdWxkIHJldHVybiB1bmRlZmluZWQgZm9yIG5vbi1kYXRhYmFzZSB0YXJnZXRzXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IG1vY2tQYWNrYWdlOiBQYWNrYWdlID0ge1xuICAgICAgICBuYW1lOiBcInRlc3QtcGFja2FnZVwiLFxuICAgICAgICByZXNvdXJjZXM6IFt7IG5hbWU6IFwidGVzdFwiLCBkYXRhOiBbXSB9XSxcbiAgICAgIH1cblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcGx1Z2luLnNhdmVQYWNrYWdlKG1vY2tQYWNrYWdlLCB7XG4gICAgICAgIHRhcmdldDogXCJ0ZXN0LmNzdlwiLFxuICAgICAgfSlcblxuICAgICAgZXhwZWN0KG1vY2tTYXZlUGFja2FnZVRvRGF0YWJhc2UpLm5vdC50b0hhdmVCZWVuQ2FsbGVkKClcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvQmVVbmRlZmluZWQoKVxuICAgIH0pXG5cbiAgICBpdChcInNob3VsZCBwYXNzIHRocm91Z2ggcGx1Z2lucyBvcHRpb25cIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgbW9ja1BhY2thZ2U6IFBhY2thZ2UgPSB7XG4gICAgICAgIG5hbWU6IFwidGVzdC1wYWNrYWdlXCIsXG4gICAgICAgIHJlc291cmNlczogW3sgbmFtZTogXCJ0ZXN0XCIsIGRhdGE6IFtdIH1dLFxuICAgICAgfVxuICAgICAgY29uc3QgbW9ja1BsdWdpbnM6IGFueVtdID0gW11cbiAgICAgIG1vY2tTYXZlUGFja2FnZVRvRGF0YWJhc2UubW9ja1Jlc29sdmVkVmFsdWUodW5kZWZpbmVkKVxuXG4gICAgICBhd2FpdCBwbHVnaW4uc2F2ZVBhY2thZ2UobW9ja1BhY2thZ2UsIHtcbiAgICAgICAgdGFyZ2V0OiBcInNxbGl0ZTovL3Rlc3QuZGJcIixcbiAgICAgICAgcGx1Z2luczogbW9ja1BsdWdpbnMsXG4gICAgICB9KVxuXG4gICAgICBleHBlY3QobW9ja1NhdmVQYWNrYWdlVG9EYXRhYmFzZSkudG9IYXZlQmVlbkNhbGxlZFdpdGgobW9ja1BhY2thZ2UsIHtcbiAgICAgICAgdGFyZ2V0OiBcInNxbGl0ZTovL3Rlc3QuZGJcIixcbiAgICAgICAgZm9ybWF0OiBcInNxbGl0ZVwiLFxuICAgICAgICBwbHVnaW5zOiBtb2NrUGx1Z2lucyxcbiAgICAgIH0pXG4gICAgfSlcbiAgfSlcblxuICBkZXNjcmliZShcImxvYWRUYWJsZVwiLCAoKSA9PiB7XG4gICAgaXQoXCJzaG91bGQgbG9hZCB0YWJsZSBmcm9tIHBvc3RncmVzcWwgcmVzb3VyY2VcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgcmVzb3VyY2U6IFBhcnRpYWw8UmVzb3VyY2U+ID0ge1xuICAgICAgICBwYXRoOiBcInBvc3RncmVzcWw6Ly9sb2NhbGhvc3QvdGVzdGRiXCIsXG4gICAgICB9XG4gICAgICBjb25zdCBtb2NrVGFibGUgPSBwbC5EYXRhRnJhbWUoKS5sYXp5KClcbiAgICAgIG1vY2tMb2FkRGF0YWJhc2VUYWJsZS5tb2NrUmVzb2x2ZWRWYWx1ZShtb2NrVGFibGUpXG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBsdWdpbi5sb2FkVGFibGUocmVzb3VyY2UpXG5cbiAgICAgIGV4cGVjdChtb2NrTG9hZERhdGFiYXNlVGFibGUpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKHtcbiAgICAgICAgLi4ucmVzb3VyY2UsXG4gICAgICAgIGZvcm1hdDogXCJwb3N0Z3Jlc3FsXCIsXG4gICAgICB9KVxuICAgICAgZXhwZWN0KHJlc3VsdCkudG9FcXVhbChtb2NrVGFibGUpXG4gICAgfSlcblxuICAgIGl0KFwic2hvdWxkIGxvYWQgdGFibGUgZnJvbSBteXNxbCByZXNvdXJjZVwiLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCByZXNvdXJjZTogUGFydGlhbDxSZXNvdXJjZT4gPSB7XG4gICAgICAgIHBhdGg6IFwibXlzcWw6Ly9sb2NhbGhvc3QvdGVzdGRiXCIsXG4gICAgICB9XG4gICAgICBjb25zdCBtb2NrVGFibGUgPSBwbC5EYXRhRnJhbWUoKS5sYXp5KClcbiAgICAgIG1vY2tMb2FkRGF0YWJhc2VUYWJsZS5tb2NrUmVzb2x2ZWRWYWx1ZShtb2NrVGFibGUpXG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBsdWdpbi5sb2FkVGFibGUocmVzb3VyY2UpXG5cbiAgICAgIGV4cGVjdChtb2NrTG9hZERhdGFiYXNlVGFibGUpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKHtcbiAgICAgICAgLi4ucmVzb3VyY2UsXG4gICAgICAgIGZvcm1hdDogXCJteXNxbFwiLFxuICAgICAgfSlcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvRXF1YWwobW9ja1RhYmxlKVxuICAgIH0pXG5cbiAgICBpdChcInNob3VsZCBsb2FkIHRhYmxlIGZyb20gc3FsaXRlIHJlc291cmNlXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHJlc291cmNlOiBQYXJ0aWFsPFJlc291cmNlPiA9IHtcbiAgICAgICAgcGF0aDogXCJzcWxpdGU6Ly90ZXN0LmRiXCIsXG4gICAgICB9XG4gICAgICBjb25zdCBtb2NrVGFibGUgPSBwbC5EYXRhRnJhbWUoKS5sYXp5KClcbiAgICAgIG1vY2tMb2FkRGF0YWJhc2VUYWJsZS5tb2NrUmVzb2x2ZWRWYWx1ZShtb2NrVGFibGUpXG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBsdWdpbi5sb2FkVGFibGUocmVzb3VyY2UpXG5cbiAgICAgIGV4cGVjdChtb2NrTG9hZERhdGFiYXNlVGFibGUpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKHtcbiAgICAgICAgLi4ucmVzb3VyY2UsXG4gICAgICAgIGZvcm1hdDogXCJzcWxpdGVcIixcbiAgICAgIH0pXG4gICAgICBleHBlY3QocmVzdWx0KS50b0VxdWFsKG1vY2tUYWJsZSlcbiAgICB9KVxuXG4gICAgaXQoXCJzaG91bGQgcmV0dXJuIHVuZGVmaW5lZCBmb3Igbm9uLWRhdGFiYXNlIHJlc291cmNlc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCByZXNvdXJjZTogUGFydGlhbDxSZXNvdXJjZT4gPSB7XG4gICAgICAgIHBhdGg6IFwidGVzdC5jc3ZcIixcbiAgICAgIH1cblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcGx1Z2luLmxvYWRUYWJsZShyZXNvdXJjZSlcblxuICAgICAgZXhwZWN0KG1vY2tMb2FkRGF0YWJhc2VUYWJsZSkubm90LnRvSGF2ZUJlZW5DYWxsZWQoKVxuICAgICAgZXhwZWN0KHJlc3VsdCkudG9CZVVuZGVmaW5lZCgpXG4gICAgfSlcblxuICAgIGl0KFwic2hvdWxkIGhhbmRsZSBleHBsaWNpdCBmb3JtYXQgc3BlY2lmaWNhdGlvblwiLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCByZXNvdXJjZTogUGFydGlhbDxSZXNvdXJjZT4gPSB7XG4gICAgICAgIHBhdGg6IFwidGVzdC50eHRcIixcbiAgICAgICAgZm9ybWF0OiBcInNxbGl0ZVwiLFxuICAgICAgfVxuICAgICAgY29uc3QgbW9ja1RhYmxlID0gcGwuRGF0YUZyYW1lKCkubGF6eSgpXG4gICAgICBtb2NrTG9hZERhdGFiYXNlVGFibGUubW9ja1Jlc29sdmVkVmFsdWUobW9ja1RhYmxlKVxuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwbHVnaW4ubG9hZFRhYmxlKHJlc291cmNlKVxuXG4gICAgICBleHBlY3QobW9ja0xvYWREYXRhYmFzZVRhYmxlKS50b0hhdmVCZWVuQ2FsbGVkV2l0aCh7XG4gICAgICAgIC4uLnJlc291cmNlLFxuICAgICAgICBmb3JtYXQ6IFwic3FsaXRlXCIsXG4gICAgICB9KVxuICAgICAgZXhwZWN0KHJlc3VsdCkudG9FcXVhbChtb2NrVGFibGUpXG4gICAgfSlcbiAgfSlcblxuICBkZXNjcmliZShcInNhdmVUYWJsZVwiLCAoKSA9PiB7XG4gICAgaXQoXCJzaG91bGQgc2F2ZSB0YWJsZSB0byBwb3N0Z3Jlc3FsIGRhdGFiYXNlXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHRhYmxlID0gcGwuRGF0YUZyYW1lKCkubGF6eSgpXG4gICAgICBjb25zdCBvcHRpb25zID0geyBwYXRoOiBcInBvc3RncmVzcWw6Ly9sb2NhbGhvc3QvdGVzdGRiXCIgfVxuICAgICAgbW9ja1NhdmVEYXRhYmFzZVRhYmxlLm1vY2tSZXNvbHZlZFZhbHVlKFwicG9zdGdyZXNxbDovL2xvY2FsaG9zdC90ZXN0ZGJcIilcblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcGx1Z2luLnNhdmVUYWJsZSh0YWJsZSwgb3B0aW9ucylcblxuICAgICAgZXhwZWN0KG1vY2tTYXZlRGF0YWJhc2VUYWJsZSkudG9IYXZlQmVlbkNhbGxlZFdpdGgodGFibGUsIHtcbiAgICAgICAgLi4ub3B0aW9ucyxcbiAgICAgICAgZm9ybWF0OiBcInBvc3RncmVzcWxcIixcbiAgICAgIH0pXG4gICAgICBleHBlY3QocmVzdWx0KS50b0JlKFwicG9zdGdyZXNxbDovL2xvY2FsaG9zdC90ZXN0ZGJcIilcbiAgICB9KVxuXG4gICAgaXQoXCJzaG91bGQgc2F2ZSB0YWJsZSB0byBteXNxbCBkYXRhYmFzZVwiLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCB0YWJsZSA9IHBsLkRhdGFGcmFtZSgpLmxhenkoKVxuICAgICAgY29uc3Qgb3B0aW9ucyA9IHsgcGF0aDogXCJteXNxbDovL2xvY2FsaG9zdC90ZXN0ZGJcIiB9XG4gICAgICBtb2NrU2F2ZURhdGFiYXNlVGFibGUubW9ja1Jlc29sdmVkVmFsdWUoXCJteXNxbDovL2xvY2FsaG9zdC90ZXN0ZGJcIilcblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcGx1Z2luLnNhdmVUYWJsZSh0YWJsZSwgb3B0aW9ucylcblxuICAgICAgZXhwZWN0KG1vY2tTYXZlRGF0YWJhc2VUYWJsZSkudG9IYXZlQmVlbkNhbGxlZFdpdGgodGFibGUsIHtcbiAgICAgICAgLi4ub3B0aW9ucyxcbiAgICAgICAgZm9ybWF0OiBcIm15c3FsXCIsXG4gICAgICB9KVxuICAgICAgZXhwZWN0KHJlc3VsdCkudG9CZShcIm15c3FsOi8vbG9jYWxob3N0L3Rlc3RkYlwiKVxuICAgIH0pXG5cbiAgICBpdChcInNob3VsZCBzYXZlIHRhYmxlIHRvIHNxbGl0ZSBkYXRhYmFzZVwiLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCB0YWJsZSA9IHBsLkRhdGFGcmFtZSgpLmxhenkoKVxuICAgICAgY29uc3Qgb3B0aW9ucyA9IHsgcGF0aDogXCJzcWxpdGU6Ly90ZXN0LmRiXCIgfVxuICAgICAgbW9ja1NhdmVEYXRhYmFzZVRhYmxlLm1vY2tSZXNvbHZlZFZhbHVlKFwic3FsaXRlOi8vdGVzdC5kYlwiKVxuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwbHVnaW4uc2F2ZVRhYmxlKHRhYmxlLCBvcHRpb25zKVxuXG4gICAgICBleHBlY3QobW9ja1NhdmVEYXRhYmFzZVRhYmxlKS50b0hhdmVCZWVuQ2FsbGVkV2l0aCh0YWJsZSwge1xuICAgICAgICAuLi5vcHRpb25zLFxuICAgICAgICBmb3JtYXQ6IFwic3FsaXRlXCIsXG4gICAgICB9KVxuICAgICAgZXhwZWN0KHJlc3VsdCkudG9CZShcInNxbGl0ZTovL3Rlc3QuZGJcIilcbiAgICB9KVxuXG4gICAgaXQoXCJzaG91bGQgcmV0dXJuIHVuZGVmaW5lZCBmb3Igbm9uLWRhdGFiYXNlIHBhdGhzXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHRhYmxlID0gcGwuRGF0YUZyYW1lKCkubGF6eSgpXG4gICAgICBjb25zdCBvcHRpb25zID0geyBwYXRoOiBcIm91dHB1dC5jc3ZcIiB9XG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBsdWdpbi5zYXZlVGFibGUodGFibGUsIG9wdGlvbnMpXG5cbiAgICAgIGV4cGVjdChtb2NrU2F2ZURhdGFiYXNlVGFibGUpLm5vdC50b0hhdmVCZWVuQ2FsbGVkKClcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvQmVVbmRlZmluZWQoKVxuICAgIH0pXG5cbiAgICBpdChcInNob3VsZCBoYW5kbGUgZXhwbGljaXQgZm9ybWF0IHNwZWNpZmljYXRpb25cIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgdGFibGUgPSBwbC5EYXRhRnJhbWUoKS5sYXp5KClcbiAgICAgIGNvbnN0IG9wdGlvbnMgPSB7IHBhdGg6IFwidGVzdC50eHRcIiwgZm9ybWF0OiBcInNxbGl0ZVwiIGFzIGNvbnN0IH1cbiAgICAgIG1vY2tTYXZlRGF0YWJhc2VUYWJsZS5tb2NrUmVzb2x2ZWRWYWx1ZShcInRlc3QudHh0XCIpXG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBsdWdpbi5zYXZlVGFibGUodGFibGUsIG9wdGlvbnMpXG5cbiAgICAgIGV4cGVjdChtb2NrU2F2ZURhdGFiYXNlVGFibGUpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKHRhYmxlLCB7XG4gICAgICAgIC4uLm9wdGlvbnMsXG4gICAgICAgIGZvcm1hdDogXCJzcWxpdGVcIixcbiAgICAgIH0pXG4gICAgICBleHBlY3QocmVzdWx0KS50b0JlKFwidGVzdC50eHRcIilcbiAgICB9KVxuICB9KVxuXG4gIGRlc2NyaWJlKFwiaW5mZXJTY2hlbWFcIiwgKCkgPT4ge1xuICAgIGl0KFwic2hvdWxkIGluZmVyIHNjaGVtYSBmb3IgcG9zdGdyZXNxbCByZXNvdXJjZVwiLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCByZXNvdXJjZTogUGFydGlhbDxSZXNvdXJjZT4gPSB7XG4gICAgICAgIHBhdGg6IFwicG9zdGdyZXNxbDovL2xvY2FsaG9zdC90ZXN0ZGJcIixcbiAgICAgIH1cbiAgICAgIGNvbnN0IG1vY2tTY2hlbWEgPSB7IGZpZWxkczogW10gfVxuICAgICAgbW9ja0luZmVyRGF0YWJhc2VTY2hlbWEubW9ja1Jlc29sdmVkVmFsdWUobW9ja1NjaGVtYSlcblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcGx1Z2luLmluZmVyU2NoZW1hKHJlc291cmNlKVxuXG4gICAgICBleHBlY3QobW9ja0luZmVyRGF0YWJhc2VTY2hlbWEpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKHtcbiAgICAgICAgLi4ucmVzb3VyY2UsXG4gICAgICAgIGZvcm1hdDogXCJwb3N0Z3Jlc3FsXCIsXG4gICAgICB9KVxuICAgICAgZXhwZWN0KHJlc3VsdCkudG9FcXVhbChtb2NrU2NoZW1hKVxuICAgIH0pXG5cbiAgICBpdChcInNob3VsZCBpbmZlciBzY2hlbWEgZm9yIG15c3FsIHJlc291cmNlXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHJlc291cmNlOiBQYXJ0aWFsPFJlc291cmNlPiA9IHtcbiAgICAgICAgcGF0aDogXCJteXNxbDovL2xvY2FsaG9zdC90ZXN0ZGJcIixcbiAgICAgIH1cbiAgICAgIGNvbnN0IG1vY2tTY2hlbWEgPSB7IGZpZWxkczogW10gfVxuICAgICAgbW9ja0luZmVyRGF0YWJhc2VTY2hlbWEubW9ja1Jlc29sdmVkVmFsdWUobW9ja1NjaGVtYSlcblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcGx1Z2luLmluZmVyU2NoZW1hKHJlc291cmNlKVxuXG4gICAgICBleHBlY3QobW9ja0luZmVyRGF0YWJhc2VTY2hlbWEpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKHtcbiAgICAgICAgLi4ucmVzb3VyY2UsXG4gICAgICAgIGZvcm1hdDogXCJteXNxbFwiLFxuICAgICAgfSlcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvRXF1YWwobW9ja1NjaGVtYSlcbiAgICB9KVxuXG4gICAgaXQoXCJzaG91bGQgaW5mZXIgc2NoZW1hIGZvciBzcWxpdGUgcmVzb3VyY2VcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgcmVzb3VyY2U6IFBhcnRpYWw8UmVzb3VyY2U+ID0ge1xuICAgICAgICBwYXRoOiBcInNxbGl0ZTovL3Rlc3QuZGJcIixcbiAgICAgIH1cbiAgICAgIGNvbnN0IG1vY2tTY2hlbWEgPSB7IGZpZWxkczogW10gfVxuICAgICAgbW9ja0luZmVyRGF0YWJhc2VTY2hlbWEubW9ja1Jlc29sdmVkVmFsdWUobW9ja1NjaGVtYSlcblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcGx1Z2luLmluZmVyU2NoZW1hKHJlc291cmNlKVxuXG4gICAgICBleHBlY3QobW9ja0luZmVyRGF0YWJhc2VTY2hlbWEpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKHtcbiAgICAgICAgLi4ucmVzb3VyY2UsXG4gICAgICAgIGZvcm1hdDogXCJzcWxpdGVcIixcbiAgICAgIH0pXG4gICAgICBleHBlY3QocmVzdWx0KS50b0VxdWFsKG1vY2tTY2hlbWEpXG4gICAgfSlcblxuICAgIGl0KFwic2hvdWxkIHJldHVybiB1bmRlZmluZWQgZm9yIG5vbi1kYXRhYmFzZSByZXNvdXJjZXNcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgcmVzb3VyY2U6IFBhcnRpYWw8UmVzb3VyY2U+ID0ge1xuICAgICAgICBwYXRoOiBcInRlc3QuY3N2XCIsXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBsdWdpbi5pbmZlclNjaGVtYShyZXNvdXJjZSlcblxuICAgICAgZXhwZWN0KG1vY2tJbmZlckRhdGFiYXNlU2NoZW1hKS5ub3QudG9IYXZlQmVlbkNhbGxlZCgpXG4gICAgICBleHBlY3QocmVzdWx0KS50b0JlVW5kZWZpbmVkKClcbiAgICB9KVxuXG4gICAgaXQoXCJzaG91bGQgaGFuZGxlIGV4cGxpY2l0IGZvcm1hdCBzcGVjaWZpY2F0aW9uXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHJlc291cmNlOiBQYXJ0aWFsPFJlc291cmNlPiA9IHtcbiAgICAgICAgcGF0aDogXCJ0ZXN0LnR4dFwiLFxuICAgICAgICBmb3JtYXQ6IFwic3FsaXRlXCIsXG4gICAgICB9XG4gICAgICBjb25zdCBtb2NrU2NoZW1hID0geyBmaWVsZHM6IFtdIH1cbiAgICAgIG1vY2tJbmZlckRhdGFiYXNlU2NoZW1hLm1vY2tSZXNvbHZlZFZhbHVlKG1vY2tTY2hlbWEpXG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBsdWdpbi5pbmZlclNjaGVtYShyZXNvdXJjZSlcblxuICAgICAgZXhwZWN0KG1vY2tJbmZlckRhdGFiYXNlU2NoZW1hKS50b0hhdmVCZWVuQ2FsbGVkV2l0aCh7XG4gICAgICAgIC4uLnJlc291cmNlLFxuICAgICAgICBmb3JtYXQ6IFwic3FsaXRlXCIsXG4gICAgICB9KVxuICAgICAgZXhwZWN0KHJlc3VsdCkudG9FcXVhbChtb2NrU2NoZW1hKVxuICAgIH0pXG4gIH0pXG59KVxuIl19
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type DatabaseFormat = "sqlite" | "postgresql" | "mysql";
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export {};
|
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRm9ybWF0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vcmVzb3VyY2UvRm9ybWF0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgdHlwZSBEYXRhYmFzZUZvcm1hdCA9IFwic3FsaXRlXCIgfCBcInBvc3RncmVzcWxcIiB8IFwibXlzcWxcIlxuIl19
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { DatabaseFormat } from "./Format.ts";
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export {};
|
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9yZXNvdXJjZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IHR5cGUgeyBEYXRhYmFzZUZvcm1hdCB9IGZyb20gXCIuL0Zvcm1hdC50c1wiXG4iXX0=
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export {};
|
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2NoZW1hLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc2NoZW1hL1NjaGVtYS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBUYWJsZU1ldGFkYXRhIH0gZnJvbSBcImt5c2VseVwiXG5cbmV4cG9ydCBpbnRlcmZhY2UgRGF0YWJhc2VTY2hlbWEgZXh0ZW5kcyBUYWJsZU1ldGFkYXRhIHtcbiAgcHJpbWFyeUtleT86IHN0cmluZ1tdXG59XG4iXX0=
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { inferDatabaseSchema } from "./infer.js";
|
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zY2hlbWEvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sWUFBWSxDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IHsgaW5mZXJEYXRhYmFzZVNjaGVtYSB9IGZyb20gXCIuL2luZmVyLnRzXCJcbmV4cG9ydCB0eXBlIHsgRGF0YWJhc2VTY2hlbWEgfSBmcm9tIFwiLi9TY2hlbWEudHNcIlxuIl19
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { resolveDialect } from "@frictionless-ts/metadata";
|
|
2
|
+
import { createAdapter } from "../adapters/create.js";
|
|
3
|
+
export async function inferDatabaseSchema(resource) {
|
|
4
|
+
const adapter = createAdapter(resource.format);
|
|
5
|
+
if (!adapter) {
|
|
6
|
+
throw new Error("Supported database format is not defined");
|
|
7
|
+
}
|
|
8
|
+
const dialect = await resolveDialect(resource.dialect);
|
|
9
|
+
if (!dialect?.table) {
|
|
10
|
+
throw new Error("Table name is not defined in dialect");
|
|
11
|
+
}
|
|
12
|
+
const path = typeof resource.path === "string" ? resource.path : undefined;
|
|
13
|
+
if (!path) {
|
|
14
|
+
throw new Error("Resource path is not defined");
|
|
15
|
+
}
|
|
16
|
+
const database = await adapter.connectDatabase(path);
|
|
17
|
+
const databaseSchemas = await database.introspection.getTables();
|
|
18
|
+
const databaseSchema = databaseSchemas.find(s => s.name === dialect.table);
|
|
19
|
+
if (!databaseSchema) {
|
|
20
|
+
throw new Error(`Table is not found in database: ${dialect.table}`);
|
|
21
|
+
}
|
|
22
|
+
return adapter.normalizeSchema(databaseSchema);
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5mZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zY2hlbWEvaW5mZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLDJCQUEyQixDQUFBO0FBQzFELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQTtBQUVyRCxNQUFNLENBQUMsS0FBSyxVQUFVLG1CQUFtQixDQUN2QyxRQUEyRTtJQUUzRSxNQUFNLE9BQU8sR0FBRyxhQUFhLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFBO0lBQzlDLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNiLE1BQU0sSUFBSSxLQUFLLENBQUMsMENBQTBDLENBQUMsQ0FBQTtJQUM3RCxDQUFDO0lBRUQsTUFBTSxPQUFPLEdBQUcsTUFBTSxjQUFjLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFBO0lBQ3RELElBQUksQ0FBQyxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUM7UUFDcEIsTUFBTSxJQUFJLEtBQUssQ0FBQyxzQ0FBc0MsQ0FBQyxDQUFBO0lBQ3pELENBQUM7SUFFRCxNQUFNLElBQUksR0FBRyxPQUFPLFFBQVEsQ0FBQyxJQUFJLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUE7SUFDMUUsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ1YsTUFBTSxJQUFJLEtBQUssQ0FBQyw4QkFBOEIsQ0FBQyxDQUFBO0lBQ2pELENBQUM7SUFFRCxNQUFNLFFBQVEsR0FBRyxNQUFNLE9BQU8sQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDcEQsTUFBTSxlQUFlLEdBQUcsTUFBTSxRQUFRLENBQUMsYUFBYSxDQUFDLFNBQVMsRUFBRSxDQUFBO0lBRWhFLE1BQU0sY0FBYyxHQUFHLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQTtJQUMxRSxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDcEIsTUFBTSxJQUFJLEtBQUssQ0FBQyxtQ0FBbUMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUE7SUFDckUsQ0FBQztJQUVELE9BQU8sT0FBTyxDQUFDLGVBQWUsQ0FBQyxjQUFjLENBQUMsQ0FBQTtBQUNoRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBSZXNvdXJjZSB9IGZyb20gXCJAZnJpY3Rpb25sZXNzLXRzL21ldGFkYXRhXCJcbmltcG9ydCB7IHJlc29sdmVEaWFsZWN0IH0gZnJvbSBcIkBmcmljdGlvbmxlc3MtdHMvbWV0YWRhdGFcIlxuaW1wb3J0IHsgY3JlYXRlQWRhcHRlciB9IGZyb20gXCIuLi9hZGFwdGVycy9jcmVhdGUudHNcIlxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5mZXJEYXRhYmFzZVNjaGVtYShcbiAgcmVzb3VyY2U6IFBhcnRpYWw8UmVzb3VyY2U+ICYgeyBmb3JtYXQ6IFwicG9zdGdyZXNxbFwiIHwgXCJteXNxbFwiIHwgXCJzcWxpdGVcIiB9LFxuKSB7XG4gIGNvbnN0IGFkYXB0ZXIgPSBjcmVhdGVBZGFwdGVyKHJlc291cmNlLmZvcm1hdClcbiAgaWYgKCFhZGFwdGVyKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwiU3VwcG9ydGVkIGRhdGFiYXNlIGZvcm1hdCBpcyBub3QgZGVmaW5lZFwiKVxuICB9XG5cbiAgY29uc3QgZGlhbGVjdCA9IGF3YWl0IHJlc29sdmVEaWFsZWN0KHJlc291cmNlLmRpYWxlY3QpXG4gIGlmICghZGlhbGVjdD8udGFibGUpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJUYWJsZSBuYW1lIGlzIG5vdCBkZWZpbmVkIGluIGRpYWxlY3RcIilcbiAgfVxuXG4gIGNvbnN0IHBhdGggPSB0eXBlb2YgcmVzb3VyY2UucGF0aCA9PT0gXCJzdHJpbmdcIiA/IHJlc291cmNlLnBhdGggOiB1bmRlZmluZWRcbiAgaWYgKCFwYXRoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwiUmVzb3VyY2UgcGF0aCBpcyBub3QgZGVmaW5lZFwiKVxuICB9XG5cbiAgY29uc3QgZGF0YWJhc2UgPSBhd2FpdCBhZGFwdGVyLmNvbm5lY3REYXRhYmFzZShwYXRoKVxuICBjb25zdCBkYXRhYmFzZVNjaGVtYXMgPSBhd2FpdCBkYXRhYmFzZS5pbnRyb3NwZWN0aW9uLmdldFRhYmxlcygpXG5cbiAgY29uc3QgZGF0YWJhc2VTY2hlbWEgPSBkYXRhYmFzZVNjaGVtYXMuZmluZChzID0+IHMubmFtZSA9PT0gZGlhbGVjdC50YWJsZSlcbiAgaWYgKCFkYXRhYmFzZVNjaGVtYSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgVGFibGUgaXMgbm90IGZvdW5kIGluIGRhdGFiYXNlOiAke2RpYWxlY3QudGFibGV9YClcbiAgfVxuXG4gIHJldHVybiBhZGFwdGVyLm5vcm1hbGl6ZVNjaGVtYShkYXRhYmFzZVNjaGVtYSlcbn1cbiJdfQ==
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { inferDatabaseSchema } from "./infer.js";
|
|
3
|
+
// TODO: Enable when SQLite support is fixed
|
|
4
|
+
describe.skip("inferDatabaseSchema", () => {
|
|
5
|
+
it("throws error when resource path is not defined", async () => {
|
|
6
|
+
await expect(inferDatabaseSchema({
|
|
7
|
+
format: "sqlite",
|
|
8
|
+
dialect: { table: "dpkit" },
|
|
9
|
+
})).rejects.toThrow("Resource path is not defined");
|
|
10
|
+
});
|
|
11
|
+
it("throws error when table name is not defined in dialect", async () => {
|
|
12
|
+
await expect(inferDatabaseSchema({
|
|
13
|
+
path: "path",
|
|
14
|
+
format: "sqlite",
|
|
15
|
+
})).rejects.toThrow("Table name is not defined in dialect");
|
|
16
|
+
});
|
|
17
|
+
it("throws error when format is not supported", async () => {
|
|
18
|
+
await expect(inferDatabaseSchema({
|
|
19
|
+
path: "path",
|
|
20
|
+
format: "unsupported",
|
|
21
|
+
dialect: { table: "dpkit" },
|
|
22
|
+
})).rejects.toThrow('Unsupported database format: "unsupported"');
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5mZXIuc3BlYy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NjaGVtYS9pbmZlci5zcGVjLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLEVBQUUsRUFBRSxNQUFNLFFBQVEsQ0FBQTtBQUM3QyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFFaEQsNENBQTRDO0FBQzVDLFFBQVEsQ0FBQyxJQUFJLENBQUMscUJBQXFCLEVBQUUsR0FBRyxFQUFFO0lBQ3hDLEVBQUUsQ0FBQyxnREFBZ0QsRUFBRSxLQUFLLElBQUksRUFBRTtRQUM5RCxNQUFNLE1BQU0sQ0FDVixtQkFBbUIsQ0FBQztZQUNsQixNQUFNLEVBQUUsUUFBUTtZQUNoQixPQUFPLEVBQUUsRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFO1NBQzVCLENBQUMsQ0FDSCxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsOEJBQThCLENBQUMsQ0FBQTtJQUNuRCxDQUFDLENBQUMsQ0FBQTtJQUVGLEVBQUUsQ0FBQyx3REFBd0QsRUFBRSxLQUFLLElBQUksRUFBRTtRQUN0RSxNQUFNLE1BQU0sQ0FDVixtQkFBbUIsQ0FBQztZQUNsQixJQUFJLEVBQUUsTUFBTTtZQUNaLE1BQU0sRUFBRSxRQUFRO1NBQ2pCLENBQUMsQ0FDSCxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsc0NBQXNDLENBQUMsQ0FBQTtJQUMzRCxDQUFDLENBQUMsQ0FBQTtJQUVGLEVBQUUsQ0FBQywyQ0FBMkMsRUFBRSxLQUFLLElBQUksRUFBRTtRQUN6RCxNQUFNLE1BQU0sQ0FDVixtQkFBbUIsQ0FBQztZQUNsQixJQUFJLEVBQUUsTUFBTTtZQUNaLE1BQU0sRUFBRSxhQUFvQjtZQUM1QixPQUFPLEVBQUUsRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFO1NBQzVCLENBQUMsQ0FDSCxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsNENBQTRDLENBQUMsQ0FBQTtJQUNqRSxDQUFDLENBQUMsQ0FBQTtBQUNKLENBQUMsQ0FBQyxDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZGVzY3JpYmUsIGV4cGVjdCwgaXQgfSBmcm9tIFwidml0ZXN0XCJcbmltcG9ydCB7IGluZmVyRGF0YWJhc2VTY2hlbWEgfSBmcm9tIFwiLi9pbmZlci50c1wiXG5cbi8vIFRPRE86IEVuYWJsZSB3aGVuIFNRTGl0ZSBzdXBwb3J0IGlzIGZpeGVkXG5kZXNjcmliZS5za2lwKFwiaW5mZXJEYXRhYmFzZVNjaGVtYVwiLCAoKSA9PiB7XG4gIGl0KFwidGhyb3dzIGVycm9yIHdoZW4gcmVzb3VyY2UgcGF0aCBpcyBub3QgZGVmaW5lZFwiLCBhc3luYyAoKSA9PiB7XG4gICAgYXdhaXQgZXhwZWN0KFxuICAgICAgaW5mZXJEYXRhYmFzZVNjaGVtYSh7XG4gICAgICAgIGZvcm1hdDogXCJzcWxpdGVcIixcbiAgICAgICAgZGlhbGVjdDogeyB0YWJsZTogXCJkcGtpdFwiIH0sXG4gICAgICB9KSxcbiAgICApLnJlamVjdHMudG9UaHJvdyhcIlJlc291cmNlIHBhdGggaXMgbm90IGRlZmluZWRcIilcbiAgfSlcblxuICBpdChcInRocm93cyBlcnJvciB3aGVuIHRhYmxlIG5hbWUgaXMgbm90IGRlZmluZWQgaW4gZGlhbGVjdFwiLCBhc3luYyAoKSA9PiB7XG4gICAgYXdhaXQgZXhwZWN0KFxuICAgICAgaW5mZXJEYXRhYmFzZVNjaGVtYSh7XG4gICAgICAgIHBhdGg6IFwicGF0aFwiLFxuICAgICAgICBmb3JtYXQ6IFwic3FsaXRlXCIsXG4gICAgICB9KSxcbiAgICApLnJlamVjdHMudG9UaHJvdyhcIlRhYmxlIG5hbWUgaXMgbm90IGRlZmluZWQgaW4gZGlhbGVjdFwiKVxuICB9KVxuXG4gIGl0KFwidGhyb3dzIGVycm9yIHdoZW4gZm9ybWF0IGlzIG5vdCBzdXBwb3J0ZWRcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGF3YWl0IGV4cGVjdChcbiAgICAgIGluZmVyRGF0YWJhc2VTY2hlbWEoe1xuICAgICAgICBwYXRoOiBcInBhdGhcIixcbiAgICAgICAgZm9ybWF0OiBcInVuc3VwcG9ydGVkXCIgYXMgYW55LFxuICAgICAgICBkaWFsZWN0OiB7IHRhYmxlOiBcImRwa2l0XCIgfSxcbiAgICAgIH0pLFxuICAgICkucmVqZWN0cy50b1Rocm93KCdVbnN1cHBvcnRlZCBkYXRhYmFzZSBmb3JtYXQ6IFwidW5zdXBwb3J0ZWRcIicpXG4gIH0pXG59KVxuIl19
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { loadDatabaseTable } from "./load.js";
|
|
2
|
+
export { saveDatabaseTable } from "./save.js";
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90YWJsZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxXQUFXLENBQUE7QUFDN0MsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sV0FBVyxDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IHsgbG9hZERhdGFiYXNlVGFibGUgfSBmcm9tIFwiLi9sb2FkLnRzXCJcbmV4cG9ydCB7IHNhdmVEYXRhYmFzZVRhYmxlIH0gZnJvbSBcIi4vc2F2ZS50c1wiXG4iXX0=
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Resource } from "@frictionless-ts/metadata";
|
|
2
|
+
import type { LoadTableOptions } from "@frictionless-ts/table";
|
|
3
|
+
import * as pl from "nodejs-polars";
|
|
4
|
+
export declare function loadDatabaseTable(resource: Partial<Resource> & {
|
|
5
|
+
format: "postgresql" | "mysql" | "sqlite";
|
|
6
|
+
}, options?: LoadTableOptions): Promise<pl.LazyDataFrame<any>>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { resolveDialect, resolveSchema } from "@frictionless-ts/metadata";
|
|
2
|
+
import { normalizeTable } from "@frictionless-ts/table";
|
|
3
|
+
import * as pl from "nodejs-polars";
|
|
4
|
+
import { createAdapter } from "../adapters/create.js";
|
|
5
|
+
import { inferDatabaseSchema } from "../schema/index.js";
|
|
6
|
+
// Currently, we use slow non-rust implementation as in the future
|
|
7
|
+
// polars-rust might be able to provide a faster native implementation
|
|
8
|
+
export async function loadDatabaseTable(resource, options) {
|
|
9
|
+
const dialect = await resolveDialect(resource.dialect);
|
|
10
|
+
if (!dialect?.table) {
|
|
11
|
+
throw new Error("Table name is not defined in dialect");
|
|
12
|
+
}
|
|
13
|
+
const path = typeof resource.path === "string" ? resource.path : undefined;
|
|
14
|
+
if (!path) {
|
|
15
|
+
throw new Error("Resource path is not defined");
|
|
16
|
+
}
|
|
17
|
+
const adapter = createAdapter(resource.format);
|
|
18
|
+
const database = await adapter.connectDatabase(path);
|
|
19
|
+
const records = await database.selectFrom(dialect.table).selectAll().execute();
|
|
20
|
+
let table = pl.DataFrame(records).lazy();
|
|
21
|
+
if (!options?.denormalized) {
|
|
22
|
+
let schema = await resolveSchema(resource.schema);
|
|
23
|
+
if (!schema)
|
|
24
|
+
schema = await inferDatabaseSchema(resource);
|
|
25
|
+
table = await normalizeTable(table, schema);
|
|
26
|
+
}
|
|
27
|
+
return table;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9hZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RhYmxlL2xvYWQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGNBQWMsRUFBRSxhQUFhLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQTtBQUV6RSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sd0JBQXdCLENBQUE7QUFFdkQsT0FBTyxLQUFLLEVBQUUsTUFBTSxlQUFlLENBQUE7QUFDbkMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHVCQUF1QixDQUFBO0FBQ3JELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLG9CQUFvQixDQUFBO0FBRXhELGtFQUFrRTtBQUNsRSxzRUFBc0U7QUFFdEUsTUFBTSxDQUFDLEtBQUssVUFBVSxpQkFBaUIsQ0FDckMsUUFBMkUsRUFDM0UsT0FBMEI7SUFFMUIsTUFBTSxPQUFPLEdBQUcsTUFBTSxjQUFjLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFBO0lBQ3RELElBQUksQ0FBQyxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUM7UUFDcEIsTUFBTSxJQUFJLEtBQUssQ0FBQyxzQ0FBc0MsQ0FBQyxDQUFBO0lBQ3pELENBQUM7SUFFRCxNQUFNLElBQUksR0FBRyxPQUFPLFFBQVEsQ0FBQyxJQUFJLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUE7SUFDMUUsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ1YsTUFBTSxJQUFJLEtBQUssQ0FBQyw4QkFBOEIsQ0FBQyxDQUFBO0lBQ2pELENBQUM7SUFFRCxNQUFNLE9BQU8sR0FBRyxhQUFhLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFBO0lBQzlDLE1BQU0sUUFBUSxHQUFHLE1BQU0sT0FBTyxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUNwRCxNQUFNLE9BQU8sR0FBRyxNQUFNLFFBQVEsQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLFNBQVMsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFBO0lBRTlFLElBQUksS0FBSyxHQUFHLEVBQUUsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUE7SUFFeEMsSUFBSSxDQUFDLE9BQU8sRUFBRSxZQUFZLEVBQUUsQ0FBQztRQUMzQixJQUFJLE1BQU0sR0FBRyxNQUFNLGFBQWEsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUE7UUFDakQsSUFBSSxDQUFDLE1BQU07WUFBRSxNQUFNLEdBQUcsTUFBTSxtQkFBbUIsQ0FBQyxRQUFRLENBQUMsQ0FBQTtRQUN6RCxLQUFLLEdBQUcsTUFBTSxjQUFjLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFBO0lBQzdDLENBQUM7SUFFRCxPQUFPLEtBQUssQ0FBQTtBQUNkLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyByZXNvbHZlRGlhbGVjdCwgcmVzb2x2ZVNjaGVtYSB9IGZyb20gXCJAZnJpY3Rpb25sZXNzLXRzL21ldGFkYXRhXCJcbmltcG9ydCB0eXBlIHsgUmVzb3VyY2UgfSBmcm9tIFwiQGZyaWN0aW9ubGVzcy10cy9tZXRhZGF0YVwiXG5pbXBvcnQgeyBub3JtYWxpemVUYWJsZSB9IGZyb20gXCJAZnJpY3Rpb25sZXNzLXRzL3RhYmxlXCJcbmltcG9ydCB0eXBlIHsgTG9hZFRhYmxlT3B0aW9ucyB9IGZyb20gXCJAZnJpY3Rpb25sZXNzLXRzL3RhYmxlXCJcbmltcG9ydCAqIGFzIHBsIGZyb20gXCJub2RlanMtcG9sYXJzXCJcbmltcG9ydCB7IGNyZWF0ZUFkYXB0ZXIgfSBmcm9tIFwiLi4vYWRhcHRlcnMvY3JlYXRlLnRzXCJcbmltcG9ydCB7IGluZmVyRGF0YWJhc2VTY2hlbWEgfSBmcm9tIFwiLi4vc2NoZW1hL2luZGV4LnRzXCJcblxuLy8gQ3VycmVudGx5LCB3ZSB1c2Ugc2xvdyBub24tcnVzdCBpbXBsZW1lbnRhdGlvbiBhcyBpbiB0aGUgZnV0dXJlXG4vLyBwb2xhcnMtcnVzdCBtaWdodCBiZSBhYmxlIHRvIHByb3ZpZGUgYSBmYXN0ZXIgbmF0aXZlIGltcGxlbWVudGF0aW9uXG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsb2FkRGF0YWJhc2VUYWJsZShcbiAgcmVzb3VyY2U6IFBhcnRpYWw8UmVzb3VyY2U+ICYgeyBmb3JtYXQ6IFwicG9zdGdyZXNxbFwiIHwgXCJteXNxbFwiIHwgXCJzcWxpdGVcIiB9LFxuICBvcHRpb25zPzogTG9hZFRhYmxlT3B0aW9ucyxcbikge1xuICBjb25zdCBkaWFsZWN0ID0gYXdhaXQgcmVzb2x2ZURpYWxlY3QocmVzb3VyY2UuZGlhbGVjdClcbiAgaWYgKCFkaWFsZWN0Py50YWJsZSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcIlRhYmxlIG5hbWUgaXMgbm90IGRlZmluZWQgaW4gZGlhbGVjdFwiKVxuICB9XG5cbiAgY29uc3QgcGF0aCA9IHR5cGVvZiByZXNvdXJjZS5wYXRoID09PSBcInN0cmluZ1wiID8gcmVzb3VyY2UucGF0aCA6IHVuZGVmaW5lZFxuICBpZiAoIXBhdGgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJSZXNvdXJjZSBwYXRoIGlzIG5vdCBkZWZpbmVkXCIpXG4gIH1cblxuICBjb25zdCBhZGFwdGVyID0gY3JlYXRlQWRhcHRlcihyZXNvdXJjZS5mb3JtYXQpXG4gIGNvbnN0IGRhdGFiYXNlID0gYXdhaXQgYWRhcHRlci5jb25uZWN0RGF0YWJhc2UocGF0aClcbiAgY29uc3QgcmVjb3JkcyA9IGF3YWl0IGRhdGFiYXNlLnNlbGVjdEZyb20oZGlhbGVjdC50YWJsZSkuc2VsZWN0QWxsKCkuZXhlY3V0ZSgpXG5cbiAgbGV0IHRhYmxlID0gcGwuRGF0YUZyYW1lKHJlY29yZHMpLmxhenkoKVxuXG4gIGlmICghb3B0aW9ucz8uZGVub3JtYWxpemVkKSB7XG4gICAgbGV0IHNjaGVtYSA9IGF3YWl0IHJlc29sdmVTY2hlbWEocmVzb3VyY2Uuc2NoZW1hKVxuICAgIGlmICghc2NoZW1hKSBzY2hlbWEgPSBhd2FpdCBpbmZlckRhdGFiYXNlU2NoZW1hKHJlc291cmNlKVxuICAgIHRhYmxlID0gYXdhaXQgbm9ybWFsaXplVGFibGUodGFibGUsIHNjaGVtYSlcbiAgfVxuXG4gIHJldHVybiB0YWJsZVxufVxuIl19
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { loadDatabaseTable } from "./load.js";
|
|
3
|
+
describe("loadDatabaseTable", () => {
|
|
4
|
+
it("throws error when resource path is not defined", async () => {
|
|
5
|
+
await expect(loadDatabaseTable({
|
|
6
|
+
format: "sqlite",
|
|
7
|
+
dialect: { table: "dpkit" },
|
|
8
|
+
})).rejects.toThrow("Resource path is not defined");
|
|
9
|
+
});
|
|
10
|
+
it("throws error when table name is not defined in dialect", async () => {
|
|
11
|
+
await expect(loadDatabaseTable({
|
|
12
|
+
path: "path",
|
|
13
|
+
format: "sqlite",
|
|
14
|
+
})).rejects.toThrow("Table name is not defined in dialect");
|
|
15
|
+
});
|
|
16
|
+
it("throws error when format is not supported", async () => {
|
|
17
|
+
await expect(loadDatabaseTable({
|
|
18
|
+
path: "path",
|
|
19
|
+
format: "unsupported",
|
|
20
|
+
dialect: { table: "dpkit" },
|
|
21
|
+
})).rejects.toThrow('Unsupported database format: "unsupported"');
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9hZC5zcGVjLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdGFibGUvbG9hZC5zcGVjLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLEVBQUUsRUFBRSxNQUFNLFFBQVEsQ0FBQTtBQUM3QyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxXQUFXLENBQUE7QUFFN0MsUUFBUSxDQUFDLG1CQUFtQixFQUFFLEdBQUcsRUFBRTtJQUNqQyxFQUFFLENBQUMsZ0RBQWdELEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDOUQsTUFBTSxNQUFNLENBQ1YsaUJBQWlCLENBQUM7WUFDaEIsTUFBTSxFQUFFLFFBQVE7WUFDaEIsT0FBTyxFQUFFLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRTtTQUM1QixDQUFDLENBQ0gsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLDhCQUE4QixDQUFDLENBQUE7SUFDbkQsQ0FBQyxDQUFDLENBQUE7SUFFRixFQUFFLENBQUMsd0RBQXdELEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDdEUsTUFBTSxNQUFNLENBQ1YsaUJBQWlCLENBQUM7WUFDaEIsSUFBSSxFQUFFLE1BQU07WUFDWixNQUFNLEVBQUUsUUFBUTtTQUNqQixDQUFDLENBQ0gsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLHNDQUFzQyxDQUFDLENBQUE7SUFDM0QsQ0FBQyxDQUFDLENBQUE7SUFFRixFQUFFLENBQUMsMkNBQTJDLEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDekQsTUFBTSxNQUFNLENBQ1YsaUJBQWlCLENBQUM7WUFDaEIsSUFBSSxFQUFFLE1BQU07WUFDWixNQUFNLEVBQUUsYUFBb0I7WUFDNUIsT0FBTyxFQUFFLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRTtTQUM1QixDQUFDLENBQ0gsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLDRDQUE0QyxDQUFDLENBQUE7SUFDakUsQ0FBQyxDQUFDLENBQUE7QUFDSixDQUFDLENBQUMsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGRlc2NyaWJlLCBleHBlY3QsIGl0IH0gZnJvbSBcInZpdGVzdFwiXG5pbXBvcnQgeyBsb2FkRGF0YWJhc2VUYWJsZSB9IGZyb20gXCIuL2xvYWQudHNcIlxuXG5kZXNjcmliZShcImxvYWREYXRhYmFzZVRhYmxlXCIsICgpID0+IHtcbiAgaXQoXCJ0aHJvd3MgZXJyb3Igd2hlbiByZXNvdXJjZSBwYXRoIGlzIG5vdCBkZWZpbmVkXCIsIGFzeW5jICgpID0+IHtcbiAgICBhd2FpdCBleHBlY3QoXG4gICAgICBsb2FkRGF0YWJhc2VUYWJsZSh7XG4gICAgICAgIGZvcm1hdDogXCJzcWxpdGVcIixcbiAgICAgICAgZGlhbGVjdDogeyB0YWJsZTogXCJkcGtpdFwiIH0sXG4gICAgICB9KSxcbiAgICApLnJlamVjdHMudG9UaHJvdyhcIlJlc291cmNlIHBhdGggaXMgbm90IGRlZmluZWRcIilcbiAgfSlcblxuICBpdChcInRocm93cyBlcnJvciB3aGVuIHRhYmxlIG5hbWUgaXMgbm90IGRlZmluZWQgaW4gZGlhbGVjdFwiLCBhc3luYyAoKSA9PiB7XG4gICAgYXdhaXQgZXhwZWN0KFxuICAgICAgbG9hZERhdGFiYXNlVGFibGUoe1xuICAgICAgICBwYXRoOiBcInBhdGhcIixcbiAgICAgICAgZm9ybWF0OiBcInNxbGl0ZVwiLFxuICAgICAgfSksXG4gICAgKS5yZWplY3RzLnRvVGhyb3coXCJUYWJsZSBuYW1lIGlzIG5vdCBkZWZpbmVkIGluIGRpYWxlY3RcIilcbiAgfSlcblxuICBpdChcInRocm93cyBlcnJvciB3aGVuIGZvcm1hdCBpcyBub3Qgc3VwcG9ydGVkXCIsIGFzeW5jICgpID0+IHtcbiAgICBhd2FpdCBleHBlY3QoXG4gICAgICBsb2FkRGF0YWJhc2VUYWJsZSh7XG4gICAgICAgIHBhdGg6IFwicGF0aFwiLFxuICAgICAgICBmb3JtYXQ6IFwidW5zdXBwb3J0ZWRcIiBhcyBhbnksXG4gICAgICAgIGRpYWxlY3Q6IHsgdGFibGU6IFwiZHBraXRcIiB9LFxuICAgICAgfSksXG4gICAgKS5yZWplY3RzLnRvVGhyb3coJ1Vuc3VwcG9ydGVkIGRhdGFiYXNlIGZvcm1hdDogXCJ1bnN1cHBvcnRlZFwiJylcbiAgfSlcbn0pXG4iXX0=
|