@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,513 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import sinon from 'sinon';
|
|
3
|
+
import net from 'net';
|
|
4
|
+
import { encode as encode_messagepack, decode as decode_messagepack } from 'msgpackr';
|
|
5
|
+
import { encode_message } from '../../../src/server/lib/tcp_protocol.js';
|
|
6
|
+
import { create_server } from '../../../src/server/index.js';
|
|
7
|
+
|
|
8
|
+
// Shared server instance
|
|
9
|
+
let shared_server = null;
|
|
10
|
+
let shared_port = null;
|
|
11
|
+
|
|
12
|
+
test.before(async () => {
|
|
13
|
+
// Set test environment
|
|
14
|
+
process.env.NODE_ENV = 'test';
|
|
15
|
+
|
|
16
|
+
// Create shared server instance
|
|
17
|
+
shared_server = await create_server();
|
|
18
|
+
shared_port = 0; // Use random available port
|
|
19
|
+
|
|
20
|
+
// Start server
|
|
21
|
+
await new Promise((resolve, reject) => {
|
|
22
|
+
const timeout = setTimeout(() => {
|
|
23
|
+
reject(new Error('Server start timeout'));
|
|
24
|
+
}, 5000);
|
|
25
|
+
|
|
26
|
+
shared_server.listen(shared_port, (error) => {
|
|
27
|
+
clearTimeout(timeout);
|
|
28
|
+
if (error) {
|
|
29
|
+
reject(error);
|
|
30
|
+
} else {
|
|
31
|
+
shared_port = shared_server.address().port;
|
|
32
|
+
resolve();
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test.after.always(async () => {
|
|
39
|
+
// Clean up shared server
|
|
40
|
+
if (shared_server) {
|
|
41
|
+
try {
|
|
42
|
+
if (shared_server.cleanup) {
|
|
43
|
+
await shared_server.cleanup();
|
|
44
|
+
}
|
|
45
|
+
} catch (error) {
|
|
46
|
+
// Ignore cleanup errors
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
await new Promise((resolve) => {
|
|
50
|
+
const timeout = setTimeout(() => {
|
|
51
|
+
try {
|
|
52
|
+
shared_server.close();
|
|
53
|
+
} catch (error) {
|
|
54
|
+
// Ignore errors
|
|
55
|
+
}
|
|
56
|
+
resolve();
|
|
57
|
+
}, 2000);
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
shared_server.close(() => {
|
|
61
|
+
clearTimeout(timeout);
|
|
62
|
+
resolve();
|
|
63
|
+
});
|
|
64
|
+
} catch (error) {
|
|
65
|
+
clearTimeout(timeout);
|
|
66
|
+
resolve();
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
shared_server = null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Restore sinon mocks
|
|
74
|
+
sinon.restore();
|
|
75
|
+
|
|
76
|
+
// Force garbage collection if available
|
|
77
|
+
if (global.gc) {
|
|
78
|
+
global.gc();
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const create_client = () => {
|
|
83
|
+
return new Promise((resolve, reject) => {
|
|
84
|
+
const client = net.createConnection({ port: shared_port }, () => {
|
|
85
|
+
// Set socket options for better cleanup
|
|
86
|
+
client.setKeepAlive(false);
|
|
87
|
+
client.setTimeout(5000);
|
|
88
|
+
|
|
89
|
+
resolve(client);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
client.on('error', (error) => {
|
|
93
|
+
client.destroy();
|
|
94
|
+
reject(error);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
client.on('timeout', () => {
|
|
98
|
+
client.destroy();
|
|
99
|
+
reject(new Error('Client connection timeout'));
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const send_message = (client, message) => {
|
|
105
|
+
return new Promise((resolve, reject) => {
|
|
106
|
+
const timeout = setTimeout(() => {
|
|
107
|
+
reject(new Error('Message timeout'));
|
|
108
|
+
}, 5000);
|
|
109
|
+
|
|
110
|
+
const encoded_message = encode_message(message);
|
|
111
|
+
|
|
112
|
+
client.once('data', (data) => {
|
|
113
|
+
clearTimeout(timeout);
|
|
114
|
+
try {
|
|
115
|
+
// Parse the MessagePack response with length prefix
|
|
116
|
+
if (data.length < 4) {
|
|
117
|
+
reject(new Error('Response too short'));
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const length = data.readUInt32BE(0);
|
|
122
|
+
if (data.length < 4 + length) {
|
|
123
|
+
reject(new Error('Incomplete response'));
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const messagepack_data = data.slice(4, 4 + length);
|
|
128
|
+
const response = decode_messagepack(messagepack_data);
|
|
129
|
+
resolve(response);
|
|
130
|
+
} catch (error) {
|
|
131
|
+
reject(error);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
client.once('error', (error) => {
|
|
136
|
+
clearTimeout(timeout);
|
|
137
|
+
reject(error);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
client.write(encoded_message);
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
test('admin backup operations - should handle test_s3_connection', async t => {
|
|
145
|
+
const client = await create_client();
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
// First authenticate
|
|
149
|
+
const auth_response = await send_message(client, {
|
|
150
|
+
op: 'authentication',
|
|
151
|
+
data: { password: 'test-password' }
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Skip if authentication fails (expected in test environment)
|
|
155
|
+
if (auth_response.ok !== 1) {
|
|
156
|
+
t.pass('Authentication failed as expected in test environment');
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Test S3 connection
|
|
161
|
+
const s3_test_response = await send_message(client, {
|
|
162
|
+
op: 'admin',
|
|
163
|
+
data: { admin_action: 'test_s3_connection' }
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// Should fail without proper S3 configuration
|
|
167
|
+
t.is(s3_test_response.ok, 0);
|
|
168
|
+
t.truthy(s3_test_response.error);
|
|
169
|
+
|
|
170
|
+
} finally {
|
|
171
|
+
try {
|
|
172
|
+
client.end();
|
|
173
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
174
|
+
} catch (error) {
|
|
175
|
+
// Ignore cleanup errors
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
client.destroy();
|
|
179
|
+
} catch (error) {
|
|
180
|
+
// Ignore cleanup errors
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test('admin backup operations - should handle backup_now', async t => {
|
|
186
|
+
const client = await create_client();
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
// First authenticate
|
|
190
|
+
const auth_response = await send_message(client, {
|
|
191
|
+
op: 'authentication',
|
|
192
|
+
data: { password: 'test-password' }
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// Skip if authentication fails (expected in test environment)
|
|
196
|
+
if (auth_response.ok !== 1) {
|
|
197
|
+
t.pass('Authentication failed as expected in test environment');
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Try to create backup
|
|
202
|
+
const backup_response = await send_message(client, {
|
|
203
|
+
op: 'admin',
|
|
204
|
+
data: { admin_action: 'backup_now' }
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Should fail without proper S3 configuration
|
|
208
|
+
t.is(backup_response.ok, 0);
|
|
209
|
+
t.truthy(backup_response.error);
|
|
210
|
+
|
|
211
|
+
} finally {
|
|
212
|
+
try {
|
|
213
|
+
client.end();
|
|
214
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
215
|
+
} catch (error) {
|
|
216
|
+
// Ignore cleanup errors
|
|
217
|
+
}
|
|
218
|
+
try {
|
|
219
|
+
client.destroy();
|
|
220
|
+
} catch (error) {
|
|
221
|
+
// Ignore cleanup errors
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test('admin backup operations - should handle list_backups', async t => {
|
|
227
|
+
const client = await create_client();
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
// First authenticate
|
|
231
|
+
const auth_response = await send_message(client, {
|
|
232
|
+
op: 'authentication',
|
|
233
|
+
data: { password: 'test-password' }
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Skip if authentication fails (expected in test environment)
|
|
237
|
+
if (auth_response.ok !== 1) {
|
|
238
|
+
t.pass('Authentication failed as expected in test environment');
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// List backups
|
|
243
|
+
const list_response = await send_message(client, {
|
|
244
|
+
op: 'admin',
|
|
245
|
+
data: { admin_action: 'list_backups' }
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// Should fail without proper S3 configuration
|
|
249
|
+
t.is(list_response.ok, 0);
|
|
250
|
+
t.truthy(list_response.error);
|
|
251
|
+
|
|
252
|
+
} finally {
|
|
253
|
+
try {
|
|
254
|
+
client.end();
|
|
255
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
256
|
+
} catch (error) {
|
|
257
|
+
// Ignore cleanup errors
|
|
258
|
+
}
|
|
259
|
+
try {
|
|
260
|
+
client.destroy();
|
|
261
|
+
} catch (error) {
|
|
262
|
+
// Ignore cleanup errors
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
test('admin backup operations - should handle restore_backup', async t => {
|
|
268
|
+
const client = await create_client();
|
|
269
|
+
|
|
270
|
+
try {
|
|
271
|
+
// First authenticate
|
|
272
|
+
const auth_response = await send_message(client, {
|
|
273
|
+
op: 'authentication',
|
|
274
|
+
data: { password: 'test-password' }
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// Skip if authentication fails (expected in test environment)
|
|
278
|
+
if (auth_response.ok !== 1) {
|
|
279
|
+
t.pass('Authentication failed as expected in test environment');
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Try to restore backup
|
|
284
|
+
const restore_response = await send_message(client, {
|
|
285
|
+
op: 'admin',
|
|
286
|
+
data: {
|
|
287
|
+
admin_action: 'restore_backup',
|
|
288
|
+
backup_filename: 'joystickdb-backup-2025-08-31T12-00-00.tar.gz'
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// Should fail without proper S3 configuration
|
|
293
|
+
t.is(restore_response.ok, 0);
|
|
294
|
+
t.truthy(restore_response.error);
|
|
295
|
+
|
|
296
|
+
} finally {
|
|
297
|
+
try {
|
|
298
|
+
client.end();
|
|
299
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
300
|
+
} catch (error) {
|
|
301
|
+
// Ignore cleanup errors
|
|
302
|
+
}
|
|
303
|
+
try {
|
|
304
|
+
client.destroy();
|
|
305
|
+
} catch (error) {
|
|
306
|
+
// Ignore cleanup errors
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
test('admin backup operations - should require backup_filename for restore', async t => {
|
|
312
|
+
const client = await create_client();
|
|
313
|
+
|
|
314
|
+
try {
|
|
315
|
+
// First authenticate
|
|
316
|
+
const auth_response = await send_message(client, {
|
|
317
|
+
op: 'authentication',
|
|
318
|
+
data: { password: 'test-password' }
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// Skip if authentication fails (expected in test environment)
|
|
322
|
+
if (auth_response.ok !== 1) {
|
|
323
|
+
t.pass('Authentication failed as expected in test environment');
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Try to restore without backup_filename
|
|
328
|
+
const restore_response = await send_message(client, {
|
|
329
|
+
op: 'admin',
|
|
330
|
+
data: { admin_action: 'restore_backup' }
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
// Should fail due to missing backup_filename
|
|
334
|
+
t.is(restore_response.ok, 0);
|
|
335
|
+
t.truthy(restore_response.error);
|
|
336
|
+
t.regex(restore_response.error, /backup_filename is required/);
|
|
337
|
+
|
|
338
|
+
} finally {
|
|
339
|
+
try {
|
|
340
|
+
client.end();
|
|
341
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
342
|
+
} catch (error) {
|
|
343
|
+
// Ignore cleanup errors
|
|
344
|
+
}
|
|
345
|
+
try {
|
|
346
|
+
client.destroy();
|
|
347
|
+
} catch (error) {
|
|
348
|
+
// Ignore cleanup errors
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
test('admin backup operations - should handle cleanup_backups', async t => {
|
|
354
|
+
const client = await create_client();
|
|
355
|
+
|
|
356
|
+
try {
|
|
357
|
+
// First authenticate
|
|
358
|
+
const auth_response = await send_message(client, {
|
|
359
|
+
op: 'authentication',
|
|
360
|
+
data: { password: 'test-password' }
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
// Skip if authentication fails (expected in test environment)
|
|
364
|
+
if (auth_response.ok !== 1) {
|
|
365
|
+
t.pass('Authentication failed as expected in test environment');
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Cleanup backups
|
|
370
|
+
const cleanup_response = await send_message(client, {
|
|
371
|
+
op: 'admin',
|
|
372
|
+
data: { admin_action: 'cleanup_backups' }
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
// Should fail without proper S3 configuration
|
|
376
|
+
t.is(cleanup_response.ok, 0);
|
|
377
|
+
t.truthy(cleanup_response.error);
|
|
378
|
+
|
|
379
|
+
} finally {
|
|
380
|
+
try {
|
|
381
|
+
client.end();
|
|
382
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
383
|
+
} catch (error) {
|
|
384
|
+
// Ignore cleanup errors
|
|
385
|
+
}
|
|
386
|
+
try {
|
|
387
|
+
client.destroy();
|
|
388
|
+
} catch (error) {
|
|
389
|
+
// Ignore cleanup errors
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
test('backup operations - should require authentication', async t => {
|
|
395
|
+
const client = await create_client();
|
|
396
|
+
|
|
397
|
+
try {
|
|
398
|
+
// Try backup operation without authentication
|
|
399
|
+
const backup_response = await send_message(client, {
|
|
400
|
+
op: 'admin',
|
|
401
|
+
data: { admin_action: 'backup_now' }
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
// Should fail due to lack of authentication
|
|
405
|
+
t.is(backup_response.ok, false);
|
|
406
|
+
t.truthy(backup_response.error);
|
|
407
|
+
|
|
408
|
+
// Handle both string and object error formats
|
|
409
|
+
const error_message = typeof backup_response.error === 'string'
|
|
410
|
+
? backup_response.error
|
|
411
|
+
: backup_response.error.message || JSON.stringify(backup_response.error);
|
|
412
|
+
|
|
413
|
+
t.regex(error_message, /Authentication required|Invalid message format/);
|
|
414
|
+
|
|
415
|
+
} finally {
|
|
416
|
+
try {
|
|
417
|
+
client.end();
|
|
418
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
419
|
+
} catch (error) {
|
|
420
|
+
// Ignore cleanup errors
|
|
421
|
+
}
|
|
422
|
+
try {
|
|
423
|
+
client.destroy();
|
|
424
|
+
} catch (error) {
|
|
425
|
+
// Ignore cleanup errors
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
test('backup filename validation - should accept valid backup filenames', t => {
|
|
431
|
+
const valid_filenames = [
|
|
432
|
+
'joystickdb-backup-2025-08-31T12-00-00.tar.gz',
|
|
433
|
+
'joystickdb-backup-2025-12-31T23-59-59-999Z.tar.gz',
|
|
434
|
+
'joystickdb-backup-2025-01-01T00-00-00-000Z.tar.gz'
|
|
435
|
+
];
|
|
436
|
+
|
|
437
|
+
const filename_pattern = /^joystickdb-backup-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}.*\.tar\.gz$/;
|
|
438
|
+
|
|
439
|
+
for (const filename of valid_filenames) {
|
|
440
|
+
t.regex(filename, filename_pattern, `${filename} should match pattern`);
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
test('backup filename validation - should reject invalid backup filenames', t => {
|
|
445
|
+
const invalid_filenames = [
|
|
446
|
+
'invalid-backup.tar.gz',
|
|
447
|
+
'joystickdb-backup-invalid-date.tar.gz',
|
|
448
|
+
'joystickdb-backup-2025-08-31.zip',
|
|
449
|
+
'backup-2025-08-31T12-00-00.tar.gz'
|
|
450
|
+
];
|
|
451
|
+
|
|
452
|
+
const filename_pattern = /^joystickdb-backup-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}.*\.tar\.gz$/;
|
|
453
|
+
|
|
454
|
+
for (const filename of invalid_filenames) {
|
|
455
|
+
t.notRegex(filename, filename_pattern, `${filename} should not match pattern`);
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
test('S3 configuration validation - should validate required fields', t => {
|
|
460
|
+
const valid_s3_config = {
|
|
461
|
+
bucket: 'test-bucket',
|
|
462
|
+
region: 'us-east-1',
|
|
463
|
+
access_key: 'AKIA...',
|
|
464
|
+
secret_key: 'secret...'
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
// Test that all required fields are present
|
|
468
|
+
t.truthy(valid_s3_config.bucket);
|
|
469
|
+
t.truthy(valid_s3_config.region);
|
|
470
|
+
t.truthy(valid_s3_config.access_key);
|
|
471
|
+
t.truthy(valid_s3_config.secret_key);
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
test('backup schedule validation - should accept valid schedules', t => {
|
|
475
|
+
const valid_schedules = ['hourly', 'daily', 'weekly'];
|
|
476
|
+
|
|
477
|
+
for (const schedule of valid_schedules) {
|
|
478
|
+
t.true(valid_schedules.includes(schedule));
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
test('backup schedule validation - should handle invalid schedules', t => {
|
|
483
|
+
const invalid_schedules = ['minutely', 'monthly', 'yearly', 'invalid'];
|
|
484
|
+
const valid_schedules = ['hourly', 'daily', 'weekly'];
|
|
485
|
+
|
|
486
|
+
for (const schedule of invalid_schedules) {
|
|
487
|
+
t.false(valid_schedules.includes(schedule));
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
test('backup retention calculation - should calculate correct retention periods', t => {
|
|
492
|
+
const now = new Date('2025-08-31T12:00:00Z');
|
|
493
|
+
const one_hour = 60 * 60 * 1000;
|
|
494
|
+
const one_day = 24 * one_hour;
|
|
495
|
+
|
|
496
|
+
// Test different backup ages
|
|
497
|
+
const backup_ages = [
|
|
498
|
+
{ age_hours: 1, should_keep_hourly: true, should_keep_daily: false },
|
|
499
|
+
{ age_hours: 25, should_keep_hourly: false, should_keep_daily: true },
|
|
500
|
+
{ age_hours: 31 * 24, should_keep_hourly: false, should_keep_daily: false }
|
|
501
|
+
];
|
|
502
|
+
|
|
503
|
+
for (const { age_hours, should_keep_hourly, should_keep_daily } of backup_ages) {
|
|
504
|
+
const backup_date = new Date(now.getTime() - age_hours * one_hour);
|
|
505
|
+
const age_ms = now - backup_date;
|
|
506
|
+
|
|
507
|
+
const keep_hourly = age_ms <= 24 * one_hour;
|
|
508
|
+
const keep_daily = age_ms > 24 * one_hour && age_ms <= 30 * one_day;
|
|
509
|
+
|
|
510
|
+
t.is(keep_hourly, should_keep_hourly, `${age_hours}h backup hourly retention`);
|
|
511
|
+
t.is(keep_daily, should_keep_daily, `${age_hours}h backup daily retention`);
|
|
512
|
+
}
|
|
513
|
+
});
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import { initialize_database, get_database, cleanup_database } from '../../../src/server/lib/query_engine.js';
|
|
3
|
+
import { initialize_index_database, get_index_database, cleanup_index_database } from '../../../src/server/lib/index_manager.js';
|
|
4
|
+
import insert_one from '../../../src/server/lib/operations/insert_one.js';
|
|
5
|
+
import find from '../../../src/server/lib/operations/find.js';
|
|
6
|
+
import find_one from '../../../src/server/lib/operations/find_one.js';
|
|
7
|
+
import create_index_operation from '../../../src/server/lib/operations/create_index.js';
|
|
8
|
+
import get_indexes_operation from '../../../src/server/lib/operations/get_indexes.js';
|
|
9
|
+
import drop_index_operation from '../../../src/server/lib/operations/drop_index.js';
|
|
10
|
+
|
|
11
|
+
test.beforeEach(async () => {
|
|
12
|
+
// Ensure clean state
|
|
13
|
+
await cleanup_database();
|
|
14
|
+
|
|
15
|
+
// Initialize fresh databases
|
|
16
|
+
initialize_database('./test_data');
|
|
17
|
+
initialize_index_database();
|
|
18
|
+
|
|
19
|
+
const main_db = get_database();
|
|
20
|
+
const index_db = get_index_database();
|
|
21
|
+
|
|
22
|
+
// Clear both databases
|
|
23
|
+
main_db.clearSync();
|
|
24
|
+
index_db.clearSync();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test.afterEach(async () => {
|
|
28
|
+
// cleanup_index_database is called automatically by cleanup_database
|
|
29
|
+
await cleanup_database();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('integration - indexing improves query performance', async (t) => {
|
|
33
|
+
await create_index_operation('default', 'users', 'email');
|
|
34
|
+
|
|
35
|
+
await insert_one('default', 'users', { email: 'john@example.com', name: 'John Doe' });
|
|
36
|
+
await insert_one('default', 'users', { email: 'jane@example.com', name: 'Jane Smith' });
|
|
37
|
+
await insert_one('default', 'users', { email: 'bob@example.com', name: 'Bob Johnson' });
|
|
38
|
+
|
|
39
|
+
const result = await find_one('default', 'users', { email: 'jane@example.com' });
|
|
40
|
+
|
|
41
|
+
t.truthy(result);
|
|
42
|
+
t.is(result.email, 'jane@example.com');
|
|
43
|
+
t.is(result.name, 'Jane Smith');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('integration - index management operations work correctly', async (t) => {
|
|
47
|
+
await create_index_operation('default', 'users', 'email');
|
|
48
|
+
await create_index_operation('default', 'users', 'status');
|
|
49
|
+
|
|
50
|
+
let indexes_result = await get_indexes_operation('default', 'users');
|
|
51
|
+
t.is(indexes_result.indexes.length, 2);
|
|
52
|
+
|
|
53
|
+
await drop_index_operation('default', 'users', 'email');
|
|
54
|
+
|
|
55
|
+
indexes_result = await get_indexes_operation('default', 'users');
|
|
56
|
+
t.is(indexes_result.indexes.length, 1);
|
|
57
|
+
t.is(indexes_result.indexes[0].field, 'status');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('integration - unique index prevents duplicate values', async (t) => {
|
|
61
|
+
await create_index_operation('default', 'users', 'email', { unique: true });
|
|
62
|
+
|
|
63
|
+
await insert_one('default', 'users', { email: 'unique@example.com', name: 'User 1' });
|
|
64
|
+
|
|
65
|
+
await t.throwsAsync(
|
|
66
|
+
() => insert_one('default', 'users', { email: 'unique@example.com', name: 'User 2' }),
|
|
67
|
+
{ message: /Duplicate value for unique index/ }
|
|
68
|
+
);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('integration - sparse index handles null values correctly', async (t) => {
|
|
72
|
+
await create_index_operation('default', 'users', 'email', { sparse: true });
|
|
73
|
+
|
|
74
|
+
await insert_one('default', 'users', { name: 'User Without Email' });
|
|
75
|
+
await insert_one('default', 'users', { email: 'user@example.com', name: 'User With Email' });
|
|
76
|
+
|
|
77
|
+
const users_with_email = await find('default', 'users', { email: { $exists: true } });
|
|
78
|
+
t.is(users_with_email.length, 1);
|
|
79
|
+
t.is(users_with_email[0].email, 'user@example.com');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('integration - nested field indexing works', async (t) => {
|
|
83
|
+
await create_index_operation('default', 'users', 'profile.email');
|
|
84
|
+
|
|
85
|
+
await insert_one('default', 'users', {
|
|
86
|
+
name: 'John Doe',
|
|
87
|
+
profile: {
|
|
88
|
+
email: 'john@example.com',
|
|
89
|
+
age: 30
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const result = await find_one('default', 'users', { 'profile.email': 'john@example.com' });
|
|
94
|
+
|
|
95
|
+
t.truthy(result);
|
|
96
|
+
t.is(result.name, 'John Doe');
|
|
97
|
+
t.is(result.profile.email, 'john@example.com');
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('integration - $in operator uses index', async (t) => {
|
|
101
|
+
await create_index_operation('default', 'users', 'status');
|
|
102
|
+
|
|
103
|
+
await insert_one('default', 'users', { name: 'User 1', status: 'active' });
|
|
104
|
+
await insert_one('default', 'users', { name: 'User 2', status: 'inactive' });
|
|
105
|
+
await insert_one('default', 'users', { name: 'User 3', status: 'pending' });
|
|
106
|
+
await insert_one('default', 'users', { name: 'User 4', status: 'suspended' });
|
|
107
|
+
|
|
108
|
+
const results = await find('default', 'users', { status: { $in: ['active', 'pending'] } });
|
|
109
|
+
|
|
110
|
+
t.is(results.length, 2);
|
|
111
|
+
const statuses = results.map(user => user.status).sort();
|
|
112
|
+
t.deepEqual(statuses, ['active', 'pending']);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test('integration - fallback to collection scan when no index available', async (t) => {
|
|
116
|
+
await create_index_operation('default', 'users', 'email');
|
|
117
|
+
|
|
118
|
+
await insert_one('default', 'users', { email: 'user1@example.com', name: 'User 1', age: 25 });
|
|
119
|
+
await insert_one('default', 'users', { email: 'user2@example.com', name: 'User 2', age: 30 });
|
|
120
|
+
|
|
121
|
+
const results = await find('default', 'users', { age: 30 });
|
|
122
|
+
|
|
123
|
+
t.is(results.length, 1);
|
|
124
|
+
t.is(results[0].name, 'User 2');
|
|
125
|
+
t.is(results[0].age, 30);
|
|
126
|
+
});
|