@fougere/adapter-file 0.6.0-alpha.0 → 0.8.0-alpha.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/README.md +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -23
- package/dist/index.js.map +1 -1
- package/package.json +3 -4
- package/src/index.ts +11 -26
package/README.md
CHANGED
|
@@ -44,13 +44,13 @@ emits a constraint, so a `ref()` across sources costs nothing.
|
|
|
44
44
|
|
|
45
45
|
## Writing your own source
|
|
46
46
|
|
|
47
|
-
This package is
|
|
47
|
+
This package is 90 lines, half of them filesystem guards. `storageOver` (`@fougere/core`)
|
|
48
48
|
derives the thirteen gestures of the storage port from four, so a new source supplies where
|
|
49
49
|
rows are and nothing else:
|
|
50
50
|
|
|
51
51
|
```ts
|
|
52
52
|
Sources.register('redis', (conf): Source => ({
|
|
53
|
-
storageFactory: storageOver((_entity, name) =>
|
|
53
|
+
storageFactory: storageOver((_entity, name) => redisStore(conf.url, name)),
|
|
54
54
|
name: conf.url,
|
|
55
55
|
}));
|
|
56
56
|
```
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAEoB,KAAK,MAAM,EACrC,MAAM,eAAe,CAAC;AAsDvB,MAAM,WAAW,iBAAiB;IAChC,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAczD"}
|
package/dist/index.js
CHANGED
|
@@ -1,19 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rows as files — one JSON per row, a directory per entity.
|
|
3
|
-
*
|
|
4
|
-
* The reason this package is short: `storageOver` derives the thirteen gestures from four,
|
|
5
|
-
* so a source that keeps rows somewhere else supplies only where. Nothing about pages,
|
|
6
|
-
* criteria or lifecycle stamps is written twice.
|
|
7
|
-
*
|
|
8
|
-
* What it costs, said here rather than discovered: `all()` reads the whole directory, so
|
|
9
|
-
* `list` with a `where` or an `orderBy` filters in memory. That is the same trade
|
|
10
|
-
* `@fougere/adapter-duckdb` documents for a page-sized read — fine for a few thousand rows
|
|
11
|
-
* held for their durability, wrong on a hot read path. And two processes over one directory
|
|
12
|
-
* have no lock: SQLite has one, a filesystem does not.
|
|
13
|
-
*
|
|
14
|
-
* No `transacted` — a directory has no unit of work, so a frame compensates and says so.
|
|
15
|
-
* `migrate` is a `mkdir` per entity, which is the whole shape a directory has.
|
|
16
|
-
*/
|
|
1
|
+
/** Files — one JSON per instance, a directory per entity. */
|
|
17
2
|
import { mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises';
|
|
18
3
|
import { join } from 'node:path';
|
|
19
4
|
import { lowerFirst } from '@fougere/schema';
|
|
@@ -25,8 +10,8 @@ function fileOf(dir, key) {
|
|
|
25
10
|
}
|
|
26
11
|
return join(dir, `${encodeURIComponent(key)}.json`);
|
|
27
12
|
}
|
|
28
|
-
/** One entity
|
|
29
|
-
function
|
|
13
|
+
/** One entity, one file each, under `<root>/<entity>/`. */
|
|
14
|
+
function dirStore(root, name) {
|
|
30
15
|
const dir = join(root, name);
|
|
31
16
|
const read = async (file) => {
|
|
32
17
|
try {
|
|
@@ -42,9 +27,9 @@ function dirRows(root, name) {
|
|
|
42
27
|
client: dir,
|
|
43
28
|
get: (key) => read(fileOf(dir, key)),
|
|
44
29
|
has: async (key) => (await read(fileOf(dir, key))) !== undefined,
|
|
45
|
-
set: async (key,
|
|
30
|
+
set: async (key, values) => {
|
|
46
31
|
await mkdir(dir, { recursive: true });
|
|
47
|
-
await writeFile(fileOf(dir, key), JSON.stringify(
|
|
32
|
+
await writeFile(fileOf(dir, key), JSON.stringify(values, null, 2), 'utf8');
|
|
48
33
|
},
|
|
49
34
|
delete: async (key) => {
|
|
50
35
|
const file = fileOf(dir, key);
|
|
@@ -63,16 +48,16 @@ function dirRows(root, name) {
|
|
|
63
48
|
return [];
|
|
64
49
|
throw error;
|
|
65
50
|
}
|
|
66
|
-
const
|
|
51
|
+
const found = await Promise.all(names
|
|
67
52
|
.filter((file) => file.endsWith('.json'))
|
|
68
53
|
.map((file) => read(join(dir, file))));
|
|
69
|
-
return
|
|
54
|
+
return found.filter((values) => values !== undefined);
|
|
70
55
|
},
|
|
71
56
|
};
|
|
72
57
|
}
|
|
73
58
|
export function setupFile(opts) {
|
|
74
59
|
return {
|
|
75
|
-
storageFactory: storageOver((_entity, name) =>
|
|
60
|
+
storageFactory: storageOver((_entity, name) => dirStore(opts.path, name)),
|
|
76
61
|
name: opts.path,
|
|
77
62
|
// A directory IS the shape, so bringing it up to date is making it exist. `elsewhere`
|
|
78
63
|
// is not read: nothing here emits a constraint, so a cross-source `ref()` costs nothing.
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fougere/adapter-file",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0-alpha.0",
|
|
4
4
|
"description": "Rows as files — one JSON per row, in a directory per entity.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fougere",
|
|
@@ -29,9 +29,8 @@
|
|
|
29
29
|
"src"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@fougere/core": "0.
|
|
33
|
-
"@fougere/schema": "0.
|
|
34
|
-
"@fougere/adapter-memory": "0.6.0-alpha.0"
|
|
32
|
+
"@fougere/core": "0.8.0-alpha.0",
|
|
33
|
+
"@fougere/schema": "0.8.0-alpha.0"
|
|
35
34
|
},
|
|
36
35
|
"publishConfig": {
|
|
37
36
|
"access": "public"
|
package/src/index.ts
CHANGED
|
@@ -1,25 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rows as files — one JSON per row, a directory per entity.
|
|
3
|
-
*
|
|
4
|
-
* The reason this package is short: `storageOver` derives the thirteen gestures from four,
|
|
5
|
-
* so a source that keeps rows somewhere else supplies only where. Nothing about pages,
|
|
6
|
-
* criteria or lifecycle stamps is written twice.
|
|
7
|
-
*
|
|
8
|
-
* What it costs, said here rather than discovered: `all()` reads the whole directory, so
|
|
9
|
-
* `list` with a `where` or an `orderBy` filters in memory. That is the same trade
|
|
10
|
-
* `@fougere/adapter-duckdb` documents for a page-sized read — fine for a few thousand rows
|
|
11
|
-
* held for their durability, wrong on a hot read path. And two processes over one directory
|
|
12
|
-
* have no lock: SQLite has one, a filesystem does not.
|
|
13
|
-
*
|
|
14
|
-
* No `transacted` — a directory has no unit of work, so a frame compensates and says so.
|
|
15
|
-
* `migrate` is a `mkdir` per entity, which is the whole shape a directory has.
|
|
16
|
-
*/
|
|
1
|
+
/** Files — one JSON per instance, a directory per entity. */
|
|
17
2
|
import { mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises';
|
|
18
3
|
import { join } from 'node:path';
|
|
19
4
|
import { lowerFirst } from '@fougere/schema';
|
|
20
5
|
import {
|
|
21
6
|
Sources, storageOver,
|
|
22
|
-
type
|
|
7
|
+
type Store, type Values, type Source, type SourceConfig, type SourceView,
|
|
23
8
|
} from '@fougere/core';
|
|
24
9
|
|
|
25
10
|
/** A key becomes a filename, so it may not leave the directory it addresses. */
|
|
@@ -31,12 +16,12 @@ function fileOf(dir: string, key: string): string {
|
|
|
31
16
|
return join(dir, `${encodeURIComponent(key)}.json`);
|
|
32
17
|
}
|
|
33
18
|
|
|
34
|
-
/** One entity
|
|
35
|
-
function
|
|
19
|
+
/** One entity, one file each, under `<root>/<entity>/`. */
|
|
20
|
+
function dirStore(root: string, name: string): Store {
|
|
36
21
|
const dir = join(root, name);
|
|
37
|
-
const read = async (file: string): Promise<
|
|
22
|
+
const read = async (file: string): Promise<Values | undefined> => {
|
|
38
23
|
try {
|
|
39
|
-
return JSON.parse(await readFile(file, 'utf8')) as
|
|
24
|
+
return JSON.parse(await readFile(file, 'utf8')) as Values;
|
|
40
25
|
} catch (error) {
|
|
41
26
|
if ((error as { code?: string }).code === 'ENOENT') return undefined;
|
|
42
27
|
throw error;
|
|
@@ -47,9 +32,9 @@ function dirRows(root: string, name: string): Rows {
|
|
|
47
32
|
client: dir,
|
|
48
33
|
get: (key) => read(fileOf(dir, key)),
|
|
49
34
|
has: async (key) => (await read(fileOf(dir, key))) !== undefined,
|
|
50
|
-
set: async (key,
|
|
35
|
+
set: async (key, values) => {
|
|
51
36
|
await mkdir(dir, { recursive: true });
|
|
52
|
-
await writeFile(fileOf(dir, key), JSON.stringify(
|
|
37
|
+
await writeFile(fileOf(dir, key), JSON.stringify(values, null, 2), 'utf8');
|
|
53
38
|
},
|
|
54
39
|
delete: async (key) => {
|
|
55
40
|
const file = fileOf(dir, key);
|
|
@@ -65,11 +50,11 @@ function dirRows(root: string, name: string): Rows {
|
|
|
65
50
|
if ((error as { code?: string }).code === 'ENOENT') return [];
|
|
66
51
|
throw error;
|
|
67
52
|
}
|
|
68
|
-
const
|
|
53
|
+
const found = await Promise.all(names
|
|
69
54
|
.filter((file) => file.endsWith('.json'))
|
|
70
55
|
.map((file) => read(join(dir, file))));
|
|
71
56
|
|
|
72
|
-
return
|
|
57
|
+
return found.filter((values): values is Values => values !== undefined);
|
|
73
58
|
},
|
|
74
59
|
};
|
|
75
60
|
}
|
|
@@ -81,7 +66,7 @@ export interface FileSourceOptions {
|
|
|
81
66
|
|
|
82
67
|
export function setupFile(opts: FileSourceOptions): Source {
|
|
83
68
|
return {
|
|
84
|
-
storageFactory: storageOver((_entity, name) =>
|
|
69
|
+
storageFactory: storageOver((_entity, name) => dirStore(opts.path, name)),
|
|
85
70
|
name: opts.path,
|
|
86
71
|
// A directory IS the shape, so bringing it up to date is making it exist. `elsewhere`
|
|
87
72
|
// is not read: nothing here emits a constraint, so a cross-source `ref()` costs nothing.
|