@joystick.js/db-canary 0.0.0-canary.2251 → 0.0.0-canary.2252
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/dist/client/database.js +1 -1
- package/dist/client/index.js +1 -1
- package/dist/server/cluster/master.js +4 -4
- package/dist/server/cluster/worker.js +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/lib/auto_index_manager.js +1 -1
- package/dist/server/lib/backup_manager.js +1 -1
- package/dist/server/lib/index_manager.js +1 -1
- package/dist/server/lib/operation_dispatcher.js +1 -1
- package/dist/server/lib/operations/admin.js +1 -1
- package/dist/server/lib/operations/bulk_write.js +1 -1
- package/dist/server/lib/operations/create_index.js +1 -1
- package/dist/server/lib/operations/delete_many.js +1 -1
- package/dist/server/lib/operations/delete_one.js +1 -1
- package/dist/server/lib/operations/find.js +1 -1
- package/dist/server/lib/operations/find_one.js +1 -1
- package/dist/server/lib/operations/insert_one.js +1 -1
- package/dist/server/lib/operations/update_one.js +1 -1
- package/dist/server/lib/send_response.js +1 -1
- package/dist/server/lib/tcp_protocol.js +1 -1
- package/package.json +2 -2
- package/src/client/database.js +92 -119
- package/src/client/index.js +279 -345
- package/src/server/cluster/master.js +265 -156
- package/src/server/cluster/worker.js +26 -18
- package/src/server/index.js +553 -330
- package/src/server/lib/auto_index_manager.js +85 -23
- package/src/server/lib/backup_manager.js +117 -70
- package/src/server/lib/index_manager.js +63 -25
- package/src/server/lib/operation_dispatcher.js +339 -168
- package/src/server/lib/operations/admin.js +343 -205
- package/src/server/lib/operations/bulk_write.js +458 -194
- package/src/server/lib/operations/create_index.js +127 -34
- package/src/server/lib/operations/delete_many.js +204 -67
- package/src/server/lib/operations/delete_one.js +164 -52
- package/src/server/lib/operations/find.js +552 -319
- package/src/server/lib/operations/find_one.js +530 -304
- package/src/server/lib/operations/insert_one.js +147 -52
- package/src/server/lib/operations/update_one.js +334 -93
- package/src/server/lib/send_response.js +37 -17
- package/src/server/lib/tcp_protocol.js +158 -53
- package/test_data_api_key_1758233848259_cglfjzhou/data.mdb +0 -0
- package/test_data_api_key_1758233848259_cglfjzhou/lock.mdb +0 -0
- package/test_data_api_key_1758233848502_urlje2utd/data.mdb +0 -0
- package/test_data_api_key_1758233848502_urlje2utd/lock.mdb +0 -0
- package/test_data_api_key_1758233848738_mtcpfe5ns/data.mdb +0 -0
- package/test_data_api_key_1758233848738_mtcpfe5ns/lock.mdb +0 -0
- package/test_data_api_key_1758233848856_9g97p6gag/data.mdb +0 -0
- package/test_data_api_key_1758233848856_9g97p6gag/lock.mdb +0 -0
- package/test_data_api_key_1758233857008_0tl9zzhj8/data.mdb +0 -0
- package/test_data_api_key_1758233857008_0tl9zzhj8/lock.mdb +0 -0
- package/test_data_api_key_1758233857120_60c2f2uhu/data.mdb +0 -0
- package/test_data_api_key_1758233857120_60c2f2uhu/lock.mdb +0 -0
- package/test_data_api_key_1758233857232_aw7fkqgd9/data.mdb +0 -0
- package/test_data_api_key_1758233857232_aw7fkqgd9/lock.mdb +0 -0
- package/test_data_api_key_1758234881285_4aeflubjb/data.mdb +0 -0
- package/test_data_api_key_1758234881285_4aeflubjb/lock.mdb +0 -0
- package/test_data_api_key_1758234881520_kb0amvtqb/data.mdb +0 -0
- package/test_data_api_key_1758234881520_kb0amvtqb/lock.mdb +0 -0
- package/test_data_api_key_1758234881756_k04gfv2va/data.mdb +0 -0
- package/test_data_api_key_1758234881756_k04gfv2va/lock.mdb +0 -0
- package/test_data_api_key_1758234881876_wn90dpo1z/data.mdb +0 -0
- package/test_data_api_key_1758234881876_wn90dpo1z/lock.mdb +0 -0
- package/test_data_api_key_1758234889461_26xz3dmbr/data.mdb +0 -0
- package/test_data_api_key_1758234889461_26xz3dmbr/lock.mdb +0 -0
- package/test_data_api_key_1758234889572_uziz7e0p5/data.mdb +0 -0
- package/test_data_api_key_1758234889572_uziz7e0p5/lock.mdb +0 -0
- package/test_data_api_key_1758234889684_5f9wmposh/data.mdb +0 -0
- package/test_data_api_key_1758234889684_5f9wmposh/lock.mdb +0 -0
- package/test_data_api_key_1758235657729_prwgm6mxr/data.mdb +0 -0
- package/test_data_api_key_1758235657729_prwgm6mxr/lock.mdb +0 -0
- package/test_data_api_key_1758235657961_rc2da0dc2/data.mdb +0 -0
- package/test_data_api_key_1758235657961_rc2da0dc2/lock.mdb +0 -0
- package/test_data_api_key_1758235658193_oqqxm0sny/data.mdb +0 -0
- package/test_data_api_key_1758235658193_oqqxm0sny/lock.mdb +0 -0
- package/test_data_api_key_1758235658309_vggac1pj6/data.mdb +0 -0
- package/test_data_api_key_1758235658309_vggac1pj6/lock.mdb +0 -0
- package/test_data_api_key_1758235665968_61ko07dd1/data.mdb +0 -0
- package/test_data_api_key_1758235665968_61ko07dd1/lock.mdb +0 -0
- package/test_data_api_key_1758235666082_50lrt6sq8/data.mdb +0 -0
- package/test_data_api_key_1758235666082_50lrt6sq8/lock.mdb +0 -0
- package/test_data_api_key_1758235666194_ykvauwlzh/data.mdb +0 -0
- package/test_data_api_key_1758235666194_ykvauwlzh/lock.mdb +0 -0
- package/test_data_api_key_1758236187207_9c4paeh09/data.mdb +0 -0
- package/test_data_api_key_1758236187207_9c4paeh09/lock.mdb +0 -0
- package/test_data_api_key_1758236187441_4n3o3gkkl/data.mdb +0 -0
- package/test_data_api_key_1758236187441_4n3o3gkkl/lock.mdb +0 -0
- package/test_data_api_key_1758236187672_jt6b21ye0/data.mdb +0 -0
- package/test_data_api_key_1758236187672_jt6b21ye0/lock.mdb +0 -0
- package/test_data_api_key_1758236187788_oo84fz9u6/data.mdb +0 -0
- package/test_data_api_key_1758236187788_oo84fz9u6/lock.mdb +0 -0
- package/test_data_api_key_1758236195507_o9zeznwlm/data.mdb +0 -0
- package/test_data_api_key_1758236195507_o9zeznwlm/lock.mdb +0 -0
- package/test_data_api_key_1758236195619_qsqd60y41/data.mdb +0 -0
- package/test_data_api_key_1758236195619_qsqd60y41/lock.mdb +0 -0
- package/test_data_api_key_1758236195731_im13iq284/data.mdb +0 -0
- package/test_data_api_key_1758236195731_im13iq284/lock.mdb +0 -0
|
@@ -9,58 +9,151 @@ import create_logger from '../logger.js';
|
|
|
9
9
|
const { create_context_logger } = create_logger('create_index');
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
13
|
-
* @param {string} database_name -
|
|
14
|
-
* @
|
|
15
|
-
* @param {string} field_name - Name of the field to index
|
|
16
|
-
* @param {Object} [options={}] - Index creation options
|
|
17
|
-
* @param {boolean} [options.unique] - Whether the index should enforce uniqueness
|
|
18
|
-
* @param {boolean} [options.sparse] - Whether the index should be sparse (skip null values)
|
|
19
|
-
* @returns {Promise<Object>} Index creation result with operation details and message
|
|
20
|
-
* @throws {Error} When database, collection name or field name is missing, or index creation fails
|
|
12
|
+
* Validates database name parameter.
|
|
13
|
+
* @param {string} database_name - Database name to validate
|
|
14
|
+
* @throws {Error} When database name is missing
|
|
21
15
|
*/
|
|
22
|
-
const
|
|
23
|
-
const log = create_context_logger();
|
|
24
|
-
|
|
16
|
+
const validate_database_name = (database_name) => {
|
|
25
17
|
if (!database_name) {
|
|
26
18
|
throw new Error('Database name is required');
|
|
27
19
|
}
|
|
28
|
-
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Validates collection name parameter.
|
|
24
|
+
* @param {string} collection_name - Collection name to validate
|
|
25
|
+
* @throws {Error} When collection name is missing
|
|
26
|
+
*/
|
|
27
|
+
const validate_collection_name = (collection_name) => {
|
|
29
28
|
if (!collection_name) {
|
|
30
29
|
throw new Error('Collection name is required');
|
|
31
30
|
}
|
|
32
|
-
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Validates field name parameter.
|
|
35
|
+
* @param {string} field_name - Field name to validate
|
|
36
|
+
* @throws {Error} When field name is missing
|
|
37
|
+
*/
|
|
38
|
+
const validate_field_name = (field_name) => {
|
|
33
39
|
if (!field_name) {
|
|
34
40
|
throw new Error('Field name is required');
|
|
35
41
|
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Validates all create index operation parameters.
|
|
46
|
+
* @param {string} database_name - Database name
|
|
47
|
+
* @param {string} collection_name - Collection name
|
|
48
|
+
* @param {string} field_name - Field name
|
|
49
|
+
*/
|
|
50
|
+
const validate_create_index_parameters = (database_name, collection_name, field_name) => {
|
|
51
|
+
validate_database_name(database_name);
|
|
52
|
+
validate_collection_name(collection_name);
|
|
53
|
+
validate_field_name(field_name);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Determines action verb based on operation type.
|
|
58
|
+
* @param {string} operation_type - Type of operation performed
|
|
59
|
+
* @returns {string} Action verb describing the operation
|
|
60
|
+
*/
|
|
61
|
+
const get_action_verb_for_operation = (operation_type) => {
|
|
62
|
+
switch (operation_type) {
|
|
63
|
+
case 'created':
|
|
64
|
+
return 'created';
|
|
65
|
+
case 'updated':
|
|
66
|
+
return 'updated';
|
|
67
|
+
default:
|
|
68
|
+
return 'already exists';
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Creates success message for index operation.
|
|
74
|
+
* @param {string} action_verb - Action verb describing operation
|
|
75
|
+
* @param {string} database_name - Database name
|
|
76
|
+
* @param {string} collection_name - Collection name
|
|
77
|
+
* @param {string} field_name - Field name
|
|
78
|
+
* @returns {string} Success message
|
|
79
|
+
*/
|
|
80
|
+
const create_success_message = (action_verb, database_name, collection_name, field_name) => {
|
|
81
|
+
return `Index ${action_verb} on ${database_name}.${collection_name}.${field_name}`;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Logs successful index operation.
|
|
86
|
+
* @param {Function} log - Logger function
|
|
87
|
+
* @param {string} action_verb - Action verb describing operation
|
|
88
|
+
* @param {string} database_name - Database name
|
|
89
|
+
* @param {string} collection_name - Collection name
|
|
90
|
+
* @param {string} field_name - Field name
|
|
91
|
+
* @param {Object} options - Index options
|
|
92
|
+
* @param {string} operation_type - Type of operation performed
|
|
93
|
+
*/
|
|
94
|
+
const log_successful_index_operation = (log, action_verb, database_name, collection_name, field_name, options, operation_type) => {
|
|
95
|
+
log.info(`Index ${action_verb} successfully`, {
|
|
96
|
+
database: database_name,
|
|
97
|
+
collection: collection_name,
|
|
98
|
+
field: field_name,
|
|
99
|
+
options,
|
|
100
|
+
operation_type
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Logs failed index operation.
|
|
106
|
+
* @param {Function} log - Logger function
|
|
107
|
+
* @param {string} database_name - Database name
|
|
108
|
+
* @param {string} collection_name - Collection name
|
|
109
|
+
* @param {string} field_name - Field name
|
|
110
|
+
* @param {Error} error - Error that occurred
|
|
111
|
+
*/
|
|
112
|
+
const log_failed_index_operation = (log, database_name, collection_name, field_name, error) => {
|
|
113
|
+
log.error('Failed to create/upsert index', {
|
|
114
|
+
database: database_name,
|
|
115
|
+
collection: collection_name,
|
|
116
|
+
field: field_name,
|
|
117
|
+
error: error.message
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Creates index operation result with message.
|
|
123
|
+
* @param {Object} result - Index creation result
|
|
124
|
+
* @param {string} message - Success message
|
|
125
|
+
* @returns {Object} Enhanced result with message
|
|
126
|
+
*/
|
|
127
|
+
const create_index_operation_result = (result, message) => ({
|
|
128
|
+
...result,
|
|
129
|
+
message
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Creates or updates an index on a specified field in a collection.
|
|
134
|
+
* @param {string} database_name - Name of the database
|
|
135
|
+
* @param {string} collection_name - Name of the collection to create index for
|
|
136
|
+
* @param {string} field_name - Name of the field to index
|
|
137
|
+
* @param {Object} options - Index creation options
|
|
138
|
+
* @returns {Promise<Object>} Index creation result with operation details and message
|
|
139
|
+
*/
|
|
140
|
+
const create_index_operation = async (database_name, collection_name, field_name, options = {}) => {
|
|
141
|
+
const log = create_context_logger();
|
|
142
|
+
|
|
143
|
+
validate_create_index_parameters(database_name, collection_name, field_name);
|
|
36
144
|
|
|
37
145
|
try {
|
|
38
146
|
const result = await create_index(database_name, collection_name, field_name, options);
|
|
39
147
|
|
|
40
148
|
const operation_type = result.operation_type || 'created';
|
|
41
|
-
const action_verb = operation_type
|
|
42
|
-
|
|
43
|
-
'already exists';
|
|
149
|
+
const action_verb = get_action_verb_for_operation(operation_type);
|
|
150
|
+
const success_message = create_success_message(action_verb, database_name, collection_name, field_name);
|
|
44
151
|
|
|
45
|
-
log
|
|
46
|
-
database: database_name,
|
|
47
|
-
collection: collection_name,
|
|
48
|
-
field: field_name,
|
|
49
|
-
options,
|
|
50
|
-
operation_type
|
|
51
|
-
});
|
|
152
|
+
log_successful_index_operation(log, action_verb, database_name, collection_name, field_name, options, operation_type);
|
|
52
153
|
|
|
53
|
-
return
|
|
54
|
-
...result,
|
|
55
|
-
message: `Index ${action_verb} on ${database_name}.${collection_name}.${field_name}`
|
|
56
|
-
};
|
|
154
|
+
return create_index_operation_result(result, success_message);
|
|
57
155
|
} catch (error) {
|
|
58
|
-
log
|
|
59
|
-
database: database_name,
|
|
60
|
-
collection: collection_name,
|
|
61
|
-
field: field_name,
|
|
62
|
-
error: error.message
|
|
63
|
-
});
|
|
156
|
+
log_failed_index_operation(log, database_name, collection_name, field_name, error);
|
|
64
157
|
throw error;
|
|
65
158
|
}
|
|
66
159
|
};
|
|
@@ -5,6 +5,75 @@ import create_logger from '../logger.js';
|
|
|
5
5
|
|
|
6
6
|
const { create_context_logger } = create_logger('delete_many');
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Validates database name parameter.
|
|
10
|
+
* @param {string} database_name - Database name to validate
|
|
11
|
+
* @throws {Error} When database name is missing
|
|
12
|
+
*/
|
|
13
|
+
const validate_database_name = (database_name) => {
|
|
14
|
+
if (!database_name) {
|
|
15
|
+
throw new Error('Database name is required');
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Validates collection name parameter.
|
|
21
|
+
* @param {string} collection_name - Collection name to validate
|
|
22
|
+
* @throws {Error} When collection name is missing
|
|
23
|
+
*/
|
|
24
|
+
const validate_collection_name = (collection_name) => {
|
|
25
|
+
if (!collection_name) {
|
|
26
|
+
throw new Error('Collection name is required');
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Validates filter parameter.
|
|
32
|
+
* @param {Object} filter - Filter to validate
|
|
33
|
+
* @throws {Error} When filter is invalid
|
|
34
|
+
*/
|
|
35
|
+
const validate_filter = (filter) => {
|
|
36
|
+
if (!filter || typeof filter !== 'object') {
|
|
37
|
+
throw new Error('Filter must be a valid object');
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Validates limit option.
|
|
43
|
+
* @param {number} limit - Limit to validate
|
|
44
|
+
* @throws {Error} When limit is invalid
|
|
45
|
+
*/
|
|
46
|
+
const validate_limit = (limit) => {
|
|
47
|
+
if (limit !== undefined && (typeof limit !== 'number' || limit < 0)) {
|
|
48
|
+
throw new Error('Limit must be a non-negative number');
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Validates all delete many operation parameters.
|
|
54
|
+
* @param {string} database_name - Database name
|
|
55
|
+
* @param {string} collection_name - Collection name
|
|
56
|
+
* @param {Object} filter - Filter criteria
|
|
57
|
+
* @param {Object} options - Delete options
|
|
58
|
+
*/
|
|
59
|
+
const validate_delete_many_parameters = (database_name, collection_name, filter, options) => {
|
|
60
|
+
validate_database_name(database_name);
|
|
61
|
+
validate_collection_name(collection_name);
|
|
62
|
+
validate_filter(filter);
|
|
63
|
+
validate_limit(options.limit);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Checks if document field matches filter value.
|
|
68
|
+
* @param {Object} document - Document to check
|
|
69
|
+
* @param {string} field - Field name
|
|
70
|
+
* @param {any} value - Expected value
|
|
71
|
+
* @returns {boolean} True if field matches value
|
|
72
|
+
*/
|
|
73
|
+
const field_matches_value = (document, field, value) => {
|
|
74
|
+
return document[field] === value;
|
|
75
|
+
};
|
|
76
|
+
|
|
8
77
|
/**
|
|
9
78
|
* Checks if a document matches the given filter criteria (simple equality check).
|
|
10
79
|
* @param {Object} document - Document to test
|
|
@@ -17,7 +86,7 @@ const matches_filter = (document, filter) => {
|
|
|
17
86
|
}
|
|
18
87
|
|
|
19
88
|
for (const [field, value] of Object.entries(filter)) {
|
|
20
|
-
if (document
|
|
89
|
+
if (!field_matches_value(document, field, value)) {
|
|
21
90
|
return false;
|
|
22
91
|
}
|
|
23
92
|
}
|
|
@@ -26,81 +95,155 @@ const matches_filter = (document, filter) => {
|
|
|
26
95
|
};
|
|
27
96
|
|
|
28
97
|
/**
|
|
29
|
-
*
|
|
30
|
-
* @param {string}
|
|
31
|
-
* @
|
|
32
|
-
* @param {Object} filter - Filter criteria to match documents for deletion
|
|
33
|
-
* @param {Object} [options={}] - Delete options
|
|
34
|
-
* @param {number} [options.limit] - Maximum number of documents to delete
|
|
35
|
-
* @returns {Promise<Object>} Delete result with acknowledged and deleted_count
|
|
36
|
-
* @throws {Error} When database name, collection name is missing or filter is invalid
|
|
98
|
+
* Attempts to parse document from JSON string.
|
|
99
|
+
* @param {string} value - JSON string
|
|
100
|
+
* @returns {Object|null} Parsed document or null
|
|
37
101
|
*/
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (!collection_name) {
|
|
46
|
-
throw new Error('Collection name is required');
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (!filter || typeof filter !== 'object') {
|
|
50
|
-
throw new Error('Filter must be a valid object');
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const { limit } = options;
|
|
54
|
-
|
|
55
|
-
if (limit !== undefined && (typeof limit !== 'number' || limit < 0)) {
|
|
56
|
-
throw new Error('Limit must be a non-negative number');
|
|
102
|
+
const parse_document_safely = (value) => {
|
|
103
|
+
try {
|
|
104
|
+
return JSON.parse(value);
|
|
105
|
+
} catch (parse_error) {
|
|
106
|
+
return null;
|
|
57
107
|
}
|
|
58
|
-
|
|
59
|
-
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Checks if deletion limit has been reached.
|
|
112
|
+
* @param {number} deleted_count - Current deleted count
|
|
113
|
+
* @param {number} limit - Maximum deletion limit
|
|
114
|
+
* @returns {boolean} True if limit reached
|
|
115
|
+
*/
|
|
116
|
+
const has_reached_deletion_limit = (deleted_count, limit) => {
|
|
117
|
+
return limit !== undefined && deleted_count >= limit;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Searches for and deletes matching documents within transaction.
|
|
122
|
+
* @param {Object} db - Database instance
|
|
123
|
+
* @param {string} database_name - Database name
|
|
124
|
+
* @param {string} collection_name - Collection name
|
|
125
|
+
* @param {Object} filter - Filter criteria
|
|
126
|
+
* @param {number} limit - Maximum number of documents to delete
|
|
127
|
+
* @returns {Object} Delete result with count and deleted documents
|
|
128
|
+
*/
|
|
129
|
+
const find_and_delete_documents = (db, database_name, collection_name, filter, limit) => {
|
|
60
130
|
let deleted_count = 0;
|
|
61
131
|
const deleted_documents = [];
|
|
62
132
|
|
|
63
|
-
|
|
64
|
-
|
|
133
|
+
const collection_prefix = `${database_name}:${collection_name}:`;
|
|
134
|
+
const range = db.getRange({ start: collection_prefix, end: collection_prefix + '\xFF' });
|
|
135
|
+
|
|
136
|
+
for (const { key, value } of range) {
|
|
137
|
+
if (has_reached_deletion_limit(deleted_count, limit)) {
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
65
140
|
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (limit !== undefined && deleted_count >= limit) {
|
|
70
|
-
break;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
try {
|
|
74
|
-
const document = JSON.parse(value);
|
|
75
|
-
if (matches_filter(document, filter)) {
|
|
76
|
-
db.remove(key);
|
|
77
|
-
deleted_documents.push(document);
|
|
78
|
-
deleted_count++;
|
|
79
|
-
}
|
|
80
|
-
} catch (parse_error) {
|
|
81
|
-
// Skip documents that can't be parsed
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
141
|
+
const document = parse_document_safely(value);
|
|
142
|
+
if (!document) {
|
|
143
|
+
continue;
|
|
84
144
|
}
|
|
85
|
-
|
|
145
|
+
|
|
146
|
+
if (matches_filter(document, filter)) {
|
|
147
|
+
db.remove(key);
|
|
148
|
+
deleted_documents.push(document);
|
|
149
|
+
deleted_count++;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
86
152
|
|
|
87
|
-
|
|
153
|
+
return { deleted_count, deleted_documents };
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Updates indexes after document deletions.
|
|
158
|
+
* @param {string} database_name - Database name
|
|
159
|
+
* @param {string} collection_name - Collection name
|
|
160
|
+
* @param {Array<Object>} deleted_documents - Array of deleted documents
|
|
161
|
+
*/
|
|
162
|
+
const update_indexes_after_deletions = async (database_name, collection_name, deleted_documents) => {
|
|
88
163
|
for (const deleted_document of deleted_documents) {
|
|
89
164
|
await update_indexes_on_delete(database_name, collection_name, deleted_document);
|
|
90
165
|
}
|
|
91
|
-
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Logs delete many operation completion.
|
|
170
|
+
* @param {Function} log - Logger function
|
|
171
|
+
* @param {string} database_name - Database name
|
|
172
|
+
* @param {string} collection_name - Collection name
|
|
173
|
+
* @param {number} deleted_count - Number of deleted documents
|
|
174
|
+
* @param {number} limit - Deletion limit
|
|
175
|
+
*/
|
|
176
|
+
const log_delete_many_completion = (log, database_name, collection_name, deleted_count, limit) => {
|
|
92
177
|
log.info('Delete many operation completed', {
|
|
93
178
|
database: database_name,
|
|
94
179
|
collection: collection_name,
|
|
95
180
|
deleted_count,
|
|
96
181
|
limit: limit || 'none'
|
|
97
182
|
});
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Creates current timestamp string.
|
|
187
|
+
* @returns {string} ISO timestamp string
|
|
188
|
+
*/
|
|
189
|
+
const create_current_timestamp = () => {
|
|
190
|
+
return new Date().toISOString();
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Creates delete many operation result.
|
|
195
|
+
* @param {number} deleted_count - Number of deleted documents
|
|
196
|
+
* @returns {Object} Delete result object
|
|
197
|
+
*/
|
|
198
|
+
const create_delete_many_result = (deleted_count) => ({
|
|
199
|
+
acknowledged: true,
|
|
200
|
+
deleted_count,
|
|
201
|
+
operation_time: create_current_timestamp()
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Creates write queue operation metadata.
|
|
206
|
+
* @param {string} database_name - Database name
|
|
207
|
+
* @param {string} collection_name - Collection name
|
|
208
|
+
* @param {Object} filter - Filter criteria
|
|
209
|
+
* @param {number} limit - Deletion limit
|
|
210
|
+
* @returns {Object} Operation metadata
|
|
211
|
+
*/
|
|
212
|
+
const create_write_queue_metadata = (database_name, collection_name, filter, limit) => ({
|
|
213
|
+
operation: 'delete_many',
|
|
214
|
+
database: database_name,
|
|
215
|
+
collection: collection_name,
|
|
216
|
+
filter_keys: Object.keys(filter || {}),
|
|
217
|
+
limit
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Internal implementation of delete_many operation without write queue serialization.
|
|
222
|
+
* @param {string} database_name - Name of the database
|
|
223
|
+
* @param {string} collection_name - Name of the collection
|
|
224
|
+
* @param {Object} filter - Filter criteria to match documents for deletion
|
|
225
|
+
* @param {Object} options - Delete options
|
|
226
|
+
* @returns {Promise<Object>} Delete result with acknowledged and deleted_count
|
|
227
|
+
*/
|
|
228
|
+
const delete_many_internal = async (database_name, collection_name, filter, options = {}) => {
|
|
229
|
+
const log = create_context_logger();
|
|
230
|
+
|
|
231
|
+
validate_delete_many_parameters(database_name, collection_name, filter, options);
|
|
232
|
+
|
|
233
|
+
const { limit } = options;
|
|
234
|
+
const db = get_database();
|
|
235
|
+
|
|
236
|
+
const delete_result = await db.transaction(() => {
|
|
237
|
+
return find_and_delete_documents(db, database_name, collection_name, filter, limit);
|
|
238
|
+
});
|
|
98
239
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
240
|
+
const { deleted_count, deleted_documents } = delete_result;
|
|
241
|
+
|
|
242
|
+
await update_indexes_after_deletions(database_name, collection_name, deleted_documents);
|
|
243
|
+
|
|
244
|
+
log_delete_many_completion(log, database_name, collection_name, deleted_count, limit);
|
|
245
|
+
|
|
246
|
+
return create_delete_many_result(deleted_count);
|
|
104
247
|
};
|
|
105
248
|
|
|
106
249
|
/**
|
|
@@ -108,22 +251,16 @@ const delete_many_internal = async (database_name, collection_name, filter, opti
|
|
|
108
251
|
* @param {string} database_name - Name of the database
|
|
109
252
|
* @param {string} collection_name - Name of the collection
|
|
110
253
|
* @param {Object} filter - Filter criteria to match documents for deletion
|
|
111
|
-
* @param {Object}
|
|
112
|
-
* @param {number} [options.limit] - Maximum number of documents to delete
|
|
254
|
+
* @param {Object} options - Delete options
|
|
113
255
|
* @returns {Promise<Object>} Delete result with acknowledged, deleted_count, and operation_time
|
|
114
256
|
*/
|
|
115
257
|
const delete_many = async (database_name, collection_name, filter, options = {}) => {
|
|
116
258
|
const write_queue = get_write_queue();
|
|
259
|
+
const operation_metadata = create_write_queue_metadata(database_name, collection_name, filter, options.limit);
|
|
117
260
|
|
|
118
261
|
return await write_queue.enqueue_write_operation(
|
|
119
262
|
() => delete_many_internal(database_name, collection_name, filter, options),
|
|
120
|
-
|
|
121
|
-
operation: 'delete_many',
|
|
122
|
-
database: database_name,
|
|
123
|
-
collection: collection_name,
|
|
124
|
-
filter_keys: Object.keys(filter || {}),
|
|
125
|
-
limit: options.limit
|
|
126
|
-
}
|
|
263
|
+
operation_metadata
|
|
127
264
|
);
|
|
128
265
|
};
|
|
129
266
|
|