@inlang/sdk 2.0.0 → 2.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/dist/json-schema/settings.d.ts +8 -10
- package/dist/json-schema/settings.d.ts.map +1 -1
- package/dist/json-schema/settings.js +4 -27
- package/dist/json-schema/settings.js.map +1 -1
- package/dist/json-schema/settings.test.d.ts +2 -0
- package/dist/json-schema/settings.test.d.ts.map +1 -0
- package/dist/json-schema/settings.test.js +26 -0
- package/dist/json-schema/settings.test.js.map +1 -0
- package/dist/plugin/importPlugins.test.js +2 -3
- package/dist/plugin/importPlugins.test.js.map +1 -1
- package/dist/project/loadProject.d.ts.map +1 -1
- package/dist/project/loadProject.js +13 -15
- package/dist/project/loadProject.js.map +1 -1
- package/dist/project/loadProjectFromDirectory.d.ts +2 -1
- package/dist/project/loadProjectFromDirectory.d.ts.map +1 -1
- package/dist/project/loadProjectFromDirectory.js +41 -53
- package/dist/project/loadProjectFromDirectory.js.map +1 -1
- package/dist/project/loadProjectFromDirectory.test.js +95 -4
- package/dist/project/loadProjectFromDirectory.test.js.map +1 -1
- package/dist/project/newProject.d.ts.map +1 -1
- package/dist/project/newProject.js +3 -3
- package/dist/project/newProject.js.map +1 -1
- package/dist/project/saveProjectToDirectory.d.ts.map +1 -1
- package/dist/project/saveProjectToDirectory.js +9 -2
- package/dist/project/saveProjectToDirectory.js.map +1 -1
- package/dist/project/saveProjectToDirectory.test.js +15 -2
- package/dist/project/saveProjectToDirectory.test.js.map +1 -1
- package/dist/services/env-variables/index.js +3 -3
- package/dist/services/env-variables/index.js.map +1 -1
- package/package.json +4 -5
- package/src/json-schema/settings.test.ts +26 -0
- package/src/json-schema/settings.ts +3 -36
- package/src/plugin/importPlugins.test.ts +0 -1
- package/src/project/loadProject.ts +15 -15
- package/src/project/loadProjectFromDirectory.test.ts +116 -2
- package/src/project/loadProjectFromDirectory.ts +49 -98
- package/src/project/newProject.ts +5 -1
- package/src/project/saveProjectToDirectory.test.ts +20 -0
- package/src/project/saveProjectToDirectory.ts +11 -1
- package/dist/project/initHandleSaveToLixOnChange.d.ts +0 -14
- package/dist/project/initHandleSaveToLixOnChange.d.ts.map +0 -1
- package/dist/project/initHandleSaveToLixOnChange.js +0 -87
- package/dist/project/initHandleSaveToLixOnChange.js.map +0 -1
- package/src/project/initHandleSaveToLixOnChange.ts +0 -93
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { newProject } from "./newProject.js";
|
|
2
2
|
import { loadProjectInMemory } from "./loadProjectInMemory.js";
|
|
3
3
|
import { type Lix } from "@lix-js/sdk";
|
|
4
|
-
|
|
5
4
|
import fs from "node:fs";
|
|
6
|
-
|
|
7
5
|
import nodePath from "node:path";
|
|
8
6
|
import type {
|
|
9
7
|
InlangPlugin,
|
|
@@ -14,6 +12,7 @@ import type { ProjectSettings } from "../json-schema/settings.js";
|
|
|
14
12
|
import type { PreprocessPluginBeforeImportFunction } from "../plugin/importPlugins.js";
|
|
15
13
|
import { PluginImportError } from "../plugin/errors.js";
|
|
16
14
|
import { upsertBundleNestedMatchByProperties } from "../import-export/upsertBundleNestedMatchByProperties.js";
|
|
15
|
+
import type { ImportFile } from "./api.js";
|
|
17
16
|
|
|
18
17
|
/**
|
|
19
18
|
* Loads a project from a directory.
|
|
@@ -62,69 +61,39 @@ export async function loadProjectFromDirectory(
|
|
|
62
61
|
syncInterval: args.syncInterval,
|
|
63
62
|
});
|
|
64
63
|
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
importPlugins,
|
|
69
|
-
exportPlugins,
|
|
70
|
-
} = categorizePlugins(await project.plugins.get());
|
|
64
|
+
const allPlugins = await project.plugins.get();
|
|
65
|
+
const { loadSavePlugins, importExportPlugins } =
|
|
66
|
+
categorizePlugins(allPlugins);
|
|
71
67
|
|
|
72
68
|
// TODO i guess we should move this validation logic into sdk2/src/project/loadProject.ts
|
|
73
69
|
// Two scenarios could arise:
|
|
74
70
|
// 1. set settings is called from an app - it should detect and reject the setting of settings -> app need to be able to validate before calling set
|
|
75
71
|
// 2. the settings file loaded from disc here is corrupted -> user has to fix the file on disc
|
|
76
|
-
if (
|
|
72
|
+
if (loadSavePlugins.length > 1) {
|
|
77
73
|
throw new Error(
|
|
78
74
|
"Max one loadMessages (found: " +
|
|
79
|
-
|
|
75
|
+
loadSavePlugins.length +
|
|
80
76
|
") and one saveMessages plugins (found: " +
|
|
81
|
-
|
|
77
|
+
loadSavePlugins.length +
|
|
82
78
|
") are allowed "
|
|
83
79
|
);
|
|
84
80
|
}
|
|
85
81
|
const importedResourceFileErrors: Error[] = [];
|
|
86
82
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
"Plugins for loadMessages (found: " +
|
|
93
|
-
loadMessagesPlugins.length +
|
|
94
|
-
") and saveMessages plugins (found: " +
|
|
95
|
-
saveMessagesPlugins.length +
|
|
96
|
-
") must not coexist with import (found: " +
|
|
97
|
-
importPlugins.length +
|
|
98
|
-
") or export (found: " +
|
|
99
|
-
exportPlugins.length +
|
|
100
|
-
") "
|
|
101
|
-
);
|
|
102
|
-
} else if (loadMessagesPlugins.length > 1 || saveMessagesPlugins.length > 1) {
|
|
103
|
-
throw new Error(
|
|
104
|
-
"Max one loadMessages (found: " +
|
|
105
|
-
loadMessagesPlugins.length +
|
|
106
|
-
") and one saveMessages plugins (found: " +
|
|
107
|
-
saveMessagesPlugins.length +
|
|
108
|
-
") are allowed "
|
|
109
|
-
);
|
|
110
|
-
} else if (importPlugins[0]) {
|
|
111
|
-
const importer = importPlugins[0];
|
|
112
|
-
const files = [];
|
|
113
|
-
|
|
114
|
-
if (importer.toBeImportedFiles) {
|
|
115
|
-
const toBeImportedFiles = await importer.toBeImportedFiles({
|
|
83
|
+
// import files from local fs
|
|
84
|
+
for (const plugin of importExportPlugins) {
|
|
85
|
+
const files: ImportFile[] = [];
|
|
86
|
+
if (plugin.toBeImportedFiles) {
|
|
87
|
+
const toBeImportedFiles = await plugin.toBeImportedFiles({
|
|
116
88
|
settings: await project.settings.get(),
|
|
117
89
|
});
|
|
118
90
|
for (const toBeImported of toBeImportedFiles) {
|
|
119
91
|
const absolute = absolutePathFromProject(args.path, toBeImported.path);
|
|
120
92
|
try {
|
|
121
93
|
const data = await args.fs.promises.readFile(absolute);
|
|
122
|
-
const name = nodePath.basename(toBeImported.path);
|
|
123
94
|
files.push({
|
|
124
|
-
name,
|
|
125
95
|
locale: toBeImported.locale,
|
|
126
96
|
content: data,
|
|
127
|
-
pluginKey: importer.key,
|
|
128
97
|
toBeImportedFilesMetadata: toBeImported.metadata,
|
|
129
98
|
});
|
|
130
99
|
} catch (e) {
|
|
@@ -143,17 +112,18 @@ export async function loadProjectFromDirectory(
|
|
|
143
112
|
}
|
|
144
113
|
|
|
145
114
|
await project.importFiles({
|
|
146
|
-
pluginKey:
|
|
147
|
-
files
|
|
115
|
+
pluginKey: plugin.key,
|
|
116
|
+
files,
|
|
148
117
|
});
|
|
149
|
-
}
|
|
150
|
-
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
for (const plugin of loadSavePlugins) {
|
|
151
121
|
await loadLegacyMessages({
|
|
152
122
|
project,
|
|
123
|
+
pluginKey: plugin.key ?? plugin.id,
|
|
124
|
+
loadMessagesFn: plugin.loadMessages!,
|
|
153
125
|
projectPath: args.path,
|
|
154
126
|
fs: args.fs,
|
|
155
|
-
pluginKey: loadMessagesPlugins[0].key ?? loadMessagesPlugins[0].id,
|
|
156
|
-
loadMessagesFn: loadMessagesPlugins[0].loadMessages,
|
|
157
127
|
});
|
|
158
128
|
}
|
|
159
129
|
|
|
@@ -569,13 +539,18 @@ async function upsertFileInLix(
|
|
|
569
539
|
path: string,
|
|
570
540
|
data: ArrayBuffer
|
|
571
541
|
) {
|
|
572
|
-
//
|
|
573
|
-
//
|
|
574
|
-
|
|
542
|
+
// force posix path when upserting into lix
|
|
543
|
+
// https://github.com/opral/inlang-sdk/issues/229
|
|
544
|
+
let posixPath = path.split(nodePath.win32.sep).join(nodePath.posix.sep);
|
|
545
|
+
|
|
546
|
+
if (posixPath.startsWith("/") === false) {
|
|
547
|
+
posixPath = "/" + posixPath;
|
|
548
|
+
}
|
|
549
|
+
|
|
575
550
|
await args.lix.db
|
|
576
551
|
.insertInto("file") // change queue
|
|
577
552
|
.values({
|
|
578
|
-
path:
|
|
553
|
+
path: posixPath,
|
|
579
554
|
data: new Uint8Array(data),
|
|
580
555
|
})
|
|
581
556
|
.onConflict((oc) =>
|
|
@@ -583,52 +558,28 @@ async function upsertFileInLix(
|
|
|
583
558
|
)
|
|
584
559
|
.execute();
|
|
585
560
|
}
|
|
561
|
+
/**
|
|
562
|
+
* Filters legacy load and save messages plugins.
|
|
563
|
+
*
|
|
564
|
+
* Legacy plugins are plugins that implement loadMessages and saveMessages but not importFiles and exportFiles.
|
|
565
|
+
*/
|
|
566
|
+
function categorizePlugins(plugins: readonly InlangPlugin[]) {
|
|
567
|
+
const loadSavePlugins: InlangPlugin[] = [];
|
|
568
|
+
const importExportPlugins: InlangPlugin[] = [];
|
|
569
|
+
|
|
570
|
+
for (const plugin of plugins) {
|
|
571
|
+
if (
|
|
572
|
+
plugin.loadMessages &&
|
|
573
|
+
plugin.saveMessages &&
|
|
574
|
+
!(plugin.importFiles && plugin.exportFiles)
|
|
575
|
+
) {
|
|
576
|
+
loadSavePlugins.push(plugin);
|
|
577
|
+
} else if (plugin.importFiles || plugin.exportFiles) {
|
|
578
|
+
importExportPlugins.push(plugin);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
586
581
|
|
|
587
|
-
|
|
588
|
-
function categorizePlugins(plugins: readonly InlangPlugin[]): {
|
|
589
|
-
loadMessagesPlugins: (InlangPlugin &
|
|
590
|
-
Required<Pick<InlangPlugin, "loadMessages">>)[];
|
|
591
|
-
saveMessagesPlugins: (InlangPlugin &
|
|
592
|
-
Required<Pick<InlangPlugin, "saveMessages">>)[];
|
|
593
|
-
importPlugins: (InlangPlugin &
|
|
594
|
-
Required<Pick<InlangPlugin, "importFiles" | "toBeImportedFiles">>)[];
|
|
595
|
-
exportPlugins: (InlangPlugin & Required<Pick<InlangPlugin, "exportFiles">>)[];
|
|
596
|
-
} {
|
|
597
|
-
const loadMessagesPlugins = plugins.filter(
|
|
598
|
-
(
|
|
599
|
-
plugin
|
|
600
|
-
): plugin is InlangPlugin & Required<Pick<InlangPlugin, "loadMessages">> =>
|
|
601
|
-
plugin.loadMessages !== undefined
|
|
602
|
-
);
|
|
603
|
-
|
|
604
|
-
const saveMessagesPlugins = plugins.filter(
|
|
605
|
-
(
|
|
606
|
-
plugin
|
|
607
|
-
): plugin is InlangPlugin & Required<Pick<InlangPlugin, "saveMessages">> =>
|
|
608
|
-
plugin.saveMessages !== undefined
|
|
609
|
-
);
|
|
610
|
-
|
|
611
|
-
const importPlugins = plugins.filter(
|
|
612
|
-
(
|
|
613
|
-
plugin
|
|
614
|
-
): plugin is InlangPlugin &
|
|
615
|
-
Required<Pick<InlangPlugin, "importFiles" | "toBeImportedFiles">> =>
|
|
616
|
-
plugin.importFiles !== undefined && plugin.toBeImportedFiles !== undefined
|
|
617
|
-
);
|
|
618
|
-
|
|
619
|
-
const exportPlugins = plugins.filter(
|
|
620
|
-
(
|
|
621
|
-
plugin
|
|
622
|
-
): plugin is InlangPlugin & Required<Pick<InlangPlugin, "exportFiles">> =>
|
|
623
|
-
plugin.exportFiles !== undefined
|
|
624
|
-
);
|
|
625
|
-
|
|
626
|
-
return {
|
|
627
|
-
loadMessagesPlugins,
|
|
628
|
-
saveMessagesPlugins,
|
|
629
|
-
importPlugins,
|
|
630
|
-
exportPlugins,
|
|
631
|
-
};
|
|
582
|
+
return { loadSavePlugins, importExportPlugins };
|
|
632
583
|
}
|
|
633
584
|
|
|
634
585
|
/**
|
|
@@ -38,7 +38,11 @@ export async function newProject(args?: {
|
|
|
38
38
|
{
|
|
39
39
|
path: "/settings.json",
|
|
40
40
|
data: new TextEncoder().encode(
|
|
41
|
-
JSON.stringify(
|
|
41
|
+
JSON.stringify(
|
|
42
|
+
args?.settings ?? defaultProjectSettings,
|
|
43
|
+
undefined,
|
|
44
|
+
2
|
|
45
|
+
)
|
|
42
46
|
),
|
|
43
47
|
},
|
|
44
48
|
{
|
|
@@ -308,3 +308,23 @@ test("it should preserve the formatting of existing json resource files", async
|
|
|
308
308
|
const fileAfterSave = await volume.promises.readFile("/foo/en.json", "utf-8");
|
|
309
309
|
expect(fileAfterSave).toBe(mockJson);
|
|
310
310
|
});
|
|
311
|
+
|
|
312
|
+
test("adds a gitignore file if it doesn't exist", async () => {
|
|
313
|
+
const fs = Volume.fromJSON({});
|
|
314
|
+
|
|
315
|
+
const project = await loadProjectInMemory({
|
|
316
|
+
blob: await newProject(),
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
await saveProjectToDirectory({
|
|
320
|
+
fs: fs.promises as any,
|
|
321
|
+
project,
|
|
322
|
+
path: "/foo/bar.inlang",
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
const gitignore = await fs.promises.readFile(
|
|
326
|
+
"/foo/bar.inlang/.gitignore",
|
|
327
|
+
"utf-8"
|
|
328
|
+
);
|
|
329
|
+
expect(gitignore).toBe("cache");
|
|
330
|
+
});
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* eslint-disable no-restricted-imports */
|
|
2
1
|
import type fs from "node:fs/promises";
|
|
3
2
|
import type { InlangProject } from "./api.js";
|
|
4
3
|
import path from "node:path";
|
|
@@ -23,16 +22,27 @@ export async function saveProjectToDirectory(args: {
|
|
|
23
22
|
.selectAll()
|
|
24
23
|
.execute();
|
|
25
24
|
|
|
25
|
+
let hasGitignore = false;
|
|
26
|
+
|
|
26
27
|
// write all files to the directory
|
|
27
28
|
for (const file of files) {
|
|
28
29
|
if (file.path.endsWith("db.sqlite")) {
|
|
29
30
|
continue;
|
|
31
|
+
} else if (file.path.endsWith(".gitignore")) {
|
|
32
|
+
hasGitignore = true;
|
|
30
33
|
}
|
|
31
34
|
const p = path.join(args.path, file.path);
|
|
32
35
|
await args.fs.mkdir(path.dirname(p), { recursive: true });
|
|
33
36
|
await args.fs.writeFile(p, new Uint8Array(file.data));
|
|
34
37
|
}
|
|
35
38
|
|
|
39
|
+
if (hasGitignore === false) {
|
|
40
|
+
await args.fs.writeFile(
|
|
41
|
+
path.join(args.path, ".gitignore"),
|
|
42
|
+
new TextEncoder().encode("cache")
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
36
46
|
// run exporters
|
|
37
47
|
const plugins = await args.project.plugins.get();
|
|
38
48
|
const settings = await args.project.settings.get();
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { Kysely } from "kysely";
|
|
2
|
-
import { type SqliteDatabase } from "sqlite-wasm-kysely";
|
|
3
|
-
import type { Lix } from "@lix-js/sdk";
|
|
4
|
-
import type { InlangDatabaseSchema } from "../database/schema.js";
|
|
5
|
-
/**
|
|
6
|
-
* Saves updates of the database (file) to lix.
|
|
7
|
-
*/
|
|
8
|
-
export declare function initHandleSaveToLixOnChange(args: {
|
|
9
|
-
sqlite: SqliteDatabase;
|
|
10
|
-
db: Kysely<InlangDatabaseSchema>;
|
|
11
|
-
lix: Lix;
|
|
12
|
-
pendingPromises: Promise<unknown>[];
|
|
13
|
-
}): Promise<void>;
|
|
14
|
-
//# sourceMappingURL=initHandleSaveToLixOnChange.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"initHandleSaveToLixOnChange.d.ts","sourceRoot":"/","sources":["project/initHandleSaveToLixOnChange.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAO,MAAM,QAAQ,CAAC;AACrC,OAAO,EAAuB,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE;;GAEG;AACH,wBAAsB,2BAA2B,CAAC,IAAI,EAAE;IACvD,MAAM,EAAE,cAAc,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC,oBAAoB,CAAC,CAAC;IACjC,GAAG,EAAE,GAAG,CAAC;IACT,eAAe,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;CACpC,iBA+EA"}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="1a4c93a4-17e3-5a38-bc7d-2850d39d1528")}catch(e){}}();
|
|
3
|
-
import { Kysely, sql } from "kysely";
|
|
4
|
-
import { contentFromDatabase } from "sqlite-wasm-kysely";
|
|
5
|
-
/**
|
|
6
|
-
* Saves updates of the database (file) to lix.
|
|
7
|
-
*/
|
|
8
|
-
export async function initHandleSaveToLixOnChange(args) {
|
|
9
|
-
args.sqlite.createFunction({
|
|
10
|
-
name: "save_db_file_to_lix",
|
|
11
|
-
arity: 0,
|
|
12
|
-
// @ts-expect-error - dynamic function
|
|
13
|
-
xFunc: () => {
|
|
14
|
-
// TODO handle in cancellable queue. only the last entry
|
|
15
|
-
// in the queue needs to be pushed to the file table
|
|
16
|
-
// because all previous entries are overwritten anyways
|
|
17
|
-
args.pendingPromises.push((async () => {
|
|
18
|
-
try {
|
|
19
|
-
// We have to await the database operations to be finished and the database to eb in a consistent state, otherwise contentFromDatabase will crash! 100 ms is too short for current test cases, but we need a proper solution for this
|
|
20
|
-
await new Promise((resolve) => setTimeout(resolve, 400));
|
|
21
|
-
const data = contentFromDatabase(args.sqlite);
|
|
22
|
-
await args.lix.db
|
|
23
|
-
.updateTable("file")
|
|
24
|
-
.set("data", data)
|
|
25
|
-
.where("path", "=", "/db.sqlite")
|
|
26
|
-
.execute();
|
|
27
|
-
}
|
|
28
|
-
catch {
|
|
29
|
-
// database has likely been closed.
|
|
30
|
-
// TODO needs better handling
|
|
31
|
-
}
|
|
32
|
-
})());
|
|
33
|
-
return;
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
// better way to write to lix on updates?
|
|
37
|
-
await sql `
|
|
38
|
-
CREATE TEMP TRIGGER bundle_insert AFTER INSERT ON bundle
|
|
39
|
-
BEGIN
|
|
40
|
-
SELECT save_db_file_to_lix();
|
|
41
|
-
END;
|
|
42
|
-
|
|
43
|
-
CREATE TEMP TRIGGER bundle_update AFTER UPDATE ON bundle
|
|
44
|
-
BEGIN
|
|
45
|
-
SELECT save_db_file_to_lix();
|
|
46
|
-
END;
|
|
47
|
-
|
|
48
|
-
CREATE TEMP TRIGGER bundle_delete AFTER DELETE ON bundle
|
|
49
|
-
BEGIN
|
|
50
|
-
SELECT save_db_file_to_lix();
|
|
51
|
-
END;
|
|
52
|
-
|
|
53
|
-
CREATE TEMP TRIGGER message_insert AFTER INSERT ON message
|
|
54
|
-
BEGIN
|
|
55
|
-
SELECT save_db_file_to_lix();
|
|
56
|
-
END;
|
|
57
|
-
|
|
58
|
-
CREATE TEMP TRIGGER message_update AFTER UPDATE ON message
|
|
59
|
-
BEGIN
|
|
60
|
-
SELECT save_db_file_to_lix();
|
|
61
|
-
END;
|
|
62
|
-
|
|
63
|
-
CREATE TEMP TRIGGER message_delete AFTER DELETE ON message
|
|
64
|
-
BEGIN
|
|
65
|
-
SELECT save_db_file_to_lix();
|
|
66
|
-
END;
|
|
67
|
-
|
|
68
|
-
CREATE TEMP TRIGGER variant_insert AFTER INSERT ON variant
|
|
69
|
-
BEGIN
|
|
70
|
-
SELECT save_db_file_to_lix();
|
|
71
|
-
END;
|
|
72
|
-
|
|
73
|
-
CREATE TEMP TRIGGER variant_update AFTER UPDATE ON variant
|
|
74
|
-
BEGIN
|
|
75
|
-
SELECT save_db_file_to_lix();
|
|
76
|
-
END;
|
|
77
|
-
|
|
78
|
-
CREATE TEMP TRIGGER variant_delete AFTER DELETE ON variant
|
|
79
|
-
BEGIN
|
|
80
|
-
SELECT save_db_file_to_lix();
|
|
81
|
-
END;
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
`.execute(args.db);
|
|
85
|
-
}
|
|
86
|
-
//# sourceMappingURL=initHandleSaveToLixOnChange.js.map
|
|
87
|
-
//# debugId=1a4c93a4-17e3-5a38-bc7d-2850d39d1528
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"initHandleSaveToLixOnChange.js","sources":["project/initHandleSaveToLixOnChange.ts"],"sourceRoot":"/","sourcesContent":["import { Kysely, sql } from \"kysely\";\nimport { contentFromDatabase, type SqliteDatabase } from \"sqlite-wasm-kysely\";\nimport type { Lix } from \"@lix-js/sdk\";\nimport type { InlangDatabaseSchema } from \"../database/schema.js\";\n\n/**\n * Saves updates of the database (file) to lix.\n */\nexport async function initHandleSaveToLixOnChange(args: {\n\tsqlite: SqliteDatabase;\n\tdb: Kysely<InlangDatabaseSchema>;\n\tlix: Lix;\n\tpendingPromises: Promise<unknown>[];\n}) {\n\targs.sqlite.createFunction({\n\t\tname: \"save_db_file_to_lix\",\n\t\tarity: 0,\n\t\t// @ts-expect-error - dynamic function\n\t\txFunc: () => {\n\t\t\t// TODO handle in cancellable queue. only the last entry\n\t\t\t// in the queue needs to be pushed to the file table\n\t\t\t// because all previous entries are overwritten anyways\n\t\t\targs.pendingPromises.push(\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// We have to await the database operations to be finished and the database to eb in a consistent state, otherwise contentFromDatabase will crash! 100 ms is too short for current test cases, but we need a proper solution for this\n\t\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 400));\n\t\t\t\t\t\tconst data = contentFromDatabase(args.sqlite);\n\t\t\t\t\t\tawait args.lix.db\n\t\t\t\t\t\t\t.updateTable(\"file\")\n\t\t\t\t\t\t\t.set(\"data\", data)\n\t\t\t\t\t\t\t.where(\"path\", \"=\", \"/db.sqlite\")\n\t\t\t\t\t\t\t.execute();\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// database has likely been closed.\n\t\t\t\t\t\t// TODO needs better handling\n\t\t\t\t\t}\n\t\t\t\t})()\n\t\t\t);\n\t\t\treturn;\n\t\t},\n\t});\n\n\t// better way to write to lix on updates?\n\tawait sql`\n\tCREATE TEMP TRIGGER bundle_insert AFTER INSERT ON bundle\n\tBEGIN\n\t SELECT save_db_file_to_lix();\n\tEND;\n\n\tCREATE TEMP TRIGGER bundle_update AFTER UPDATE ON bundle\n\tBEGIN\n\t SELECT save_db_file_to_lix();\n\tEND;\n\n\tCREATE TEMP TRIGGER bundle_delete AFTER DELETE ON bundle\n\tBEGIN\n\t SELECT save_db_file_to_lix();\n\tEND;\n\n\t\tCREATE TEMP TRIGGER message_insert AFTER INSERT ON message\n\tBEGIN\n\t SELECT save_db_file_to_lix();\n\tEND;\n\n\tCREATE TEMP TRIGGER message_update AFTER UPDATE ON message\n\tBEGIN\n\t SELECT save_db_file_to_lix();\n\tEND;\n\n\tCREATE TEMP TRIGGER message_delete AFTER DELETE ON message\n\tBEGIN\n\t SELECT save_db_file_to_lix();\n\tEND;\n\n\tCREATE TEMP TRIGGER variant_insert AFTER INSERT ON variant\n\tBEGIN\n\t SELECT save_db_file_to_lix();\n\tEND;\n\n\tCREATE TEMP TRIGGER variant_update AFTER UPDATE ON variant\n\tBEGIN\n\t SELECT save_db_file_to_lix();\n\tEND;\n\n\tCREATE TEMP TRIGGER variant_delete AFTER DELETE ON variant\n\tBEGIN\n\t SELECT save_db_file_to_lix();\n\tEND;\n\n\n\t`.execute(args.db);\n}\n"],"names":[],"mappings":";;AAAA,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAuB,MAAM,oBAAoB,CAAC;AAI9E;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,IAKjD;IACA,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC;QAC1B,IAAI,EAAE,qBAAqB;QAC3B,KAAK,EAAE,CAAC;QACR,sCAAsC;QACtC,KAAK,EAAE,GAAG,EAAE;YACX,wDAAwD;YACxD,oDAAoD;YACpD,uDAAuD;YACvD,IAAI,CAAC,eAAe,CAAC,IAAI,CACxB,CAAC,KAAK,IAAI,EAAE;gBACX,IAAI,CAAC;oBACJ,qOAAqO;oBACrO,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;oBACzD,MAAM,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBAC9C,MAAM,IAAI,CAAC,GAAG,CAAC,EAAE;yBACf,WAAW,CAAC,MAAM,CAAC;yBACnB,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC;yBACjB,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,YAAY,CAAC;yBAChC,OAAO,EAAE,CAAC;gBACb,CAAC;gBAAC,MAAM,CAAC;oBACR,mCAAmC;oBACnC,6BAA6B;gBAC9B,CAAC;YACF,CAAC,CAAC,EAAE,CACJ,CAAC;YACF,OAAO;QACR,CAAC;KACD,CAAC,CAAC;IAEH,yCAAyC;IACzC,MAAM,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+CR,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACpB,CAAC","debug_id":"1a4c93a4-17e3-5a38-bc7d-2850d39d1528"}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { Kysely, sql } from "kysely";
|
|
2
|
-
import { contentFromDatabase, type SqliteDatabase } from "sqlite-wasm-kysely";
|
|
3
|
-
import type { Lix } from "@lix-js/sdk";
|
|
4
|
-
import type { InlangDatabaseSchema } from "../database/schema.js";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Saves updates of the database (file) to lix.
|
|
8
|
-
*/
|
|
9
|
-
export async function initHandleSaveToLixOnChange(args: {
|
|
10
|
-
sqlite: SqliteDatabase;
|
|
11
|
-
db: Kysely<InlangDatabaseSchema>;
|
|
12
|
-
lix: Lix;
|
|
13
|
-
pendingPromises: Promise<unknown>[];
|
|
14
|
-
}) {
|
|
15
|
-
args.sqlite.createFunction({
|
|
16
|
-
name: "save_db_file_to_lix",
|
|
17
|
-
arity: 0,
|
|
18
|
-
// @ts-expect-error - dynamic function
|
|
19
|
-
xFunc: () => {
|
|
20
|
-
// TODO handle in cancellable queue. only the last entry
|
|
21
|
-
// in the queue needs to be pushed to the file table
|
|
22
|
-
// because all previous entries are overwritten anyways
|
|
23
|
-
args.pendingPromises.push(
|
|
24
|
-
(async () => {
|
|
25
|
-
try {
|
|
26
|
-
// We have to await the database operations to be finished and the database to eb in a consistent state, otherwise contentFromDatabase will crash! 100 ms is too short for current test cases, but we need a proper solution for this
|
|
27
|
-
await new Promise((resolve) => setTimeout(resolve, 400));
|
|
28
|
-
const data = contentFromDatabase(args.sqlite);
|
|
29
|
-
await args.lix.db
|
|
30
|
-
.updateTable("file")
|
|
31
|
-
.set("data", data)
|
|
32
|
-
.where("path", "=", "/db.sqlite")
|
|
33
|
-
.execute();
|
|
34
|
-
} catch {
|
|
35
|
-
// database has likely been closed.
|
|
36
|
-
// TODO needs better handling
|
|
37
|
-
}
|
|
38
|
-
})()
|
|
39
|
-
);
|
|
40
|
-
return;
|
|
41
|
-
},
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// better way to write to lix on updates?
|
|
45
|
-
await sql`
|
|
46
|
-
CREATE TEMP TRIGGER bundle_insert AFTER INSERT ON bundle
|
|
47
|
-
BEGIN
|
|
48
|
-
SELECT save_db_file_to_lix();
|
|
49
|
-
END;
|
|
50
|
-
|
|
51
|
-
CREATE TEMP TRIGGER bundle_update AFTER UPDATE ON bundle
|
|
52
|
-
BEGIN
|
|
53
|
-
SELECT save_db_file_to_lix();
|
|
54
|
-
END;
|
|
55
|
-
|
|
56
|
-
CREATE TEMP TRIGGER bundle_delete AFTER DELETE ON bundle
|
|
57
|
-
BEGIN
|
|
58
|
-
SELECT save_db_file_to_lix();
|
|
59
|
-
END;
|
|
60
|
-
|
|
61
|
-
CREATE TEMP TRIGGER message_insert AFTER INSERT ON message
|
|
62
|
-
BEGIN
|
|
63
|
-
SELECT save_db_file_to_lix();
|
|
64
|
-
END;
|
|
65
|
-
|
|
66
|
-
CREATE TEMP TRIGGER message_update AFTER UPDATE ON message
|
|
67
|
-
BEGIN
|
|
68
|
-
SELECT save_db_file_to_lix();
|
|
69
|
-
END;
|
|
70
|
-
|
|
71
|
-
CREATE TEMP TRIGGER message_delete AFTER DELETE ON message
|
|
72
|
-
BEGIN
|
|
73
|
-
SELECT save_db_file_to_lix();
|
|
74
|
-
END;
|
|
75
|
-
|
|
76
|
-
CREATE TEMP TRIGGER variant_insert AFTER INSERT ON variant
|
|
77
|
-
BEGIN
|
|
78
|
-
SELECT save_db_file_to_lix();
|
|
79
|
-
END;
|
|
80
|
-
|
|
81
|
-
CREATE TEMP TRIGGER variant_update AFTER UPDATE ON variant
|
|
82
|
-
BEGIN
|
|
83
|
-
SELECT save_db_file_to_lix();
|
|
84
|
-
END;
|
|
85
|
-
|
|
86
|
-
CREATE TEMP TRIGGER variant_delete AFTER DELETE ON variant
|
|
87
|
-
BEGIN
|
|
88
|
-
SELECT save_db_file_to_lix();
|
|
89
|
-
END;
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
`.execute(args.db);
|
|
93
|
-
}
|