@joystick.js/db-canary 0.0.0-canary.2250 → 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.
Files changed (49) hide show
  1. package/dist/client/database.js +1 -1
  2. package/dist/client/index.js +1 -1
  3. package/dist/server/cluster/master.js +4 -4
  4. package/dist/server/cluster/worker.js +1 -1
  5. package/dist/server/index.js +1 -1
  6. package/dist/server/lib/auto_index_manager.js +1 -1
  7. package/dist/server/lib/backup_manager.js +1 -1
  8. package/dist/server/lib/index_manager.js +1 -1
  9. package/dist/server/lib/operation_dispatcher.js +1 -1
  10. package/dist/server/lib/operations/admin.js +1 -1
  11. package/dist/server/lib/operations/bulk_write.js +1 -1
  12. package/dist/server/lib/operations/create_index.js +1 -1
  13. package/dist/server/lib/operations/delete_many.js +1 -1
  14. package/dist/server/lib/operations/delete_one.js +1 -1
  15. package/dist/server/lib/operations/find.js +1 -1
  16. package/dist/server/lib/operations/find_one.js +1 -1
  17. package/dist/server/lib/operations/insert_one.js +1 -1
  18. package/dist/server/lib/operations/update_one.js +1 -1
  19. package/dist/server/lib/send_response.js +1 -1
  20. package/dist/server/lib/tcp_protocol.js +1 -1
  21. package/package.json +2 -2
  22. package/src/client/database.js +92 -119
  23. package/src/client/index.js +279 -345
  24. package/src/server/cluster/master.js +265 -156
  25. package/src/server/cluster/worker.js +26 -18
  26. package/src/server/index.js +553 -330
  27. package/src/server/lib/auto_index_manager.js +85 -23
  28. package/src/server/lib/backup_manager.js +117 -70
  29. package/src/server/lib/index_manager.js +63 -25
  30. package/src/server/lib/operation_dispatcher.js +339 -168
  31. package/src/server/lib/operations/admin.js +343 -205
  32. package/src/server/lib/operations/bulk_write.js +458 -194
  33. package/src/server/lib/operations/create_index.js +127 -34
  34. package/src/server/lib/operations/delete_many.js +204 -67
  35. package/src/server/lib/operations/delete_one.js +164 -52
  36. package/src/server/lib/operations/find.js +563 -201
  37. package/src/server/lib/operations/find_one.js +544 -188
  38. package/src/server/lib/operations/insert_one.js +147 -52
  39. package/src/server/lib/operations/update_one.js +334 -93
  40. package/src/server/lib/send_response.js +37 -17
  41. package/src/server/lib/tcp_protocol.js +158 -53
  42. package/tests/server/cluster/master_read_write_operations.test.js +5 -14
  43. package/tests/server/integration/authentication_integration.test.js +18 -10
  44. package/tests/server/integration/backup_integration.test.js +35 -27
  45. package/tests/server/lib/api_key_manager.test.js +88 -32
  46. package/tests/server/lib/development_mode.test.js +2 -2
  47. package/tests/server/lib/operations/admin.test.js +20 -12
  48. package/tests/server/lib/operations/delete_one.test.js +10 -4
  49. package/tests/server/lib/operations/find_array_queries.test.js +261 -0
@@ -5,6 +5,62 @@ import create_logger from '../logger.js';
5
5
 
