@rebasepro/server-mongodb 0.0.1-canary.09e5ec5

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 (286) hide show
  1. package/LICENSE +6 -0
  2. package/dist/ensure-collections-CNrcwVgY.js +74 -0
  3. package/dist/ensure-collections-CNrcwVgY.js.map +1 -0
  4. package/dist/ensure-history-collection-DBIiwmCm.js +15 -0
  5. package/dist/ensure-history-collection-DBIiwmCm.js.map +1 -0
  6. package/dist/index.es.js +1734 -0
  7. package/dist/index.es.js.map +1 -0
  8. package/dist/index.umd.js +2043 -0
  9. package/dist/index.umd.js.map +1 -0
  10. package/dist/server-core/src/api/ast-schema-editor.d.ts +22 -0
  11. package/dist/server-core/src/api/ast-schema-editor.d.ts.map +1 -0
  12. package/dist/server-core/src/api/errors.d.ts +36 -0
  13. package/dist/server-core/src/api/errors.d.ts.map +1 -0
  14. package/dist/server-core/src/api/graphql/graphql-schema-generator.d.ts +36 -0
  15. package/dist/server-core/src/api/graphql/graphql-schema-generator.d.ts.map +1 -0
  16. package/dist/server-core/src/api/graphql/index.d.ts +2 -0
  17. package/dist/server-core/src/api/graphql/index.d.ts.map +1 -0
  18. package/dist/server-core/src/api/index.d.ts +10 -0
  19. package/dist/server-core/src/api/index.d.ts.map +1 -0
  20. package/dist/server-core/src/api/openapi-generator.d.ts +17 -0
  21. package/dist/server-core/src/api/openapi-generator.d.ts.map +1 -0
  22. package/dist/server-core/src/api/rest/api-generator.d.ts +65 -0
  23. package/dist/server-core/src/api/rest/api-generator.d.ts.map +1 -0
  24. package/dist/server-core/src/api/rest/index.d.ts +2 -0
  25. package/dist/server-core/src/api/rest/index.d.ts.map +1 -0
  26. package/dist/server-core/src/api/rest/query-parser.d.ts +10 -0
  27. package/dist/server-core/src/api/rest/query-parser.d.ts.map +1 -0
  28. package/dist/server-core/src/api/schema-editor-routes.d.ts +4 -0
  29. package/dist/server-core/src/api/schema-editor-routes.d.ts.map +1 -0
  30. package/dist/server-core/src/api/server.d.ts +41 -0
  31. package/dist/server-core/src/api/server.d.ts.map +1 -0
  32. package/dist/server-core/src/api/types.d.ts +91 -0
  33. package/dist/server-core/src/api/types.d.ts.map +1 -0
  34. package/dist/server-core/src/auth/admin-routes.d.ts +17 -0
  35. package/dist/server-core/src/auth/admin-routes.d.ts.map +1 -0
  36. package/dist/server-core/src/auth/apple-oauth.d.ts +31 -0
  37. package/dist/server-core/src/auth/apple-oauth.d.ts.map +1 -0
  38. package/dist/server-core/src/auth/bitbucket-oauth.d.ts +12 -0
  39. package/dist/server-core/src/auth/bitbucket-oauth.d.ts.map +1 -0
  40. package/dist/server-core/src/auth/discord-oauth.d.ts +15 -0
  41. package/dist/server-core/src/auth/discord-oauth.d.ts.map +1 -0
  42. package/dist/server-core/src/auth/facebook-oauth.d.ts +15 -0
  43. package/dist/server-core/src/auth/facebook-oauth.d.ts.map +1 -0
  44. package/dist/server-core/src/auth/github-oauth.d.ts +16 -0
  45. package/dist/server-core/src/auth/github-oauth.d.ts.map +1 -0
  46. package/dist/server-core/src/auth/gitlab-oauth.d.ts +14 -0
  47. package/dist/server-core/src/auth/gitlab-oauth.d.ts.map +1 -0
  48. package/dist/server-core/src/auth/google-oauth.d.ts +15 -0
  49. package/dist/server-core/src/auth/google-oauth.d.ts.map +1 -0
  50. package/dist/server-core/src/auth/index.d.ts +24 -0
  51. package/dist/server-core/src/auth/index.d.ts.map +1 -0
  52. package/dist/server-core/src/auth/interfaces.d.ts +310 -0
  53. package/dist/server-core/src/auth/interfaces.d.ts.map +1 -0
  54. package/dist/server-core/src/auth/jwt.d.ts +44 -0
  55. package/dist/server-core/src/auth/jwt.d.ts.map +1 -0
  56. package/dist/server-core/src/auth/linkedin-oauth.d.ts +19 -0
  57. package/dist/server-core/src/auth/linkedin-oauth.d.ts.map +1 -0
  58. package/dist/server-core/src/auth/microsoft-oauth.d.ts +17 -0
  59. package/dist/server-core/src/auth/microsoft-oauth.d.ts.map +1 -0
  60. package/dist/server-core/src/auth/middleware.d.ts +82 -0
  61. package/dist/server-core/src/auth/middleware.d.ts.map +1 -0
  62. package/dist/server-core/src/auth/password.d.ts +23 -0
  63. package/dist/server-core/src/auth/password.d.ts.map +1 -0
  64. package/dist/server-core/src/auth/rate-limiter.d.ts +32 -0
  65. package/dist/server-core/src/auth/rate-limiter.d.ts.map +1 -0
  66. package/dist/server-core/src/auth/routes.d.ts +28 -0
  67. package/dist/server-core/src/auth/routes.d.ts.map +1 -0
  68. package/dist/server-core/src/auth/slack-oauth.d.ts +13 -0
  69. package/dist/server-core/src/auth/slack-oauth.d.ts.map +1 -0
  70. package/dist/server-core/src/auth/spotify-oauth.d.ts +13 -0
  71. package/dist/server-core/src/auth/spotify-oauth.d.ts.map +1 -0
  72. package/dist/server-core/src/auth/twitter-oauth.d.ts +19 -0
  73. package/dist/server-core/src/auth/twitter-oauth.d.ts.map +1 -0
  74. package/dist/server-core/src/collections/BackendCollectionRegistry.d.ts +14 -0
  75. package/dist/server-core/src/collections/BackendCollectionRegistry.d.ts.map +1 -0
  76. package/dist/server-core/src/collections/loader.d.ts +6 -0
  77. package/dist/server-core/src/collections/loader.d.ts.map +1 -0
  78. package/dist/server-core/src/cron/cron-loader.d.ts +18 -0
  79. package/dist/server-core/src/cron/cron-loader.d.ts.map +1 -0
  80. package/dist/server-core/src/cron/cron-routes.d.ts +15 -0
  81. package/dist/server-core/src/cron/cron-routes.d.ts.map +1 -0
  82. package/dist/server-core/src/cron/cron-scheduler.d.ts +62 -0
  83. package/dist/server-core/src/cron/cron-scheduler.d.ts.map +1 -0
  84. package/dist/server-core/src/cron/cron-store.d.ts +33 -0
  85. package/dist/server-core/src/cron/cron-store.d.ts.map +1 -0
  86. package/dist/server-core/src/cron/index.d.ts +7 -0
  87. package/dist/server-core/src/cron/index.d.ts.map +1 -0
  88. package/dist/server-core/src/db/interfaces.d.ts +19 -0
  89. package/dist/server-core/src/db/interfaces.d.ts.map +1 -0
  90. package/dist/server-core/src/email/index.d.ts +7 -0
  91. package/dist/server-core/src/email/index.d.ts.map +1 -0
  92. package/dist/server-core/src/email/smtp-email-service.d.ts +26 -0
  93. package/dist/server-core/src/email/smtp-email-service.d.ts.map +1 -0
  94. package/dist/server-core/src/email/templates.d.ts +43 -0
  95. package/dist/server-core/src/email/templates.d.ts.map +1 -0
  96. package/dist/server-core/src/email/types.d.ts +108 -0
  97. package/dist/server-core/src/email/types.d.ts.map +1 -0
  98. package/dist/server-core/src/functions/function-loader.d.ts +18 -0
  99. package/dist/server-core/src/functions/function-loader.d.ts.map +1 -0
  100. package/dist/server-core/src/functions/function-routes.d.ts +11 -0
  101. package/dist/server-core/src/functions/function-routes.d.ts.map +1 -0
  102. package/dist/server-core/src/functions/index.d.ts +4 -0
  103. package/dist/server-core/src/functions/index.d.ts.map +1 -0
  104. package/dist/server-core/src/history/history-routes.d.ts +24 -0
  105. package/dist/server-core/src/history/history-routes.d.ts.map +1 -0
  106. package/dist/server-core/src/history/index.d.ts +2 -0
  107. package/dist/server-core/src/history/index.d.ts.map +1 -0
  108. package/dist/server-core/src/index.d.ts +30 -0
  109. package/dist/server-core/src/index.d.ts.map +1 -0
  110. package/dist/server-core/src/init.d.ts +160 -0
  111. package/dist/server-core/src/init.d.ts.map +1 -0
  112. package/dist/server-core/src/serve-spa.d.ts +31 -0
  113. package/dist/server-core/src/serve-spa.d.ts.map +1 -0
  114. package/dist/server-core/src/services/driver-registry.d.ts +79 -0
  115. package/dist/server-core/src/services/driver-registry.d.ts.map +1 -0
  116. package/dist/server-core/src/singleton.d.ts +36 -0
  117. package/dist/server-core/src/singleton.d.ts.map +1 -0
  118. package/dist/server-core/src/storage/LocalStorageController.d.ts +47 -0
  119. package/dist/server-core/src/storage/LocalStorageController.d.ts.map +1 -0
  120. package/dist/server-core/src/storage/S3StorageController.d.ts +37 -0
  121. package/dist/server-core/src/storage/S3StorageController.d.ts.map +1 -0
  122. package/dist/server-core/src/storage/index.d.ts +26 -0
  123. package/dist/server-core/src/storage/index.d.ts.map +1 -0
  124. package/dist/server-core/src/storage/routes.d.ts +39 -0
  125. package/dist/server-core/src/storage/routes.d.ts.map +1 -0
  126. package/dist/server-core/src/storage/storage-registry.d.ts +79 -0
  127. package/dist/server-core/src/storage/storage-registry.d.ts.map +1 -0
  128. package/dist/server-core/src/storage/types.d.ts +104 -0
  129. package/dist/server-core/src/storage/types.d.ts.map +1 -0
  130. package/dist/server-core/src/types/index.d.ts +12 -0
  131. package/dist/server-core/src/types/index.d.ts.map +1 -0
  132. package/dist/server-core/src/utils/dev-port.d.ts +36 -0
  133. package/dist/server-core/src/utils/dev-port.d.ts.map +1 -0
  134. package/dist/server-core/src/utils/logger.d.ts +32 -0
  135. package/dist/server-core/src/utils/logger.d.ts.map +1 -0
  136. package/dist/server-core/src/utils/logging.d.ts +10 -0
  137. package/dist/server-core/src/utils/logging.d.ts.map +1 -0
  138. package/dist/server-core/src/utils/request-logger.d.ts +20 -0
  139. package/dist/server-core/src/utils/request-logger.d.ts.map +1 -0
  140. package/dist/server-core/src/utils/sql.d.ts +28 -0
  141. package/dist/server-core/src/utils/sql.d.ts.map +1 -0
  142. package/dist/server-mongodb/src/MongoBootstrapper.d.ts +18 -0
  143. package/dist/server-mongodb/src/MongoBootstrapper.d.ts.map +1 -0
  144. package/dist/server-mongodb/src/auth/ensure-collections.d.ts +3 -0
  145. package/dist/server-mongodb/src/auth/ensure-collections.d.ts.map +1 -0
  146. package/dist/server-mongodb/src/auth/services.d.ts +135 -0
  147. package/dist/server-mongodb/src/auth/services.d.ts.map +1 -0
  148. package/dist/server-mongodb/src/connection.d.ts +35 -0
  149. package/dist/server-mongodb/src/connection.d.ts.map +1 -0
  150. package/dist/server-mongodb/src/db/MongoConditionBuilder.d.ts +64 -0
  151. package/dist/server-mongodb/src/db/MongoConditionBuilder.d.ts.map +1 -0
  152. package/dist/server-mongodb/src/db/MongoEntityService.d.ts +98 -0
  153. package/dist/server-mongodb/src/db/MongoEntityService.d.ts.map +1 -0
  154. package/dist/server-mongodb/src/factory.d.ts +142 -0
  155. package/dist/server-mongodb/src/factory.d.ts.map +1 -0
  156. package/dist/server-mongodb/src/history/ensure-history-collection.d.ts +3 -0
  157. package/dist/server-mongodb/src/history/ensure-history-collection.d.ts.map +1 -0
  158. package/dist/server-mongodb/src/index.d.ts +18 -0
  159. package/dist/server-mongodb/src/index.d.ts.map +1 -0
  160. package/dist/server-mongodb/src/services/MongoDriver.d.ts +83 -0
  161. package/dist/server-mongodb/src/services/MongoDriver.d.ts.map +1 -0
  162. package/dist/server-mongodb/src/services/MongoHistoryService.d.ts +37 -0
  163. package/dist/server-mongodb/src/services/MongoHistoryService.d.ts.map +1 -0
  164. package/dist/server-mongodb/src/services/MongoRealtimeService.d.ts +86 -0
  165. package/dist/server-mongodb/src/services/MongoRealtimeService.d.ts.map +1 -0
  166. package/dist/server-mongodb/src/useMongoDriver.d.ts +18 -0
  167. package/dist/server-mongodb/src/useMongoDriver.d.ts.map +1 -0
  168. package/dist/server-mongodb/src/utils.d.ts +10 -0
  169. package/dist/server-mongodb/src/utils.d.ts.map +1 -0
  170. package/dist/server-mongodb/src/websocket.d.ts +7 -0
  171. package/dist/server-mongodb/src/websocket.d.ts.map +1 -0
  172. package/dist/types/src/controllers/analytics_controller.d.ts +8 -0
  173. package/dist/types/src/controllers/analytics_controller.d.ts.map +1 -0
  174. package/dist/types/src/controllers/auth.d.ts +120 -0
  175. package/dist/types/src/controllers/auth.d.ts.map +1 -0
  176. package/dist/types/src/controllers/client.d.ts +171 -0
  177. package/dist/types/src/controllers/client.d.ts.map +1 -0
  178. package/dist/types/src/controllers/collection_registry.d.ts +46 -0
  179. package/dist/types/src/controllers/collection_registry.d.ts.map +1 -0
  180. package/dist/types/src/controllers/customization_controller.d.ts +61 -0
  181. package/dist/types/src/controllers/customization_controller.d.ts.map +1 -0
  182. package/dist/types/src/controllers/data.d.ts +169 -0
  183. package/dist/types/src/controllers/data.d.ts.map +1 -0
  184. package/dist/types/src/controllers/data_driver.d.ts +161 -0
  185. package/dist/types/src/controllers/data_driver.d.ts.map +1 -0
  186. package/dist/types/src/controllers/database_admin.d.ts +12 -0
  187. package/dist/types/src/controllers/database_admin.d.ts.map +1 -0
  188. package/dist/types/src/controllers/dialogs_controller.d.ts +37 -0
  189. package/dist/types/src/controllers/dialogs_controller.d.ts.map +1 -0
  190. package/dist/types/src/controllers/effective_role.d.ts +5 -0
  191. package/dist/types/src/controllers/effective_role.d.ts.map +1 -0
  192. package/dist/types/src/controllers/email.d.ts +35 -0
  193. package/dist/types/src/controllers/email.d.ts.map +1 -0
  194. package/dist/types/src/controllers/index.d.ts +19 -0
  195. package/dist/types/src/controllers/index.d.ts.map +1 -0
  196. package/dist/types/src/controllers/local_config_persistence.d.ts +21 -0
  197. package/dist/types/src/controllers/local_config_persistence.d.ts.map +1 -0
  198. package/dist/types/src/controllers/navigation.d.ts +214 -0
  199. package/dist/types/src/controllers/navigation.d.ts.map +1 -0
  200. package/dist/types/src/controllers/registry.d.ts +55 -0
  201. package/dist/types/src/controllers/registry.d.ts.map +1 -0
  202. package/dist/types/src/controllers/side_dialogs_controller.d.ts +68 -0
  203. package/dist/types/src/controllers/side_dialogs_controller.d.ts.map +1 -0
  204. package/dist/types/src/controllers/side_entity_controller.d.ts +91 -0
  205. package/dist/types/src/controllers/side_entity_controller.d.ts.map +1 -0
  206. package/dist/types/src/controllers/snackbar.d.ts +25 -0
  207. package/dist/types/src/controllers/snackbar.d.ts.map +1 -0
  208. package/dist/types/src/controllers/storage.d.ts +172 -0
  209. package/dist/types/src/controllers/storage.d.ts.map +1 -0
  210. package/dist/types/src/index.d.ts +5 -0
  211. package/dist/types/src/index.d.ts.map +1 -0
  212. package/dist/types/src/rebase_context.d.ts +106 -0
  213. package/dist/types/src/rebase_context.d.ts.map +1 -0
  214. package/dist/types/src/types/backend.d.ts +537 -0
  215. package/dist/types/src/types/backend.d.ts.map +1 -0
  216. package/dist/types/src/types/builders.d.ts +16 -0
  217. package/dist/types/src/types/builders.d.ts.map +1 -0
  218. package/dist/types/src/types/chips.d.ts +6 -0
  219. package/dist/types/src/types/chips.d.ts.map +1 -0
  220. package/dist/types/src/types/collections.d.ts +857 -0
  221. package/dist/types/src/types/collections.d.ts.map +1 -0
  222. package/dist/types/src/types/cron.d.ts +103 -0
  223. package/dist/types/src/types/cron.d.ts.map +1 -0
  224. package/dist/types/src/types/data_source.d.ts +65 -0
  225. package/dist/types/src/types/data_source.d.ts.map +1 -0
  226. package/dist/types/src/types/entities.d.ts +146 -0
  227. package/dist/types/src/types/entities.d.ts.map +1 -0
  228. package/dist/types/src/types/entity_actions.d.ts +99 -0
  229. package/dist/types/src/types/entity_actions.d.ts.map +1 -0
  230. package/dist/types/src/types/entity_callbacks.d.ts +174 -0
  231. package/dist/types/src/types/entity_callbacks.d.ts.map +1 -0
  232. package/dist/types/src/types/entity_link_builder.d.ts +8 -0
  233. package/dist/types/src/types/entity_link_builder.d.ts.map +1 -0
  234. package/dist/types/src/types/entity_overrides.d.ts +11 -0
  235. package/dist/types/src/types/entity_overrides.d.ts.map +1 -0
  236. package/dist/types/src/types/entity_views.d.ts +62 -0
  237. package/dist/types/src/types/entity_views.d.ts.map +1 -0
  238. package/dist/types/src/types/export_import.d.ts +22 -0
  239. package/dist/types/src/types/export_import.d.ts.map +1 -0
  240. package/dist/types/src/types/index.d.ts +24 -0
  241. package/dist/types/src/types/index.d.ts.map +1 -0
  242. package/dist/types/src/types/locales.d.ts +5 -0
  243. package/dist/types/src/types/locales.d.ts.map +1 -0
  244. package/dist/types/src/types/modify_collections.d.ts +6 -0
  245. package/dist/types/src/types/modify_collections.d.ts.map +1 -0
  246. package/dist/types/src/types/plugins.d.ts +280 -0
  247. package/dist/types/src/types/plugins.d.ts.map +1 -0
  248. package/dist/types/src/types/properties.d.ts +1177 -0
  249. package/dist/types/src/types/properties.d.ts.map +1 -0
  250. package/dist/types/src/types/property_config.d.ts +71 -0
  251. package/dist/types/src/types/property_config.d.ts.map +1 -0
  252. package/dist/types/src/types/relations.d.ts +337 -0
  253. package/dist/types/src/types/relations.d.ts.map +1 -0
  254. package/dist/types/src/types/slots.d.ts +253 -0
  255. package/dist/types/src/types/slots.d.ts.map +1 -0
  256. package/dist/types/src/types/translations.d.ts +871 -0
  257. package/dist/types/src/types/translations.d.ts.map +1 -0
  258. package/dist/types/src/types/user_management_delegate.d.ts +122 -0
  259. package/dist/types/src/types/user_management_delegate.d.ts.map +1 -0
  260. package/dist/types/src/types/websockets.d.ts +79 -0
  261. package/dist/types/src/types/websockets.d.ts.map +1 -0
  262. package/dist/types/src/users/index.d.ts +3 -0
  263. package/dist/types/src/users/index.d.ts.map +1 -0
  264. package/dist/types/src/users/roles.d.ts +23 -0
  265. package/dist/types/src/users/roles.d.ts.map +1 -0
  266. package/dist/types/src/users/user.d.ts +47 -0
  267. package/dist/types/src/users/user.d.ts.map +1 -0
  268. package/dist/websocket-BZlPuJrt.js +220 -0
  269. package/dist/websocket-BZlPuJrt.js.map +1 -0
  270. package/package.json +79 -0
  271. package/src/MongoBootstrapper.ts +177 -0
  272. package/src/auth/ensure-collections.ts +94 -0
  273. package/src/auth/services.ts +638 -0
  274. package/src/connection.ts +60 -0
  275. package/src/db/MongoConditionBuilder.ts +181 -0
  276. package/src/db/MongoEntityService.ts +350 -0
  277. package/src/factory.ts +289 -0
  278. package/src/history/ensure-history-collection.ts +19 -0
  279. package/src/index.ts +25 -0
  280. package/src/services/MongoDriver.ts +297 -0
  281. package/src/services/MongoDriver.ts.backup +266 -0
  282. package/src/services/MongoHistoryService.ts +154 -0
  283. package/src/services/MongoRealtimeService.ts +394 -0
  284. package/src/useMongoDriver.ts +519 -0
  285. package/src/utils.ts +28 -0
  286. package/src/websocket.ts +257 -0
