jexidb 2.0.3 → 2.1.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.
Files changed (79) hide show
  1. package/.babelrc +13 -0
  2. package/.gitattributes +2 -0
  3. package/CHANGELOG.md +132 -101
  4. package/LICENSE +21 -21
  5. package/README.md +301 -639
  6. package/babel.config.json +5 -0
  7. package/dist/Database.cjs +5204 -0
  8. package/docs/API.md +908 -241
  9. package/docs/EXAMPLES.md +701 -177
  10. package/docs/README.md +194 -184
  11. package/examples/iterate-usage-example.js +157 -0
  12. package/examples/simple-iterate-example.js +115 -0
  13. package/jest.config.js +24 -0
  14. package/package.json +63 -54
  15. package/scripts/README.md +47 -0
  16. package/scripts/benchmark-array-serialization.js +108 -0
  17. package/scripts/clean-test-files.js +75 -0
  18. package/scripts/prepare.js +31 -0
  19. package/scripts/run-tests.js +80 -0
  20. package/scripts/score-mode-demo.js +45 -0
  21. package/src/Database.mjs +5325 -0
  22. package/src/FileHandler.mjs +1140 -0
  23. package/src/OperationQueue.mjs +279 -0
  24. package/src/SchemaManager.mjs +268 -0
  25. package/src/Serializer.mjs +702 -0
  26. package/src/managers/ConcurrencyManager.mjs +257 -0
  27. package/src/managers/IndexManager.mjs +2094 -0
  28. package/src/managers/QueryManager.mjs +1490 -0
  29. package/src/managers/StatisticsManager.mjs +262 -0
  30. package/src/managers/StreamingProcessor.mjs +429 -0
  31. package/src/managers/TermManager.mjs +278 -0
  32. package/src/utils/operatorNormalizer.mjs +116 -0
  33. package/test/$not-operator-with-and.test.js +282 -0
  34. package/test/README.md +8 -0
  35. package/test/close-init-cycle.test.js +256 -0
  36. package/test/coverage-method.test.js +93 -0
  37. package/test/critical-bugs-fixes.test.js +1069 -0
  38. package/test/deserialize-corruption-fixes.test.js +296 -0
  39. package/test/exists-method.test.js +318 -0
  40. package/test/explicit-indexes-comparison.test.js +219 -0
  41. package/test/filehandler-non-adjacent-ranges-bug.test.js +175 -0
  42. package/test/index-line-number-regression.test.js +100 -0
  43. package/test/index-missing-index-data.test.js +91 -0
  44. package/test/index-persistence.test.js +491 -0
  45. package/test/index-serialization.test.js +314 -0
  46. package/test/indexed-query-mode.test.js +360 -0
  47. package/test/insert-session-auto-flush.test.js +353 -0
  48. package/test/iterate-method.test.js +272 -0
  49. package/test/legacy-operator-compat.test.js +154 -0
  50. package/test/query-operators.test.js +238 -0
  51. package/test/regex-array-fields.test.js +129 -0
  52. package/test/score-method.test.js +298 -0
  53. package/test/setup.js +17 -0
  54. package/test/term-mapping-minimal.test.js +154 -0
  55. package/test/term-mapping-simple.test.js +257 -0
  56. package/test/term-mapping.test.js +514 -0
  57. package/test/writebuffer-flush-resilience.test.js +204 -0
  58. package/dist/FileHandler.js +0 -688
  59. package/dist/IndexManager.js +0 -353
  60. package/dist/IntegrityChecker.js +0 -364
  61. package/dist/JSONLDatabase.js +0 -1333
  62. package/dist/index.js +0 -617
  63. package/docs/MIGRATION.md +0 -295
  64. package/examples/auto-save-example.js +0 -158
  65. package/examples/cjs-usage.cjs +0 -82
  66. package/examples/close-vs-delete-example.js +0 -71
  67. package/examples/esm-usage.js +0 -113
  68. package/examples/example-columns.idx.jdb +0 -0
  69. package/examples/example-columns.jdb +0 -9
  70. package/examples/example-options.idx.jdb +0 -0
  71. package/examples/example-options.jdb +0 -0
  72. package/examples/example-users.idx.jdb +0 -0
  73. package/examples/example-users.jdb +0 -5
  74. package/examples/simple-test.js +0 -55
  75. package/src/FileHandler.js +0 -674
  76. package/src/IndexManager.js +0 -363
  77. package/src/IntegrityChecker.js +0 -379
  78. package/src/JSONLDatabase.js +0 -1391
  79. package/src/index.js +0 -608