6
6
  const { create_context_logger } = create_logger('delete_one');
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 all delete operation parameters.
43
+ * @param {string} database_name - Database name
44
+ * @param {string} collection_name - Collection name
45
+ * @param {Object} filter - Filter criteria
46
+ */
47
+ const validate_delete_parameters = (database_name, collection_name, filter) => {
48
+ validate_database_name(database_name);
49
+ validate_collection_name(collection_name);
50
+ validate_filter(filter);
51
+ };
52
+
53
+ /**
54
+ * Checks if document field matches filter value.
55
+ * @param {Object} document - Document to check
56
+ * @param {string} field - Field name
57
+ * @param {any} value - Expected value
58
+ * @returns {boolean} True if field matches value
59
+ */
60
+ const field_matches_value = (document, field, value) => {
61
+ return document[field] === value;
62
+ };
63
+
8
64
  /**
9
65
  * Checks if a document matches the given filter criteria (simple equality check).
10
66
  * @param {Object} document - Document to test
@@ -17,7 +73,7 @@ const matches_filter = (document, filter) => {
17
73
  }
18
74
 
19
75
  for (const [field, value] of Object.entries(filter)) {
20
- if (document[field] !== value) {
76
+ if (!field_matches_value(document, field, value)) {
21
77
  return false;
22
78
  }
23
79
  }
@@ -26,67 +82,127 @@ const matches_filter = (document, filter) => {
26
82
  };
27
83
 
28
84
  /**
29
- * Internal implementation of delete_one operation without write queue serialization.
30
- * @param {string} database_name - Name of the database
31
- * @param {string} collection_name - Name of the collection
32
- * @param {Object} filter - Filter criteria to match document for deletion
33
- * @param {Object} [options={}] - Delete options (currently unused)
34
- * @returns {Promise<Object>} Delete result with acknowledged and deleted_count
35
- * @throws {Error} When database name, collection name is missing or filter is invalid
85
+ * Attempts to parse document from JSON string.
86
+ * @param {string} value - JSON string
87
+ * @returns {Object|null} Parsed document or null
36
88
  */
