@delma/fylo 2.0.1 → 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.
Files changed (43) hide show
  1. package/README.md +185 -267
  2. package/package.json +2 -5
  3. package/src/core/directory.ts +22 -354
  4. package/src/engines/s3-files/documents.ts +65 -0
  5. package/src/engines/s3-files/filesystem.ts +172 -0
  6. package/src/engines/s3-files/query.ts +291 -0
  7. package/src/engines/s3-files/types.ts +42 -0
  8. package/src/engines/s3-files.ts +391 -690
  9. package/src/engines/types.ts +1 -1
  10. package/src/index.ts +142 -1237
  11. package/src/sync.ts +58 -0
  12. package/src/types/fylo.d.ts +66 -161
  13. package/src/types/node-runtime.d.ts +1 -0
  14. package/tests/collection/truncate.test.js +11 -10
  15. package/tests/helpers/root.js +7 -0
  16. package/tests/integration/create.test.js +9 -9
  17. package/tests/integration/delete.test.js +16 -14
  18. package/tests/integration/edge-cases.test.js +29 -25
  19. package/tests/integration/encryption.test.js +47 -30
  20. package/tests/integration/export.test.js +11 -11
  21. package/tests/integration/join-modes.test.js +16 -16
  22. package/tests/integration/nested.test.js +26 -24
  23. package/tests/integration/operators.test.js +43 -29
  24. package/tests/integration/read.test.js +25 -21
  25. package/tests/integration/rollback.test.js +21 -51
  26. package/tests/integration/s3-files.performance.test.js +75 -0
  27. package/tests/integration/s3-files.test.js +57 -44
  28. package/tests/integration/sync.test.js +154 -0
  29. package/tests/integration/update.test.js +24 -18
  30. package/src/adapters/redis.ts +0 -487
  31. package/src/adapters/s3.ts +0 -61
  32. package/src/core/walker.ts +0 -174
  33. package/src/core/write-queue.ts +0 -59
  34. package/src/migrate-cli.ts +0 -22
  35. package/src/migrate.ts +0 -74
  36. package/src/types/write-queue.ts +0 -42
  37. package/src/worker.ts +0 -18
  38. package/src/workers/write-worker.ts +0 -120
  39. package/tests/index.js +0 -14
  40. package/tests/integration/migration.test.js +0 -38
  41. package/tests/integration/queue.test.js +0 -83
  42. package/tests/mocks/redis.js +0 -123
  43. package/tests/mocks/s3.js +0 -80
@@ -1,14 +1,13 @@
1
- import { test, expect, describe, beforeAll, afterAll, mock } from 'bun:test'
1
+ import { test, expect, describe, beforeAll, afterAll } from 'bun:test'
2
+ import { rm } from 'node:fs/promises'
2
3
  import Fylo from '../../src'
3
4
  import { albumURL } from '../data'
4
- import S3Mock from '../mocks/s3'
5
- import RedisMock from '../mocks/redis'
5
+ import { createTestRoot } from '../helpers/root'
6
6
  const ALBUMS = 'ops-album'
