http-request-manager 18.15.32 → 18.15.34
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/README.md +2 -0
- package/TEST_COVERAGE_SUMMARY.md +458 -0
- package/ng-package.json +8 -0
- package/package.json +5 -13
- package/src/docs/ADVANCED_WEBSOCKET.md +633 -0
- package/src/docs/ARCHITECTURE.md +633 -0
- package/src/docs/BATCH_REQUEST_README.md +467 -0
- package/src/docs/COMPLETE_API_REFERENCE.md +1037 -0
- package/src/docs/DATABASE_README.md +1195 -0
- package/src/docs/ENCRYPTION_README.md +403 -0
- package/src/docs/HTTP_MANAGER_README.md +628 -0
- package/src/docs/HTTP_SINGNALS_MANAGER_README.md +654 -0
- package/src/docs/HTTP_STATE_MANAGER_README.md +1391 -0
- package/src/docs/INTERCEPTOR_README.md +549 -0
- package/src/docs/LOCAL_STORAGE_README.md +1056 -0
- package/src/docs/LOCAL_STORAGE_SIGNALS_README.md +338 -0
- package/src/docs/LOGGER_README.md +310 -0
- package/src/docs/MESSAGE_TRACKER_README.md +518 -0
- package/src/docs/MESSAGE_TRACKER_SIGNALS_README.md +563 -0
- package/src/docs/MODELS_README.md +1264 -0
- package/src/docs/SIGNAL_SERVICES_README.md +238 -0
- package/src/docs/SQL_DIXIE_README.md +574 -0
- package/src/docs/STORE_STATE_MANAGER_README.md +556 -0
- package/src/docs/STORE_STATE_SIGNALS_README.md +600 -0
- package/src/docs/UPLOAD_REQUEST_README.md +324 -0
- package/src/docs/UTILS_README.md +1604 -0
- package/src/docs/WEBSOCKET_MESSAGE_SERVICE.md +799 -0
- package/src/docs/WEBSOCKET_SIGNALS_README.md +641 -0
- package/src/docs/WEBSOCKET_SINGLETON_REFACTORING.md +201 -0
- package/src/docs/WS_MANAGER_README.md +613 -0
- package/src/lib/http-request-manager.module.ts +147 -0
- package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.html +116 -0
- package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.scss +0 -0
- package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.ts +255 -0
- package/src/lib/http-request-services-demo/http-request-services-demo.component.html +123 -0
- package/src/lib/http-request-services-demo/http-request-services-demo.component.scss +6 -0
- package/src/lib/http-request-services-demo/http-request-services-demo.component.ts +53 -0
- package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.html +195 -0
- package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.scss +17 -0
- package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.ts +208 -0
- package/src/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.html +200 -0
- package/src/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.scss +17 -0
- package/src/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.ts +214 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/download-file/download-file.component.html +53 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/download-file/download-file.component.scss +60 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/download-file/download-file.component.ts +72 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/file-download.module.ts +28 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/file-downloader.component.html +10 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/file-downloader.component.scss +29 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/file-downloader.component.ts +100 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/models/download-labels-model.ts +22 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/spinner/spinner.component.html +8 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/spinner/spinner.component.scss +19 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/file-downloader/spinner/spinner.component.ts +26 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/models/app-session.model.ts +30 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/models/app.model.ts +19 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/models/get-sample.model.ts +25 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/models/sample-ai-prompt.ts +19 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/models/sample-client-details.ts +24 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/models/sample-client-info.ts +30 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/models/sample-client.model.ts +49 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/models/sample-mapper-client-info.ts +33 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/request-manager-basic-demo.component.html +279 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/request-manager-basic-demo.component.scss +24 -0
- package/src/lib/http-request-services-demo/request-manager-basic-demo/request-manager-basic-demo.component.ts +461 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.html +53 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.scss +60 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.ts +72 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-download.module.ts +28 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.html +10 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.scss +29 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.ts +100 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/models/download-labels-model.ts +22 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.html +8 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.scss +19 -0
- package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.ts +26 -0
- package/src/lib/http-request-services-demo/request-manager-demo/models/app-session.model.ts +30 -0
- package/src/lib/http-request-services-demo/request-manager-demo/models/app.model.ts +19 -0
- package/src/lib/http-request-services-demo/request-manager-demo/models/get-sample.model.ts +25 -0
- package/src/lib/http-request-services-demo/request-manager-demo/models/sample-ai-prompt.ts +19 -0
- package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client-details.ts +24 -0
- package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client-info.ts +30 -0
- package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client.model.ts +49 -0
- package/src/lib/http-request-services-demo/request-manager-demo/models/sample-mapper-client-info.ts +33 -0
- package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.html +622 -0
- package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.scss +106 -0
- package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.ts +687 -0
- package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.html +418 -0
- package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.scss +24 -0
- package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.ts +576 -0
- package/src/lib/http-request-services-demo/request-manager-state-demo/services/state-manager-demo.service.ts +89 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/services/state-data-request.service.ts +119 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-ai-messaging/ws-ai-messaging.component.css +0 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-ai-messaging/ws-ai-messaging.component.html +3 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-ai-messaging/ws-ai-messaging.component.ts +16 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-chats/ws-chats.component.css +0 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-chats/ws-chats.component.html +3 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-chats/ws-chats.component.ts +16 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.css +31 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.html +94 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.scss +41 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.spec.ts +203 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.ts +144 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.css +11 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.html +102 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.spec.ts +40 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.ts +230 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.css +30 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.html +172 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.spec.ts +31 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.ts +239 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/models/oidc-client.model.ts +31 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/models/user-data.model.ts +32 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/request-manager-ws-demo.component.css +0 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/request-manager-ws-demo.component.html +84 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/request-manager-ws-demo.component.ts +40 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/services/index.ts +3 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/services/jwt-token.service.ts +62 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/services/message-service-demo.service.ts +83 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/services/notification-service-demo.service.ts +147 -0
- package/src/lib/http-request-services-demo/request-manager-ws-demo/services/state-service-demo.service.ts +168 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/download-file/download-file.component.html +53 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/download-file/download-file.component.scss +60 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/download-file/download-file.component.ts +72 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-download.module.ts +28 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-downloader.component.html +10 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-downloader.component.scss +29 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-downloader.component.ts +100 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/models/download-labels-model.ts +22 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/spinner/spinner.component.html +8 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/spinner/spinner.component.scss +19 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/spinner/spinner.component.ts +26 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/models/app-session.model.ts +30 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/models/app.model.ts +19 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/models/get-sample.model.ts +25 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-ai-prompt.ts +19 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client-details.ts +24 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client-info.ts +30 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client.model.ts +49 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-mapper-client-info.ts +33 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.html +380 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.scss +24 -0
- package/src/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.ts +410 -0
- package/src/lib/http-request-services-demo/store-state-manager-demo/models/settings.model.ts +28 -0
- package/src/lib/http-request-services-demo/store-state-manager-demo/services/settings-state.service.ts +49 -0
- package/src/lib/http-request-services-demo/store-state-manager-demo/store-state-manager-demo.component.css +0 -0
- package/src/lib/http-request-services-demo/store-state-manager-demo/store-state-manager-demo.component.html +23 -0
- package/src/lib/http-request-services-demo/store-state-manager-demo/store-state-manager-demo.component.ts +36 -0
- package/src/lib/http-request-services-demo/store-state-signals-demo/store-state-signals-demo.component.ts +161 -0
- package/src/lib/http-request-services-demo/upload-demo/models/index.ts +1 -0
- package/src/lib/http-request-services-demo/upload-demo/models/upload-state.model.ts +30 -0
- package/src/lib/http-request-services-demo/upload-demo/upload-demo.component.html +89 -0
- package/src/lib/http-request-services-demo/upload-demo/upload-demo.component.scss +160 -0
- package/src/lib/http-request-services-demo/upload-demo/upload-demo.component.spec.ts +101 -0
- package/src/lib/http-request-services-demo/upload-demo/upload-demo.component.ts +136 -0
- package/src/lib/index.ts +3 -0
- package/src/lib/interceptors/credentials.interceptor.ts +16 -0
- package/src/lib/interceptors/index.ts +6 -0
- package/src/lib/interceptors/models/error-settings.model.ts +22 -0
- package/src/lib/interceptors/models/index.ts +2 -0
- package/src/lib/interceptors/proxy-debugger.interceptor.ts +46 -0
- package/src/lib/interceptors/request-error.interceptor.ts +65 -0
- package/src/lib/interceptors/request-header.interceptor.ts +56 -0
- package/src/lib/message-display/README.md +509 -0
- package/src/lib/message-display/index.ts +4 -0
- package/src/lib/message-display/models/action.model.ts +27 -0
- package/src/lib/message-display/models/communication-message.model.ts +77 -0
- package/src/lib/message-display/models/display-config.model.ts +35 -0
- package/src/lib/message-display/models/display-rule.interface.ts +28 -0
- package/src/lib/message-display/models/display-strategy.interface.ts +8 -0
- package/src/lib/message-display/models/index.ts +6 -0
- package/src/lib/message-display/models/slide.model.ts +24 -0
- package/src/lib/message-display/rules/default-display-rules.ts +35 -0
- package/src/lib/message-display/services/message-display-router.service.ts +63 -0
- package/src/lib/message-display/strategies/snackbar.strategy.ts +46 -0
- package/src/lib/models/batch-options.model.ts +33 -0
- package/src/lib/models/batch-progress.model.ts +19 -0
- package/src/lib/models/batch-request-state.model.ts +40 -0
- package/src/lib/models/batch-result.model.ts +30 -0
- package/src/lib/models/config-http-options.model.ts +45 -0
- package/src/lib/models/config-local-storage-options.model.ts +27 -0
- package/src/lib/models/config-options.model.ts +27 -0
- package/src/lib/models/config-token.model.ts +9 -0
- package/src/lib/models/data-type.enum.ts +5 -0
- package/src/lib/models/database-storage.model.ts +24 -0
- package/src/lib/models/index.ts +16 -0
- package/src/lib/models/retry-options.model.ts +22 -0
- package/src/lib/models/upload-validation-error.model.ts +46 -0
- package/src/lib/services/SQL-DixieJS service/dexie-query-executor.ts +246 -0
- package/src/lib/services/SQL-DixieJS service/dexie-sql.service.ts +31 -0
- package/src/lib/services/SQL-DixieJS service/index.ts +4 -0
- package/src/lib/services/SQL-DixieJS service/models/execution-plan.model.ts +52 -0
- package/src/lib/services/SQL-DixieJS service/models/index.ts +3 -0
- package/src/lib/services/SQL-DixieJS service/models/sql-errors.model.ts +13 -0
- package/src/lib/services/SQL-DixieJS service/models/sql-options.model.ts +3 -0
- package/src/lib/services/SQL-DixieJS service/query-planner.ts +284 -0
- package/src/lib/services/SQL-DixieJS service/schema-validator.ts +217 -0
- package/src/lib/services/SQL-DixieJS service/sql-parser.ts +35 -0
- package/src/lib/services/database-manager-service/database.manager.service.ts +384 -0
- package/src/lib/services/database-manager-service/db.storage.service.ts +240 -0
- package/src/lib/services/database-manager-service/index.ts +4 -0
- package/src/lib/services/database-manager-service/models/index.ts +2 -0
- package/src/lib/services/database-manager-service/models/table-schema.ts +33 -0
- package/src/lib/services/index.ts +20 -0
- package/src/lib/services/local-storage-manager-service/index.ts +4 -0
- package/src/lib/services/local-storage-manager-service/local-storage-manager.service.spec.ts +71 -0
- package/src/lib/services/local-storage-manager-service/local-storage-manager.service.ts +567 -0
- package/src/lib/services/local-storage-manager-service/local-storage-signals-manager.service.spec.ts +67 -0
- package/src/lib/services/local-storage-manager-service/local-storage-signals-manager.service.ts +437 -0
- package/src/lib/services/local-storage-manager-service/models/global-store-options.model.ts +30 -0
- package/src/lib/services/local-storage-manager-service/models/index.ts +6 -0
- package/src/lib/services/local-storage-manager-service/models/setting-options.model.ts +35 -0
- package/src/lib/services/local-storage-manager-service/models/storage-data.model.ts +24 -0
- package/src/lib/services/local-storage-manager-service/models/storage-option.model.ts +32 -0
- package/src/lib/services/local-storage-manager-service/models/storage-type.enum.ts +5 -0
- package/src/lib/services/request-manager-services/README.md +282 -0
- package/src/lib/services/request-manager-services/http-manager-signals.service.ts +674 -0
- package/src/lib/services/request-manager-services/http-manager.service.spec.ts +353 -0
- package/src/lib/services/request-manager-services/http-manager.service.ts +727 -0
- package/src/lib/services/request-manager-services/index.ts +8 -0
- package/src/lib/services/request-manager-services/request-signals.service.ts +372 -0
- package/src/lib/services/request-manager-services/request.service.ts +435 -0
- package/src/lib/services/request-manager-services/rxjs-operators/countdown.ts +17 -0
- package/src/lib/services/request-manager-services/rxjs-operators/delay-retry.ts +16 -0
- package/src/lib/services/request-manager-services/rxjs-operators/index.ts +4 -0
- package/src/lib/services/request-manager-services/rxjs-operators/request-polling.ts +35 -0
- package/src/lib/services/request-manager-services/rxjs-operators/request-streaming.ts +468 -0
- package/src/lib/services/request-manager-state-service/http-manager-state.store.spec.ts +665 -0
- package/src/lib/services/request-manager-state-service/http-manager-state.store.ts +2395 -0
- package/src/lib/services/request-manager-state-service/index.ts +3 -0
- package/src/lib/services/request-manager-state-service/models/api-request.model.ts +86 -0
- package/src/lib/services/request-manager-state-service/models/index.ts +14 -0
- package/src/lib/services/request-manager-state-service/models/operation-result.model.ts +18 -0
- package/src/lib/services/request-manager-state-service/models/parsing-result.model.ts +21 -0
- package/src/lib/services/request-manager-state-service/models/request-options.model.ts +37 -0
- package/src/lib/services/request-manager-state-service/models/stream-config.model.ts +20 -0
- package/src/lib/services/request-manager-state-service/models/stream-event-metadata.model.ts +23 -0
- package/src/lib/services/request-manager-state-service/models/stream-event.model.ts +23 -0
- package/src/lib/services/request-manager-state-service/models/stream-output.model.ts +23 -0
- package/src/lib/services/request-manager-state-service/models/stream-progress.model.ts +24 -0
- package/src/lib/services/request-manager-state-service/models/stream-type.enum.ts +13 -0
- package/src/lib/services/request-manager-state-service/models/ws-options.model.ts +42 -0
- package/src/lib/services/store-state-manager-service/index.ts +4 -0
- package/src/lib/services/store-state-manager-service/models/index.ts +3 -0
- package/src/lib/services/store-state-manager-service/models/state-operation-result.model.ts +30 -0
- package/src/lib/services/store-state-manager-service/models/state-storage-options.model.ts +24 -0
- package/src/lib/services/store-state-manager-service/store-state-manager-signals.service.ts +169 -0
- package/src/lib/services/store-state-manager-service/store-state-manager.service.ts +153 -0
- package/src/lib/services/utils/app.service.spec.ts +25 -0
- package/src/lib/services/utils/app.service.ts +21 -0
- package/src/lib/services/utils/encryption/README.md +79 -0
- package/src/lib/services/utils/encryption/asymmetrical-encryption.service.ts +282 -0
- package/src/lib/services/utils/encryption/encryption-test.service.ts +39 -0
- package/src/lib/services/utils/encryption/index.ts +5 -0
- package/src/lib/services/utils/encryption/random.ts +81 -0
- package/src/lib/services/utils/encryption/symmetrical-encryption.service.ts +106 -0
- package/src/lib/services/utils/headers.service.spec.ts +80 -0
- package/src/lib/services/utils/headers.service.ts +18 -0
- package/src/lib/services/utils/index.ts +9 -0
- package/src/lib/services/utils/logger.service.ts +90 -0
- package/src/lib/services/utils/models/index.ts +4 -0
- package/src/lib/services/utils/models/normalized-request-options.model.ts +24 -0
- package/src/lib/services/utils/models/path-tracker-state.model.ts +20 -0
- package/src/lib/services/utils/models/query-params-tracker-options.model.ts +24 -0
- package/src/lib/services/utils/models/query-tracker-state.model.ts +23 -0
- package/src/lib/services/utils/object-merger.service.spec.ts +18 -0
- package/src/lib/services/utils/object-merger.service.ts +78 -0
- package/src/lib/services/utils/path-query.service.spec.ts +117 -0
- package/src/lib/services/utils/path-query.service.ts +69 -0
- package/src/lib/services/utils/query-params-tracker.service.ts +442 -0
- package/src/lib/services/utils/random-color.utils.ts +83 -0
- package/src/lib/services/utils/utils.service.spec.ts +165 -0
- package/src/lib/services/utils/utils.service.ts +192 -0
- package/src/lib/services/ws-manager-service/index.ts +13 -0
- package/src/lib/services/ws-manager-service/message-tracker-signals.service.ts +147 -0
- package/src/lib/services/ws-manager-service/message-tracker.service.ts +477 -0
- package/src/lib/services/ws-manager-service/models/channel-info.model.ts +29 -0
- package/src/lib/services/ws-manager-service/models/channel-message-data.model.ts +24 -0
- package/src/lib/services/ws-manager-service/models/channel-message.model.ts +36 -0
- package/src/lib/services/ws-manager-service/models/channel-type.enum.ts +6 -0
- package/src/lib/services/ws-manager-service/models/communication-type.enum.ts +5 -0
- package/src/lib/services/ws-manager-service/models/index.ts +10 -0
- package/src/lib/services/ws-manager-service/models/notification-message.model.ts +29 -0
- package/src/lib/services/ws-manager-service/models/public-message.model.ts +18 -0
- package/src/lib/services/ws-manager-service/models/state-message.model.ts +18 -0
- package/src/lib/services/ws-manager-service/models/ws-user.model.ts +38 -0
- package/src/lib/services/ws-manager-service/services/index.ts +4 -0
- package/src/lib/services/ws-manager-service/services/websocket-message.service.ts +129 -0
- package/src/lib/services/ws-manager-service/services/websocket.service.ts +434 -0
- package/src/lib/services/ws-manager-service/websocket-service/index.ts +1 -0
- package/src/lib/services/ws-manager-service/websocket-service/websocket-manager.service.ts +716 -0
- package/src/lib/services/ws-manager-service/websocket-services-complete.spec.ts +596 -0
- package/src/lib/services/ws-manager-service/websocket-signals-manager.service.ts +141 -0
- package/src/public-api.ts +19 -0
- package/tsconfig.lib.json +34 -0
- package/tsconfig.lib.prod.json +10 -0
- package/tsconfig.spec.json +14 -0
- package/fesm2022/http-request-manager.mjs +0 -13297
- package/fesm2022/http-request-manager.mjs.map +0 -1
- package/http-request-manager-18.15.32.tgz +0 -0
- package/types/http-request-manager.d.ts +0 -3875
|
@@ -0,0 +1,1195 @@
|
|
|
1
|
+
# Database Manager Service
|
|
2
|
+
|
|
3
|
+
The `DatabaseManagerService` is a wrapper service for Dexie.js that provides IndexedDB interactions using RxJS Observables. It enables offline-first applications with sophisticated local data storage and querying capabilities.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This service provides:
|
|
8
|
+
|
|
9
|
+
- **IndexedDB Management** - Complete wrapper around Dexie.js for IndexedDB operations
|
|
10
|
+
- **Observable API** - All operations return Observables for reactive programming
|
|
11
|
+
- **Table Management** - Create and manage database tables with flexible schemas
|
|
12
|
+
- **CRUD Operations** - Full support for Create, Read, Update, Delete operations
|
|
13
|
+
- **Querying** - Advanced querying capabilities with filtering and sorting
|
|
14
|
+
- **Bulk Operations** - Optimized methods for batch operations
|
|
15
|
+
- **Schema Inspection** - Check table existence and retrieve schema definitions
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { HttpRequestManagerModule } from 'http-request-manager';
|
|
21
|
+
|
|
22
|
+
@NgModule({
|
|
23
|
+
imports: [HttpRequestManagerModule.forRoot({})]
|
|
24
|
+
})
|
|
25
|
+
export class AppModule { }
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Basic Usage
|
|
29
|
+
|
|
30
|
+
### Service Injection
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { Component, inject } from '@angular/core';
|
|
34
|
+
import { DatabaseManagerService, TableSchemaDef } from 'http-request-manager';
|
|
35
|
+
|
|
36
|
+
@Component({
|
|
37
|
+
selector: 'app-database-demo',
|
|
38
|
+
template: `
|
|
39
|
+
<div class="database-demo">
|
|
40
|
+
<h2>Database Operations Demo</h2>
|
|
41
|
+
|
|
42
|
+
<div class="actions">
|
|
43
|
+
<button (click)="initializeTables()">Initialize Tables</button>
|
|
44
|
+
<button (click)="addSampleData()">Add Sample Data</button>
|
|
45
|
+
<button (click)="loadData()">Load Data</button>
|
|
46
|
+
<button (click)="clearData()">Clear All</button>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<div class="status">
|
|
50
|
+
<p>Loading: {{ isLoading ? 'Yes' : 'No' }}</p>
|
|
51
|
+
<p>Table Status: {{ tableStatus }}</p>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<div class="data-display" *ngIf="data.length > 0">
|
|
55
|
+
<h3>Stored Data ({{ data.length }} records)</h3>
|
|
56
|
+
<div *ngFor="let item of data" class="data-item">
|
|
57
|
+
<strong>{{ item.name }}</strong> - {{ item.email }}
|
|
58
|
+
<button (click)="deleteItem(item.id)">Delete</button>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<div class="search-section">
|
|
63
|
+
<h3>Search</h3>
|
|
64
|
+
<input [(ngModel)]="searchQuery" placeholder="Search by name...">
|
|
65
|
+
<button (click)="search()">Search</button>
|
|
66
|
+
<div *ngFor="let result of searchResults" class="search-result">
|
|
67
|
+
{{ result.name }} - {{ result.email }}
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
`
|
|
72
|
+
})
|
|
73
|
+
export class DatabaseDemoComponent {
|
|
74
|
+
private dbManager = inject(DatabaseManagerService);
|
|
75
|
+
|
|
76
|
+
data: any[] = [];
|
|
77
|
+
searchResults: any[] = [];
|
|
78
|
+
searchQuery = '';
|
|
79
|
+
isLoading = false;
|
|
80
|
+
tableStatus = 'Not initialized';
|
|
81
|
+
|
|
82
|
+
initializeTables() {
|
|
83
|
+
const tableDef = TableSchemaDef.adapt({
|
|
84
|
+
table: 'users',
|
|
85
|
+
schema: '++id, name, email, age, createdAt'
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
this.dbManager.createDatabaseTable(tableDef).subscribe({
|
|
89
|
+
next: () => {
|
|
90
|
+
this.tableStatus = 'Table created successfully';
|
|
91
|
+
console.log('Users table initialized');
|
|
92
|
+
},
|
|
93
|
+
error: (error) => {
|
|
94
|
+
this.tableStatus = `Error: ${error.message}`;
|
|
95
|
+
console.error('Table creation failed:', error);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
addSampleData() {
|
|
101
|
+
const users = [
|
|
102
|
+
{ name: 'John Doe', email: 'john@example.com', age: 30, createdAt: new Date() },
|
|
103
|
+
{ name: 'Jane Smith', email: 'jane@example.com', age: 25, createdAt: new Date() },
|
|
104
|
+
{ name: 'Bob Johnson', email: 'bob@example.com', age: 35, createdAt: new Date() }
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
this.dbManager.createTableRecords('users', users).subscribe({
|
|
108
|
+
next: () => {
|
|
109
|
+
console.log('Sample data added');
|
|
110
|
+
this.loadData();
|
|
111
|
+
},
|
|
112
|
+
error: (error) => console.error('Failed to add data:', error)
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
loadData() {
|
|
117
|
+
this.isLoading = true;
|
|
118
|
+
this.dbManager.getTableRecords('users').subscribe({
|
|
119
|
+
next: (users) => {
|
|
120
|
+
this.data = users;
|
|
121
|
+
this.isLoading = false;
|
|
122
|
+
console.log('Data loaded:', users);
|
|
123
|
+
},
|
|
124
|
+
error: (error) => {
|
|
125
|
+
console.error('Failed to load data:', error);
|
|
126
|
+
this.isLoading = false;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
deleteItem(id: number) {
|
|
132
|
+
this.dbManager.deleteTableRecord('users', id).subscribe({
|
|
133
|
+
next: () => {
|
|
134
|
+
console.log('Record deleted');
|
|
135
|
+
this.loadData();
|
|
136
|
+
},
|
|
137
|
+
error: (error) => console.error('Delete failed:', error)
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
search() {
|
|
142
|
+
if (this.searchQuery.trim()) {
|
|
143
|
+
this.dbManager.findTableRecords('users', 'name', this.searchQuery).subscribe({
|
|
144
|
+
next: (results) => {
|
|
145
|
+
this.searchResults = results;
|
|
146
|
+
console.log('Search results:', results);
|
|
147
|
+
},
|
|
148
|
+
error: (error) => console.error('Search failed:', error)
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
clearData() {
|
|
154
|
+
// Clear only the 'users' table (Observable - subscribe to complete)
|
|
155
|
+
this.dbManager.clearTable('users').subscribe({
|
|
156
|
+
next: () => {
|
|
157
|
+
this.data = [];
|
|
158
|
+
this.searchResults = [];
|
|
159
|
+
console.log('All user records cleared');
|
|
160
|
+
},
|
|
161
|
+
error: (error) => console.error('Clear failed:', error)
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
// To wipe the entire IndexedDB and clear the library's localStorage metadata (query trackers, expirations, etc.), call:
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
// Fire-and-forget - subscription handled internally
|
|
171
|
+
this.dbManager.clearDatabase();
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
This will delete the DB, clear the in-memory state and also invoke `LocalStorageManagerService.clearAllStoredData()` to remove metadata stored in localStorage.
|
|
175
|
+
|
|
176
|
+
Service to use for these operations:
|
|
177
|
+
|
|
178
|
+
- **`DatabaseManagerService`** — provides table-level CRUD and maintenance methods (`createTableRecords`, `getTableRecords`, `clearTable`, `deleteTableRecord`, etc.) and a convenience `clearDatabase()` method which wipes the whole DB and related localStorage metadata.
|
|
179
|
+
|
|
180
|
+
Notes:
|
|
181
|
+
|
|
182
|
+
- `clearDatabase()` subscribes internally and is fire-and-forget. Call it directly with `this.dbManager.clearDatabase()` (no `.subscribe()` required).
|
|
183
|
+
- Table-level methods such as `clearTable(table)` return `Observable`s and should be subscribed to by callers when they need to react to completion.
|
|
184
|
+
|
|
185
|
+
## API Reference
|
|
186
|
+
|
|
187
|
+
### Table Management
|
|
188
|
+
|
|
189
|
+
#### createDatabaseTable(tableDef: TableSchemaDef): Observable<void>
|
|
190
|
+
|
|
191
|
+
Create a new database table:
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
const tableDef = TableSchemaDef.adapt({
|
|
195
|
+
table: 'products',
|
|
196
|
+
schema: '++id, name, price, category, createdAt'
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
this.dbManager.createDatabaseTable(tableDef).subscribe(() => {
|
|
200
|
+
console.log('Products table created');
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
#### hasDatabaseTable(tableName: string): Observable<boolean>
|
|
205
|
+
|
|
206
|
+
Check if table exists:
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
this.dbManager.hasDatabaseTable('users').subscribe(exists => {
|
|
210
|
+
if (exists) {
|
|
211
|
+
console.log('Users table exists');
|
|
212
|
+
} else {
|
|
213
|
+
console.log('Users table does not exist');
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
#### getTableSchema(tableName: string): Observable<any>
|
|
219
|
+
|
|
220
|
+
Get table schema definition:
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
this.dbManager.getTableSchema('users').subscribe(schema => {
|
|
224
|
+
console.log('Table schema:', schema);
|
|
225
|
+
});
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### CRUD Operations
|
|
229
|
+
|
|
230
|
+
#### createTableRecord(tableName: string, data: any): Observable<any>
|
|
231
|
+
|
|
232
|
+
Create a single record:
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
this.dbManager.createTableRecord('users', {
|
|
236
|
+
name: 'John Doe',
|
|
237
|
+
email: 'john@example.com',
|
|
238
|
+
age: 30
|
|
239
|
+
}).subscribe(createdRecord => {
|
|
240
|
+
console.log('Record created with ID:', createdRecord.id);
|
|
241
|
+
});
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
#### createTableRecords(tableName: string, dataArray: any[]): Observable<any[]>
|
|
245
|
+
|
|
246
|
+
Create multiple records:
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
const users = [
|
|
250
|
+
{ name: 'John Doe', email: 'john@example.com', age: 30 },
|
|
251
|
+
{ name: 'Jane Smith', email: 'jane@example.com', age: 25 },
|
|
252
|
+
{ name: 'Bob Johnson', email: 'bob@example.com', age: 35 }
|
|
253
|
+
];
|
|
254
|
+
|
|
255
|
+
this.dbManager.createTableRecords('users', users).subscribe(createdRecords => {
|
|
256
|
+
console.log('Created', createdRecords.length, 'records');
|
|
257
|
+
});
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
#### getTableRecords(tableName: string): Observable<any[]>
|
|
261
|
+
|
|
262
|
+
Get all records from a table:
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
this.dbManager.getTableRecords('users').subscribe(users => {
|
|
266
|
+
console.log('All users:', users);
|
|
267
|
+
});
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
#### getTableRecord(tableName: string, id: any): Observable<any>
|
|
271
|
+
|
|
272
|
+
Get a specific record by ID:
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
this.dbManager.getTableRecord('users', 1).subscribe(user => {
|
|
276
|
+
console.log('User with ID 1:', user);
|
|
277
|
+
});
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
#### updateTableRecord(tableName: string, data: any): Observable<any>
|
|
281
|
+
|
|
282
|
+
Update an existing record:
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
this.dbManager.updateTableRecord('users', {
|
|
286
|
+
id: 1,
|
|
287
|
+
name: 'John Smith',
|
|
288
|
+
email: 'john.smith@example.com',
|
|
289
|
+
age: 31
|
|
290
|
+
}).subscribe(updatedRecord => {
|
|
291
|
+
console.log('Updated record:', updatedRecord);
|
|
292
|
+
});
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
#### deleteTableRecord(tableName: string, id: any): Observable<void>
|
|
296
|
+
|
|
297
|
+
Delete a record by ID:
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
this.dbManager.deleteTableRecord('users', 1).subscribe(() => {
|
|
301
|
+
console.log('Record deleted');
|
|
302
|
+
});
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Querying Operations
|
|
306
|
+
|
|
307
|
+
#### findTableRecords(tableName: string, field: string, value: any): Observable<any[]>
|
|
308
|
+
|
|
309
|
+
Find records by field value:
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
// Find users by age
|
|
313
|
+
this.dbManager.findTableRecords('users', 'age', 30).subscribe(users => {
|
|
314
|
+
console.log('Users aged 30:', users);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// Find users by name (partial match)
|
|
318
|
+
this.dbManager.findTableRecords('users', 'name', 'John').subscribe(users => {
|
|
319
|
+
console.log('Users with "John" in name:', users);
|
|
320
|
+
});
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
#### queryTableRecords(tableName: string, queryFn: Function): Observable<any[]>
|
|
324
|
+
|
|
325
|
+
Execute custom queries:
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
this.dbManager.queryTableRecords('users', (table) => {
|
|
329
|
+
return table
|
|
330
|
+
.where('age')
|
|
331
|
+
.above(25)
|
|
332
|
+
.sortBy('name');
|
|
333
|
+
}).subscribe(users => {
|
|
334
|
+
console.log('Users over 25, sorted by name:', users);
|
|
335
|
+
});
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
#### countTableRecords(tableName: string): Observable<number>
|
|
339
|
+
|
|
340
|
+
Count records in a table:
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
this.dbManager.countTableRecords('users').subscribe(count => {
|
|
344
|
+
console.log('Total users:', count);
|
|
345
|
+
});
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Bulk Operations
|
|
349
|
+
|
|
350
|
+
#### bulkCreateTableRecords(tableName: string, dataArray: any[]): Observable<any[]>
|
|
351
|
+
|
|
352
|
+
Optimized bulk insert:
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
const largeDataset = Array.from({length: 1000}, (_, i) => ({
|
|
356
|
+
name: `User ${i}`,
|
|
357
|
+
email: `user${i}@example.com`,
|
|
358
|
+
age: Math.floor(Math.random() * 50) + 18
|
|
359
|
+
}));
|
|
360
|
+
|
|
361
|
+
this.dbManager.bulkCreateTableRecords('users', largeDataset).subscribe(result => {
|
|
362
|
+
console.log('Bulk insert completed:', result.length, 'records');
|
|
363
|
+
});
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
#### bulkDeleteTableRecords(tableName: string, ids: any[]): Observable<void>
|
|
367
|
+
|
|
368
|
+
Bulk delete by IDs:
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
const idsToDelete = [1, 2, 3, 4, 5];
|
|
372
|
+
|
|
373
|
+
this.dbManager.bulkDeleteTableRecords('users', idsToDelete).subscribe(() => {
|
|
374
|
+
console.log('Bulk delete completed');
|
|
375
|
+
});
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Table Maintenance
|
|
379
|
+
|
|
380
|
+
#### clearTable(table: string): Observable<any>
|
|
381
|
+
|
|
382
|
+
Clear all records from a table:
|
|
383
|
+
|
|
384
|
+
```typescript
|
|
385
|
+
this.dbManager.clearTable('users').subscribe(() => {
|
|
386
|
+
console.log('All user records cleared');
|
|
387
|
+
});
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
#### deleteDatabaseTable(tableName: string): Observable<void>
|
|
391
|
+
|
|
392
|
+
Delete an entire table:
|
|
393
|
+
|
|
394
|
+
```typescript
|
|
395
|
+
this.dbManager.deleteDatabaseTable('old_table').subscribe(() => {
|
|
396
|
+
console.log('Table deleted');
|
|
397
|
+
});
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
## Configuration
|
|
401
|
+
|
|
402
|
+
### Table Schema Definition
|
|
403
|
+
|
|
404
|
+
```typescript
|
|
405
|
+
interface TableSchemaDef {
|
|
406
|
+
table: string; // Table name
|
|
407
|
+
schema: string; // Dexie schema syntax
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Common schema patterns
|
|
411
|
+
const schemas = {
|
|
412
|
+
// Simple table with auto-increment ID
|
|
413
|
+
simple: '++id, name, email',
|
|
414
|
+
|
|
415
|
+
// Table with custom primary key
|
|
416
|
+
customKey: 'id, name, email',
|
|
417
|
+
|
|
418
|
+
// Table with indexes
|
|
419
|
+
indexed: '++id, name, email, age',
|
|
420
|
+
|
|
421
|
+
// Table with compound indexes
|
|
422
|
+
compound: '++id, [firstName+lastName], email, age',
|
|
423
|
+
|
|
424
|
+
// Table with dates and complex types
|
|
425
|
+
complex: '++id, name, email, createdAt, metadata'
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
// Create schema definition
|
|
429
|
+
const tableDef = TableSchemaDef.adapt({
|
|
430
|
+
table: 'users',
|
|
431
|
+
schema: '++id, name, email, age, createdAt'
|
|
432
|
+
});
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### Schema Syntax Reference
|
|
436
|
+
|
|
437
|
+
| Syntax | Description | Example |
|
|
438
|
+
|--------|-------------|---------|
|
|
439
|
+
| `++id` | Auto-increment primary key | `++id` |
|
|
440
|
+
| `id` | String/increment primary key | `id` |
|
|
441
|
+
| `name` | Indexed field | `name` |
|
|
442
|
+
| `[field1+field2]` | Compound index | `[firstName+lastName]` |
|
|
443
|
+
| `*tags` | Multi-entry index | `*tags` |
|
|
444
|
+
|
|
445
|
+
## Advanced Examples
|
|
446
|
+
|
|
447
|
+
### E-commerce Product Catalog
|
|
448
|
+
|
|
449
|
+
```typescript
|
|
450
|
+
@Injectable()
|
|
451
|
+
export class ProductCatalogService {
|
|
452
|
+
private dbManager = inject(DatabaseManagerService);
|
|
453
|
+
|
|
454
|
+
constructor() {
|
|
455
|
+
this.initializeProductTables();
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
private initializeProductTables() {
|
|
459
|
+
// Products table
|
|
460
|
+
const productSchema = TableSchemaDef.adapt({
|
|
461
|
+
table: 'products',
|
|
462
|
+
schema: '++id, name, description, price, categoryId, brand, tags, createdAt, updatedAt'
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
// Categories table
|
|
466
|
+
const categorySchema = TableSchemaDef.adapt({
|
|
467
|
+
table: 'categories',
|
|
468
|
+
schema: '++id, name, description, parentId'
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
// Reviews table
|
|
472
|
+
const reviewSchema = TableSchemaDef.adapt({
|
|
473
|
+
table: 'reviews',
|
|
474
|
+
schema: '++id, productId, userId, rating, comment, createdAt'
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
// Initialize all tables
|
|
478
|
+
[productSchema, categorySchema, reviewSchema].forEach(schema => {
|
|
479
|
+
this.dbManager.createDatabaseTable(schema).subscribe({
|
|
480
|
+
next: () => console.log(`Table ${schema.table} initialized`),
|
|
481
|
+
error: (error) => console.error(`Failed to create ${schema.table}:`, error)
|
|
482
|
+
});
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Product operations
|
|
487
|
+
addProduct(product: any) {
|
|
488
|
+
return this.dbManager.createTableRecord('products', {
|
|
489
|
+
...product,
|
|
490
|
+
createdAt: new Date(),
|
|
491
|
+
updatedAt: new Date()
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
getProduct(id: number) {
|
|
496
|
+
return this.dbManager.getTableRecord('products', id);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
getAllProducts() {
|
|
500
|
+
return this.dbManager.getTableRecords('products');
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
updateProduct(product: any) {
|
|
504
|
+
return this.dbManager.updateTableRecord('products', {
|
|
505
|
+
...product,
|
|
506
|
+
updatedAt: new Date()
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
deleteProduct(id: number) {
|
|
511
|
+
// Delete product and its reviews
|
|
512
|
+
return this.dbManager.deleteTableRecord('products', id).pipe(
|
|
513
|
+
switchMap(() => this.dbManager.queryTableRecords('reviews', (table) =>
|
|
514
|
+
table.where('productId').equals(id).delete()
|
|
515
|
+
))
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Search and filtering
|
|
520
|
+
searchProducts(query: string) {
|
|
521
|
+
return this.dbManager.queryTableRecords('products', (table) => {
|
|
522
|
+
return table
|
|
523
|
+
.filter(product =>
|
|
524
|
+
product.name.toLowerCase().includes(query.toLowerCase()) ||
|
|
525
|
+
product.description.toLowerCase().includes(query.toLowerCase())
|
|
526
|
+
)
|
|
527
|
+
.sortBy('name');
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
getProductsByCategory(categoryId: number) {
|
|
532
|
+
return this.dbManager.findTableRecords('products', 'categoryId', categoryId);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
getProductsByPriceRange(minPrice: number, maxPrice: number) {
|
|
536
|
+
return this.dbManager.queryTableRecords('products', (table) => {
|
|
537
|
+
return table
|
|
538
|
+
.where('price')
|
|
539
|
+
.between(minPrice, maxPrice)
|
|
540
|
+
.sortBy('price');
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
getPopularProducts(limit: number = 10) {
|
|
545
|
+
return this.dbManager.queryTableRecords('reviews', (table) => {
|
|
546
|
+
return table
|
|
547
|
+
.toArray()
|
|
548
|
+
.then(reviews => {
|
|
549
|
+
// Calculate average ratings
|
|
550
|
+
const productRatings = new Map();
|
|
551
|
+
reviews.forEach(review => {
|
|
552
|
+
const current = productRatings.get(review.productId) || { total: 0, count: 0 };
|
|
553
|
+
productRatings.set(review.productId, {
|
|
554
|
+
total: current.total + review.rating,
|
|
555
|
+
count: current.count + 1
|
|
556
|
+
});
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
// Get top rated products
|
|
560
|
+
const topRated = Array.from(productRatings.entries())
|
|
561
|
+
.map(([productId, rating]) => ({
|
|
562
|
+
productId,
|
|
563
|
+
averageRating: rating.total / rating.count,
|
|
564
|
+
reviewCount: rating.count
|
|
565
|
+
}))
|
|
566
|
+
.sort((a, b) => b.averageRating - a.averageRating)
|
|
567
|
+
.slice(0, limit);
|
|
568
|
+
|
|
569
|
+
return topRated;
|
|
570
|
+
});
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
### Offline-First User Profile Management
|
|
577
|
+
|
|
578
|
+
```typescript
|
|
579
|
+
@Injectable()
|
|
580
|
+
export class UserProfileService {
|
|
581
|
+
private dbManager = inject(DatabaseManagerService);
|
|
582
|
+
private syncQueue: any[] = [];
|
|
583
|
+
|
|
584
|
+
constructor() {
|
|
585
|
+
this.initializeUserTables();
|
|
586
|
+
this.setupOnlineSync();
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
private initializeUserTables() {
|
|
590
|
+
const userSchema = TableSchemaDef.adapt({
|
|
591
|
+
table: 'user_profiles',
|
|
592
|
+
schema: '++id, userId, email, profileData, lastSyncAt, isDirty'
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
const activitySchema = TableSchemaDef.adapt({
|
|
596
|
+
table: 'user_activities',
|
|
597
|
+
schema: '++id, userId, activityType, data, timestamp'
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
[userSchema, activitySchema].forEach(schema => {
|
|
601
|
+
this.dbManager.createDatabaseTable(schema).subscribe({
|
|
602
|
+
next: () => console.log(`Table ${schema.table} initialized`),
|
|
603
|
+
error: (error) => console.error(`Failed to create ${schema.table}:`, error)
|
|
604
|
+
});
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// Profile management
|
|
609
|
+
saveProfile(userId: string, profileData: any) {
|
|
610
|
+
const profile = {
|
|
611
|
+
userId,
|
|
612
|
+
email: profileData.email,
|
|
613
|
+
profileData,
|
|
614
|
+
lastSyncAt: new Date(),
|
|
615
|
+
isDirty: !navigator.onLine // Mark as dirty if offline
|
|
616
|
+
};
|
|
617
|
+
|
|
618
|
+
return this.dbManager.createTableRecord('user_profiles', profile).pipe(
|
|
619
|
+
tap(() => {
|
|
620
|
+
if (!navigator.onLine) {
|
|
621
|
+
this.syncQueue.push({ action: 'create', data: profile });
|
|
622
|
+
this.saveSyncQueue();
|
|
623
|
+
}
|
|
624
|
+
})
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
getProfile(userId: string) {
|
|
629
|
+
return this.dbManager.findTableRecords('user_profiles', 'userId', userId).pipe(
|
|
630
|
+
map(profiles => profiles[0] || null)
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
updateProfile(userId: string, updates: any) {
|
|
635
|
+
return this.getProfile(userId).pipe(
|
|
636
|
+
switchMap(profile => {
|
|
637
|
+
if (!profile) {
|
|
638
|
+
throw new Error('Profile not found');
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
const updatedProfile = {
|
|
642
|
+
...profile,
|
|
643
|
+
...updates,
|
|
644
|
+
lastSyncAt: new Date(),
|
|
645
|
+
isDirty: !navigator.onLine
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
return this.dbManager.updateTableRecord('user_profiles', updatedProfile).pipe(
|
|
649
|
+
tap(() => {
|
|
650
|
+
if (!navigator.onLine) {
|
|
651
|
+
this.syncQueue.push({ action: 'update', data: updatedProfile });
|
|
652
|
+
this.saveSyncQueue();
|
|
653
|
+
}
|
|
654
|
+
})
|
|
655
|
+
);
|
|
656
|
+
})
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// Activity tracking
|
|
661
|
+
logActivity(userId: string, activityType: string, data: any) {
|
|
662
|
+
const activity = {
|
|
663
|
+
userId,
|
|
664
|
+
activityType,
|
|
665
|
+
data,
|
|
666
|
+
timestamp: new Date()
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
return this.dbManager.createTableRecord('user_activities', activity);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
getUserActivities(userId: string, limit: number = 50) {
|
|
673
|
+
return this.dbManager.queryTableRecords('user_activities', (table) => {
|
|
674
|
+
return table
|
|
675
|
+
.where('userId')
|
|
676
|
+
.equals(userId)
|
|
677
|
+
.reverse()
|
|
678
|
+
.limit(limit)
|
|
679
|
+
.toArray();
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// Sync management
|
|
684
|
+
private setupOnlineSync() {
|
|
685
|
+
window.addEventListener('online', () => {
|
|
686
|
+
console.log('Back online, syncing data...');
|
|
687
|
+
this.syncPendingChanges();
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
private syncPendingChanges() {
|
|
692
|
+
const queue = this.loadSyncQueue();
|
|
693
|
+
|
|
694
|
+
queue.forEach(item => {
|
|
695
|
+
switch (item.action) {
|
|
696
|
+
case 'create':
|
|
697
|
+
this.syncCreate(item.data);
|
|
698
|
+
break;
|
|
699
|
+
case 'update':
|
|
700
|
+
this.syncUpdate(item.data);
|
|
701
|
+
break;
|
|
702
|
+
case 'delete':
|
|
703
|
+
this.syncDelete(item.data);
|
|
704
|
+
break;
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
|
|
708
|
+
// Clear queue after successful sync
|
|
709
|
+
this.syncQueue = [];
|
|
710
|
+
this.saveSyncQueue();
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
private syncCreate(data: any) {
|
|
714
|
+
// Sync with server API
|
|
715
|
+
console.log('Syncing create operation:', data);
|
|
716
|
+
// Implementation would depend on your API
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
private syncUpdate(data: any) {
|
|
720
|
+
// Sync with server API
|
|
721
|
+
console.log('Syncing update operation:', data);
|
|
722
|
+
// Implementation would depend on your API
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
private syncDelete(data: any) {
|
|
726
|
+
// Sync with server API
|
|
727
|
+
console.log('Syncing delete operation:', data);
|
|
728
|
+
// Implementation would depend on your API
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
private saveSyncQueue() {
|
|
732
|
+
localStorage.setItem('sync_queue', JSON.stringify(this.syncQueue));
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
private loadSyncQueue(): any[] {
|
|
736
|
+
try {
|
|
737
|
+
const queue = localStorage.getItem('sync_queue');
|
|
738
|
+
return queue ? JSON.parse(queue) : [];
|
|
739
|
+
} catch (error) {
|
|
740
|
+
console.error('Failed to load sync queue:', error);
|
|
741
|
+
return [];
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// Data export/import for backup
|
|
746
|
+
exportUserData(userId: string) {
|
|
747
|
+
return combineLatest([
|
|
748
|
+
this.getProfile(userId),
|
|
749
|
+
this.getUserActivities(userId, 1000) // Export more activities
|
|
750
|
+
]).pipe(
|
|
751
|
+
map(([profile, activities]) => ({
|
|
752
|
+
profile,
|
|
753
|
+
activities,
|
|
754
|
+
exportedAt: new Date().toISOString()
|
|
755
|
+
}))
|
|
756
|
+
);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
importUserData(userId: string, data: any) {
|
|
760
|
+
return this.dbManager.createTableRecords('user_profiles', [data.profile]).pipe(
|
|
761
|
+
switchMap(() =>
|
|
762
|
+
this.dbManager.createTableRecords('user_activities', data.activities)
|
|
763
|
+
)
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
### Real-time Analytics Data Store
|
|
770
|
+
|
|
771
|
+
```typescript
|
|
772
|
+
@Injectable()
|
|
773
|
+
export class AnalyticsDataService {
|
|
774
|
+
private dbManager = inject(DatabaseManagerService);
|
|
775
|
+
private readonly MAX_RECORDS = 10000;
|
|
776
|
+
|
|
777
|
+
constructor() {
|
|
778
|
+
this.initializeAnalyticsTables();
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
private initializeAnalyticsTables() {
|
|
782
|
+
const eventsSchema = TableSchemaDef.adapt({
|
|
783
|
+
table: 'analytics_events',
|
|
784
|
+
schema: '++id, eventType, userId, sessionId, timestamp, data'
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
const sessionsSchema = TableSchemaDef.adapt({
|
|
788
|
+
table: 'analytics_sessions',
|
|
789
|
+
schema: '++id, sessionId, userId, startTime, endTime, duration, pageViews'
|
|
790
|
+
});
|
|
791
|
+
|
|
792
|
+
const metricsSchema = TableSchemaDef.adapt({
|
|
793
|
+
table: 'analytics_metrics',
|
|
794
|
+
schema: '++id, metricName, value, timestamp, dimensions'
|
|
795
|
+
});
|
|
796
|
+
|
|
797
|
+
[eventsSchema, sessionsSchema, metricsSchema].forEach(schema => {
|
|
798
|
+
this.dbManager.createDatabaseTable(schema).subscribe({
|
|
799
|
+
next: () => console.log(`Analytics table ${schema.table} initialized`),
|
|
800
|
+
error: (error) => console.error(`Failed to create analytics table:`, error)
|
|
801
|
+
});
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
// Event tracking
|
|
806
|
+
trackEvent(eventType: string, userId: string, sessionId: string, data: any) {
|
|
807
|
+
const event = {
|
|
808
|
+
eventType,
|
|
809
|
+
userId,
|
|
810
|
+
sessionId,
|
|
811
|
+
timestamp: new Date(),
|
|
812
|
+
data
|
|
813
|
+
};
|
|
814
|
+
|
|
815
|
+
return this.dbManager.createTableRecord('analytics_events', event).pipe(
|
|
816
|
+
tap(() => this.cleanupOldEvents())
|
|
817
|
+
);
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
// Session management
|
|
821
|
+
startSession(userId: string, sessionId: string) {
|
|
822
|
+
const session = {
|
|
823
|
+
sessionId,
|
|
824
|
+
userId,
|
|
825
|
+
startTime: new Date(),
|
|
826
|
+
endTime: null,
|
|
827
|
+
duration: 0,
|
|
828
|
+
pageViews: 0
|
|
829
|
+
};
|
|
830
|
+
|
|
831
|
+
return this.dbManager.createTableRecord('analytics_sessions', session);
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
endSession(sessionId: string) {
|
|
835
|
+
return this.dbManager.queryTableRecords('analytics_sessions', (table) => {
|
|
836
|
+
return table.where('sessionId').equals(sessionId).first();
|
|
837
|
+
}).pipe(
|
|
838
|
+
switchMap(session => {
|
|
839
|
+
if (!session) {
|
|
840
|
+
throw new Error('Session not found');
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
const endTime = new Date();
|
|
844
|
+
const duration = endTime.getTime() - session.startTime.getTime();
|
|
845
|
+
|
|
846
|
+
const updatedSession = {
|
|
847
|
+
...session,
|
|
848
|
+
endTime,
|
|
849
|
+
duration
|
|
850
|
+
};
|
|
851
|
+
|
|
852
|
+
return this.dbManager.updateTableRecord('analytics_sessions', updatedSession);
|
|
853
|
+
})
|
|
854
|
+
);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
// Metrics calculation
|
|
858
|
+
recordMetric(metricName: string, value: number, dimensions: any = {}) {
|
|
859
|
+
const metric = {
|
|
860
|
+
metricName,
|
|
861
|
+
value,
|
|
862
|
+
timestamp: new Date(),
|
|
863
|
+
dimensions
|
|
864
|
+
};
|
|
865
|
+
|
|
866
|
+
return this.dbManager.createTableRecord('analytics_metrics', metric);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
getDailyMetrics(metricName: string, date: Date) {
|
|
870
|
+
const startOfDay = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
871
|
+
const endOfDay = new Date(startOfDay.getTime() + 24 * 60 * 60 * 1000);
|
|
872
|
+
|
|
873
|
+
return this.dbManager.queryTableRecords('analytics_metrics', (table) => {
|
|
874
|
+
return table
|
|
875
|
+
.where('metricName')
|
|
876
|
+
.equals(metricName)
|
|
877
|
+
.and(metric =>
|
|
878
|
+
metric.timestamp >= startOfDay && metric.timestamp < endOfDay
|
|
879
|
+
)
|
|
880
|
+
.toArray();
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
getUserBehaviorReport(userId: string, days: number = 7) {
|
|
885
|
+
const startDate = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
|
|
886
|
+
|
|
887
|
+
return this.dbManager.queryTableRecords('analytics_events', (table) => {
|
|
888
|
+
return table
|
|
889
|
+
.where('userId')
|
|
890
|
+
.equals(userId)
|
|
891
|
+
.and(event => event.timestamp >= startDate)
|
|
892
|
+
.sortBy('timestamp');
|
|
893
|
+
}).pipe(
|
|
894
|
+
map(events => {
|
|
895
|
+
// Process events into meaningful metrics
|
|
896
|
+
const eventCounts = events.reduce((acc, event) => {
|
|
897
|
+
acc[event.eventType] = (acc[event.eventType] || 0) + 1;
|
|
898
|
+
return acc;
|
|
899
|
+
}, {});
|
|
900
|
+
|
|
901
|
+
const sessionData = events.reduce((acc, event) => {
|
|
902
|
+
const sessionId = event.sessionId;
|
|
903
|
+
if (!acc[sessionId]) {
|
|
904
|
+
acc[sessionId] = {
|
|
905
|
+
sessionId,
|
|
906
|
+
eventCount: 0,
|
|
907
|
+
startTime: event.timestamp,
|
|
908
|
+
endTime: event.timestamp,
|
|
909
|
+
duration: 0
|
|
910
|
+
};
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
acc[sessionId].eventCount++;
|
|
914
|
+
acc[sessionId].endTime = event.timestamp;
|
|
915
|
+
acc[sessionId].duration = acc[sessionId].endTime - acc[sessionId].startTime;
|
|
916
|
+
|
|
917
|
+
return acc;
|
|
918
|
+
}, {});
|
|
919
|
+
|
|
920
|
+
return {
|
|
921
|
+
userId,
|
|
922
|
+
period: { startDate, endDate: new Date() },
|
|
923
|
+
totalEvents: events.length,
|
|
924
|
+
eventTypes: eventCounts,
|
|
925
|
+
sessions: Object.values(sessionData),
|
|
926
|
+
averageSessionDuration: Object.values(sessionData).reduce((sum: number, session: any) =>
|
|
927
|
+
sum + session.duration, 0) / Object.keys(sessionData).length
|
|
928
|
+
};
|
|
929
|
+
})
|
|
930
|
+
);
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
// Data cleanup
|
|
934
|
+
private cleanupOldEvents() {
|
|
935
|
+
this.dbManager.countTableRecords('analytics_events').subscribe(count => {
|
|
936
|
+
if (count > this.MAX_RECORDS) {
|
|
937
|
+
const recordsToDelete = count - this.MAX_RECORDS;
|
|
938
|
+
|
|
939
|
+
this.dbManager.queryTableRecords('analytics_events', (table) => {
|
|
940
|
+
return table
|
|
941
|
+
.orderBy('timestamp')
|
|
942
|
+
.limit(recordsToDelete)
|
|
943
|
+
.toArray()
|
|
944
|
+
.then(events => {
|
|
945
|
+
const ids = events.map(event => event.id);
|
|
946
|
+
return this.dbManager.bulkDeleteTableRecords('analytics_events', ids);
|
|
947
|
+
});
|
|
948
|
+
}).subscribe();
|
|
949
|
+
}
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
// Aggregated data for dashboard
|
|
954
|
+
getDashboardMetrics() {
|
|
955
|
+
const today = new Date();
|
|
956
|
+
const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000);
|
|
957
|
+
const weekAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000);
|
|
958
|
+
|
|
959
|
+
return combineLatest([
|
|
960
|
+
this.getDailyMetrics('page_views', today),
|
|
961
|
+
this.getDailyMetrics('page_views', yesterday),
|
|
962
|
+
this.dbManager.queryTableRecords('analytics_sessions', (table) =>
|
|
963
|
+
table.where('startTime').above(weekAgo).toArray()
|
|
964
|
+
)
|
|
965
|
+
]).pipe(
|
|
966
|
+
map(([todayViews, yesterdayViews, weeklySessions]) => ({
|
|
967
|
+
todayViews: todayViews.length,
|
|
968
|
+
yesterdayViews: yesterdayViews.length,
|
|
969
|
+
weeklyActiveUsers: new Set(weeklySessions.map(s => s.userId)).size,
|
|
970
|
+
weeklySessions: weeklySessions.length,
|
|
971
|
+
averageSessionDuration: weeklySessions.reduce((sum, s) => sum + s.duration, 0) / weeklySessions.length
|
|
972
|
+
}))
|
|
973
|
+
);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
```
|
|
977
|
+
|
|
978
|
+
## Performance Optimization
|
|
979
|
+
|
|
980
|
+
### Indexing Strategy
|
|
981
|
+
|
|
982
|
+
```typescript
|
|
983
|
+
// ✅ Good - Proper indexing
|
|
984
|
+
const wellIndexedSchema = TableSchemaDef.adapt({
|
|
985
|
+
table: 'products',
|
|
986
|
+
schema: `
|
|
987
|
+
++id,
|
|
988
|
+
name,
|
|
989
|
+
price,
|
|
990
|
+
categoryId,
|
|
991
|
+
[categoryId+brand],
|
|
992
|
+
*tags,
|
|
993
|
+
createdAt
|
|
994
|
+
`
|
|
995
|
+
});
|
|
996
|
+
|
|
997
|
+
// ❌ Avoid - No indexes on frequently queried fields
|
|
998
|
+
const poorSchema = TableSchemaDef.adapt({
|
|
999
|
+
table: 'products',
|
|
1000
|
+
schema: '++id, name, price, categoryId, description'
|
|
1001
|
+
});
|
|
1002
|
+
```
|
|
1003
|
+
|
|
1004
|
+
### Batch Operations
|
|
1005
|
+
|
|
1006
|
+
```typescript
|
|
1007
|
+
@Injectable()
|
|
1008
|
+
export class OptimizedDataService {
|
|
1009
|
+
private dbManager = inject(DatabaseManagerService);
|
|
1010
|
+
|
|
1011
|
+
// Batch insert for better performance
|
|
1012
|
+
bulkInsertUsers(users: any[]) {
|
|
1013
|
+
// Process in chunks to avoid memory issues
|
|
1014
|
+
const chunkSize = 100;
|
|
1015
|
+
const chunks = this.chunkArray(users, chunkSize);
|
|
1016
|
+
|
|
1017
|
+
return from(chunks).pipe(
|
|
1018
|
+
mergeMap(chunk =>
|
|
1019
|
+
this.dbManager.bulkCreateTableRecords('users', chunk),
|
|
1020
|
+
2 // Process 2 chunks concurrently
|
|
1021
|
+
)
|
|
1022
|
+
);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
// Efficient searching
|
|
1026
|
+
searchUsersAdvanced(query: string, filters: any) {
|
|
1027
|
+
return this.dbManager.queryTableRecords('users', (table) => {
|
|
1028
|
+
let result = table.toCollection();
|
|
1029
|
+
|
|
1030
|
+
// Apply filters efficiently using indexes
|
|
1031
|
+
if (filters.ageMin !== undefined) {
|
|
1032
|
+
result = result.and(user => user.age >= filters.ageMin);
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
if (filters.ageMax !== undefined) {
|
|
1036
|
+
result = result.and(user => user.age <= filters.ageMax);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
if (query) {
|
|
1040
|
+
result = result.and(user =>
|
|
1041
|
+
user.name.toLowerCase().includes(query.toLowerCase()) ||
|
|
1042
|
+
user.email.toLowerCase().includes(query.toLowerCase())
|
|
1043
|
+
);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
return result.sortBy('name');
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
private chunkArray(array: any[], size: number): any[][] {
|
|
1051
|
+
const chunks = [];
|
|
1052
|
+
for (let i = 0; i < array.length; i += size) {
|
|
1053
|
+
chunks.push(array.slice(i, i + size));
|
|
1054
|
+
}
|
|
1055
|
+
return chunks;
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
```
|
|
1059
|
+
|
|
1060
|
+
## Best Practices
|
|
1061
|
+
|
|
1062
|
+
### 1. Schema Design
|
|
1063
|
+
|
|
1064
|
+
```typescript
|
|
1065
|
+
// ✅ Good - Well-designed schema
|
|
1066
|
+
const goodSchema = TableSchemaDef.adapt({
|
|
1067
|
+
table: 'ecommerce_products',
|
|
1068
|
+
schema: `
|
|
1069
|
+
++id, // Auto-increment ID
|
|
1070
|
+
name, // Searchable field
|
|
1071
|
+
price, // Filterable field
|
|
1072
|
+
categoryId, // Foreign key
|
|
1073
|
+
[categoryId+brand], // Compound index for common queries
|
|
1074
|
+
*tags, // Multi-entry for filtering
|
|
1075
|
+
createdAt, // Timestamp for sorting
|
|
1076
|
+
updatedAt // Change tracking
|
|
1077
|
+
`
|
|
1078
|
+
});
|
|
1079
|
+
|
|
1080
|
+
// ❌ Avoid - Poor schema design
|
|
1081
|
+
const badSchema = TableSchemaDef.adapt({
|
|
1082
|
+
table: 'products',
|
|
1083
|
+
schema: '++id, name, price, description, category, brand, tags, created, updated'
|
|
1084
|
+
});
|
|
1085
|
+
```
|
|
1086
|
+
|
|
1087
|
+
### 2. Error Handling
|
|
1088
|
+
|
|
1089
|
+
```typescript
|
|
1090
|
+
// ✅ Good - Comprehensive error handling
|
|
1091
|
+
addUser(user: any) {
|
|
1092
|
+
return this.dbManager.createTableRecord('users', user).pipe(
|
|
1093
|
+
catchError(error => {
|
|
1094
|
+
if (error.name === 'ConstraintError') {
|
|
1095
|
+
return throwError(() => new Error('User already exists'));
|
|
1096
|
+
}
|
|
1097
|
+
return throwError(() => new Error('Database operation failed'));
|
|
1098
|
+
})
|
|
1099
|
+
);
|
|
1100
|
+
}
|
|
1101
|
+
```
|
|
1102
|
+
|
|
1103
|
+
### 3. Memory Management
|
|
1104
|
+
|
|
1105
|
+
```typescript
|
|
1106
|
+
// ✅ Good - Limit query results
|
|
1107
|
+
getRecentUsers(limit: number = 50) {
|
|
1108
|
+
return this.dbManager.queryTableRecords('users', (table) => {
|
|
1109
|
+
return table
|
|
1110
|
+
.orderBy('createdAt')
|
|
1111
|
+
.reverse()
|
|
1112
|
+
.limit(limit)
|
|
1113
|
+
.toArray();
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1116
|
+
```
|
|
1117
|
+
|
|
1118
|
+
## Troubleshooting
|
|
1119
|
+
|
|
1120
|
+
### Common Issues
|
|
1121
|
+
|
|
1122
|
+
#### 1. Schema Conflicts
|
|
1123
|
+
```typescript
|
|
1124
|
+
// Check existing schema
|
|
1125
|
+
this.dbManager.getTableSchema('users').subscribe(schema => {
|
|
1126
|
+
console.log('Existing schema:', schema);
|
|
1127
|
+
});
|
|
1128
|
+
|
|
1129
|
+
// Handle schema updates carefully
|
|
1130
|
+
// Version your database schema
|
|
1131
|
+
const currentVersion = 1;
|
|
1132
|
+
const newVersion = 2;
|
|
1133
|
+
|
|
1134
|
+
// Implement migration logic
|
|
1135
|
+
if (currentVersion < newVersion) {
|
|
1136
|
+
this.migrateDatabase();
|
|
1137
|
+
}
|
|
1138
|
+
```
|
|
1139
|
+
|
|
1140
|
+
#### 2. Large Dataset Performance
|
|
1141
|
+
```typescript
|
|
1142
|
+
// Use pagination for large datasets
|
|
1143
|
+
getPaginatedUsers(page: number, pageSize: number) {
|
|
1144
|
+
const offset = (page - 1) * pageSize;
|
|
1145
|
+
|
|
1146
|
+
return this.dbManager.queryTableRecords('users', (table) => {
|
|
1147
|
+
return table
|
|
1148
|
+
.offset(offset)
|
|
1149
|
+
.limit(pageSize)
|
|
1150
|
+
.toArray();
|
|
1151
|
+
});
|
|
1152
|
+
}
|
|
1153
|
+
```
|
|
1154
|
+
|
|
1155
|
+
#### 3. Storage Quota
|
|
1156
|
+
```typescript
|
|
1157
|
+
// Monitor storage usage
|
|
1158
|
+
@Injectable()
|
|
1159
|
+
export class StorageMonitorService {
|
|
1160
|
+
private dbManager = inject(DatabaseManagerService);
|
|
1161
|
+
|
|
1162
|
+
checkStorageUsage() {
|
|
1163
|
+
if ('storage' in navigator && 'estimate' in navigator.storage) {
|
|
1164
|
+
navigator.storage.estimate().then(estimate => {
|
|
1165
|
+
const used = estimate.usage || 0;
|
|
1166
|
+
const quota = estimate.quota || 0;
|
|
1167
|
+
const percentage = (used / quota) * 100;
|
|
1168
|
+
|
|
1169
|
+
console.log(`Storage used: ${used} / ${quota} (${percentage.toFixed(2)}%)`);
|
|
1170
|
+
|
|
1171
|
+
if (percentage > 80) {
|
|
1172
|
+
this.cleanupOldData();
|
|
1173
|
+
}
|
|
1174
|
+
});
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
private cleanupOldData() {
|
|
1179
|
+
// Implement cleanup logic
|
|
1180
|
+
const cutoffDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); // 30 days ago
|
|
1181
|
+
|
|
1182
|
+
this.dbManager.queryTableRecords('analytics_events', (table) => {
|
|
1183
|
+
return table.where('timestamp').below(cutoffDate).delete();
|
|
1184
|
+
}).subscribe();
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
```
|
|
1188
|
+
|
|
1189
|
+
## Related Documentation
|
|
1190
|
+
|
|
1191
|
+
- [HTTP State Service](http-state/README.md)
|
|
1192
|
+
- [Local Storage Service](local-storage/README.md)
|
|
1193
|
+
- [Utils Service](utils/README.md)
|
|
1194
|
+
- [Architecture Overview](../architecture/README.md)
|
|
1195
|
+
- [Dexie.js Documentation](https://dexie.org/docs/)
|