37
- const delete_one_internal = async (database_name, collection_name, filter, options = {}) => {
38
- const log = create_context_logger();
39
-
40
- if (!database_name) {
41
- throw new Error('Database name is required');
42
- }
43
-
44
- if (!collection_name) {
45
- throw new Error('Collection name is required');
46
- }
47
-
48
- if (!filter || typeof filter !== 'object') {
49
- throw new Error('Filter must be a valid object');
89
+ const parse_document_safely = (value) => {
90
+ try {
91
+ return JSON.parse(value);
92
+ } catch (parse_error) {
93
+ return null;
50
94
  }
51
-
52
- const db = get_database();
95
+ };
96
+
97
+ /**
98
+ * Searches for and deletes matching document within transaction.
99
+ * @param {Object} db - Database instance
100
+ * @param {string} database_name - Database name
101
+ * @param {string} collection_name - Collection name
102
+ * @param {Object} filter - Filter criteria
103
+ * @returns {Object} Delete result with count and deleted document
104
+ */
105
+ const find_and_delete_document = (db, database_name, collection_name, filter) => {
53
106
  let deleted_count = 0;
54
107
  let deleted_document = null;
55
108
 
56
- await db.transaction(() => {
57
- const collection_prefix = `${database_name}:${collection_name}:`;
109
+ const collection_prefix = `${database_name}:${collection_name}:`;
110
+ const range = db.getRange({ start: collection_prefix, end: collection_prefix + '\xFF' });
111
+
112
+ for (const { key, value } of range) {
113
+ const document = parse_document_safely(value);
114
+ if (!document) {
115
+ continue;
116
+ }
58
117
 
59
- const range = db.getRange({ start: collection_prefix, end: collection_prefix + '\xFF' });
60
- for (const { key, value } of range) {
61
- try {
62
- const document = JSON.parse(value);
63
- if (matches_filter(document, filter)) {
64
- db.remove(key);
65
- deleted_document = document;
66
- deleted_count = 1;
67
- break;
68
- }
69
- } catch (parse_error) {
70
- // Skip documents that can't be parsed
71
- continue;
72
- }
118
+ if (matches_filter(document, filter)) {
119
+ db.remove(key);
120
+ deleted_document = document;
121
+ deleted_count = 1;
122
+ break;
73
123
  }
74
- });
124
+ }
75
125
 
126
+ return { deleted_count, deleted_document };
127
+ };
128
+
129
+ /**
130
+ * Updates indexes after document deletion.
131
+ * @param {string} database_name - Database name
132
+ * @param {string} collection_name - Collection name
133
+ * @param {Object} deleted_document - Deleted document
134
+ */
135
+ const update_indexes_after_deletion = async (database_name, collection_name, deleted_document) => {
76
136
  if (deleted_document) {
77
137
  await update_indexes_on_delete(database_name, collection_name, deleted_document);
78
138
  }
79
-
139
+ };
140
+
141
+ /**
142
+ * Logs delete operation completion.
143
+ * @param {Function} log - Logger function
144
+ * @param {string} database_name - Database name
145
+ * @param {string} collection_name - Collection name
146
+ * @param {number} deleted_count - Number of deleted documents
147
+ */
148
+ const log_delete_completion = (log, database_name, collection_name, deleted_count) => {
80
149
  log.info('Delete operation completed', {
81
150
  database: database_name,
82
151
  collection: collection_name,
83
152
  deleted_count
84
153
  });
154
+ };
155
+
156
+ /**
157
+ * Creates delete operation result.
158
+ * @param {number} deleted_count - Number of deleted documents
159
+ * @returns {Object} Delete result object
160
+ */
161
+ const create_delete_result = (deleted_count) => ({
162
+ acknowledged: true,
163
+ deleted_count
164
+ });
165
+
166
+ /**
167
+ * Creates write queue operation metadata.
168
+ * @param {string} database_name - Database name
169
+ * @param {string} collection_name - Collection name
170
+ * @param {Object} filter - Filter criteria
171
+ * @returns {Object} Operation metadata
172
+ */
173
+ const create_write_queue_metadata = (database_name, collection_name, filter) => ({
174
+ operation: 'delete_one',
175
+ database: database_name,
176
+ collection: collection_name,
177
+ filter_keys: Object.keys(filter || {})
178
+ });
179
+
180
+ /**
181
+ * Internal implementation of delete_one operation without write queue serialization.
182
+ * @param {string} database_name - Name of the database
183
+ * @param {string} collection_name - Name of the collection
184
+ * @param {Object} filter - Filter criteria to match document for deletion
185
+ * @param {Object} options - Delete options (currently unused)
186
+ * @returns {Promise<Object>} Delete result with acknowledged and deleted_count
187
+ */
188
+ const delete_one_internal = async (database_name, collection_name, filter, options = {}) => {
189
+ const log = create_context_logger();
190
+
191
+ validate_delete_parameters(database_name, collection_name, filter);
192
+
193
+ const db = get_database();
194
+
195
+ const delete_result = await db.transaction(() => {
196
+ return find_and_delete_document(db, database_name, collection_name, filter);
197
+ });
85
198
 
86
- return {
87
- acknowledged: true,
88
- deleted_count
89
- };
199
+ const { deleted_count, deleted_document } = delete_result;
200
+
201
+ await update_indexes_after_deletion(database_name, collection_name, deleted_document);
202
+
203
+ log_delete_completion(log, database_name, collection_name, deleted_count);
204
+
205
+ return create_delete_result(deleted_count);
90
206
  };
91
207
 
92
208
  /**
@@ -94,20 +210,16 @@ const delete_one_internal = async (database_name, collection_name, filter, optio
94
210
  * @param {string} database_name - Name of the database
95
211
  * @param {string} collection_name - Name of the collection
96
212
  * @param {Object} filter - Filter criteria to match document for deletion
97
- * @param {Object} [options={}] - Delete options
213
+ * @param {Object} options - Delete options
98
214
  * @returns {Promise<Object>} Delete result with acknowledged and deleted_count
99
215
  */
100
216
  const delete_one = async (database_name, collection_name, filter, options = {}) => {
101
217
  const write_queue = get_write_queue();
218
+ const operation_metadata = create_write_queue_metadata(database_name, collection_name, filter);
102
219
 
103
220
  return await write_queue.enqueue_write_operation(
104
221
  () => delete_one_internal(database_name, collection_name, filter, options),
105
- {
106
- operation: 'delete_one',
107
- database: database_name,
108
- collection: collection_name,
109
- filter_keys: Object.keys(filter || {})
110
- }
222
+ operation_metadata
111
223
  );
112
224
  };
113
225