jexidb 2.0.3 → 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/.babelrc +13 -0
- package/.gitattributes +2 -0
- package/CHANGELOG.md +132 -101
- package/LICENSE +21 -21
- package/README.md +301 -639
- package/babel.config.json +5 -0
- package/dist/Database.cjs +3896 -0
- package/docs/API.md +1051 -390
- package/docs/EXAMPLES.md +701 -177
- package/docs/README.md +194 -184
- package/examples/iterate-usage-example.js +157 -0
- package/examples/simple-iterate-example.js +115 -0
- package/jest.config.js +24 -0
- package/package.json +63 -54
- package/scripts/README.md +47 -0
- package/scripts/clean-test-files.js +75 -0
- package/scripts/prepare.js +31 -0
- package/scripts/run-tests.js +80 -0
- package/src/Database.mjs +4130 -0
- package/src/FileHandler.mjs +1101 -0
- package/src/OperationQueue.mjs +279 -0
- package/src/SchemaManager.mjs +268 -0
- package/src/Serializer.mjs +511 -0
- package/src/managers/ConcurrencyManager.mjs +257 -0
- package/src/managers/IndexManager.mjs +1403 -0
- package/src/managers/QueryManager.mjs +1273 -0
- package/src/managers/StatisticsManager.mjs +262 -0
- package/src/managers/StreamingProcessor.mjs +429 -0
- package/src/managers/TermManager.mjs +278 -0
- package/test/$not-operator-with-and.test.js +282 -0
- package/test/README.md +8 -0
- package/test/close-init-cycle.test.js +256 -0
- package/test/critical-bugs-fixes.test.js +1069 -0
- package/test/index-persistence.test.js +306 -0
- package/test/index-serialization.test.js +314 -0
- package/test/indexed-query-mode.test.js +360 -0
- package/test/iterate-method.test.js +272 -0
- package/test/query-operators.test.js +238 -0
- package/test/regex-array-fields.test.js +129 -0
- package/test/score-method.test.js +238 -0
- package/test/setup.js +17 -0
- package/test/term-mapping-minimal.test.js +154 -0
- package/test/term-mapping-simple.test.js +257 -0
- package/test/term-mapping.test.js +514 -0
- package/test/writebuffer-flush-resilience.test.js +204 -0
- package/dist/FileHandler.js +0 -688
- package/dist/IndexManager.js +0 -353
- package/dist/IntegrityChecker.js +0 -364
- package/dist/JSONLDatabase.js +0 -1333
- package/dist/index.js +0 -617
- package/docs/MIGRATION.md +0 -295
- package/examples/auto-save-example.js +0 -158
- package/examples/cjs-usage.cjs +0 -82
- package/examples/close-vs-delete-example.js +0 -71
- package/examples/esm-usage.js +0 -113
- package/examples/example-columns.idx.jdb +0 -0
- package/examples/example-columns.jdb +0 -9
- package/examples/example-options.idx.jdb +0 -0
- package/examples/example-options.jdb +0 -0
- package/examples/example-users.idx.jdb +0 -0
- package/examples/example-users.jdb +0 -5
- package/examples/simple-test.js +0 -55
- package/src/FileHandler.js +0 -674
- package/src/IndexManager.js +0 -363
- package/src/IntegrityChecker.js +0 -379
- package/src/JSONLDatabase.js +0 -1391
- 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
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
3
|
+
"version": "2.1.0",
|
|
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
|
-
"
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
},
|
|
14
|
-
"./package.json": "./package.json"
|
|
10
|
+
"require": "./dist/Database.cjs",
|
|
11
|
+
"import": "./src/Database.mjs"
|
|
12
|
+
}
|
|
15
13
|
},
|
|
16
14
|
"scripts": {
|
|
17
|
-
"
|
|
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:
|
|
22
|
-
"test:
|
|
23
|
-
"test
|
|
24
|
-
"
|
|
25
|
-
"
|
|
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
|
-
"
|
|
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.
|
|
51
|
-
"@babel/core": "^7.
|
|
52
|
-
"@babel/
|
|
53
|
-
"
|
|
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
|
-
"
|
|
56
|
-
"
|
|
47
|
+
"directories": {
|
|
48
|
+
"test": "test"
|
|
57
49
|
},
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
"
|
|
64
|
-
"
|
|
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
|
-
"
|
|
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,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
|
+
})
|