http-request-manager 18.7.20 → 18.7.21

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