package/jest.config.js ADDED
@@ -0,0 +1,24 @@
1
+ export default {
2
+ testEnvironment: 'node',
3
+ testMatch: ['**/test/**/*.test.js', '**/test/**/*.test.mjs'],
4
+ collectCoverage: true,
5
+ coverageDirectory: 'coverage',
6
+ coverageReporters: ['text', 'lcov', 'html'],
7
+ coveragePathIgnorePatterns: [
8
+ '/node_modules/',
9
+ '/test/',
10
+ '/dist/'
11
+ ],
12
+ verbose: true,
13
+ testTimeout: 10000,
14
+ maxWorkers: '50%', // Allow parallel test execution for better performance
15
+ detectOpenHandles: true, // Detect open handles to identify resource leaks
16
+ transform: {
17
+ '^.+\\.mjs$': 'babel-jest',
18
+ '^.+\\.js$': 'babel-jest'
19
+ },
20
+ transformIgnorePatterns: [
21
+ 'node_modules/(?!(.*\\.mjs$|p-limit|yocto-queue))'
22
+ ],
23
+ setupFilesAfterEnv: ['<rootDir>/test/setup.js']
24
+ };
package/package.json CHANGED
@@ -1,68 +1,77 @@
1
1
  {
2
2
  "name": "jexidb",
3
- "version": "2.0.3",
4
- "description": "JexiDB - A fast and reliable local CRUD database for Electron apps with pure JavaScript JSONL architecture",
5
- "main": "./dist/index.js",
6
- "module": "./src/index.js",
7
- "types": "./dist/index.d.ts",
3
+ "version": "2.1.1",
4
+ "type": "module",
5
+ "description": "JexiDB is a pure JS NPM library for managing data on disk efficiently, without the need for a server.",
6
+ "main": "./dist/Database.cjs",
7
+ "module": "./src/Database.mjs",
8
8
  "exports": {
9
9
  ".": {
10
- "import": "./src/index.js",
11
- "require": "./dist/index.js",
12
- "types": "./dist/index.d.ts"
13
- },
14
- "./package.json": "./package.json"
10
+ "require": "./dist/Database.cjs",
11
+ "import": "./src/Database.mjs"
12
+ }
15
13
  },
16
14
  "scripts": {
17
- "build": "babel src -d dist",
18
- "dev": "babel src -d dist --watch",
19
- "test": "jest && node scripts/cleanup-after-tests.js",
15
+ "test": "node scripts/run-tests.js",
20
16
  "test:watch": "jest --watch",
21
- "test:clean": "node scripts/cleanup-after-tests.js",
22
- "test:optimized": "node scripts/optimize-tests.js --performance",
23
- "test:parallel": "node scripts/optimize-tests.js --parallel --workers 4",
24
- "test:fast": "node scripts/optimize-tests.js --parallel --workers 4 --performance --no-isolation",
25
- "prepublishOnly": "npm run build",
26
- "generate-test-db": "node scripts/run-test-db.js",
27
- "generate-test-db:multiple": "node scripts/run-test-db.js --multiple",
28
- "list-test-dbs": "node scripts/list-test-dbs.js",
29
- "verify-test-db": "node scripts/verify-test-db.js",
30
- "test-optimization": "node scripts/test-optimization.js",
31
- "benchmark-compression": "node scripts/benchmark-compression.js",
32
- "benchmark-performance": "node scripts/benchmark-performance.js",
33
- "generate-docs": "node scripts/generate-docs.js"
17
+ "test:coverage": "jest --coverage && npm run clean:test-files",
18
+ "test:legacy": "node --expose-gc test/test.mjs",
19
+ "clean:test-files": "node scripts/clean-test-files.js",
20
+ "build": "npx babel src/Database.mjs --plugins @babel/plugin-transform-async-generator-functions --out-file-extension .cjs --out-dir dist",
21
+ "prepare": "node scripts/prepare.js"
34
22
  },
35
- "keywords": [
36
- "database",
37
- "crud",
38
- "local",
39
- "electron",
40
- "javascript",
41
- "json",
42
- "storage",
43
- "jexidb",
44
- "jsonl",
45
- "nosql"
46
- ],
47
- "author": "Edenware",
23
+ "author": "EdenwareApps",
48
24
  "license": "MIT",
