dimond-db 1.0.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/LICENSE +21 -0
- package/README.md +362 -0
- package/package.json +46 -0
- package/src/database/Collection.js +401 -0
- package/src/database/Database.js +121 -0
- package/src/engine/QueryEngine.js +166 -0
- package/src/engine/StorageEngine.js +177 -0
- package/src/errors/DatabaseError.js +68 -0
- package/src/index.js +18 -0
- package/src/query/operators.js +187 -0
- package/src/storage/FileStorage.js +131 -0
- package/src/utils/deepClone.js +31 -0
- package/src/utils/idGenerator.js +35 -0
- package/src/utils/validator.js +133 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { ValidationError } from '../errors/DatabaseError.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Validates a document before insertion or update
|
|
5
|
+
* @param {*} doc - The document to validate
|
|
6
|
+
* @throws {ValidationError} If validation fails
|
|
7
|
+
*/
|
|
8
|
+
export function validateDocument(doc) {
|
|
9
|
+
if (doc === null || doc === undefined) {
|
|
10
|
+
throw new ValidationError('Document cannot be null or undefined');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (typeof doc !== 'object') {
|
|
14
|
+
throw new ValidationError('Document must be an object');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (Array.isArray(doc)) {
|
|
18
|
+
throw new ValidationError('Document cannot be an array');
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Validates an array of documents
|
|
24
|
+
* @param {Array} docs - The documents to validate
|
|
25
|
+
* @throws {ValidationError} If validation fails
|
|
26
|
+
*/
|
|
27
|
+
export function validateDocuments(docs) {
|
|
28
|
+
if (!Array.isArray(docs)) {
|
|
29
|
+
throw new ValidationError('Documents must be an array');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (docs.length === 0) {
|
|
33
|
+
throw new ValidationError('Documents array cannot be empty');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
docs.forEach((doc, index) => {
|
|
37
|
+
try {
|
|
38
|
+
validateDocument(doc);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
throw new ValidationError(`Document at index ${index}: ${error.message}`);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Validates a query filter object
|
|
47
|
+
* @param {Object} filter - The filter to validate
|
|
48
|
+
* @throws {ValidationError} If validation fails
|
|
49
|
+
*/
|
|
50
|
+
export function validateFilter(filter) {
|
|
51
|
+
if (filter === null || filter === undefined) {
|
|
52
|
+
return; // Empty filter is valid (matches all)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (typeof filter !== 'object') {
|
|
56
|
+
throw new ValidationError('Filter must be an object');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (Array.isArray(filter)) {
|
|
60
|
+
throw new ValidationError('Filter cannot be an array');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Validates an update operation object
|
|
66
|
+
* @param {Object} update - The update operation to validate
|
|
67
|
+
* @throws {ValidationError} If validation fails
|
|
68
|
+
*/
|
|
69
|
+
export function validateUpdate(update) {
|
|
70
|
+
if (update === null || update === undefined) {
|
|
71
|
+
throw new ValidationError('Update cannot be null or undefined');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (typeof update !== 'object') {
|
|
75
|
+
throw new ValidationError('Update must be an object');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (Array.isArray(update)) {
|
|
79
|
+
throw new ValidationError('Update cannot be an array');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (Object.keys(update).length === 0) {
|
|
83
|
+
throw new ValidationError('Update cannot be empty');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Check if all top-level keys are valid operators
|
|
87
|
+
const validOperators = ['$set', '$unset', '$inc', '$push'];
|
|
88
|
+
const keys = Object.keys(update);
|
|
89
|
+
|
|
90
|
+
const hasOperators = keys.some(key => key.startsWith('$'));
|
|
91
|
+
const hasNonOperators = keys.some(key => !key.startsWith('$'));
|
|
92
|
+
|
|
93
|
+
if (hasOperators && hasNonOperators) {
|
|
94
|
+
throw new ValidationError('Update cannot mix operators and direct field assignments');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (hasOperators) {
|
|
98
|
+
const invalidOperators = keys.filter(key => !validOperators.includes(key));
|
|
99
|
+
if (invalidOperators.length > 0) {
|
|
100
|
+
throw new ValidationError(`Invalid update operators: ${invalidOperators.join(', ')}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Validates a collection name
|
|
107
|
+
* @param {string} name - The collection name to validate
|
|
108
|
+
* @throws {ValidationError} If validation fails
|
|
109
|
+
*/
|
|
110
|
+
export function validateCollectionName(name) {
|
|
111
|
+
if (typeof name !== 'string') {
|
|
112
|
+
throw new ValidationError('Collection name must be a string');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (name.length === 0) {
|
|
116
|
+
throw new ValidationError('Collection name cannot be empty');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (name.length > 64) {
|
|
120
|
+
throw new ValidationError('Collection name cannot exceed 64 characters');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Check for invalid characters
|
|
124
|
+
const invalidChars = /[\\/:*?"<>|]/;
|
|
125
|
+
if (invalidChars.test(name)) {
|
|
126
|
+
throw new ValidationError('Collection name contains invalid characters');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Prevent reserved names
|
|
130
|
+
if (name.startsWith('system.')) {
|
|
131
|
+
throw new ValidationError('Collection name cannot start with "system."');
|
|
132
|
+
}
|
|
133
|
+
}
|