@@ -0,0 +1,181 @@
1
+ /**
2
+ * MongoDB Condition Builder
3
+ *
4
+ * Translates Rebase filter conditions to MongoDB query operators.
5
+ */
6
+
7
+ import { FilterValues, WhereFilterOp } from "@rebasepro/types";
8
+ import { Filter, Document } from "mongodb";
9
+
10
+ /**
11
+ * Mapping from Rebase filter operators to MongoDB query operators
12
+ */
13
+ const REBASE_TO_MONGO_OP: Record<WhereFilterOp, string> = {
14
+ "<": "$lt",
15
+ "<=": "$lte",
16
+ "==": "$eq",
17
+ "!=": "$ne",
18
+ ">=": "$gte",
19
+ ">": "$gt",
20
+ "array-contains": "$elemMatch",
21
+ "array-contains-any": "$in",
22
+ "in": "$in",
23
+ "not-in": "$nin"
24
+ };
25
+
26
+ /**
27
+ * MongoDB Condition Builder
28
+ *
29
+ * Provides static methods to translate Rebase filter conditions
30
+ * to MongoDB query filters.
31
+ */
32
+ export class MongoConditionBuilder {
33
+ /**
34
+ * Build MongoDB filter conditions from Rebase FilterValues
35
+ *
36
+ * @param filter - Rebase filter values
37
+ * @returns Array of MongoDB filter objects
38
+ */
39
+ static buildFilterConditions<M extends Record<string, any>>(
40
+ filter: FilterValues<Extract<keyof M, string>>
41
+ ): Filter<Document>[] {
42
+ if (!filter) return [];
43
+
44
+ const conditions: Filter<Document>[] = [];
45
+
46
+ for (const [field, filterParam] of Object.entries(filter)) {
47
+ if (!filterParam) continue;
48
+
49
+ const [op, value] = filterParam as [WhereFilterOp, any];
50
+ const mongoOp = REBASE_TO_MONGO_OP[op];
51
+
52
+ if (!mongoOp) {
53
+ console.warn(`Unsupported filter operator: ${op}`);
54
+ continue;
55
+ }
56
+
57
+ // Handle array-contains specially
58
+ if (op === "array-contains") {
59
+ conditions.push({
60
+ [field]: { $elemMatch: { $eq: value } }
61
+ });
62
+ } else {
63
+ conditions.push({
64
+ [field]: { [mongoOp]: value }
65
+ });
66
+ }
67
+ }
68
+
69
+ return conditions;
70
+ }
71
+
72
+ /**
73
+ * Build search conditions for text search
74
+ *
75
+ * @param searchString - Text to search for
76
+ * @param properties - Properties to search in
77
+ * @returns Array of MongoDB filter objects for text search
78
+ */
79
+ static buildSearchConditions(
80
+ searchString: string,
81
+ properties: Record<string, any>
82
+ ): Filter<Document>[] {
83
+ if (!searchString) return [];
84
+
85
+ // Build regex conditions for each searchable string property
86
+ const orConditions: Filter<Document>[] = [];
87
+ const searchRegex = new RegExp(searchString, "i");
88
+
89
+ for (const [key, prop] of Object.entries(properties)) {
90
+ // Only search in string-type properties
91
+ if (prop?.dataType === "string" || typeof prop === "string") {
92
+ orConditions.push({
93
+ [key]: { $regex: searchRegex }
94
+ });
95
+ }
96
+ }
97
+
98
+ // If no properties to search, use MongoDB text search
99
+ if (orConditions.length === 0) {
100
+ return [{ $text: { $search: searchString } }];
101
+ }
102
+
103
+ return orConditions;
104
+ }
105
+
106
+ /**
107
+ * Combine multiple conditions with AND operator
108
+ *
109
+ * @param conditions - Array of filter conditions
110
+ * @returns Combined filter or undefined if empty
111
+ */
112
+ static combineConditionsWithAnd(conditions: Filter<Document>[]): Filter<Document> | undefined {
113
+ if (conditions.length === 0) return undefined;
114
+ if (conditions.length === 1) return conditions[0];
115
+ return { $and: conditions };
116
+ }
117
+
118
+ /**
119
+ * Combine multiple conditions with OR operator
120
+ *
121
+ * @param conditions - Array of filter conditions
122
+ * @returns Combined filter or undefined if empty
123
+ */
124
+ static combineConditionsWithOr(conditions: Filter<Document>[]): Filter<Document> | undefined {
125
+ if (conditions.length === 0) return undefined;
126
+ if (conditions.length === 1) return conditions[0];
127
+ return { $or: conditions };
128
+ }
129
+
130
+ /**
131
+ * Build a complete MongoDB query from Rebase options
132
+ *
133
+ * @param options - Rebase fetch options
134
+ * @returns MongoDB filter object
135
+ */
136
+ static buildQuery<M extends Record<string, any>>(options: {
137
+ filter?: FilterValues<Extract<keyof M, string>>;
138
+ searchString?: string;
139
+ properties?: Record<string, any>;
140
+ }): Filter<Document> {
141
+ const conditions: Filter<Document>[] = [];
142
+
143
+ // Add filter conditions
144
+ if (options.filter) {
145
+ const filterConditions = this.buildFilterConditions<M>(options.filter);
146
+ conditions.push(...filterConditions);
147
+ }
148
+
149
+ // Add search conditions
150
+ if (options.searchString && options.properties) {
151
+ const searchConditions = this.buildSearchConditions(
152
+ options.searchString,
153
+ options.properties
154
+ );
155
+ if (searchConditions.length > 0) {
156
+ // Search conditions are OR'd together
157
+ const searchFilter = this.combineConditionsWithOr(searchConditions);
158
+ if (searchFilter) {
159
+ conditions.push(searchFilter);
160
+ }
161
+ }
162
+ }
163
+
164
+ return this.combineConditionsWithAnd(conditions) ?? {};
165
+ }
166
+
167
+ /**
168
+ * Build MongoDB sort options from Rebase options
169
+ *
170
+ * @param orderBy - Field to order by
171
+ * @param order - Sort direction
172
+ * @returns MongoDB sort object
173
+ */
174
+ static buildSort(
175
+ orderBy?: string,
176
+ order?: "asc" | "desc"
177
+ ): Record<string, 1 | -1> | undefined {
178
+ if (!orderBy) return undefined;
179
+ return { [orderBy]: order === "desc" ? -1 : 1 };
180
+ }
181
+ }
@@ -0,0 +1,350 @@
1
+ /**
2
+ * MongoDB Entity Service
3
+ *
4
+ * Implements EntityRepository interface for MongoDB.
5
+ * Provides all CRUD operations for entities.
6
+ */
7
+
8
+ import { Db, ObjectId, Collection, Document, FindOptions, Filter } from "mongodb";
9
+ import { Entity, FilterValues, EntityRepository, EntityCollection } from "@rebasepro/types";
10
+ import { MongoConditionBuilder } from "./MongoConditionBuilder";
11
+
12
+ /**
13
+ * MongoDB Entity Service
14
+ *
15
+ * Implements the EntityRepository interface for MongoDB.
16
+ * Provides all CRUD operations for entities stored in MongoDB collections.
17
+ */
18
+ export class MongoEntityService implements EntityRepository {
19
+ constructor(private db: Db) { }
20
+
21
+ /**
22
+ * Get a MongoDB collection by its path
23
+ */
24
+ private getCollection(collectionPath: string): Collection<Document> {
25
+ // Handle nested paths (e.g., "posts/123/comments" -> "posts_123_comments")
26
+ const collectionName = collectionPath.replace(/\//g, "_");
27
+ return this.db.collection(collectionName);
28
+ }
29
+
30
+ /**
31
+ * Convert a string ID to ObjectId if it's a valid ObjectId string
32
+ */
33
+ private toObjectId(id: string | number): ObjectId | string | number {
34
+ if (typeof id === "string" && ObjectId.isValid(id) && id.length === 24) {
35
+ return new ObjectId(id);
36
+ }
37
+ return id;
38
+ }
39
+
40
+ /**
41
+ * Convert a MongoDB document to a Rebase Entity
42
+ */
43
+ private documentToEntity<M extends Record<string, any>>(
44
+ doc: Document,
45
+ path: string
46
+ ): Entity<M> {
47
+ const { _id, ...values } = doc;
48
+ return {
49
+ id: _id.toString(),
50
+ path,
51
+ values: this.convertFromMongoValues(values) as M
52
+ };
53
+ }
54
+
55
+ /**
56
+ * Convert values from MongoDB format to Rebase format
57
+ */
58
+ private convertFromMongoValues(values: Record<string, any>): Record<string, any> {
59
+ const result: Record<string, any> = {};
60
+
61
+ for (const [key, value] of Object.entries(values)) {
62
+ result[key] = this.convertFromMongoValue(value);
63
+ }
64
+
65
+ return result;
66
+ }
67
+
68
+ /**
69
+ * Convert a single value from MongoDB format
70
+ */
71
+ private convertFromMongoValue(value: any): any {
72
+ if (value === null || value === undefined) return value;
73
+
74
+ // Handle ObjectId
75
+ if (value instanceof ObjectId) {
76
+ return value.toString();
77
+ }
78
+
79
+ // Handle Date
80
+ if (value instanceof Date) {
81
+ return value;
82
+ }
83
+
84
+ // Handle arrays
85
+ if (Array.isArray(value)) {
86
+ return value.map(v => this.convertFromMongoValue(v));
87
+ }
88
+
89
+ // Handle EntityReference-like objects
90
+ if (typeof value === "object" && "path" in value && "id" in value) {
91
+ return {
92
+ path: value.path,
93
+ id: value.id instanceof ObjectId ? value.id.toString() : value.id
94
+ };
95
+ }
96
+
97
+ // Handle nested objects
98
+ if (typeof value === "object") {
99
+ return this.convertFromMongoValues(value);
100
+ }
101
+
102
+ return value;
103
+ }
104
+
105
+ /**
106
+ * Convert values to MongoDB format for storage
107
+ */
108
+ private convertToMongoValues(values: Record<string, any>): Record<string, any> {
109
+ const result: Record<string, any> = {};
110
+
111
+ for (const [key, value] of Object.entries(values)) {
112
+ result[key] = this.convertToMongoValue(value);
113
+ }
114
+
115
+ return result;
116
+ }
117
+
118
+ /**
119
+ * Convert a single value to MongoDB format
120
+ */
121
+ private convertToMongoValue(value: any): any {
122
+ if (value === null || value === undefined) return value;
123
+
124
+ // Handle EntityReference
125
+ if (typeof value === "object" && value.isEntityReference?.()) {
126
+ return {
127
+ id: ObjectId.isValid(value.id) ? new ObjectId(value.id) : value.id,
128
+ path: value.path
129
+ };
130
+ }
131
+
132
+ // Handle Date
133
+ if (value instanceof Date) {
134
+ return value;
135
+ }
136
+
137
+ // Handle arrays
138
+ if (Array.isArray(value)) {
139
+ return value.map(v => this.convertToMongoValue(v));
140
+ }
141
+
142
+ // Handle nested objects
143
+ if (typeof value === "object") {
144
+ return this.convertToMongoValues(value);
145
+ }
146
+
147
+ return value;
148
+ }
149
+
150
+ // =============================================================
151
+ // EntityRepository Implementation
152
+ // =============================================================
153
+
154
+ /**
155
+ * Fetch a single entity by ID
156
+ */
157
+ async fetchEntity<M extends Record<string, any>>(
158
+ collectionPath: string,
159
+ entityId: string | number,
160
+ _databaseId?: string
161
+ ): Promise<Entity<M> | undefined> {
162
+ const collection = this.getCollection(collectionPath);
163
+ const id = this.toObjectId(entityId);
164
+
165
+ const doc = await collection.findOne({ _id: id } as Filter<Document>);
166
+
167
+ if (!doc) return undefined;
168
+
169
+ return this.documentToEntity<M>(doc, collectionPath);
170
+ }
171
+
172
+ /**
173
+ * Fetch a collection of entities with optional filtering, ordering, and pagination
174
+ */
175
+ async fetchCollection<M extends Record<string, any>>(
176
+ collectionPath: string,
177
+ options: {
178
+ filter?: FilterValues<Extract<keyof M, string>>;
179
+ orderBy?: string;
180
+ order?: "desc" | "asc";
181
+ limit?: number;
182
+ startAfter?: any;
183
+ searchString?: string;
184
+ databaseId?: string;
185
+ collection?: EntityCollection;
186
+ } = {}
187
+ ): Promise<Entity<M>[]> {
188
+ const collection = this.getCollection(collectionPath);
189
+
190
+ // Build query
191
+ const query = MongoConditionBuilder.buildQuery<M>({
192
+ filter: options.filter,
193
+ searchString: options.searchString,
194
+ properties: options.collection?.properties ?? {}
195
+ });
196
+
197
+ // Build find options
198
+ const findOptions: FindOptions<Document> = {};
199
+
200
+ // Apply sorting
201
+ const sort = MongoConditionBuilder.buildSort(options.orderBy, options.order);
202
+ if (sort) {
203
+ findOptions.sort = sort;
204
+ }
205
+
206
+ // Apply limit
207
+ if (options.limit) {
208
+ findOptions.limit = options.limit;
209
+ }
210
+
211
+ // Apply pagination (skip-based for now, cursor-based would be better)
212
+ if (options.startAfter !== undefined) {
213
+ findOptions.skip = Number(options.startAfter);
214
+ }
215
+
216
+ const docs = await collection.find(query, findOptions).toArray();
217
+
218
+ return docs.map((doc: Document) => this.documentToEntity<M>(doc, collectionPath));
219
+ }
220
+
221
+ /**
222
+ * Search entities by text
223
+ */
224
+ async searchEntities<M extends Record<string, any>>(
225
+ collectionPath: string,
226
+ searchString: string,
227
+ options: {
228
+ filter?: FilterValues<Extract<keyof M, string>>;
229
+ orderBy?: string;
230
+ order?: "desc" | "asc";
231
+ limit?: number;
232
+ databaseId?: string;
233
+ collection?: EntityCollection;
234
+ } = {}
235
+ ): Promise<Entity<M>[]> {
236
+ return this.fetchCollection<M>(collectionPath, {
237
+ ...options,
238
+ searchString
239
+ });
240
+ }
241
+
242
+ /**
243
+ * Count entities in a collection
244
+ */
245
+ async countEntities<M extends Record<string, any>>(
246
+ collectionPath: string,
247
+ options: {
248
+ filter?: FilterValues<Extract<keyof M, string>>;
249
+ databaseId?: string;
250
+ } = {}
251
+ ): Promise<number> {
252
+ const collection = this.getCollection(collectionPath);
253
+
254
+ const query = options.filter
255
+ ? MongoConditionBuilder.buildQuery<M>({ filter: options.filter })
256
+ : {};
257
+
258
+ return collection.countDocuments(query);
259
+ }
260
+
261
+ /**
262
+ * Save an entity (create or update)
263
+ */
264
+ async saveEntity<M extends Record<string, any>>(
265
+ collectionPath: string,
266
+ values: Partial<M>,
267
+ entityId?: string | number,
268
+ _databaseId?: string
269
+ ): Promise<Entity<M>> {
270
+ const collection = this.getCollection(collectionPath);
271
+ const mongoValues = this.convertToMongoValues(values as Record<string, any>);
272
+
273
+ if (entityId) {
274
+ // Update existing entity
275
+ const id = this.toObjectId(entityId);
276
+ await collection.updateOne(
277
+ { _id: id } as Filter<Document>,
278
+ { $set: mongoValues },
279
+ { upsert: true }
280
+ );
281
+
282
+ return {
283
+ id: entityId.toString(),
284
+ path: collectionPath,
285
+ values: values as M
286
+ };
287
+ } else {
288
+ // Create new entity
289
+ const newId = new ObjectId();
290
+ await collection.insertOne({
291
+ _id: newId,
292
+ ...mongoValues
293
+ });
294
+
295
+ return {
296
+ id: newId.toString(),
297
+ path: collectionPath,
298
+ values: values as M
299
+ };
300
+ }
301
+ }
302
+
303
+ /**
304
+ * Delete an entity by ID
305
+ */
306
+ async deleteEntity(
307
+ collectionPath: string,
308
+ entityId: string | number,
309
+ _databaseId?: string
310
+ ): Promise<void> {
311
+ const collection = this.getCollection(collectionPath);
312
+ const id = this.toObjectId(entityId);
313
+
314
+ const result = await collection.deleteOne({ _id: id } as Filter<Document>);
315
+
316
+ if (result.deletedCount === 0) {
317
+ console.warn(`Entity ${entityId} not found in collection ${collectionPath}`);
318
+ }
319
+ }
320
+
321
+ /**
322
+ * Check if a field value is unique in a collection
323
+ */
324
+ async checkUniqueField(
325
+ collectionPath: string,
326
+ fieldName: string,
327
+ value: any,
328
+ excludeEntityId?: string,
329
+ _databaseId?: string
330
+ ): Promise<boolean> {
331
+ const collection = this.getCollection(collectionPath);
332
+
333
+ const query: Filter<Document> = { [fieldName]: value };
334
+
335
+ if (excludeEntityId) {
336
+ const id = this.toObjectId(excludeEntityId);
337
+ (query as Record<string, unknown>)._id = { $ne: id };
338
+ }
339
+
340
+ const count = await collection.countDocuments(query);
341
+ return count === 0;
342
+ }
343
+
344
+ /**
345
+ * Generate a new entity ID
346
+ */
347
+ generateEntityId(): string {
348
+ return new ObjectId().toString();
349
+ }
350
+ }