49
25
  "devDependencies": {
50
- "@babel/cli": "^7.23.0",
51
- "@babel/core": "^7.23.0",
52
- "@babel/preset-env": "^7.23.0",
53
- "jest": "^29.7.0"
26
+ "@babel/cli": "^7.25.6",
27
+ "@babel/core": "^7.25.2",
28
+ "@babel/plugin-transform-async-generator-functions": "^7.25.4",
29
+ "@babel/preset-env": "^7.28.3",
30
+ "@rollup/plugin-commonjs": "^28.0.6",
31
+ "@rollup/plugin-node-resolve": "^16.0.1",
32
+ "babel-jest": "^30.0.5",
33
+ "jest": "^30.1.3",
34
+ "jest-extended": "^6.0.0",
35
+ "rollup": "^4.48.1"
36
+ },
37
+ "dependencies": {
38
+ "@valentech/sializer": "^0.3.9",
39
+ "async-mutex": "^0.5.0",
40
+ "p-limit": "^6.1.0"
41
+ },
42
+ "optionalDependencies": {
43
+ "fast-deep-equal": "^3.1.3",
44
+ "fast-json-stringify": "^5.7.0",
45
+ "msgpack": "^1.0.3"
54
46
  },
55
- "engines": {
56
- "node": ">=14.0.0"
47
+ "directories": {
48
+ "test": "test"
57
49
  },
58
- "files": [
59
- "dist",
60
- "src",
61
- "README.md",
62
- "CHANGELOG.md",
63
- "docs",
64
- "examples"
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "git+https://github.com/EdenwareApps/jexidb.git"
53
+ },
54
+ "keywords": [
55
+ "couchdb",
56
+ "database",
57
+ "nosql",
58
+ "pouchdb",
59
+ "local-storage",
60
+ "db",
61
+ "persistent-storage",
62
+ "dexiejs",
63
+ "embedded-database",
64
+ "data-management",
65
+ "nedb",
66
+ "lowdb",
67
+ "dexie",
68
+ "offline-database",
69
+ "simple-database",
70
+ "fast-database",
71
+ "jexidb"
65
72
  ],
66
- "dependencies": {
67
- }
73
+ "bugs": {
74
+ "url": "https://github.com/EdenwareApps/jexidb/issues"
75
+ },
76
+ "homepage": "https://github.com/EdenwareApps/jexidb#readme"
68
77
  }
