@inlang/sdk 0.34.2 → 0.34.4
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 +201 -0
- package/dist/adapter/solidAdapter.test.js +1 -1
- package/dist/createMessagesQuery.d.ts +14 -2
- package/dist/createMessagesQuery.d.ts.map +1 -1
- package/dist/createMessagesQuery.js +338 -6
- package/dist/createMessagesQuery.test.js +133 -88
- package/dist/createNodeishFsWithWatcher.d.ts +1 -0
- package/dist/createNodeishFsWithWatcher.d.ts.map +1 -1
- package/dist/createNodeishFsWithWatcher.js +2 -2
- package/dist/createNodeishFsWithWatcher.test.js +8 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +12 -2
- package/dist/loadProject.d.ts.map +1 -1
- package/dist/loadProject.js +21 -487
- package/dist/persistence/filelock/acquireFileLock.d.ts +3 -0
- package/dist/persistence/filelock/acquireFileLock.d.ts.map +1 -0
- package/dist/persistence/filelock/acquireFileLock.js +109 -0
- package/dist/persistence/filelock/releaseLock.d.ts +3 -0
- package/dist/persistence/filelock/releaseLock.d.ts.map +1 -0
- package/dist/persistence/filelock/releaseLock.js +23 -0
- package/package.json +8 -8
- package/src/adapter/solidAdapter.test.ts +1 -1
- package/src/createMessagesQuery.test.ts +147 -109
- package/src/createMessagesQuery.ts +477 -8
- package/src/createNodeishFsWithWatcher.test.ts +13 -0
- package/src/createNodeishFsWithWatcher.ts +2 -2
- package/src/errors.ts +16 -4
- package/src/loadProject.ts +20 -666
- package/src/persistence/filelock/acquireFileLock.ts +124 -0
- package/src/persistence/filelock/releaseLock.ts +28 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import {} from "@lix-js/fs";
|
|
2
|
+
import _debug from "debug";
|
|
3
|
+
const debug = _debug("sdk:acquireFileLock");
|
|
4
|
+
const maxRetries = 10;
|
|
5
|
+
const nProbes = 50;
|
|
6
|
+
const probeInterval = 100;
|
|
7
|
+
export async function acquireFileLock(fs, lockDirPath, lockOrigin, tryCount = 0) {
|
|
8
|
+
if (tryCount > maxRetries) {
|
|
9
|
+
throw new Error(lockOrigin + " exceeded maximum Retries (5) to acquire lockfile " + tryCount);
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
debug(lockOrigin + " tries to acquire a lockfile Retry Nr.: " + tryCount);
|
|
13
|
+
await fs.mkdir(lockDirPath);
|
|
14
|
+
const stats = await fs.stat(lockDirPath);
|
|
15
|
+
debug(lockOrigin + " acquired a lockfile Retry Nr.: " + tryCount);
|
|
16
|
+
return stats.mtimeMs;
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
if (error.code !== "EEXIST") {
|
|
20
|
+
// we only expect the error that the file exists already (locked by other process)
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
let currentLockTime;
|
|
25
|
+
try {
|
|
26
|
+
const stats = await fs.stat(lockDirPath);
|
|
27
|
+
currentLockTime = stats.mtimeMs;
|
|
28
|
+
}
|
|
29
|
+
catch (fstatError) {
|
|
30
|
+
if (fstatError.code === "ENOENT") {
|
|
31
|
+
// lock file seems to be gone :) - lets try again
|
|
32
|
+
debug(lockOrigin + " tryCount++ lock file seems to be gone :) - lets try again " + tryCount);
|
|
33
|
+
return acquireFileLock(fs, lockDirPath, lockOrigin, tryCount + 1);
|
|
34
|
+
}
|
|
35
|
+
throw fstatError;
|
|
36
|
+
}
|
|
37
|
+
debug(lockOrigin +
|
|
38
|
+
" tries to acquire a lockfile - lock currently in use... starting probe phase " +
|
|
39
|
+
tryCount);
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
let probeCounts = 0;
|
|
42
|
+
const scheduleProbationTimeout = () => {
|
|
43
|
+
setTimeout(async () => {
|
|
44
|
+
probeCounts += 1;
|
|
45
|
+
let lockFileStats = undefined;
|
|
46
|
+
try {
|
|
47
|
+
debug(lockOrigin + " tries to acquire a lockfile - check if the lock is free now " + tryCount);
|
|
48
|
+
// alright lets give it another try
|
|
49
|
+
lockFileStats = await fs.stat(lockDirPath);
|
|
50
|
+
}
|
|
51
|
+
catch (fstatError) {
|
|
52
|
+
if (fstatError.code === "ENOENT") {
|
|
53
|
+
debug(lockOrigin +
|
|
54
|
+
" tryCount++ in Promise - tries to acquire a lockfile - lock file seems to be free now - try to acquire " +
|
|
55
|
+
tryCount);
|
|
56
|
+
const lock = acquireFileLock(fs, lockDirPath, lockOrigin, tryCount + 1);
|
|
57
|
+
return resolve(lock);
|
|
58
|
+
}
|
|
59
|
+
return reject(fstatError);
|
|
60
|
+
}
|
|
61
|
+
// still the same locker! -
|
|
62
|
+
if (lockFileStats.mtimeMs === currentLockTime) {
|
|
63
|
+
if (probeCounts >= nProbes) {
|
|
64
|
+
// ok maximum lock time ran up (we waitetd nProbes * probeInterval) - we consider the lock to be stale
|
|
65
|
+
debug(lockOrigin +
|
|
66
|
+
" tries to acquire a lockfile - lock not free - but stale lets drop it" +
|
|
67
|
+
tryCount);
|
|
68
|
+
try {
|
|
69
|
+
await fs.rmdir(lockDirPath);
|
|
70
|
+
}
|
|
71
|
+
catch (rmLockError) {
|
|
72
|
+
if (rmLockError.code === "ENOENT") {
|
|
73
|
+
// lock already gone?
|
|
74
|
+
// Option 1: The "stale process" decided to get rid of it
|
|
75
|
+
// Option 2: Another process acquiring the lock and detected a stale one as well
|
|
76
|
+
}
|
|
77
|
+
return reject(rmLockError);
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
debug(lockOrigin +
|
|
81
|
+
" tryCount++ same locker - try to acquire again after removing stale lock " +
|
|
82
|
+
tryCount);
|
|
83
|
+
const lock = await acquireFileLock(fs, lockDirPath, lockOrigin, tryCount + 1);
|
|
84
|
+
return resolve(lock);
|
|
85
|
+
}
|
|
86
|
+
catch (lockAquireException) {
|
|
87
|
+
return reject(lockAquireException);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// lets schedule a new probation
|
|
92
|
+
return scheduleProbationTimeout();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
try {
|
|
97
|
+
debug(lockOrigin + " tryCount++ different locker - try to acquire again " + tryCount);
|
|
98
|
+
const lock = await acquireFileLock(fs, lockDirPath, lockOrigin, tryCount + 1);
|
|
99
|
+
return resolve(lock);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
return reject(error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}, probeInterval);
|
|
106
|
+
};
|
|
107
|
+
scheduleProbationTimeout();
|
|
108
|
+
});
|
|
109
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"releaseLock.d.ts","sourceRoot":"","sources":["../../../src/persistence/filelock/releaseLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAInD,wBAAsB,WAAW,CAChC,EAAE,EAAE,iBAAiB,EACrB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,iBAmBhB"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {} from "@lix-js/fs";
|
|
2
|
+
import _debug from "debug";
|
|
3
|
+
const debug = _debug("sdk:releaseLock");
|
|
4
|
+
export async function releaseLock(fs, lockDirPath, lockOrigin, lockTime) {
|
|
5
|
+
debug(lockOrigin + " releasing the lock ");
|
|
6
|
+
try {
|
|
7
|
+
const stats = await fs.stat(lockDirPath);
|
|
8
|
+
if (stats.mtimeMs === lockTime) {
|
|
9
|
+
// this can be corrupt as welll since the last getStat and the current a modification could have occured :-/
|
|
10
|
+
await fs.rmdir(lockDirPath);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
catch (statError) {
|
|
14
|
+
debug(lockOrigin + " couldn't release the lock");
|
|
15
|
+
if (statError.code === "ENOENT") {
|
|
16
|
+
// ok seeks like the log was released by someone else
|
|
17
|
+
debug(lockOrigin + " WARNING - the lock was released by a different process");
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
debug(statError);
|
|
21
|
+
throw statError;
|
|
22
|
+
}
|
|
23
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inlang/sdk",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.34.
|
|
4
|
+
"version": "0.34.4",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -33,16 +33,16 @@
|
|
|
33
33
|
"solid-js": "1.6.12",
|
|
34
34
|
"throttle-debounce": "^5.0.0",
|
|
35
35
|
"@inlang/language-tag": "1.5.1",
|
|
36
|
+
"@inlang/json-types": "1.1.0",
|
|
37
|
+
"@inlang/message-lint-rule": "1.4.7",
|
|
38
|
+
"@inlang/project-settings": "2.4.2",
|
|
39
|
+
"@inlang/plugin": "2.4.11",
|
|
36
40
|
"@inlang/message": "2.1.0",
|
|
37
|
-
"@inlang/message-lint-rule": "1.4.6",
|
|
38
|
-
"@inlang/module": "1.2.10",
|
|
39
|
-
"@inlang/plugin": "2.4.10",
|
|
40
41
|
"@inlang/result": "1.1.0",
|
|
41
|
-
"@inlang/
|
|
42
|
+
"@inlang/module": "1.2.11",
|
|
42
43
|
"@inlang/translatable": "1.3.1",
|
|
43
|
-
"@
|
|
44
|
-
"@lix-js/fs": "1.0.0"
|
|
45
|
-
"@lix-js/client": "1.4.0"
|
|
44
|
+
"@lix-js/client": "1.4.0",
|
|
45
|
+
"@lix-js/fs": "1.0.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/debug": "^4.1.12",
|
|
@@ -232,7 +232,7 @@ describe("messages", () => {
|
|
|
232
232
|
// TODO: how can we await `setConfig` correctly
|
|
233
233
|
await new Promise((resolve) => setTimeout(resolve, 510))
|
|
234
234
|
|
|
235
|
-
expect(effectOnMessagesCounter).toBe(
|
|
235
|
+
expect(effectOnMessagesCounter).toBe(7) // 7 = initial effect, setSetting, loadMessage (2x - one per message), setResolvedPlugins, loadMessages (2x - one per message)
|
|
236
236
|
expect(Object.values(project.query.messages.getAll()).length).toBe(2)
|
|
237
237
|
})
|
|
238
238
|
|
|
@@ -2,15 +2,72 @@
|
|
|
2
2
|
import { describe, it, expect } from "vitest"
|
|
3
3
|
import { createMessagesQuery } from "./createMessagesQuery.js"
|
|
4
4
|
import { createEffect, createRoot, createSignal } from "./reactivity/solid.js"
|
|
5
|
-
import
|
|
5
|
+
import { Message, type Text } from "@inlang/message"
|
|
6
6
|
import { createMessage } from "./test-utilities/createMessage.js"
|
|
7
|
+
import { createNodeishMemoryFs } from "@lix-js/fs"
|
|
8
|
+
import type { resolveModules } from "./resolve-modules/resolveModules.js"
|
|
9
|
+
import type { ProjectSettings } from "./versionedInterfaces.js"
|
|
10
|
+
import type { InlangProject } from "./api.js"
|
|
7
11
|
|
|
8
12
|
const createChangeListener = async (cb: () => void) => createEffect(cb)
|
|
9
13
|
const nextTick = () => new Promise((resolve) => setTimeout(resolve, 0))
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
16
|
+
const awaitableCreateMessageQuery = async (_messages: () => Message[]) => {
|
|
17
|
+
const fs = createNodeishMemoryFs()
|
|
18
|
+
const settings: ProjectSettings = {
|
|
19
|
+
sourceLanguageTag: "en",
|
|
20
|
+
languageTags: ["en"],
|
|
21
|
+
modules: ["plugin.js", "lintRule.js"],
|
|
22
|
+
messageLintRuleLevels: {
|
|
23
|
+
"messageLintRule.project.missingTranslation": "error",
|
|
24
|
+
},
|
|
25
|
+
"plugin.project.i18next": {
|
|
26
|
+
pathPattern: "./examples/example01/{languageTag}.json",
|
|
27
|
+
variableReferencePattern: ["{", "}"],
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let messages: any = _messages()
|
|
32
|
+
|
|
33
|
+
const resolvedModules: Awaited<ReturnType<typeof resolveModules>> = {
|
|
34
|
+
meta: [],
|
|
35
|
+
plugins: [],
|
|
36
|
+
messageLintRules: [],
|
|
37
|
+
resolvedPluginApi: {
|
|
38
|
+
loadMessages: (() => {
|
|
39
|
+
return messages
|
|
40
|
+
}) as any,
|
|
41
|
+
saveMessages: ((newMessages: any) => {
|
|
42
|
+
messages = newMessages
|
|
43
|
+
}) as any,
|
|
44
|
+
customApi: {},
|
|
45
|
+
},
|
|
46
|
+
errors: [],
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return new Promise<InlangProject["query"]["messages"]>((res, rej) => {
|
|
50
|
+
const query = createMessagesQuery({
|
|
51
|
+
projectPath: "",
|
|
52
|
+
nodeishFs: fs,
|
|
53
|
+
settings: () => settings,
|
|
54
|
+
resolvedModules: () => resolvedModules,
|
|
55
|
+
onInitialMessageLoadResult: (error) => {
|
|
56
|
+
if (error) {
|
|
57
|
+
rej(error)
|
|
58
|
+
} else {
|
|
59
|
+
res(query)
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
onLoadMessageResult: () => {},
|
|
63
|
+
onSaveMessageResult: () => {},
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
describe("create", async () => {
|
|
69
|
+
it("should create a message", async () => {
|
|
70
|
+
const query = await awaitableCreateMessageQuery(() => [])
|
|
14
71
|
expect(query.get({ where: { id: "first-message" } })).toBeUndefined()
|
|
15
72
|
|
|
16
73
|
const mockMessage = createMessage("first-message", { en: "Hello World" })
|
|
@@ -20,8 +77,8 @@ describe("create", () => {
|
|
|
20
77
|
expect(created).toBe(true)
|
|
21
78
|
})
|
|
22
79
|
|
|
23
|
-
it("query.getByDefaultAlias should return a message with a default alias", () => {
|
|
24
|
-
const query =
|
|
80
|
+
it("query.getByDefaultAlias should return a message with a default alias", async () => {
|
|
81
|
+
const query = await awaitableCreateMessageQuery(() => [])
|
|
25
82
|
expect(query.get({ where: { id: "first-message" } })).toBeUndefined()
|
|
26
83
|
|
|
27
84
|
const mockMessage = createMessage("first-message", { en: "Hello World" })
|
|
@@ -33,8 +90,10 @@ describe("create", () => {
|
|
|
33
90
|
expect(created).toBe(true)
|
|
34
91
|
})
|
|
35
92
|
|
|
36
|
-
it("should return false if message with id already exists", () => {
|
|
37
|
-
const query =
|
|
93
|
+
it("should return false if message with id already exists", async () => {
|
|
94
|
+
const query = await awaitableCreateMessageQuery(() => [
|
|
95
|
+
createMessage("first-message", { en: "Hello World" }),
|
|
96
|
+
])
|
|
38
97
|
expect(query.get({ where: { id: "first-message" } })).toBeDefined()
|
|
39
98
|
|
|
40
99
|
const mockMessage = createMessage("first-message", { en: "Some Text" })
|
|
@@ -45,23 +104,35 @@ describe("create", () => {
|
|
|
45
104
|
})
|
|
46
105
|
})
|
|
47
106
|
|
|
48
|
-
describe("get", () => {
|
|
49
|
-
it("should return undefined if a message does not exist", () => {
|
|
50
|
-
const query =
|
|
107
|
+
describe("get", async () => {
|
|
108
|
+
it("should return undefined if a message does not exist", async () => {
|
|
109
|
+
const query = await awaitableCreateMessageQuery(() => [
|
|
110
|
+
createMessage("first-message", { en: "Hello World" }),
|
|
111
|
+
])
|
|
112
|
+
|
|
51
113
|
const message = query.get({ where: { id: "none-existent-message" } })
|
|
52
114
|
expect(message).toBeUndefined()
|
|
53
115
|
})
|
|
54
116
|
|
|
55
|
-
it("should return an object, not an array", () => {
|
|
56
|
-
const query =
|
|
117
|
+
it("should return an object, not an array", async () => {
|
|
118
|
+
const query = await awaitableCreateMessageQuery(() => [
|
|
119
|
+
createMessage("first-message", { en: "Hello World" }),
|
|
120
|
+
])
|
|
121
|
+
expect(query.get({ where: { id: "first-message" } })).toBeDefined()
|
|
122
|
+
|
|
123
|
+
const mockMessageInit = createMessage("first-message", { en: "Hello World" })
|
|
124
|
+
query.create({ data: mockMessageInit })
|
|
125
|
+
|
|
57
126
|
const message = query.get({ where: { id: "first-message" } })
|
|
58
127
|
expect(message).toBeDefined()
|
|
59
128
|
expect(Array.isArray(message)).toBe(false)
|
|
60
129
|
})
|
|
61
130
|
|
|
62
131
|
// todo: improve the readonly type
|
|
63
|
-
it.skip("mutating the returned value should not affect subsequent return values", () => {
|
|
64
|
-
const query =
|
|
132
|
+
it.skip("mutating the returned value should not affect subsequent return values", async () => {
|
|
133
|
+
const query = await awaitableCreateMessageQuery(() => [
|
|
134
|
+
createMessage("first-message", { en: "Hello World" }),
|
|
135
|
+
])
|
|
65
136
|
const message1 = query.get({ where: { id: "first-message" } })!
|
|
66
137
|
;(message1.variants.find((v) => v.languageTag === "en")!.pattern![0]! as Text).value =
|
|
67
138
|
"Hello World 2"
|
|
@@ -76,16 +147,16 @@ describe("get", () => {
|
|
|
76
147
|
})
|
|
77
148
|
})
|
|
78
149
|
|
|
79
|
-
describe("getAll", () => {
|
|
80
|
-
it("should return an empty array if no messages exist", () => {
|
|
81
|
-
const query =
|
|
150
|
+
describe("getAll", async () => {
|
|
151
|
+
it("should return an empty array if no messages exist", async () => {
|
|
152
|
+
const query = await awaitableCreateMessageQuery(() => [])
|
|
82
153
|
const messages = query.getAll()
|
|
83
154
|
|
|
84
155
|
expect(Object.values(messages!)).toEqual([])
|
|
85
156
|
})
|
|
86
157
|
|
|
87
|
-
it("should return all message objects", () => {
|
|
88
|
-
const query =
|
|
158
|
+
it("should return all message objects", async () => {
|
|
159
|
+
const query = await awaitableCreateMessageQuery(() => [])
|
|
89
160
|
const mockMessage1 = createMessage("first-message", { en: "Hello World" })
|
|
90
161
|
const mockMessage2 = createMessage("second-message", { en: "Hello World 2" })
|
|
91
162
|
query.create({ data: mockMessage1 })
|
|
@@ -96,8 +167,11 @@ describe("getAll", () => {
|
|
|
96
167
|
})
|
|
97
168
|
|
|
98
169
|
// todo: improve the readonly type
|
|
99
|
-
it.skip("mutating the returned value should not affect subsequent return values", () => {
|
|
100
|
-
const query =
|
|
170
|
+
it.skip("mutating the returned value should not affect subsequent return values", async () => {
|
|
171
|
+
const query = await awaitableCreateMessageQuery(() => [
|
|
172
|
+
createMessage("first-message", { en: "Hello World" }),
|
|
173
|
+
])
|
|
174
|
+
|
|
101
175
|
const messages1 = query.getAll()
|
|
102
176
|
;(
|
|
103
177
|
Object.values(messages1!)[0]!.variants.find((v) => v.languageTag === "en")!
|
|
@@ -113,9 +187,12 @@ describe("getAll", () => {
|
|
|
113
187
|
})
|
|
114
188
|
})
|
|
115
189
|
|
|
116
|
-
describe("update", () => {
|
|
117
|
-
it("should update a message", () => {
|
|
118
|
-
const query =
|
|
190
|
+
describe("update", async () => {
|
|
191
|
+
it("should update a message", async () => {
|
|
192
|
+
const query = await awaitableCreateMessageQuery(() => [
|
|
193
|
+
createMessage("first-message", { en: "Hello World" }),
|
|
194
|
+
])
|
|
195
|
+
|
|
119
196
|
expect(query.get({ where: { id: "first-message" } })).toBeDefined()
|
|
120
197
|
|
|
121
198
|
const mockMessage = createMessage("first-message", { en: "Hello World 2" })
|
|
@@ -125,8 +202,8 @@ describe("update", () => {
|
|
|
125
202
|
expect(updated).toBe(true)
|
|
126
203
|
})
|
|
127
204
|
|
|
128
|
-
it("should return false if message with id does not exist exists", () => {
|
|
129
|
-
const query =
|
|
205
|
+
it("should return false if message with id does not exist exists", async () => {
|
|
206
|
+
const query = await awaitableCreateMessageQuery(() => [])
|
|
130
207
|
expect(query.get({ where: { id: "first-message" } })).toBeUndefined()
|
|
131
208
|
|
|
132
209
|
const mockMessage = createMessage("first-message", { en: "Hello World" })
|
|
@@ -135,9 +212,9 @@ describe("update", () => {
|
|
|
135
212
|
})
|
|
136
213
|
})
|
|
137
214
|
|
|
138
|
-
describe("upsert", () => {
|
|
139
|
-
it("should create a message if not present yet", () => {
|
|
140
|
-
const query =
|
|
215
|
+
describe("upsert", async () => {
|
|
216
|
+
it("should create a message if not present yet", async () => {
|
|
217
|
+
const query = await awaitableCreateMessageQuery(() => [])
|
|
141
218
|
expect(query.get({ where: { id: "first-message" } })).toBeUndefined()
|
|
142
219
|
|
|
143
220
|
const mockMessage = createMessage("first-message", { en: "Hello World" })
|
|
@@ -147,8 +224,15 @@ describe("upsert", () => {
|
|
|
147
224
|
expect(upserted).toBe(true)
|
|
148
225
|
})
|
|
149
226
|
|
|
150
|
-
it("should update message if id already exists", () => {
|
|
151
|
-
const query =
|
|
227
|
+
it("should update message if id already exists", async () => {
|
|
228
|
+
const query = await awaitableCreateMessageQuery(() => [
|
|
229
|
+
createMessage("first-message", { en: "Hello World" }),
|
|
230
|
+
])
|
|
231
|
+
expect(query.get({ where: { id: "first-message" } })).toBeDefined()
|
|
232
|
+
|
|
233
|
+
const mockMessageInit = createMessage("first-message", { en: "Hello World" })
|
|
234
|
+
query.create({ data: mockMessageInit })
|
|
235
|
+
|
|
152
236
|
expect(query.get({ where: { id: "first-message" } })).toBeDefined()
|
|
153
237
|
|
|
154
238
|
const mockMessage = createMessage("first-message", { en: "Hello World 2" })
|
|
@@ -159,9 +243,12 @@ describe("upsert", () => {
|
|
|
159
243
|
})
|
|
160
244
|
})
|
|
161
245
|
|
|
162
|
-
describe("delete", () => {
|
|
163
|
-
it("should delete a message", () => {
|
|
164
|
-
const query =
|
|
246
|
+
describe("delete", async () => {
|
|
247
|
+
it("should delete a message", async () => {
|
|
248
|
+
const query = await awaitableCreateMessageQuery(() => [
|
|
249
|
+
createMessage("first-message", { en: "Hello World" }),
|
|
250
|
+
])
|
|
251
|
+
|
|
165
252
|
expect(query.get({ where: { id: "first-message" } })).toBeDefined()
|
|
166
253
|
|
|
167
254
|
const deleted = query.delete({ where: { id: "first-message" } })
|
|
@@ -170,8 +257,8 @@ describe("delete", () => {
|
|
|
170
257
|
expect(deleted).toBe(true)
|
|
171
258
|
})
|
|
172
259
|
|
|
173
|
-
it("should return false if message with id does not exist", () => {
|
|
174
|
-
const query =
|
|
260
|
+
it("should return false if message with id does not exist", async () => {
|
|
261
|
+
const query = await awaitableCreateMessageQuery(() => [])
|
|
175
262
|
expect(query.get({ where: { id: "first-message" } })).toBeUndefined()
|
|
176
263
|
|
|
177
264
|
const deleted = query.delete({ where: { id: "first-message" } })
|
|
@@ -179,11 +266,11 @@ describe("delete", () => {
|
|
|
179
266
|
})
|
|
180
267
|
})
|
|
181
268
|
|
|
182
|
-
describe("reactivity", () => {
|
|
183
|
-
describe("get", () => {
|
|
269
|
+
describe("reactivity", async () => {
|
|
270
|
+
describe("get", async () => {
|
|
184
271
|
it("should react to `create`", async () => {
|
|
185
272
|
await createRoot(async () => {
|
|
186
|
-
const query =
|
|
273
|
+
const query = await awaitableCreateMessageQuery(() => [])
|
|
187
274
|
|
|
188
275
|
// eslint-disable-next-line unicorn/no-null
|
|
189
276
|
let message: Message | undefined | null = null
|
|
@@ -201,7 +288,9 @@ describe("reactivity", () => {
|
|
|
201
288
|
|
|
202
289
|
it("should react to `update`", async () => {
|
|
203
290
|
await createRoot(async () => {
|
|
204
|
-
const query =
|
|
291
|
+
const query = await awaitableCreateMessageQuery(() => [
|
|
292
|
+
createMessage("1", { en: "before" }),
|
|
293
|
+
])
|
|
205
294
|
|
|
206
295
|
let message: Message | undefined
|
|
207
296
|
await createChangeListener(() => (message = query.get({ where: { id: "1" } })))
|
|
@@ -221,7 +310,7 @@ describe("reactivity", () => {
|
|
|
221
310
|
|
|
222
311
|
it("should react to `upsert`", async () => {
|
|
223
312
|
await createRoot(async () => {
|
|
224
|
-
const query =
|
|
313
|
+
const query = await awaitableCreateMessageQuery(() => [])
|
|
225
314
|
|
|
226
315
|
let message: Message | undefined
|
|
227
316
|
await createChangeListener(() => (message = query.get({ where: { id: "1" } })))
|
|
@@ -244,7 +333,7 @@ describe("reactivity", () => {
|
|
|
244
333
|
|
|
245
334
|
it("should react to `delete`", async () => {
|
|
246
335
|
await createRoot(async () => {
|
|
247
|
-
const query =
|
|
336
|
+
const query = await awaitableCreateMessageQuery(() => [createMessage("1", { en: "" })])
|
|
248
337
|
|
|
249
338
|
let message: Message | undefined
|
|
250
339
|
await createChangeListener(() => (message = query.get({ where: { id: "1" } })))
|
|
@@ -254,37 +343,13 @@ describe("reactivity", () => {
|
|
|
254
343
|
expect(message).toBeUndefined()
|
|
255
344
|
})
|
|
256
345
|
})
|
|
257
|
-
|
|
258
|
-
it("should react to changes to the input `messages`", async () => {
|
|
259
|
-
const [messages, setMessages] = createSignal<Message[]>([])
|
|
260
|
-
const query = createMessagesQuery(messages)
|
|
261
|
-
|
|
262
|
-
// eslint-disable-next-line unicorn/no-null
|
|
263
|
-
let message: Message | undefined | null = null
|
|
264
|
-
await createChangeListener(() => (message = query.get({ where: { id: "1" } })))
|
|
265
|
-
expect(message).toBeUndefined()
|
|
266
|
-
|
|
267
|
-
query.create({ data: createMessage("1", { en: "before" }) })
|
|
268
|
-
expect(message).toBeDefined()
|
|
269
|
-
expect(
|
|
270
|
-
(message!.variants.find((variant) => variant.languageTag === "en")?.pattern[0] as Text)
|
|
271
|
-
.value
|
|
272
|
-
).toBe("before")
|
|
273
|
-
|
|
274
|
-
setMessages([createMessage("1", { en: "after" })])
|
|
275
|
-
expect(message).toBeDefined()
|
|
276
|
-
expect(
|
|
277
|
-
(message!.variants.find((variant) => variant.languageTag === "en")?.pattern[0] as Text)
|
|
278
|
-
.value
|
|
279
|
-
).toBe("after")
|
|
280
|
-
})
|
|
281
346
|
})
|
|
282
347
|
|
|
283
|
-
describe("subscribe", () => {
|
|
284
|
-
describe("get", () => {
|
|
348
|
+
describe("subscribe", async () => {
|
|
349
|
+
describe("get", async () => {
|
|
285
350
|
it("should subscribe to `create`", async () => {
|
|
286
351
|
await createRoot(async () => {
|
|
287
|
-
const query =
|
|
352
|
+
const query = await awaitableCreateMessageQuery(() => [])
|
|
288
353
|
|
|
289
354
|
// eslint-disable-next-line unicorn/no-null
|
|
290
355
|
let message: Message | undefined | null = null
|
|
@@ -299,10 +364,10 @@ describe("reactivity", () => {
|
|
|
299
364
|
})
|
|
300
365
|
})
|
|
301
366
|
})
|
|
302
|
-
describe("getByDefaultAlias", () => {
|
|
367
|
+
describe("getByDefaultAlias", async () => {
|
|
303
368
|
it("should subscribe to `create`", async () => {
|
|
304
369
|
await createRoot(async () => {
|
|
305
|
-
const query =
|
|
370
|
+
const query = await awaitableCreateMessageQuery(() => [])
|
|
306
371
|
|
|
307
372
|
// eslint-disable-next-line unicorn/no-null
|
|
308
373
|
let message: Message | undefined | null = null
|
|
@@ -322,10 +387,10 @@ describe("reactivity", () => {
|
|
|
322
387
|
})
|
|
323
388
|
})
|
|
324
389
|
|
|
325
|
-
describe("getAll", () => {
|
|
390
|
+
describe("getAll", async () => {
|
|
326
391
|
it("should react to `create`", async () => {
|
|
327
392
|
await createRoot(async () => {
|
|
328
|
-
const query =
|
|
393
|
+
const query = await awaitableCreateMessageQuery(() => [])
|
|
329
394
|
|
|
330
395
|
let messages: Readonly<Message[]> | undefined = undefined
|
|
331
396
|
await createChangeListener(() => (messages = query.getAll()))
|
|
@@ -344,7 +409,9 @@ describe("reactivity", () => {
|
|
|
344
409
|
|
|
345
410
|
it("should react to `update`", async () => {
|
|
346
411
|
await createRoot(async () => {
|
|
347
|
-
const query =
|
|
412
|
+
const query = await awaitableCreateMessageQuery(() => [
|
|
413
|
+
createMessage("1", { en: "before" }),
|
|
414
|
+
])
|
|
348
415
|
|
|
349
416
|
let messages: Readonly<Message[]> | undefined = undefined
|
|
350
417
|
await createChangeListener(() => (messages = query.getAll()))
|
|
@@ -369,7 +436,7 @@ describe("reactivity", () => {
|
|
|
369
436
|
|
|
370
437
|
it("should react to `upsert`", async () => {
|
|
371
438
|
await createRoot(async () => {
|
|
372
|
-
const query =
|
|
439
|
+
const query = await awaitableCreateMessageQuery(() => [])
|
|
373
440
|
|
|
374
441
|
let messages: Readonly<Message[]> | undefined = undefined
|
|
375
442
|
await createChangeListener(() => (messages = query.getAll()))
|
|
@@ -396,7 +463,7 @@ describe("reactivity", () => {
|
|
|
396
463
|
|
|
397
464
|
it("should react to `delete`", async () => {
|
|
398
465
|
await createRoot(async () => {
|
|
399
|
-
const query =
|
|
466
|
+
const query = await awaitableCreateMessageQuery(() => [
|
|
400
467
|
createMessage("1", { en: "" }),
|
|
401
468
|
createMessage("2", { en: "" }),
|
|
402
469
|
createMessage("3", { en: "" }),
|
|
@@ -421,38 +488,9 @@ describe("reactivity", () => {
|
|
|
421
488
|
})
|
|
422
489
|
})
|
|
423
490
|
|
|
424
|
-
it("should react to changes to the input `messages`", async () => {
|
|
425
|
-
const [inputMessages, setMessages] = createSignal<Message[]>([
|
|
426
|
-
createMessage("1", { en: "before" }),
|
|
427
|
-
])
|
|
428
|
-
const query = createMessagesQuery(inputMessages)
|
|
429
|
-
|
|
430
|
-
let messages: Readonly<Message[]> | undefined = undefined
|
|
431
|
-
await createChangeListener(() => (messages = query.getAll()))
|
|
432
|
-
expect(Object.values(messages!)).toHaveLength(1)
|
|
433
|
-
|
|
434
|
-
query.create({ data: createMessage("2", { en: "" }) })
|
|
435
|
-
expect(Object.values(messages!)).toHaveLength(2)
|
|
436
|
-
expect(
|
|
437
|
-
(
|
|
438
|
-
Object.values(messages!)![0]!.variants.find((variant) => variant.languageTag === "en")!
|
|
439
|
-
.pattern[0]! as Text
|
|
440
|
-
).value
|
|
441
|
-
).toBe("before")
|
|
442
|
-
|
|
443
|
-
setMessages([createMessage("1", { en: "after" })])
|
|
444
|
-
expect(Object.values(messages!)).toHaveLength(1)
|
|
445
|
-
expect(
|
|
446
|
-
(
|
|
447
|
-
Object.values(messages!)![0]!.variants.find((variant) => variant.languageTag === "en")!
|
|
448
|
-
.pattern[0]! as Text
|
|
449
|
-
).value
|
|
450
|
-
).toBe("after")
|
|
451
|
-
})
|
|
452
|
-
|
|
453
491
|
it("should not mutate messages signal outside the query when using the query", async () => {
|
|
454
492
|
const [inputMessages] = createSignal<Message[]>([createMessage("1", { en: "before" })])
|
|
455
|
-
const query =
|
|
493
|
+
const query = await awaitableCreateMessageQuery(inputMessages)
|
|
456
494
|
|
|
457
495
|
let messages: Readonly<Message[]> | undefined = undefined
|
|
458
496
|
await createChangeListener(() => (messages = query.getAll()))
|
|
@@ -467,8 +505,8 @@ describe("reactivity", () => {
|
|
|
467
505
|
|
|
468
506
|
it("instances should not share state", async () => {
|
|
469
507
|
await createRoot(async () => {
|
|
470
|
-
const query1 =
|
|
471
|
-
const query2 =
|
|
508
|
+
const query1 = await awaitableCreateMessageQuery(() => [createMessage("1", { en: "before" })])
|
|
509
|
+
const query2 = await awaitableCreateMessageQuery(() => [])
|
|
472
510
|
|
|
473
511
|
// eslint-disable-next-line unicorn/no-null
|
|
474
512
|
let message1: Message | undefined | null = null
|