7
- const fylo = new Fylo()
8
- mock.module('../../src/adapters/s3', () => ({ S3: S3Mock }))
9
- mock.module('../../src/adapters/redis', () => ({ Redis: RedisMock }))
7
+ const root = await createTestRoot('fylo-operators-')
8
+ const fylo = new Fylo({ root })
10
9
  beforeAll(async () => {
11
- await Fylo.createCollection(ALBUMS)
10
+ await fylo.createCollection(ALBUMS)
12
11
  try {
13
12
  await fylo.importBulkData(ALBUMS, new URL(albumURL), 100)
14
13
  } catch {
@@ -16,14 +15,17 @@ beforeAll(async () => {
16
15
  }
17
16
  })
18
17
  afterAll(async () => {
19
- await Fylo.dropCollection(ALBUMS)
18
+ await fylo.dropCollection(ALBUMS)
19
+ await rm(root, { recursive: true, force: true })
20
20
  })
21
21
  describe('NO-SQL', async () => {
22
22
  test('$ne — excludes matching value', async () => {
23
23
  let results = {}
24
- for await (const data of Fylo.findDocs(ALBUMS, {
25
- $ops: [{ userId: { $ne: 1 } }]
26
- }).collect()) {
24
+ for await (const data of fylo
25
+ .findDocs(ALBUMS, {
26
+ $ops: [{ userId: { $ne: 1 } }]
27
+ })
28
+ .collect()) {
27
29
  results = { ...results, ...data }
28
30
  }
29
31
  const albums = Object.values(results)
@@ -33,9 +35,11 @@ describe('NO-SQL', async () => {
33
35
  })
34
36
  test('$lt — returns documents where field is less than value', async () => {
35
37
  let results = {}
36
- for await (const data of Fylo.findDocs(ALBUMS, {
37
- $ops: [{ userId: { $lt: 5 } }]
38
- }).collect()) {
38
+ for await (const data of fylo
39
+ .findDocs(ALBUMS, {
40
+ $ops: [{ userId: { $lt: 5 } }]
41
+ })
42
+ .collect()) {
39
43
  results = { ...results, ...data }
40
44
  }
41
45
  const albums = Object.values(results)
@@ -45,9 +49,11 @@ describe('NO-SQL', async () => {
45
49
  })
46
50
  test('$lte — returns documents where field is less than or equal to value', async () => {
47
51
  let results = {}
48
- for await (const data of Fylo.findDocs(ALBUMS, {
49
- $ops: [{ userId: { $lte: 5 } }]
50
- }).collect()) {
52
+ for await (const data of fylo
53
+ .findDocs(ALBUMS, {
54
+ $ops: [{ userId: { $lte: 5 } }]
55
+ })
56
+ .collect()) {
51
57
  results = { ...results, ...data }
52
58
  }
53
59
  const albums = Object.values(results)
@@ -57,9 +63,11 @@ describe('NO-SQL', async () => {
57
63
  })
58
64
  test('$gt — returns documents where field is greater than value', async () => {
59
65
  let results = {}
60
- for await (const data of Fylo.findDocs(ALBUMS, {
61
- $ops: [{ userId: { $gt: 5 } }]
62
- }).collect()) {
66
+ for await (const data of fylo
67
+ .findDocs(ALBUMS, {
68
+ $ops: [{ userId: { $gt: 5 } }]
69
+ })
70
+ .collect()) {
63
71
  results = { ...results, ...data }
64
72
  }
65
73
  const albums = Object.values(results)
@@ -69,9 +77,11 @@ describe('NO-SQL', async () => {
69
77
  })
70
78
  test('$gte — returns documents where field is greater than or equal to value', async () => {
71
79
  let results = {}
72
- for await (const data of Fylo.findDocs(ALBUMS, {
73
- $ops: [{ userId: { $gte: 5 } }]
74
- }).collect()) {
80
+ for await (const data of fylo
81
+ .findDocs(ALBUMS, {
82
+ $ops: [{ userId: { $gte: 5 } }]
83
+ })
84
+ .collect()) {
75
85
  results = { ...results, ...data }
76
86
  }
77
87
  const albums = Object.values(results)
@@ -81,9 +91,11 @@ describe('NO-SQL', async () => {
81
91
  })
82
92
  test('$like — matches substring pattern', async () => {
83
93
  let results = {}
84
- for await (const data of Fylo.findDocs(ALBUMS, {
85
- $ops: [{ title: { $like: '%quidem%' } }]
86
- }).collect()) {
94
+ for await (const data of fylo
95
+ .findDocs(ALBUMS, {
96
+ $ops: [{ title: { $like: '%quidem%' } }]
97
+ })
98
+ .collect()) {
87
99
  results = { ...results, ...data }
88
100
  }
89
101
  const albums = Object.values(results)
@@ -93,9 +105,11 @@ describe('NO-SQL', async () => {
93
105
  })
94
106
  test('$like — prefix pattern', async () => {
95
107
  let results = {}
96
- for await (const data of Fylo.findDocs(ALBUMS, {
97
- $ops: [{ title: { $like: 'omnis%' } }]
98
- }).collect()) {
108
+ for await (const data of fylo
109
+ .findDocs(ALBUMS, {
110
+ $ops: [{ title: { $like: 'omnis%' } }]
111
+ })
112
+ .collect()) {
99
113
  results = { ...results, ...data }
100
114
  }
101
115
  const albums = Object.values(results)
@@ -1,16 +1,15 @@
1
- import { test, expect, describe, beforeAll, afterAll, mock } from 'bun:test'
1
+ import { test, expect, describe, beforeAll, afterAll } from 'bun:test'
2
+ import { rm } from 'node:fs/promises'
2
3
  import Fylo from '../../src'
3
4
  import { albumURL, postsURL } from '../data'
4
- import S3Mock from '../mocks/s3'
5
- import RedisMock from '../mocks/redis'
5
+ import { createTestRoot } from '../helpers/root'
6
6
  const POSTS = `post`
7
7
  const ALBUMS = `album`
8
8
  let count = 0
9
- const fylo = new Fylo()
10
- mock.module('../../src/adapters/s3', () => ({ S3: S3Mock }))
11
- mock.module('../../src/adapters/redis', () => ({ Redis: RedisMock }))
9
+ const root = await createTestRoot('fylo-read-')
10
+ const fylo = new Fylo({ root })
12
11
  beforeAll(async () => {
13
- await Promise.all([Fylo.createCollection(ALBUMS), fylo.executeSQL(`CREATE TABLE ${POSTS}`)])
12
+ await Promise.all([fylo.createCollection(ALBUMS), fylo.executeSQL(`CREATE TABLE ${POSTS}`)])
14
13
  try {
15
14
  count = await fylo.importBulkData(ALBUMS, new URL(albumURL), 100)
16
15
  await fylo.importBulkData(POSTS, new URL(postsURL), 100)
@@ -19,19 +18,20 @@ beforeAll(async () => {
19
18
  }
20
19
  })
21
20
  afterAll(async () => {
22
- await Promise.all([Fylo.dropCollection(ALBUMS), Fylo.dropCollection(POSTS)])
21
+ await Promise.all([fylo.dropCollection(ALBUMS), fylo.dropCollection(POSTS)])
22
+ await rm(root, { recursive: true, force: true })
23
23
  })
24
24
  describe('NO-SQL', async () => {
25
25
  test('SELECT ALL', async () => {
26
26
  let results = {}
27
- for await (const data of Fylo.findDocs(ALBUMS).collect()) {
27
+ for await (const data of fylo.findDocs(ALBUMS).collect()) {
28
28
  results = { ...results, ...data }
29
29
  }
30
30
  expect(Object.keys(results).length).toBe(count)
31
31
  })
32
32
  test('SELECT PARTIAL', async () => {
33
33
  let results = {}
34
- for await (const data of Fylo.findDocs(ALBUMS, { $select: ['title'] }).collect()) {
34
+ for await (const data of fylo.findDocs(ALBUMS, { $select: ['title'] }).collect()) {
35
35
  results = { ...results, ...data }
36
36
  }
37
37
  const allAlbums = Object.values(results)
@@ -40,18 +40,20 @@ describe('NO-SQL', async () => {
40
40
  })
41
41
  test('GET ONE', async () => {
42
42
  const ids = []
43
- for await (const data of Fylo.findDocs(ALBUMS, { $limit: 1, $onlyIds: true }).collect()) {
43
+ for await (const data of fylo.findDocs(ALBUMS, { $limit: 1, $onlyIds: true }).collect()) {
44
44
  ids.push(data)
45
45
  }
46
- const result = await Fylo.getDoc(ALBUMS, ids[0]).once()
46
+ const result = await fylo.getDoc(ALBUMS, ids[0]).once()
47
47
  const _id = Object.keys(result).shift()
48
48
  expect(ids[0]).toEqual(_id)
49
49
  })
50
50
  test('SELECT CLAUSE', async () => {
51
51
  let results = {}
52
- for await (const data of Fylo.findDocs(ALBUMS, {
53
- $ops: [{ userId: { $eq: 2 } }]
54
- }).collect()) {
52
+ for await (const data of fylo
53
+ .findDocs(ALBUMS, {
54
+ $ops: [{ userId: { $eq: 2 } }]
55
+ })
56
+ .collect()) {
55
57
  results = { ...results, ...data }
56
58
  }
57
59
  const allAlbums = Object.values(results)
@@ -60,23 +62,25 @@ describe('NO-SQL', async () => {
60
62
  })
61
63
  test('SELECT LIMIT', async () => {
62
64
  let results = {}
63
- for await (const data of Fylo.findDocs(ALBUMS, { $limit: 5 }).collect()) {
65
+ for await (const data of fylo.findDocs(ALBUMS, { $limit: 5 }).collect()) {
64
66
  results = { ...results, ...data }
65
67
  }
66
68
  expect(Object.keys(results).length).toBe(5)
67
69
  })
68
70
  test('SELECT GROUP BY', async () => {
69
71
  let results = {}
70
- for await (const data of Fylo.findDocs(ALBUMS, {
71
- $groupby: 'userId',
72
- $onlyIds: true
73
- }).collect()) {
72
+ for await (const data of fylo
73
+ .findDocs(ALBUMS, {
74
+ $groupby: 'userId',
75
+ $onlyIds: true
76
+ })
77
+ .collect()) {
74
78
  results = Object.appendGroup(results, data)
75
79
  }
76
80
  expect(Object.keys(results).length).toBeGreaterThan(0)
77
81
  })
78
82
  test('SELECT JOIN', async () => {
79
- const results = await Fylo.joinDocs({
83
+ const results = await fylo.joinDocs({
80
84
  $leftCollection: ALBUMS,
81
85
  $rightCollection: POSTS,
82
86
  $mode: 'inner',
@@ -1,60 +1,30 @@
1
- import { test, expect, describe, beforeAll, afterAll, mock } from 'bun:test'
1
+ import { afterAll, beforeAll, describe, expect, test } from 'bun:test'
2
+ import { mkdtemp, rm } from 'node:fs/promises'
3
+ import os from 'node:os'
4
+ import path from 'node:path'
2
5
  import Fylo from '../../src'
3
- import S3Mock from '../mocks/s3'
4
- import RedisMock from '../mocks/redis'
6
+
7
+ const root = await mkdtemp(path.join(os.tmpdir(), 'fylo-rollback-'))
5
8
  const POSTS = 'rb-post'
6
- const fylo = new Fylo()
7
- mock.module('../../src/adapters/s3', () => ({ S3: S3Mock }))
8
- mock.module('../../src/adapters/redis', () => ({ Redis: RedisMock }))
9
+ const fylo = new Fylo({ root })
10
+
9
11
  beforeAll(async () => {
10
- await Fylo.createCollection(POSTS)
12
+ await fylo.createCollection(POSTS)
11
13
  })
14
+
12
15
  afterAll(async () => {
13
- await Fylo.dropCollection(POSTS)
16
+ await rm(root, { recursive: true, force: true })
14
17
  })
15
- describe('NO-SQL', () => {
16
- test('INSERT then rollback — document is not retrievable', async () => {
17
- const _id = await fylo.putData(POSTS, {
18
- userId: 99,
19
- id: 9001,
20
- title: 'Rollback Me',
21
- body: 'This document should disappear after rollback'
18
+
19
+ describe('rollback compatibility', () => {
20
+ test('rollback is a safe no-op in filesystem-first FYLO', async () => {
21
+ const id = await fylo.putData(POSTS, {
22
+ title: 'Still here'
22
23
  })
23
- const before = await Fylo.getDoc(POSTS, _id).once()
24
- expect(Object.keys(before).length).toBe(1)
25
- await fylo.rollback()
26
- const after = await Fylo.getDoc(POSTS, _id).once()
27
- expect(Object.keys(after).length).toBe(0)
28
- })
29
- test('DELETE then rollback — document is restored', async () => {
30
- const freshFylo = new Fylo()
31
- const _id = await freshFylo.putData(POSTS, {
32
- userId: 99,
33
- id: 9002,
34
- title: 'Restore Me',
35
- body: 'This document should reappear after delete rollback'
36
- })
37
- const deleteInstance = new Fylo()
38
- await deleteInstance.delDoc(POSTS, _id)
39
- const after = await Fylo.getDoc(POSTS, _id).once()
40
- expect(Object.keys(after).length).toBe(0)
41
- await deleteInstance.rollback()
42
- const restored = await Fylo.getDoc(POSTS, _id).once()
43
- expect(Object.keys(restored).length).toBe(1)
44
- expect(restored[_id].title).toBe('Restore Me')
45
- })
46
- test('batch INSERT then rollback — all documents are removed', async () => {
47
- const batchFylo = new Fylo()
48
- const batch = [
49
- { userId: 98, id: 9003, title: 'Batch A', body: 'body a' },
50
- { userId: 98, id: 9004, title: 'Batch B', body: 'body b' },
51
- { userId: 98, id: 9005, title: 'Batch C', body: 'body c' }
52
- ]
53
- const ids = await batchFylo.batchPutData(POSTS, batch)
54
- const beforeResults = await Promise.all(ids.map((id) => Fylo.getDoc(POSTS, id).once()))
55
- expect(beforeResults.every((r) => Object.keys(r).length === 1)).toBe(true)
56
- await batchFylo.rollback()
57
- const afterResults = await Promise.all(ids.map((id) => Fylo.getDoc(POSTS, id).once()))
58
- expect(afterResults.every((r) => Object.keys(r).length === 0)).toBe(true)
24
+
25
+ await expect(fylo.rollback()).resolves.toBeUndefined()
26
+
27
+ const after = await fylo.getDoc(POSTS, id).once()
28
+ expect(after[id].title).toBe('Still here')
59
29
  })
60
30
  })
@@ -0,0 +1,75 @@
1
+ import { afterAll, beforeAll, describe, expect, test } from 'bun:test'
2
+ import { mkdtemp, rm, stat } from 'node:fs/promises'
3
+ import { performance } from 'node:perf_hooks'
4
+ import os from 'node:os'
5
+ import path from 'node:path'
6
+ import Fylo from '../../src'
7
+
8
+ const runPerf = process.env.FYLO_RUN_PERF_TESTS === 'true'
9
+
10
+ describe.skipIf(!runPerf)('s3-files engine performance', () => {
11
+ let root = path.join(os.tmpdir(), `fylo-s3files-perf-${Date.now()}`)
12
+ const collection = 's3files-perf'
13
+ let fylo = new Fylo({ root })
14
+
15
+ beforeAll(async () => {
16
+ root = await mkdtemp(root)
17
+ fylo = new Fylo({ root })
18
+ await fylo.createCollection(collection)
19
+ })
20
+
21
+ afterAll(async () => {
22
+ await rm(root, { recursive: true, force: true })
23
+ })
24
+
25
+ test('keeps a single durable index file while querying a large dataset', async () => {
26
+ const totalDocs = 2000
27
+ const insertStart = performance.now()
28
+
29
+ for (let index = 0; index < totalDocs; index++) {
30
+ await fylo.putData(collection, {
31
+ title: `doc-${index}`,
32
+ group: index % 10,
33
+ tags: [`tag-${index % 5}`, `batch-${Math.floor(index / 100)}`],
34
+ meta: { score: index }
35
+ })
36
+ }
37
+
38
+ const insertMs = performance.now() - insertStart
39
+
40
+ const exactStart = performance.now()
41
+ let exactResults = {}
42
+ for await (const data of fylo
43
+ .findDocs(collection, {
44
+ $ops: [{ title: { $eq: 'doc-1555' } }]
45
+ })
46
+ .collect()) {
47
+ exactResults = { ...exactResults, ...data }
48
+ }
49
+ const exactMs = performance.now() - exactStart
50
+
51
+ const rangeStart = performance.now()
52
+ let rangeCount = 0
53
+ for await (const data of fylo
54
+ .findDocs(collection, {
55
+ $ops: [{ ['meta.score']: { $gte: 1900 } }]
56
+ })
57
+ .collect()) {
58
+ rangeCount += Object.keys(data).length
59
+ }
60
+ const rangeMs = performance.now() - rangeStart
61
+
62
+ const indexFile = path.join(root, collection, '.fylo', 'indexes', `${collection}.idx.json`)
63
+ const indexStats = await stat(indexFile)
64
+
65
+ expect(Object.keys(exactResults)).toHaveLength(1)
66
+ expect(rangeCount).toBe(100)
67
+ expect(indexStats.isFile()).toBe(true)
68
+
69
+ console.log(
70
+ `[FYLO perf] docs=${totalDocs} insertMs=${insertMs.toFixed(1)} exactMs=${exactMs.toFixed(
71
+ 1
72
+ )} rangeMs=${rangeMs.toFixed(1)} indexBytes=${indexStats.size}`
73
+ )
74
+ }, 120_000)
75
+ })
@@ -1,11 +1,10 @@
1
1
  import { afterAll, beforeAll, describe, expect, test } from 'bun:test'
2
- import { mkdtemp, rm, stat } from 'node:fs/promises'
2
+ import { mkdtemp, readFile, rm, stat } from 'node:fs/promises'
3
3
  import os from 'node:os'
4
4
  import path from 'node:path'
5
- import { Database } from 'bun:sqlite'
6
5
  import Fylo from '../../src'
7
6
  const root = await mkdtemp(path.join(os.tmpdir(), 'fylo-s3files-'))
8
- const fylo = new Fylo({ engine: 's3-files', s3FilesRoot: root })
7
+ const fylo = new Fylo({ root })
9
8
  const POSTS = 's3files-posts'
10
9
  const USERS = 's3files-users'
11
10
  describe('s3-files engine', () => {
@@ -60,12 +59,34 @@ describe('s3-files engine', () => {
60
59
  const result = await fylo.getDoc(POSTS, id).once()
61
60
  expect(result[id].body).toBe(longBody)
62
61
  })
63
- test('stores indexes in a single SQLite database instead of per-entry files', async () => {
64
- const dbStat = await stat(path.join(root, POSTS, '.fylo', 'index.db'))
65
- expect(dbStat.isFile()).toBe(true)
66
- await expect(stat(path.join(root, POSTS, '.fylo', 'indexes'))).rejects.toThrow()
62
+ test('stores only user document data in the file body', async () => {
63
+ const id = await fylo.putData(POSTS, {
64
+ title: 'Lean doc',
65
+ body: 'payload only'
66
+ })
67
+ const raw = JSON.parse(
68
+ await readFile(
69
+ path.join(root, POSTS, '.fylo', 'docs', id.slice(0, 2), `${id}.json`),
70
+ 'utf8'
71
+ )
72
+ )
73
+
74
+ expect(raw).toEqual({
75
+ title: 'Lean doc',
76
+ body: 'payload only'
77
+ })
78
+ expect(raw.id).toBeUndefined()
79
+ expect(raw.createdAt).toBeUndefined()
80
+ expect(raw.updatedAt).toBeUndefined()
81
+ })
82
+ test('stores indexes in a single collection file instead of SQLite or per-entry files', async () => {
83
+ const indexStat = await stat(
84
+ path.join(root, POSTS, '.fylo', 'indexes', `${POSTS}.idx.json`)
85
+ )
86
+ expect(indexStat.isFile()).toBe(true)
87
+ await expect(stat(path.join(root, POSTS, '.fylo', 'index.db'))).rejects.toThrow()
67
88
  })
68
- test('uses SQLite index rows to support exact, range, and contains queries', async () => {
89
+ test('uses the collection index file to support exact, range, and contains queries', async () => {
69
90
  const queryCollection = 's3files-query'
70
91
  await fylo.createCollection(queryCollection)
71
92
 
@@ -111,39 +132,33 @@ describe('s3-files engine', () => {
111
132
  expect(Object.keys(containsResults)).toEqual([bunId])
112
133
  expect(containsResults[nodeId]).toBeUndefined()
113
134
 
114
- const db = new Database(path.join(root, queryCollection, '.fylo', 'index.db'))
115
- const rows = db
116
- .query(
117
- `SELECT doc_id, field_path, raw_value, value_type, numeric_value
118
- FROM doc_index_entries
119
- WHERE doc_id = ?
120
- ORDER BY field_path, raw_value`
135
+ const index = JSON.parse(
136
+ await readFile(
137
+ path.join(root, queryCollection, '.fylo', 'indexes', `${queryCollection}.idx.json`),
138
+ 'utf8'
121
139
  )
122
- .all(bunId)
123
- db.close()
140
+ )
141
+ const rows = index.docs[bunId]
124
142
 
125
143
  expect(rows).toEqual(
126
144
  expect.arrayContaining([
127
145
  expect.objectContaining({
128
- doc_id: bunId,
129
- field_path: 'title',
130
- raw_value: 'Bun launch',
131
- value_type: 'string',
132
- numeric_value: null
146
+ fieldPath: 'title',
147
+ rawValue: 'Bun launch',
148
+ valueType: 'string',
149
+ numericValue: null
133
150
  }),
134
151
  expect.objectContaining({
135
- doc_id: bunId,
136
- field_path: 'meta/score',
137
- raw_value: '10',
138
- value_type: 'number',
139
- numeric_value: 10
152
+ fieldPath: 'meta/score',
153
+ rawValue: '10',
154
+ valueType: 'number',
155
+ numericValue: 10
140
156
  }),
141
157
  expect.objectContaining({
142
- doc_id: bunId,
143
- field_path: 'tags/1',
144
- raw_value: 'aws',
145
- value_type: 'string',
146
- numeric_value: null
158
+ fieldPath: 'tags/1',
159
+ rawValue: 'aws',
160
+ valueType: 'string',
161
+ numericValue: null
147
162
  })
148
163
  ])
149
164
  )
@@ -163,30 +178,28 @@ describe('s3-files engine', () => {
163
178
  })
164
179
  test('queue APIs are explicitly unsupported', async () => {
165
180
  await expect(fylo.queuePutData(POSTS, { title: 'no queue' })).rejects.toThrow(
166
- 'queuePutData is not supported'
167
- )
168
- await expect(fylo.processQueuedWrites(1)).rejects.toThrow(
169
- 'processQueuedWrites is not supported'
181
+ 'queuePutData was removed'
170
182
  )
183
+ await expect(fylo.processQueuedWrites(1)).rejects.toThrow('processQueuedWrites was removed')
171
184
  })
172
185
  test('rejects collection names that are unsafe for cross-platform filesystems', async () => {
173
186
  await expect(fylo.createCollection('bad/name')).rejects.toThrow('Invalid collection name')
174
187
  await expect(fylo.createCollection('bad\\name')).rejects.toThrow('Invalid collection name')
175
188
  await expect(fylo.createCollection('bad:name')).rejects.toThrow('Invalid collection name')
176
189
  })
177
- test('static helpers can use s3-files through env defaults', async () => {
178
- const prevEngine = process.env.FYLO_STORAGE_ENGINE
179
- const prevRoot = process.env.FYLO_S3FILES_ROOT
180
- process.env.FYLO_STORAGE_ENGINE = 's3-files'
190
+ test('static helpers can use filesystem root env defaults', async () => {
191
+ const prevFyloRoot = process.env.FYLO_ROOT
192
+ const prevS3FilesRoot = process.env.FYLO_S3FILES_ROOT
193
+ process.env.FYLO_ROOT = root
181
194
  process.env.FYLO_S3FILES_ROOT = root
182
195
  const collection = 's3files-static'
183
196
  await Fylo.createCollection(collection)
184
197
  const id = await fylo.putData(collection, { title: 'Static path' })
185
198
  const result = await Fylo.getDoc(collection, id).once()
186
199
  expect(result[id].title).toBe('Static path')
187
- if (prevEngine === undefined) delete process.env.FYLO_STORAGE_ENGINE
188
- else process.env.FYLO_STORAGE_ENGINE = prevEngine
189
- if (prevRoot === undefined) delete process.env.FYLO_S3FILES_ROOT
190
- else process.env.FYLO_S3FILES_ROOT = prevRoot
200
+ if (prevFyloRoot === undefined) delete process.env.FYLO_ROOT
201
+ else process.env.FYLO_ROOT = prevFyloRoot
202
+ if (prevS3FilesRoot === undefined) delete process.env.FYLO_S3FILES_ROOT
203
+ else process.env.FYLO_S3FILES_ROOT = prevS3FilesRoot
191
204
  })
192
205
  })