@joystick.js/db-canary 0.0.0-canary.2209
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/.build/getFilesToBuild.js +26 -0
- package/.build/getPlatformSafeFilePath.js +6 -0
- package/.build/getPlatformSafePath.js +6 -0
- package/.build/index.js +88 -0
- package/.build/isWindows.js +3 -0
- package/API_KEY +1 -0
- package/README.md +1821 -0
- package/data/data.mdb +0 -0
- package/data/lock.mdb +0 -0
- package/dist/client/database.js +1 -0
- package/dist/client/index.js +1 -0
- package/dist/server/cluster/index.js +1 -0
- package/dist/server/cluster/master.js +20 -0
- package/dist/server/cluster/worker.js +1 -0
- package/dist/server/index.js +1 -0
- package/dist/server/lib/api_key_manager.js +9 -0
- package/dist/server/lib/auth_manager.js +1 -0
- package/dist/server/lib/auto_index_manager.js +1 -0
- package/dist/server/lib/backup_manager.js +1 -0
- package/dist/server/lib/connection_manager.js +1 -0
- package/dist/server/lib/disk_utils.js +2 -0
- package/dist/server/lib/http_server.js +405 -0
- package/dist/server/lib/index_manager.js +1 -0
- package/dist/server/lib/load_settings.js +1 -0
- package/dist/server/lib/logger.js +1 -0
- package/dist/server/lib/op_types.js +1 -0
- package/dist/server/lib/operation_dispatcher.js +1 -0
- package/dist/server/lib/operations/admin.js +1 -0
- package/dist/server/lib/operations/bulk_write.js +1 -0
- package/dist/server/lib/operations/create_index.js +1 -0
- package/dist/server/lib/operations/delete_one.js +1 -0
- package/dist/server/lib/operations/drop_index.js +1 -0
- package/dist/server/lib/operations/find.js +1 -0
- package/dist/server/lib/operations/find_one.js +1 -0
- package/dist/server/lib/operations/get_indexes.js +1 -0
- package/dist/server/lib/operations/insert_one.js +1 -0
- package/dist/server/lib/operations/update_one.js +1 -0
- package/dist/server/lib/performance_monitor.js +1 -0
- package/dist/server/lib/query_engine.js +1 -0
- package/dist/server/lib/recovery_manager.js +1 -0
- package/dist/server/lib/replication_manager.js +1 -0
- package/dist/server/lib/safe_json_parse.js +1 -0
- package/dist/server/lib/send_response.js +1 -0
- package/dist/server/lib/tcp_protocol.js +1 -0
- package/dist/server/lib/write_forwarder.js +1 -0
- package/dist/server/lib/write_queue.js +1 -0
- package/increment_version.js +3 -0
- package/logs/.013e15b54597d05db4b4b53ecc37b10c92a72927-audit.json +20 -0
- package/logs/.02de550a67ea0f5961faa2dfd458a4d06f59ebd1-audit.json +20 -0
- package/logs/.03494ba24eb3c72214b4068a77d54b8993bee651-audit.json +20 -0
- package/logs/.06309ec60b339be1259a7993dd09c732f8907fbc-audit.json +20 -0
- package/logs/.0663a04dcfa17285661e5e1b8cfa51f41523b210-audit.json +20 -0
- package/logs/.0f06e6c4c9b824622729e13927587479e5060391-audit.json +20 -0
- package/logs/.16ccf58682ecb22b3e3ec63f0da1b7fe9be56528-audit.json +20 -0
- package/logs/.1fa1a5d02f496474b1ab473524c65c984146a9ad-audit.json +20 -0
- package/logs/.2223c0ae3bea6f0d62c62b1d319cc8634856abb7-audit.json +20 -0
- package/logs/.23dc79ffda3e083665e6f5993f59397adcbf4a46-audit.json +20 -0
- package/logs/.28104f49b03906b189eefd1cd462cb46c3c0af22-audit.json +20 -0
- package/logs/.29cdbf13808abe6a0ce70ee2f2efdd680ce3fd8e-audit.json +20 -0
- package/logs/.2a9889afd071f77f41f5170d08703a0afca866b7-audit.json +20 -0
- package/logs/.2acec3d1940a2bbed487528b703ee5948959a599-audit.json +20 -0
- package/logs/.2fb60ff326338c02bfedbcd0e936444e4a216750-audit.json +20 -0
- package/logs/.318fc7a19530d76a345f030f7cad00dda15300e7-audit.json +20 -0
- package/logs/.3cf27043e19085f908cedc7701e6d013463208ee-audit.json +25 -0
- package/logs/.3d90d785415817fc443402843b7c95f8371adc9b-audit.json +20 -0
- package/logs/.4074bca620375f72966fc52dfd439577727671e5-audit.json +20 -0
- package/logs/.40eecf018417ea80a70ea8ec7a3cc9406bc6334b-audit.json +20 -0
- package/logs/.50e974f1ef7c365fca6a1251b2e2c2252914cb5e-audit.json +20 -0
- package/logs/.52cb7d9e4223cf26ba36006ac26b949a97c7923c-audit.json +20 -0
- package/logs/.54befcdb84c15aad980705a31bcc9f555c3577ab-audit.json +20 -0
- package/logs/.57dfb70e22eddb84db2e3c0ceeefac5c0b9baffa-audit.json +20 -0
- package/logs/.5f0b24705a1eaad4eca4968f2d86f91b3f9be683-audit.json +20 -0
- package/logs/.61ba98fdda7db58576b382fee07904e5db1169d6-audit.json +20 -0
- package/logs/.6235017727ef6b199d569a99d6aa8c8e80a1b475-audit.json +20 -0
- package/logs/.63db16193699219489d218a1ddea5dde3750cae4-audit.json +20 -0
- package/logs/.64fb67dfe14149c9eef728d79bf30a54da809c60-audit.json +20 -0
- package/logs/.669137453368987c1f311b5345342527afb54e50-audit.json +20 -0
- package/logs/.7a71f8c89ea28ae266d356aeff6306e876a30fbb-audit.json +20 -0
- package/logs/.7afbaa90fe9dc3a7d682676f9bb79f9a1b1fd9a6-audit.json +20 -0
- package/logs/.7ca29e322cd05327035de850099e7610864f2347-audit.json +20 -0
- package/logs/.83335ab3347e449dae03455a110aaf7f120d4802-audit.json +20 -0
- package/logs/.8c2487b5fd445d2c8e5c483c80b9fa99bbf1ca58-audit.json +20 -0
- package/logs/.8c8b9dc386922c9f3b4c13251af7052aac1d24c0-audit.json +20 -0
- package/logs/.8d6155d94640c4863301ae0fee5e4e7372a21446-audit.json +20 -0
- package/logs/.944a3119a243deea7c8270d5d9e582bb1d0eaa10-audit.json +20 -0
- package/logs/.9816a845c30fb2909f3b26a23eeb3538ebcad5db-audit.json +20 -0
- package/logs/.9dc08784e38b865488177c26d4af5934555e0323-audit.json +20 -0
- package/logs/.9dd27d2e0e454ac0a37600206d1cac5493b0d7ee-audit.json +20 -0
- package/logs/.a3d486feeac7654c59b547de96600e8849a06d4f-audit.json +20 -0
- package/logs/.a5b811f4def22250f86cc18870d7c4573625df22-audit.json +20 -0
- package/logs/.a61648eb5f830e0b6f508ac35e4f8f629d2ad4c7-audit.json +20 -0
- package/logs/.a89016d507045771b4b5a65656944a9c0f1e528b-audit.json +20 -0
- package/logs/.a99bee160a1c590be959af46bacc02724803f691-audit.json +20 -0
- package/logs/.ada7906d6243fd7da802f03d86c4ae5dd9df6236-audit.json +20 -0
- package/logs/.b518339ee942143b6af983af167f5bbb6983b4de-audit.json +20 -0
- package/logs/.b51b124b166d53c9519017856ea610d61d65fabe-audit.json +20 -0
- package/logs/.b7a6aee19f58e55633d5e4a3709041c47dfff975-audit.json +20 -0
- package/logs/.bd7a8a6ba9c55d557a4867ab53f02e3ec2e1553d-audit.json +20 -0
- package/logs/.c1435dafe453b169d6392b25065f3cf4ab6fbb21-audit.json +20 -0
- package/logs/.c17e1ce043109f77dc2f0e2aa290a9d1ed842c03-audit.json +20 -0
- package/logs/.ca62637ce9540e5a38a2fbedb2115febb6ad308a-audit.json +15 -0
- package/logs/.ccee67b9c176967f8977071409a41f5cb5cd6ad4-audit.json +20 -0
- package/logs/.db24043417ea79a6f14cd947476399e53930b48d-audit.json +20 -0
- package/logs/.e0f12acccb57829f5f33712bb2e2607ecd808147-audit.json +20 -0
- package/logs/.e9b6cc33d0bbd2e644c4e2bf44d177f850016557-audit.json +20 -0
- package/logs/.f15291d434808e3bdca7963ccd2e73893be027e6-audit.json +20 -0
- package/logs/.f4bdf9e21ef84f8a3fae3ffb32bbc39275991351-audit.json +15 -0
- package/logs/.fbac3aefac1e81b4230df5aa50667cb90d51024f-audit.json +20 -0
- package/logs/.fcfd495c0a9169db243f4a4f21878ee02b76413c-audit.json +20 -0
- package/logs/admin-2025-09-12.log +580 -0
- package/logs/admin-2025-09-15.log +283 -0
- package/logs/admin-error-2025-09-12.log +22 -0
- package/logs/admin-error-2025-09-15.log +10 -0
- package/logs/api_key_manager-2025-09-12.log +658 -0
- package/logs/api_key_manager-2025-09-15.log +295 -0
- package/logs/api_key_manager-error-2025-09-12.log +0 -0
- package/logs/api_key_manager-error-2025-09-15.log +0 -0
- package/logs/auth_manager-2025-09-12.log +4432 -0
- package/logs/auth_manager-2025-09-15.log +2000 -0
- package/logs/auth_manager-error-2025-09-12.log +11 -0
- package/logs/auth_manager-error-2025-09-15.log +5 -0
- package/logs/auto_index_manager-2025-09-12.log +84 -0
- package/logs/auto_index_manager-2025-09-15.log +45 -0
- package/logs/auto_index_manager-error-2025-09-12.log +6 -0
- package/logs/auto_index_manager-error-2025-09-15.log +0 -0
- package/logs/backup_manager-2025-09-12.log +198 -0
- package/logs/backup_manager-2025-09-15.log +90 -0
- package/logs/backup_manager-error-2025-09-12.log +198 -0
- package/logs/backup_manager-error-2025-09-15.log +90 -0
- package/logs/bulk_write-2025-09-12.log +66 -0
- package/logs/bulk_write-2025-09-15.log +38 -0
- package/logs/bulk_write-error-2025-09-12.log +0 -0
- package/logs/bulk_write-error-2025-09-15.log +0 -0
- package/logs/connection_manager-2025-09-12.log +2412 -0
- package/logs/connection_manager-2025-09-15.log +1132 -0
- package/logs/connection_manager-error-2025-09-12.log +0 -0
- package/logs/connection_manager-error-2025-09-15.log +0 -0
- package/logs/create_index-2025-09-12.log +302 -0
- package/logs/create_index-2025-09-15.log +158 -0
- package/logs/create_index-error-2025-09-12.log +30 -0
- package/logs/create_index-error-2025-09-15.log +13 -0
- package/logs/delete_one-2025-09-12.log +73 -0
- package/logs/delete_one-2025-09-15.log +43 -0
- package/logs/delete_one-error-2025-09-12.log +0 -0
- package/logs/delete_one-error-2025-09-15.log +0 -0
- package/logs/disk_utils-2025-09-12.log +4954 -0
- package/logs/disk_utils-2025-09-15.log +2446 -0
- package/logs/disk_utils-error-2025-09-12.log +0 -0
- package/logs/disk_utils-error-2025-09-15.log +0 -0
- package/logs/drop_index-2025-09-12.log +41 -0
- package/logs/drop_index-2025-09-15.log +23 -0
- package/logs/drop_index-error-2025-09-12.log +11 -0
- package/logs/drop_index-error-2025-09-15.log +5 -0
- package/logs/find-2025-09-12.log +1050 -0
- package/logs/find-2025-09-15.log +592 -0
- package/logs/find-error-2025-09-12.log +1 -0
- package/logs/find-error-2025-09-15.log +0 -0
- package/logs/find_one-2025-09-12.log +425 -0
- package/logs/find_one-2025-09-15.log +264 -0
- package/logs/find_one-error-2025-09-12.log +5 -0
- package/logs/find_one-error-2025-09-15.log +0 -0
- package/logs/get_indexes-2025-09-12.log +84 -0
- package/logs/get_indexes-2025-09-15.log +56 -0
- package/logs/get_indexes-error-2025-09-12.log +6 -0
- package/logs/get_indexes-error-2025-09-15.log +0 -0
- package/logs/http_server-2025-09-12.log +2772 -0
- package/logs/http_server-2025-09-15.log +1276 -0
- package/logs/http_server-error-2025-09-12.log +212 -0
- package/logs/http_server-error-2025-09-15.log +44 -0
- package/logs/index_manager-2025-09-12.log +5031 -0
- package/logs/index_manager-2025-09-15.log +2909 -0
- package/logs/index_manager-error-2025-09-12.log +80 -0
- package/logs/index_manager-error-2025-09-15.log +38 -0
- package/logs/insert_one-2025-09-12.log +2181 -0
- package/logs/insert_one-2025-09-15.log +1293 -0
- package/logs/insert_one-error-2025-09-12.log +0 -0
- package/logs/insert_one-error-2025-09-15.log +0 -0
- package/logs/master-2025-09-12.log +1882 -0
- package/logs/master-2025-09-15.log +910 -0
- package/logs/master-error-2025-09-12.log +80 -0
- package/logs/master-error-2025-09-15.log +0 -0
- package/logs/operation_dispatcher-2025-09-12.log +751 -0
- package/logs/operation_dispatcher-2025-09-15.log +359 -0
- package/logs/operation_dispatcher-error-2025-09-12.log +33 -0
- package/logs/operation_dispatcher-error-2025-09-15.log +11 -0
- package/logs/performance_monitor-2025-09-12.log +14889 -0
- package/logs/performance_monitor-2025-09-15.log +6803 -0
- package/logs/performance_monitor-error-2025-09-12.log +0 -0
- package/logs/performance_monitor-error-2025-09-15.log +0 -0
- package/logs/query_engine-2025-09-12.log +5310 -0
- package/logs/query_engine-2025-09-15.log +2639 -0
- package/logs/query_engine-error-2025-09-12.log +0 -0
- package/logs/query_engine-error-2025-09-15.log +0 -0
- package/logs/recovery_manager-2025-09-12.log +462 -0
- package/logs/recovery_manager-2025-09-15.log +210 -0
- package/logs/recovery_manager-error-2025-09-12.log +22 -0
- package/logs/recovery_manager-error-2025-09-15.log +10 -0
- package/logs/replication-2025-09-12.log +1923 -0
- package/logs/replication-2025-09-15.log +917 -0
- package/logs/replication-error-2025-09-12.log +33 -0
- package/logs/replication-error-2025-09-15.log +15 -0
- package/logs/server-2025-09-12.log +2601 -0
- package/logs/server-2025-09-15.log +1191 -0
- package/logs/server-error-2025-09-12.log +0 -0
- package/logs/server-error-2025-09-15.log +0 -0
- package/logs/tcp_protocol-2025-09-12.log +22 -0
- package/logs/tcp_protocol-2025-09-15.log +10 -0
- package/logs/tcp_protocol-error-2025-09-12.log +22 -0
- package/logs/tcp_protocol-error-2025-09-15.log +10 -0
- package/logs/test-2025-09-12.log +0 -0
- package/logs/test-2025-09-15.log +0 -0
- package/logs/test-error-2025-09-12.log +0 -0
- package/logs/test-error-2025-09-15.log +0 -0
- package/logs/update_one-2025-09-12.log +173 -0
- package/logs/update_one-2025-09-15.log +118 -0
- package/logs/update_one-error-2025-09-12.log +0 -0
- package/logs/update_one-error-2025-09-15.log +0 -0
- package/logs/worker-2025-09-12.log +1457 -0
- package/logs/worker-2025-09-15.log +695 -0
- package/logs/worker-error-2025-09-12.log +0 -0
- package/logs/worker-error-2025-09-15.log +0 -0
- package/logs/write_forwarder-2025-09-12.log +1956 -0
- package/logs/write_forwarder-2025-09-15.log +932 -0
- package/logs/write_forwarder-error-2025-09-12.log +66 -0
- package/logs/write_forwarder-error-2025-09-15.log +30 -0
- package/logs/write_queue-2025-09-12.log +612 -0
- package/logs/write_queue-2025-09-15.log +301 -0
- package/logs/write_queue-error-2025-09-12.log +184 -0
- package/logs/write_queue-error-2025-09-15.log +83 -0
- package/package.json +48 -0
- package/prompts/01-core-infrastructure.md +56 -0
- package/prompts/02-secondary-indexing.md +65 -0
- package/prompts/03-write-serialization.md +63 -0
- package/prompts/04-enhanced-authentication.md +75 -0
- package/prompts/05-comprehensive-admin-operations.md +75 -0
- package/prompts/06-backup-and-restore-system.md +106 -0
- package/prompts/07-production-safety-features.md +107 -0
- package/prompts/08-tcp-client-library.md +121 -0
- package/prompts/09-api-method-chaining.md +134 -0
- package/prompts/10-automatic-index-creation.md +223 -0
- package/prompts/11-operation-naming-consistency.md +268 -0
- package/prompts/12-tcp-replication-system.md +333 -0
- package/prompts/13-master-read-write-operations.md +57 -0
- package/prompts/14-index-upsert-operations.md +68 -0
- package/prompts/15-client-api-return-types.md +81 -0
- package/prompts/16-server-setup-ui.md +97 -0
- package/prompts/17-emergency-password-change.md +108 -0
- package/prompts/18-joystick-framework-integration.md +116 -0
- package/prompts/19-api-key-authentication-system.md +137 -0
- package/prompts/20-configurable-server-port.md +105 -0
- package/prompts/21-multi-database-support.md +161 -0
- package/prompts/FULL_TEXT_SEARCH.md +293 -0
- package/prompts/PROMPTS.md +158 -0
- package/prompts/README.md +221 -0
- package/prompts/TYPESCRIPT_GENERATION.md +179 -0
- package/src/client/database.js +166 -0
- package/src/client/index.js +752 -0
- package/src/server/cluster/index.js +53 -0
- package/src/server/cluster/master.js +774 -0
- package/src/server/cluster/worker.js +537 -0
- package/src/server/index.js +540 -0
- package/src/server/lib/api_key_manager.js +473 -0
- package/src/server/lib/auth_manager.js +375 -0
- package/src/server/lib/auto_index_manager.js +681 -0
- package/src/server/lib/backup_manager.js +650 -0
- package/src/server/lib/connection_manager.js +218 -0
- package/src/server/lib/disk_utils.js +118 -0
- package/src/server/lib/http_server.js +1165 -0
- package/src/server/lib/index_manager.js +756 -0
- package/src/server/lib/load_settings.js +143 -0
- package/src/server/lib/logger.js +135 -0
- package/src/server/lib/op_types.js +29 -0
- package/src/server/lib/operation_dispatcher.js +268 -0
- package/src/server/lib/operations/admin.js +808 -0
- package/src/server/lib/operations/bulk_write.js +367 -0
- package/src/server/lib/operations/create_index.js +68 -0
- package/src/server/lib/operations/delete_one.js +114 -0
- package/src/server/lib/operations/drop_index.js +58 -0
- package/src/server/lib/operations/find.js +340 -0
- package/src/server/lib/operations/find_one.js +319 -0
- package/src/server/lib/operations/get_indexes.js +52 -0
- package/src/server/lib/operations/insert_one.js +113 -0
- package/src/server/lib/operations/update_one.js +225 -0
- package/src/server/lib/performance_monitor.js +313 -0
- package/src/server/lib/query_engine.js +243 -0
- package/src/server/lib/recovery_manager.js +388 -0
- package/src/server/lib/replication_manager.js +727 -0
- package/src/server/lib/safe_json_parse.js +21 -0
- package/src/server/lib/send_response.js +47 -0
- package/src/server/lib/tcp_protocol.js +130 -0
- package/src/server/lib/write_forwarder.js +636 -0
- package/src/server/lib/write_queue.js +335 -0
- package/test_data/data.mdb +0 -0
- package/test_data/lock.mdb +0 -0
- package/tests/client/index.test.js +1232 -0
- package/tests/server/cluster/cluster.test.js +248 -0
- package/tests/server/cluster/master_read_write_operations.test.js +577 -0
- package/tests/server/index.test.js +651 -0
- package/tests/server/integration/authentication_integration.test.js +294 -0
- package/tests/server/integration/auto_indexing_integration.test.js +268 -0
- package/tests/server/integration/backup_integration.test.js +513 -0
- package/tests/server/integration/indexing_integration.test.js +126 -0
- package/tests/server/integration/production_safety_integration.test.js +358 -0
- package/tests/server/integration/replication_integration.test.js +227 -0
- package/tests/server/integration/write_serialization_integration.test.js +246 -0
- package/tests/server/lib/api_key_manager.test.js +516 -0
- package/tests/server/lib/auth_manager.test.js +317 -0
- package/tests/server/lib/auto_index_manager.test.js +275 -0
- package/tests/server/lib/backup_manager.test.js +238 -0
- package/tests/server/lib/connection_manager.test.js +221 -0
- package/tests/server/lib/disk_utils.test.js +63 -0
- package/tests/server/lib/http_server.test.js +389 -0
- package/tests/server/lib/index_manager.test.js +301 -0
- package/tests/server/lib/load_settings.test.js +107 -0
- package/tests/server/lib/load_settings_port_config.test.js +243 -0
- package/tests/server/lib/logger.test.js +282 -0
- package/tests/server/lib/operations/admin.test.js +638 -0
- package/tests/server/lib/operations/bulk_write.test.js +128 -0
- package/tests/server/lib/operations/create_index.test.js +138 -0
- package/tests/server/lib/operations/delete_one.test.js +52 -0
- package/tests/server/lib/operations/drop_index.test.js +72 -0
- package/tests/server/lib/operations/find.test.js +93 -0
- package/tests/server/lib/operations/find_one.test.js +91 -0
- package/tests/server/lib/operations/get_indexes.test.js +87 -0
- package/tests/server/lib/operations/insert_one.test.js +42 -0
- package/tests/server/lib/operations/update_one.test.js +89 -0
- package/tests/server/lib/performance_monitor.test.js +185 -0
- package/tests/server/lib/query_engine.test.js +46 -0
- package/tests/server/lib/recovery_manager.test.js +414 -0
- package/tests/server/lib/replication_manager.test.js +202 -0
- package/tests/server/lib/safe_json_parse.test.js +45 -0
- package/tests/server/lib/send_response.test.js +155 -0
- package/tests/server/lib/tcp_protocol.test.js +169 -0
- package/tests/server/lib/write_forwarder.test.js +258 -0
- package/tests/server/lib/write_queue.test.js +255 -0
- package/tsconfig.json +30 -0
- package/types/client/index.d.ts +447 -0
- package/types/server/cluster/index.d.ts +28 -0
- package/types/server/cluster/master.d.ts +115 -0
- package/types/server/cluster/worker.d.ts +1 -0
- package/types/server/lib/auth_manager.d.ts +13 -0
- package/types/server/lib/backup_manager.d.ts +43 -0
- package/types/server/lib/connection_manager.d.ts +15 -0
- package/types/server/lib/disk_utils.d.ts +3 -0
- package/types/server/lib/index_manager.d.ts +24 -0
- package/types/server/lib/load_settings.d.ts +4 -0
- package/types/server/lib/logger.d.ts +44 -0
- package/types/server/lib/op_types.d.ts +6 -0
- package/types/server/lib/performance_monitor.d.ts +68 -0
- package/types/server/lib/query_engine.d.ts +10 -0
- package/types/server/lib/safe_json_parse.d.ts +7 -0
- package/types/server/lib/send_response.d.ts +3 -0
- package/types/server/lib/tcp_protocol.d.ts +12 -0
- package/types/server/lib/write_queue.d.ts +2 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Bulk write operations for JoystickDB with transaction support.
|
|
3
|
+
* Provides atomic bulk operations including insert, update, and delete operations
|
|
4
|
+
* with comprehensive error handling, index management, and write queue integration.
|
|
5
|
+
* Supports both snake_case and camelCase operation names for backward compatibility.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { get_database, generate_document_id, build_collection_key } from '../query_engine.js';
|
|
9
|
+
import { get_write_queue } from '../write_queue.js';
|
|
10
|
+
import create_logger from '../logger.js';
|
|
11
|
+
|
|
12
|
+
const { create_context_logger } = create_logger('bulk_write');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Applies MongoDB-style update operators to a document.
|
|
16
|
+
* Supports $set, $unset, $inc, $push, and $pull operators for document modification.
|
|
17
|
+
* Creates a new document object without mutating the original.
|
|
18
|
+
* @param {Object} document - Original document to update
|
|
19
|
+
* @param {Object} update_operations - Update operations to apply
|
|
20
|
+
* @returns {Object} Updated document with applied operations
|
|
21
|
+
* @throws {Error} When unsupported update operator is used
|
|
22
|
+
*/
|
|
23
|
+
const apply_update_operators = (document, update_operations) => {
|
|
24
|
+
const updated_document = { ...document };
|
|
25
|
+
|
|
26
|
+
for (const [operator, operations] of Object.entries(update_operations)) {
|
|
27
|
+
switch (operator) {
|
|
28
|
+
case '$set':
|
|
29
|
+
Object.assign(updated_document, operations);
|
|
30
|
+
break;
|
|
31
|
+
|
|
32
|
+
case '$unset':
|
|
33
|
+
for (const field of Object.keys(operations)) {
|
|
34
|
+
delete updated_document[field];
|
|
35
|
+
}
|
|
36
|
+
break;
|
|
37
|
+
|
|
38
|
+
case '$inc':
|
|
39
|
+
for (const [field, value] of Object.entries(operations)) {
|
|
40
|
+
updated_document[field] = (updated_document[field] || 0) + value;
|
|
41
|
+
}
|
|
42
|
+
break;
|
|
43
|
+
|
|
44
|
+
case '$push':
|
|
45
|
+
for (const [field, value] of Object.entries(operations)) {
|
|
46
|
+
if (!Array.isArray(updated_document[field])) {
|
|
47
|
+
updated_document[field] = [];
|
|
48
|
+
}
|
|
49
|
+
updated_document[field].push(value);
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
|
|
53
|
+
case '$pull':
|
|
54
|
+
for (const [field, value] of Object.entries(operations)) {
|
|
55
|
+
if (Array.isArray(updated_document[field])) {
|
|
56
|
+
updated_document[field] = updated_document[field].filter(item => item !== value);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
break;
|
|
60
|
+
|
|
61
|
+
default:
|
|
62
|
+
throw new Error(`Unsupported update operator: ${operator}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return updated_document;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Checks if a document matches the provided filter criteria.
|
|
71
|
+
* Performs exact field matching for all filter properties.
|
|
72
|
+
* Empty or null filters match all documents.
|
|
73
|
+
* @param {Object} document - Document to check against filter
|
|
74
|
+
* @param {Object} filter - Filter criteria for matching
|
|
75
|
+
* @returns {boolean} True if document matches all filter criteria
|
|
76
|
+
*/
|
|
77
|
+
const matches_filter = (document, filter) => {
|
|
78
|
+
if (!filter || Object.keys(filter).length === 0) {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
for (const [field, value] of Object.entries(filter)) {
|
|
83
|
+
if (document[field] !== value) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return true;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Processes a single insert operation within a bulk write transaction.
|
|
93
|
+
* Validates document, generates ID if needed, checks for duplicates, and inserts document.
|
|
94
|
+
* Adds creation and update timestamps automatically.
|
|
95
|
+
* @param {Object} db - LMDB database instance
|
|
96
|
+
* @param {string} database_name - Name of the database
|
|
97
|
+
* @param {string} collection_name - Name of the collection
|
|
98
|
+
* @param {Object} operation - Insert operation data
|
|
99
|
+
* @param {Object} operation.document - Document to insert
|
|
100
|
+
* @returns {Object} Insert result with inserted_id
|
|
101
|
+
* @throws {Error} When document is invalid or already exists
|
|
102
|
+
*/
|
|
103
|
+
const process_insert_one = (db, database_name, collection_name, operation) => {
|
|
104
|
+
const document_data = operation.document;
|
|
105
|
+
|
|
106
|
+
if (!document_data || typeof document_data !== 'object') {
|
|
107
|
+
throw new Error('insertOne operation requires a valid document');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const document_id = document_data._id || generate_document_id();
|
|
111
|
+
const collection_key = build_collection_key(database_name, collection_name, document_id);
|
|
112
|
+
|
|
113
|
+
const existing_document_data = db.get(collection_key);
|
|
114
|
+
if (existing_document_data) {
|
|
115
|
+
throw new Error(`Document with _id ${document_id} already exists`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const document_to_insert = {
|
|
119
|
+
...document_data,
|
|
120
|
+
_id: document_id,
|
|
121
|
+
_created_at: new Date().toISOString(),
|
|
122
|
+
_updated_at: new Date().toISOString()
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
db.put(collection_key, JSON.stringify(document_to_insert));
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
inserted_id: document_id
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Processes a single update operation within a bulk write transaction.
|
|
134
|
+
* Finds matching document, applies update operators, and handles upsert if specified.
|
|
135
|
+
* Updates modification timestamp and tracks match/modification counts.
|
|
136
|
+
* @param {Object} db - LMDB database instance
|
|
137
|
+
* @param {string} database_name - Name of the database
|
|
138
|
+
* @param {string} collection_name - Name of the collection
|
|
139
|
+
* @param {Object} operation - Update operation data
|
|
140
|
+
* @param {Object} operation.filter - Filter to find document to update
|
|
141
|
+
* @param {Object} operation.update - Update operations to apply
|
|
142
|
+
* @param {boolean} [operation.upsert=false] - Whether to insert if no match found
|
|
143
|
+
* @returns {Object} Update result with counts and upserted_id if applicable
|
|
144
|
+
* @throws {Error} When filter or update is invalid
|
|
145
|
+
*/
|
|
146
|
+
const process_update_one = (db, database_name, collection_name, operation) => {
|
|
147
|
+
const { filter, update, upsert = false } = operation;
|
|
148
|
+
|
|
149
|
+
if (!filter || typeof filter !== 'object') {
|
|
150
|
+
throw new Error('updateOne operation requires a valid filter');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (!update || typeof update !== 'object') {
|
|
154
|
+
throw new Error('updateOne operation requires a valid update');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const collection_prefix = `${database_name}:${collection_name}:`;
|
|
158
|
+
let matched_count = 0;
|
|
159
|
+
let modified_count = 0;
|
|
160
|
+
let upserted_id = null;
|
|
161
|
+
|
|
162
|
+
const range = db.getRange({ start: collection_prefix, end: collection_prefix + '\xFF' });
|
|
163
|
+
for (const { key, value: document_data } of range) {
|
|
164
|
+
const document = JSON.parse(document_data);
|
|
165
|
+
if (matches_filter(document, filter)) {
|
|
166
|
+
matched_count = 1;
|
|
167
|
+
|
|
168
|
+
const updated_document = apply_update_operators(document, update);
|
|
169
|
+
updated_document._updated_at = new Date().toISOString();
|
|
170
|
+
|
|
171
|
+
if (JSON.stringify(document) !== JSON.stringify(updated_document)) {
|
|
172
|
+
db.put(key, JSON.stringify(updated_document));
|
|
173
|
+
modified_count = 1;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return { matched_count, modified_count };
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (upsert) {
|
|
181
|
+
const document_id = generate_document_id();
|
|
182
|
+
const collection_key = build_collection_key(database_name, collection_name, document_id);
|
|
183
|
+
|
|
184
|
+
const new_document = {
|
|
185
|
+
...filter,
|
|
186
|
+
_id: document_id,
|
|
187
|
+
_created_at: new Date().toISOString(),
|
|
188
|
+
_updated_at: new Date().toISOString()
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const upserted_document = apply_update_operators(new_document, update);
|
|
192
|
+
db.put(collection_key, JSON.stringify(upserted_document));
|
|
193
|
+
|
|
194
|
+
upserted_id = document_id;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return { matched_count, modified_count, upserted_id };
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Processes a single delete operation within a bulk write transaction.
|
|
202
|
+
* Finds first matching document and removes it from the database.
|
|
203
|
+
* Returns count of deleted documents (0 or 1).
|
|
204
|
+
* @param {Object} db - LMDB database instance
|
|
205
|
+
* @param {string} database_name - Name of the database
|
|
206
|
+
* @param {string} collection_name - Name of the collection
|
|
207
|
+
* @param {Object} operation - Delete operation data
|
|
208
|
+
* @param {Object} operation.filter - Filter to find document to delete
|
|
209
|
+
* @returns {Object} Delete result with deleted_count
|
|
210
|
+
* @throws {Error} When filter is invalid
|
|
211
|
+
*/
|
|
212
|
+
const process_delete_one = (db, database_name, collection_name, operation) => {
|
|
213
|
+
const { filter } = operation;
|
|
214
|
+
|
|
215
|
+
if (!filter || typeof filter !== 'object') {
|
|
216
|
+
throw new Error('deleteOne operation requires a valid filter');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const collection_prefix = `${database_name}:${collection_name}:`;
|
|
220
|
+
|
|
221
|
+
const range = db.getRange({ start: collection_prefix, end: collection_prefix + '\xFF' });
|
|
222
|
+
for (const { key, value: document_data } of range) {
|
|
223
|
+
const document = JSON.parse(document_data);
|
|
224
|
+
if (matches_filter(document, filter)) {
|
|
225
|
+
db.remove(key);
|
|
226
|
+
return { deleted_count: 1 };
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return { deleted_count: 0 };
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Internal bulk write implementation with transaction support.
|
|
235
|
+
* Processes all operations atomically within a single database transaction.
|
|
236
|
+
* Supports insert_one, update_one, and delete_one operations with both naming conventions.
|
|
237
|
+
* @param {string} database_name - Name of the database to operate on
|
|
238
|
+
* @param {string} collection_name - Name of the collection to operate on
|
|
239
|
+
* @param {Array<Object>} operations - Array of bulk operations to execute
|
|
240
|
+
* @param {Object} [options={}] - Additional options for bulk write
|
|
241
|
+
* @returns {Promise<Object>} Bulk write results with operation counts and IDs
|
|
242
|
+
* @throws {Error} When database name, collection name is missing, operations are invalid, or operation fails
|
|
243
|
+
*/
|
|
244
|
+
const bulk_write_internal = async (database_name, collection_name, operations, options = {}) => {
|
|
245
|
+
const log = create_context_logger();
|
|
246
|
+
|
|
247
|
+
if (!database_name) {
|
|
248
|
+
throw new Error('Database name is required');
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (!collection_name) {
|
|
252
|
+
throw new Error('Collection name is required');
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (!Array.isArray(operations) || operations.length === 0) {
|
|
256
|
+
throw new Error('Operations must be a non-empty array');
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const db = get_database();
|
|
260
|
+
const results = {
|
|
261
|
+
acknowledged: true,
|
|
262
|
+
inserted_count: 0,
|
|
263
|
+
matched_count: 0,
|
|
264
|
+
modified_count: 0,
|
|
265
|
+
deleted_count: 0,
|
|
266
|
+
upserted_count: 0,
|
|
267
|
+
inserted_ids: {},
|
|
268
|
+
upserted_ids: {}
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
await db.transaction(() => {
|
|
272
|
+
operations.forEach((operation, index) => {
|
|
273
|
+
const operation_type = Object.keys(operation)[0];
|
|
274
|
+
const operation_data = operation[operation_type];
|
|
275
|
+
|
|
276
|
+
// NOTE: Support both snake_case (preferred) and camelCase (backward compatibility).
|
|
277
|
+
switch (operation_type) {
|
|
278
|
+
case 'insert_one':
|
|
279
|
+
case 'insertOne': {
|
|
280
|
+
const result = process_insert_one(db, database_name, collection_name, operation_data);
|
|
281
|
+
results.inserted_count++;
|
|
282
|
+
results.inserted_ids[index] = result.inserted_id;
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
case 'update_one':
|
|
287
|
+
case 'updateOne': {
|
|
288
|
+
const result = process_update_one(db, database_name, collection_name, operation_data);
|
|
289
|
+
results.matched_count += result.matched_count;
|
|
290
|
+
results.modified_count += result.modified_count;
|
|
291
|
+
|
|
292
|
+
if (result.upserted_id) {
|
|
293
|
+
results.upserted_count++;
|
|
294
|
+
results.upserted_ids[index] = result.upserted_id;
|
|
295
|
+
}
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
case 'delete_one':
|
|
300
|
+
case 'deleteOne': {
|
|
301
|
+
const result = process_delete_one(db, database_name, collection_name, operation_data);
|
|
302
|
+
results.deleted_count += result.deleted_count;
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
default:
|
|
307
|
+
throw new Error(`Unsupported bulk operation: ${operation_type}`);
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
log.info('Bulk write operation completed', {
|
|
313
|
+
database: database_name,
|
|
314
|
+
collection: collection_name,
|
|
315
|
+
operations_count: operations.length,
|
|
316
|
+
results
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
return results;
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Executes bulk write operations with write queue serialization.
|
|
324
|
+
* Provides atomic execution of multiple write operations within a single transaction.
|
|
325
|
+
* Enqueues operation through write queue to ensure proper serialization and consistency.
|
|
326
|
+
* @param {string} database_name - Name of the database to operate on
|
|
327
|
+
* @param {string} collection_name - Name of the collection to operate on
|
|
328
|
+
* @param {Array<Object>} operations - Array of bulk operations to execute
|
|
329
|
+
* @param {Object} [options={}] - Additional options for bulk write
|
|
330
|
+
* @returns {Promise<Object>} Bulk write results
|
|
331
|
+
* @returns {boolean} returns.acknowledged - Whether operation was acknowledged
|
|
332
|
+
* @returns {number} returns.inserted_count - Number of documents inserted
|
|
333
|
+
* @returns {number} returns.matched_count - Number of documents matched for updates
|
|
334
|
+
* @returns {number} returns.modified_count - Number of documents actually modified
|
|
335
|
+
* @returns {number} returns.deleted_count - Number of documents deleted
|
|
336
|
+
* @returns {number} returns.upserted_count - Number of documents upserted
|
|
337
|
+
* @returns {Object} returns.inserted_ids - Map of operation index to inserted document ID
|
|
338
|
+
* @returns {Object} returns.upserted_ids - Map of operation index to upserted document ID
|
|
339
|
+
* @throws {Error} When database name, collection name is missing or operations array is invalid
|
|
340
|
+
*/
|
|
341
|
+
const bulk_write = async (database_name, collection_name, operations, options = {}) => {
|
|
342
|
+
if (!database_name) {
|
|
343
|
+
throw new Error('Database name is required');
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (!collection_name) {
|
|
347
|
+
throw new Error('Collection name is required');
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (!Array.isArray(operations) || operations.length === 0) {
|
|
351
|
+
throw new Error('Operations must be a non-empty array');
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const write_queue = get_write_queue();
|
|
355
|
+
|
|
356
|
+
return await write_queue.enqueue_write_operation(
|
|
357
|
+
() => bulk_write_internal(database_name, collection_name, operations, options),
|
|
358
|
+
{
|
|
359
|
+
operation: 'bulk_write',
|
|
360
|
+
database: database_name,
|
|
361
|
+
collection: collection_name,
|
|
362
|
+
operations_count: operations.length
|
|
363
|
+
}
|
|
364
|
+
);
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
export default bulk_write;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Create index operation for JoystickDB collections.
|
|
3
|
+
* Provides functionality to create secondary indexes on collection fields with upsert capabilities.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { create_index } from '../index_manager.js';
|
|
7
|
+
import create_logger from '../logger.js';
|
|
8
|
+
|
|
9
|
+
const { create_context_logger } = create_logger('create_index');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Creates or updates an index on a specified field in a collection.
|
|
13
|
+
* @param {string} database_name - Name of the database
|
|
14
|
+
* @param {string} collection_name - Name of the collection to create index for
|
|
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
|
|
21
|
+
*/
|
|
22
|
+
const create_index_operation = async (database_name, collection_name, field_name, options = {}) => {
|
|
23
|
+
const log = create_context_logger();
|
|
24
|
+
|
|
25
|
+
if (!database_name) {
|
|
26
|
+
throw new Error('Database name is required');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!collection_name) {
|
|
30
|
+
throw new Error('Collection name is required');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!field_name) {
|
|
34
|
+
throw new Error('Field name is required');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
const result = await create_index(database_name, collection_name, field_name, options);
|
|
39
|
+
|
|
40
|
+
const operation_type = result.operation_type || 'created';
|
|
41
|
+
const action_verb = operation_type === 'created' ? 'created' :
|
|
42
|
+
operation_type === 'updated' ? 'updated' :
|
|
43
|
+
'already exists';
|
|
44
|
+
|
|
45
|
+
log.info(`Index ${action_verb} successfully`, {
|
|
46
|
+
database: database_name,
|
|
47
|
+
collection: collection_name,
|
|
48
|
+
field: field_name,
|
|
49
|
+
options,
|
|
50
|
+
operation_type
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
...result,
|
|
55
|
+
message: `Index ${action_verb} on ${database_name}.${collection_name}.${field_name}`
|
|
56
|
+
};
|
|
57
|
+
} catch (error) {
|
|
58
|
+
log.error('Failed to create/upsert index', {
|
|
59
|
+
database: database_name,
|
|
60
|
+
collection: collection_name,
|
|
61
|
+
field: field_name,
|
|
62
|
+
error: error.message
|
|
63
|
+
});
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export default create_index_operation;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { get_database } from '../query_engine.js';
|
|
2
|
+
import { update_indexes_on_delete } from '../index_manager.js';
|
|
3
|
+
import { get_write_queue } from '../write_queue.js';
|
|
4
|
+
import create_logger from '../logger.js';
|
|
5
|
+
|
|
6
|
+
const { create_context_logger } = create_logger('delete_one');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Checks if a document matches the given filter criteria (simple equality check).
|
|
10
|
+
* @param {Object} document - Document to test
|
|
11
|
+
* @param {Object} filter - Filter criteria
|
|
12
|
+
* @returns {boolean} True if document matches filter
|
|
13
|
+
*/
|
|
14
|
+
const matches_filter = (document, filter) => {
|
|
15
|
+
if (!filter || Object.keys(filter).length === 0) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
for (const [field, value] of Object.entries(filter)) {
|
|
20
|
+
if (document[field] !== value) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return true;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
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
|
|
36
|
+
*/
|
|
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');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const db = get_database();
|
|
53
|
+
let deleted_count = 0;
|
|
54
|
+
let deleted_document = null;
|
|
55
|
+
|
|
56
|
+
await db.transaction(() => {
|
|
57
|
+
const collection_prefix = `${database_name}:${collection_name}:`;
|
|
58
|
+
|
|
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
|
+
}
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
if (deleted_document) {
|
|
77
|
+
await update_indexes_on_delete(database_name, collection_name, deleted_document);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
log.info('Delete operation completed', {
|
|
81
|
+
database: database_name,
|
|
82
|
+
collection: collection_name,
|
|
83
|
+
deleted_count
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
acknowledged: true,
|
|
88
|
+
deleted_count
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Deletes a single document from a collection with write queue serialization.
|
|
94
|
+
* @param {string} database_name - Name of the database
|
|
95
|
+
* @param {string} collection_name - Name of the collection
|
|
96
|
+
* @param {Object} filter - Filter criteria to match document for deletion
|
|
97
|
+
* @param {Object} [options={}] - Delete options
|
|
98
|
+
* @returns {Promise<Object>} Delete result with acknowledged and deleted_count
|
|
99
|
+
*/
|
|
100
|
+
const delete_one = async (database_name, collection_name, filter, options = {}) => {
|
|
101
|
+
const write_queue = get_write_queue();
|
|
102
|
+
|
|
103
|
+
return await write_queue.enqueue_write_operation(
|
|
104
|
+
() => 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
|
+
}
|
|
111
|
+
);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export default delete_one;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Drop index operation for JoystickDB collections.
|
|
3
|
+
* Provides functionality to remove secondary indexes from collection fields.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { drop_index } from '../index_manager.js';
|
|
7
|
+
import create_logger from '../logger.js';
|
|
8
|
+
|
|
9
|
+
const { create_context_logger } = create_logger('drop_index');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Drops an existing index from a specified field in a collection.
|
|
13
|
+
* @param {string} database_name - Name of the database containing the collection
|
|
14
|
+
* @param {string} collection_name - Name of the collection to drop index from
|
|
15
|
+
* @param {string} field_name - Name of the field to remove index from
|
|
16
|
+
* @returns {Promise<Object>} Index drop result with operation details and message
|
|
17
|
+
* @throws {Error} When database name, collection name or field name is missing, or index drop fails
|
|
18
|
+
*/
|
|
19
|
+
const drop_index_operation = async (database_name, collection_name, field_name) => {
|
|
20
|
+
const log = create_context_logger();
|
|
21
|
+
|
|
22
|
+
if (!database_name) {
|
|
23
|
+
throw new Error('Database name is required');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!collection_name) {
|
|
27
|
+
throw new Error('Collection name is required');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!field_name) {
|
|
31
|
+
throw new Error('Field name is required');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const result = await drop_index(database_name, collection_name, field_name);
|
|
36
|
+
|
|
37
|
+
log.info('Index dropped successfully', {
|
|
38
|
+
database: database_name,
|
|
39
|
+
collection: collection_name,
|
|
40
|
+
field: field_name
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
...result,
|
|
45
|
+
message: `Index dropped on ${database_name}.${collection_name}.${field_name}`
|
|
46
|
+
};
|
|
47
|
+
} catch (error) {
|
|
48
|
+
log.error('Failed to drop index', {
|
|
49
|
+
database: database_name,
|
|
50
|
+
collection: collection_name,
|
|
51
|
+
field: field_name,
|
|
52
|
+
error: error.message
|
|
53
|
+
});
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default drop_index_operation;
|