@@ -0,0 +1,47 @@
1
+ # Scripts
2
+
3
+ This directory contains utility scripts for the JexiDB project.
4
+
5
+ ## clean-test-files.js
6
+
7
+ A Node.js script that automatically cleans up test files generated during test execution.
8
+
9
+ ### Usage
10
+
11
+ ```bash
12
+ # Run manually
13
+ node scripts/clean-test-files.js
14
+
15
+ # Run via npm script
16
+ npm run clean:test-files
17
+ ```
18
+
19
+ ### What it cleans
20
+
21
+ The script removes files matching these patterns:
22
+ - `test-db-*` (with or without extensions)
23
+ - `test-db-*.jdb`
24
+ - `test-db-*.idx.jdb` (contains both index and offsets data)
25
+ - `test-normalize*` (with or without extensions)
26
+ - `test-confusion*` (with or without extensions)
27
+ - `debug-*` (with or without extensions)
28
+ - `test-simple-*`
29
+ - `test-count.jdb`
30
+
31
+ ### Integration with npm test
32
+
33
+ The cleanup script is automatically executed after running tests:
34
+
35
+ ```bash
36
+ npm test # Runs jest && npm run clean:test-files
37
+ ```
38
+
39
+ This ensures that test files are automatically cleaned up after each test run, keeping the project directory clean.
40
+
41
+ ### Features
42
+
43
+ - **Pattern-based cleanup**: Uses regex patterns to identify test files
44
+ - **Safe deletion**: Only deletes files, not directories
45
+ - **Error handling**: Continues execution even if some files can't be deleted
46
+ - **Verbose output**: Shows which files were cleaned
47
+ - **Summary**: Reports total number of files cleaned
@@ -0,0 +1,108 @@
1
+ import { performance } from 'node:perf_hooks'
2
+ import Serializer from '../src/Serializer.mjs'
3
+
4
+ const ITERATIONS = parseInt(process.env.BENCH_ITERATIONS ?? '200', 10)
5
+ const RECORDS_PER_ITERATION = parseInt(process.env.BENCH_RECORDS ?? '2000', 10)
6
+
7
+ const serializer = new Serializer({
8
+ enableAdvancedSerialization: true,
9
+ enableArraySerialization: true,
10
+ debugMode: false
11
+ })
12
+
13
+ // Ensure schema is initialized to trigger array serialization path
14
+ const schemaFields = ['id', 'name', 'value', 'tags', 'metadata', 'score', 'createdAt']
15
+ serializer.schemaManager.initializeSchema(schemaFields)
16
+
17
+ function createRecord(index) {
18
+ return {
19
+ id: `rec-${index}`,
20
+ name: `Record ${index}`,
21
+ value: index,
22
+ tags: [`tag-${index % 10}`, `tag-${(index + 3) % 10}`],
23
+ metadata: {
24
+ active: index % 2 === 0,
25
+ category: `category-${index % 5}`,
26
+ flags: [index % 7 === 0, index % 11 === 0]
27
+ },
28
+ score: Math.sin(index) * 100,
29
+ createdAt: new Date(1700000000000 + index * 60000).toISOString()
30
+ }
31
+ }
32
+
33
+ function prepareData() {
34
+ const raw = new Array(RECORDS_PER_ITERATION)
35
+ const arrayFormat = new Array(RECORDS_PER_ITERATION)
36
+ const normalized = new Array(RECORDS_PER_ITERATION)
37
+
38
+ for (let i = 0; i < RECORDS_PER_ITERATION; i++) {
39
+ const record = createRecord(i)
40
+ raw[i] = record
41
+ const arr = serializer.convertToArrayFormat(record)
42
+ arrayFormat[i] = arr
43
+ normalized[i] = serializer.deepNormalizeEncoding(arr)
44
+ }
45
+
46
+ return { raw, arrayFormat, normalized }
47
+ }
48
+
49
+ function benchFastPath(normalizedArrays) {
50
+ let totalLength = 0
51
+ for (let i = 0; i < normalizedArrays.length; i++) {
52
+ const json = serializer._stringifyNormalizedArray(normalizedArrays[i])
53
+ totalLength += json.length
54
+ }
55
+ return totalLength
56
+ }
57
+
58
+ function benchLegacyPath(normalizedArrays) {
59
+ let totalLength = 0
60
+ for (let i = 0; i < normalizedArrays.length; i++) {
61
+ const json = JSON.stringify(normalizedArrays[i])
62
+ totalLength += json.length
63
+ }
64
+ return totalLength
65
+ }
66
+
67
+ function runBenchmarks() {
68
+ const { normalized } = prepareData()
69
+
70
+ // Warm-up
71
+ benchFastPath(normalized)
72
+ benchLegacyPath(normalized)
73
+
74
+ let fastDuration = 0
75
+ let legacyDuration = 0
76
+ let fastTotal = 0
77
+ let legacyTotal = 0
78
+
79
+ for (let i = 0; i < ITERATIONS; i++) {
80
+ const startFast = performance.now()
81
+ fastTotal += benchFastPath(normalized)
82
+ fastDuration += performance.now() - startFast
83
+
84
+ const startLegacy = performance.now()
85
+ legacyTotal += benchLegacyPath(normalized)
86
+ legacyDuration += performance.now() - startLegacy
87
+ }
88
+
89
+ console.log(`Benchmark settings:`)
90
+ console.log(` iterations: ${ITERATIONS}`)
91
+ console.log(` records/iteration: ${RECORDS_PER_ITERATION}`)
92
+ console.log('')
93
+ console.log(`Fast path total time: ${fastDuration.toFixed(2)} ms`)
94
+ console.log(`Legacy path total time: ${legacyDuration.toFixed(2)} ms`)
95
+ console.log('')
96
+ console.log(`Average fast path per iteration: ${(fastDuration / ITERATIONS).toFixed(4)} ms`)
97
+ console.log(`Average legacy path per iteration: ${(legacyDuration / ITERATIONS).toFixed(4)} ms`)
98
+ console.log('')
99
+ console.log(`Output size parity check: fast=${fastTotal} legacy=${legacyTotal}`)
100
+ }
101
+
102
+ try {
103
+ runBenchmarks()
104
+ } catch (error) {
105
+ console.error('Benchmark failed:', error)
106
+ process.exit(1)
107
+ }
108
+
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+
6
+ function cleanTestFiles() {
7
+ const startTime = Date.now();
8
+ const currentDir = process.cwd();
9
+ const files = fs.readdirSync(currentDir);
10
+
11
+ const testFilePatterns = [
12
+ /^test-db-.*\.jdb$/,
13
+ /^test-db-.*\.offsets\.jdb$/,
14
+ /^test-db-.*\.idx\.jdb$/,
15
+ /^test-db-.*$/, // Files without extension
16
+ /^test-normalize.*\.jdb$/,
17
+ /^test-normalize.*\.offsets\.jdb$/,
18
+ /^test-normalize.*\.idx\.jdb$/,
19
+ /^test-normalize.*$/, // Files without extension
20
+ /^test-confusion.*\.jdb$/,
21
+ /^test-confusion.*\.offsets\.jdb$/,
22
+ /^test-confusion.*\.idx\.jdb$/,
23
+ /^test-confusion.*$/, // Files without extension
24
+ /^debug-.*\.jdb$/,
25
+ /^debug-.*\.offsets\.jdb$/,
26
+ /^debug-.*\.idx\.jdb$/,
27
+ /^debug-.*$/, // Files without extension
28
+ /^test-simple-.*$/, // test-simple files
29
+ /^test-count\.jdb$/, // test-count.jdb file
30
+ /^test-index-persistence-.*\.jdb$/, // index persistence test files
31
+ /^test-index-persistence-.*\.idx\.jdb$/, // index persistence idx files
32
+ /^test-indexed-mode-.*\.jdb$/, // indexed mode test files
33
+ /^test-indexed-mode-.*\.idx\.jdb$/, // indexed mode idx files
34
+ /^test-term-mapping-.*\.jdb$/, // term mapping test files
35
+ /^test-term-mapping-.*\.idx\.jdb$/, // term mapping idx files
36
+ /^test-.*\.jdb$/, // Any test file with .jdb extension
37
+ /^test-.*\.idx\.jdb$/ // Any test file with .idx.jdb extension
38
+ ];
39
+
40
+ let cleanedCount = 0;
41
+
42
+ files.forEach(file => {
43
+ const filePath = path.join(currentDir, file);
44
+ const stats = fs.statSync(filePath);
45
+
46
+ if (stats.isFile()) {
47
+ const shouldDelete = testFilePatterns.some(pattern => pattern.test(file));
48
+
49
+ if (shouldDelete) {
50
+ try {
51
+ fs.unlinkSync(filePath);
52
+ cleanedCount++;
53
+ } catch (error) {
54
+ console.warn(`Warning: Could not delete ${file}: ${error.message}`);
55
+ }
56
+ }
57
+ }
58
+ });
59
+
60
+ const endTime = Date.now();
61
+ const duration = endTime - startTime;
62
+
63
+ if (cleanedCount > 0) {
64
+ console.log(`✅ Cleaned ${cleanedCount} test files.`);
65
+ } else {
66
+ console.log('No test files found to clean.');
67
+ }
68
+ }
69
+
70
+ // Run cleanup if this script is executed directly
71
+ if (import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith('clean-test-files.js')) {
72
+ cleanTestFiles();
73
+ }
74
+
75
+ export default cleanTestFiles;
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { existsSync } from 'fs';
4
+ import { execSync } from 'child_process';
5
+ import { fileURLToPath } from 'url';
6
+ import { dirname, join } from 'path';
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = dirname(__filename);
10
+ const rootDir = join(__dirname, '..');
11
+ const distFile = join(rootDir, 'dist', 'Database.cjs');
12
+
13
+ // Check if the bundle already exists
14
+ if (existsSync(distFile)) {
15
+ console.log('✅ Bundle already exists, skipping build');
16
+ process.exit(0);
17
+ }
18
+
19
+ console.log('📦 Bundle not found, building...');
20
+
21
+ try {
22
+ execSync('npm run build', {
23
+ stdio: 'inherit',
24
+ cwd: rootDir
25
+ });
26
+ console.log('✅ Build completed successfully');
27
+ } catch (error) {
28
+ console.error('❌ Build failed:', error.message);
29
+ process.exit(1);
30
+ }
31
+
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { spawn } from 'child_process'
4
+ import { fileURLToPath } from 'url'
5
+ import { dirname, join } from 'path'
6
+
7
+ const __filename = fileURLToPath(import.meta.url)
8
+ const __dirname = dirname(__filename)
9
+
10
+ async function runTests() {
11
+ const startTime = Date.now()
12
+
13
+ console.log('🧪 Running JexiDB tests...')
14
+
15
+ // Run Jest tests
16
+ const jestProcess = spawn('npx', ['jest', ...process.argv.slice(2)], {
17
+ stdio: 'inherit',
18
+ shell: true
19
+ })
20
+
21
+ jestProcess.on('close', async (code) => {
22
+ if (code !== 0) {
23
+ console.error(`❌ Tests failed with exit code ${code}`)
24
+ process.exit(code)
25
+ }
26
+
27
+ // Run cleanup
28
+ const cleanupProcess = spawn('npm', ['run', 'clean:test-files'], {
29
+ stdio: 'inherit',
30
+ shell: true
31
+ })
32
+
33
+ cleanupProcess.on('close', (cleanupCode) => {
34
+ const endTime = Date.now()
35
+ const duration = Math.round((endTime - startTime) / 1000)
36
+
37
+ // Display completion time
38
+ const completionTime = new Date().toLocaleString('en-US', {
39
+ year: 'numeric',
40
+ month: '2-digit',
41
+ day: '2-digit',
42
+ hour: '2-digit',
43
+ minute: '2-digit',
44
+ second: '2-digit',
45
+ hour12: true
46
+ });
47
+
48
+ console.log(`✅ Tests completed at: ${completionTime}`);
49
+ console.log(`📦 Total execution time: ${duration}s`)
50
+
51
+ if (cleanupCode !== 0) {
52
+ console.warn(`⚠️ Cleanup completed with warnings (exit code: ${cleanupCode})`)
53
+ }
54
+
55
+ process.exit(0)
56
+ })
57
+ })
58
+
59
+ jestProcess.on('error', (error) => {
60
+ console.error('❌ Failed to start Jest:', error.message)
61
+ process.exit(1)
62
+ })
63
+ }
64
+
65
+ // Handle process termination
66
+ process.on('SIGINT', () => {
67
+ console.log('\n🛑 Test execution interrupted by user')
68
+ process.exit(0)
69
+ })
70
+
71
+ process.on('SIGTERM', () => {
72
+ console.log('\n🛑 Test execution terminated')
73
+ process.exit(0)
74
+ })
75
+
76
+ // Run the tests
77
+ runTests().catch(error => {
78
+ console.error('❌ Fatal error:', error.message)
79
+ process.exit(1)
80
+ })
@@ -0,0 +1,45 @@
1
+ import { Database } from '../src/Database.mjs'
2
+ import path from 'path'
3
+ import fs from 'fs'
4
+
5
+ const dbPath = path.join(process.cwd(), 'temp-score-demo.jdb')
6
+ const idxPath = dbPath.replace('.jdb', '.idx.jdb')
7
+
8
+ for (const file of [dbPath, idxPath]) {
9
+ if (fs.existsSync(file)) {
10
+ fs.unlinkSync(file)
11
+ }
12
+ }
13
+
14
+ const db = new Database(dbPath, {
15
+ indexes: { terms: 'array:string' }
16
+ })
17
+
18
+ await db.init()
19
+
20
+ await db.insert({ id: 1, title: 'Ação', terms: ['action'] })
21
+ await db.insert({ id: 2, title: 'Comédia', terms: ['comedy'] })
22
+ await db.insert({ id: 3, title: 'Ação + Comédia', terms: ['action', 'comedy'] })
23
+ await db.save()
24
+
25
+ const weights = { action: 2.0, comedy: 1.0 }
26
+
27
+ const modes = ['sum', 'max', 'avg', 'first']
28
+
29
+ for (const mode of modes) {
30
+ const results = await db.score('terms', weights, { mode })
31
+ console.log(`\nmode=${mode}`)
32
+ for (const entry of results) {
33
+ console.log(` ${entry.title.padEnd(16)} score=${entry.score}`)
34
+ }
35
+ }
36
+
37
+ await db.destroy()
38
+
39
+ for (const file of [dbPath, idxPath]) {
40
+ if (fs.existsSync(file)) {
41
+ fs.unlinkSync(file)
42
+ }
43
+ }
44
+
45
+