@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.
- package/LICENSE +6 -0
- package/dist/ensure-collections-CNrcwVgY.js +74 -0
- package/dist/ensure-collections-CNrcwVgY.js.map +1 -0
- package/dist/ensure-history-collection-DBIiwmCm.js +15 -0
- package/dist/ensure-history-collection-DBIiwmCm.js.map +1 -0
- package/dist/index.es.js +1734 -0
- package/dist/index.es.js.map +1 -0
- package/dist/index.umd.js +2043 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/server-core/src/api/ast-schema-editor.d.ts +22 -0
- package/dist/server-core/src/api/ast-schema-editor.d.ts.map +1 -0
- package/dist/server-core/src/api/errors.d.ts +36 -0
- package/dist/server-core/src/api/errors.d.ts.map +1 -0
- package/dist/server-core/src/api/graphql/graphql-schema-generator.d.ts +36 -0
- package/dist/server-core/src/api/graphql/graphql-schema-generator.d.ts.map +1 -0
- package/dist/server-core/src/api/graphql/index.d.ts +2 -0
- package/dist/server-core/src/api/graphql/index.d.ts.map +1 -0
- package/dist/server-core/src/api/index.d.ts +10 -0
- package/dist/server-core/src/api/index.d.ts.map +1 -0
- package/dist/server-core/src/api/openapi-generator.d.ts +17 -0
- package/dist/server-core/src/api/openapi-generator.d.ts.map +1 -0
- package/dist/server-core/src/api/rest/api-generator.d.ts +65 -0
- package/dist/server-core/src/api/rest/api-generator.d.ts.map +1 -0
- package/dist/server-core/src/api/rest/index.d.ts +2 -0
- package/dist/server-core/src/api/rest/index.d.ts.map +1 -0
- package/dist/server-core/src/api/rest/query-parser.d.ts +10 -0
- package/dist/server-core/src/api/rest/query-parser.d.ts.map +1 -0
- package/dist/server-core/src/api/schema-editor-routes.d.ts +4 -0
- package/dist/server-core/src/api/schema-editor-routes.d.ts.map +1 -0
- package/dist/server-core/src/api/server.d.ts +41 -0
- package/dist/server-core/src/api/server.d.ts.map +1 -0
- package/dist/server-core/src/api/types.d.ts +91 -0
- package/dist/server-core/src/api/types.d.ts.map +1 -0
- package/dist/server-core/src/auth/admin-routes.d.ts +17 -0
- package/dist/server-core/src/auth/admin-routes.d.ts.map +1 -0
- package/dist/server-core/src/auth/apple-oauth.d.ts +31 -0
- package/dist/server-core/src/auth/apple-oauth.d.ts.map +1 -0
- package/dist/server-core/src/auth/bitbucket-oauth.d.ts +12 -0
- package/dist/server-core/src/auth/bitbucket-oauth.d.ts.map +1 -0
- package/dist/server-core/src/auth/discord-oauth.d.ts +15 -0
- package/dist/server-core/src/auth/discord-oauth.d.ts.map +1 -0
- package/dist/server-core/src/auth/facebook-oauth.d.ts +15 -0
- package/dist/server-core/src/auth/facebook-oauth.d.ts.map +1 -0
- package/dist/server-core/src/auth/github-oauth.d.ts +16 -0
- package/dist/server-core/src/auth/github-oauth.d.ts.map +1 -0
- package/dist/server-core/src/auth/gitlab-oauth.d.ts +14 -0
- package/dist/server-core/src/auth/gitlab-oauth.d.ts.map +1 -0
- package/dist/server-core/src/auth/google-oauth.d.ts +15 -0
- package/dist/server-core/src/auth/google-oauth.d.ts.map +1 -0
- package/dist/server-core/src/auth/index.d.ts +24 -0
- package/dist/server-core/src/auth/index.d.ts.map +1 -0
- package/dist/server-core/src/auth/interfaces.d.ts +310 -0
- package/dist/server-core/src/auth/interfaces.d.ts.map +1 -0
- package/dist/server-core/src/auth/jwt.d.ts +44 -0
- package/dist/server-core/src/auth/jwt.d.ts.map +1 -0
- package/dist/server-core/src/auth/linkedin-oauth.d.ts +19 -0
- package/dist/server-core/src/auth/linkedin-oauth.d.ts.map +1 -0
- package/dist/server-core/src/auth/microsoft-oauth.d.ts +17 -0
- package/dist/server-core/src/auth/microsoft-oauth.d.ts.map +1 -0
- package/dist/server-core/src/auth/middleware.d.ts +82 -0
- package/dist/server-core/src/auth/middleware.d.ts.map +1 -0
- package/dist/server-core/src/auth/password.d.ts +23 -0
- package/dist/server-core/src/auth/password.d.ts.map +1 -0
- package/dist/server-core/src/auth/rate-limiter.d.ts +32 -0
- package/dist/server-core/src/auth/rate-limiter.d.ts.map +1 -0
- package/dist/server-core/src/auth/routes.d.ts +28 -0
- package/dist/server-core/src/auth/routes.d.ts.map +1 -0
- package/dist/server-core/src/auth/slack-oauth.d.ts +13 -0
- package/dist/server-core/src/auth/slack-oauth.d.ts.map +1 -0
- package/dist/server-core/src/auth/spotify-oauth.d.ts +13 -0
- package/dist/server-core/src/auth/spotify-oauth.d.ts.map +1 -0
- package/dist/server-core/src/auth/twitter-oauth.d.ts +19 -0
- package/dist/server-core/src/auth/twitter-oauth.d.ts.map +1 -0
- package/dist/server-core/src/collections/BackendCollectionRegistry.d.ts +14 -0
- package/dist/server-core/src/collections/BackendCollectionRegistry.d.ts.map +1 -0
- package/dist/server-core/src/collections/loader.d.ts +6 -0
- package/dist/server-core/src/collections/loader.d.ts.map +1 -0
- package/dist/server-core/src/cron/cron-loader.d.ts +18 -0
- package/dist/server-core/src/cron/cron-loader.d.ts.map +1 -0
- package/dist/server-core/src/cron/cron-routes.d.ts +15 -0
- package/dist/server-core/src/cron/cron-routes.d.ts.map +1 -0
- package/dist/server-core/src/cron/cron-scheduler.d.ts +62 -0
- package/dist/server-core/src/cron/cron-scheduler.d.ts.map +1 -0
- package/dist/server-core/src/cron/cron-store.d.ts +33 -0
- package/dist/server-core/src/cron/cron-store.d.ts.map +1 -0
- package/dist/server-core/src/cron/index.d.ts +7 -0
- package/dist/server-core/src/cron/index.d.ts.map +1 -0
- package/dist/server-core/src/db/interfaces.d.ts +19 -0
- package/dist/server-core/src/db/interfaces.d.ts.map +1 -0
- package/dist/server-core/src/email/index.d.ts +7 -0
- package/dist/server-core/src/email/index.d.ts.map +1 -0
- package/dist/server-core/src/email/smtp-email-service.d.ts +26 -0
- package/dist/server-core/src/email/smtp-email-service.d.ts.map +1 -0
- package/dist/server-core/src/email/templates.d.ts +43 -0
- package/dist/server-core/src/email/templates.d.ts.map +1 -0
- package/dist/server-core/src/email/types.d.ts +108 -0
- package/dist/server-core/src/email/types.d.ts.map +1 -0
- package/dist/server-core/src/functions/function-loader.d.ts +18 -0
- package/dist/server-core/src/functions/function-loader.d.ts.map +1 -0
- package/dist/server-core/src/functions/function-routes.d.ts +11 -0
- package/dist/server-core/src/functions/function-routes.d.ts.map +1 -0
- package/dist/server-core/src/functions/index.d.ts +4 -0
- package/dist/server-core/src/functions/index.d.ts.map +1 -0
- package/dist/server-core/src/history/history-routes.d.ts +24 -0
- package/dist/server-core/src/history/history-routes.d.ts.map +1 -0
- package/dist/server-core/src/history/index.d.ts +2 -0
- package/dist/server-core/src/history/index.d.ts.map +1 -0
- package/dist/server-core/src/index.d.ts +30 -0
- package/dist/server-core/src/index.d.ts.map +1 -0
- package/dist/server-core/src/init.d.ts +160 -0
- package/dist/server-core/src/init.d.ts.map +1 -0
- package/dist/server-core/src/serve-spa.d.ts +31 -0
- package/dist/server-core/src/serve-spa.d.ts.map +1 -0
- package/dist/server-core/src/services/driver-registry.d.ts +79 -0
- package/dist/server-core/src/services/driver-registry.d.ts.map +1 -0
- package/dist/server-core/src/singleton.d.ts +36 -0
- package/dist/server-core/src/singleton.d.ts.map +1 -0
- package/dist/server-core/src/storage/LocalStorageController.d.ts +47 -0
- package/dist/server-core/src/storage/LocalStorageController.d.ts.map +1 -0
- package/dist/server-core/src/storage/S3StorageController.d.ts +37 -0
- package/dist/server-core/src/storage/S3StorageController.d.ts.map +1 -0
- package/dist/server-core/src/storage/index.d.ts +26 -0
- package/dist/server-core/src/storage/index.d.ts.map +1 -0
- package/dist/server-core/src/storage/routes.d.ts +39 -0
- package/dist/server-core/src/storage/routes.d.ts.map +1 -0
- package/dist/server-core/src/storage/storage-registry.d.ts +79 -0
- package/dist/server-core/src/storage/storage-registry.d.ts.map +1 -0
- package/dist/server-core/src/storage/types.d.ts +104 -0
- package/dist/server-core/src/storage/types.d.ts.map +1 -0
- package/dist/server-core/src/types/index.d.ts +12 -0
- package/dist/server-core/src/types/index.d.ts.map +1 -0
- package/dist/server-core/src/utils/dev-port.d.ts +36 -0
- package/dist/server-core/src/utils/dev-port.d.ts.map +1 -0
- package/dist/server-core/src/utils/logger.d.ts +32 -0
- package/dist/server-core/src/utils/logger.d.ts.map +1 -0
- package/dist/server-core/src/utils/logging.d.ts +10 -0
- package/dist/server-core/src/utils/logging.d.ts.map +1 -0
- package/dist/server-core/src/utils/request-logger.d.ts +20 -0
- package/dist/server-core/src/utils/request-logger.d.ts.map +1 -0
- package/dist/server-core/src/utils/sql.d.ts +28 -0
- package/dist/server-core/src/utils/sql.d.ts.map +1 -0
- package/dist/server-mongodb/src/MongoBootstrapper.d.ts +18 -0
- package/dist/server-mongodb/src/MongoBootstrapper.d.ts.map +1 -0
- package/dist/server-mongodb/src/auth/ensure-collections.d.ts +3 -0
- package/dist/server-mongodb/src/auth/ensure-collections.d.ts.map +1 -0
- package/dist/server-mongodb/src/auth/services.d.ts +135 -0
- package/dist/server-mongodb/src/auth/services.d.ts.map +1 -0
- package/dist/server-mongodb/src/connection.d.ts +35 -0
- package/dist/server-mongodb/src/connection.d.ts.map +1 -0
- package/dist/server-mongodb/src/db/MongoConditionBuilder.d.ts +64 -0
- package/dist/server-mongodb/src/db/MongoConditionBuilder.d.ts.map +1 -0
- package/dist/server-mongodb/src/db/MongoEntityService.d.ts +98 -0
- package/dist/server-mongodb/src/db/MongoEntityService.d.ts.map +1 -0
- package/dist/server-mongodb/src/factory.d.ts +142 -0
- package/dist/server-mongodb/src/factory.d.ts.map +1 -0
- package/dist/server-mongodb/src/history/ensure-history-collection.d.ts +3 -0
- package/dist/server-mongodb/src/history/ensure-history-collection.d.ts.map +1 -0
- package/dist/server-mongodb/src/index.d.ts +18 -0
- package/dist/server-mongodb/src/index.d.ts.map +1 -0
- package/dist/server-mongodb/src/services/MongoDriver.d.ts +83 -0
- package/dist/server-mongodb/src/services/MongoDriver.d.ts.map +1 -0
- package/dist/server-mongodb/src/services/MongoHistoryService.d.ts +37 -0
- package/dist/server-mongodb/src/services/MongoHistoryService.d.ts.map +1 -0
- package/dist/server-mongodb/src/services/MongoRealtimeService.d.ts +86 -0
- package/dist/server-mongodb/src/services/MongoRealtimeService.d.ts.map +1 -0
- package/dist/server-mongodb/src/useMongoDriver.d.ts +18 -0
- package/dist/server-mongodb/src/useMongoDriver.d.ts.map +1 -0
- package/dist/server-mongodb/src/utils.d.ts +10 -0
- package/dist/server-mongodb/src/utils.d.ts.map +1 -0
- package/dist/server-mongodb/src/websocket.d.ts +7 -0
- package/dist/server-mongodb/src/websocket.d.ts.map +1 -0
- package/dist/types/src/controllers/analytics_controller.d.ts +8 -0
- package/dist/types/src/controllers/analytics_controller.d.ts.map +1 -0
- package/dist/types/src/controllers/auth.d.ts +120 -0
- package/dist/types/src/controllers/auth.d.ts.map +1 -0
- package/dist/types/src/controllers/client.d.ts +171 -0
- package/dist/types/src/controllers/client.d.ts.map +1 -0
- package/dist/types/src/controllers/collection_registry.d.ts +46 -0
- package/dist/types/src/controllers/collection_registry.d.ts.map +1 -0
- package/dist/types/src/controllers/customization_controller.d.ts +61 -0
- package/dist/types/src/controllers/customization_controller.d.ts.map +1 -0
- package/dist/types/src/controllers/data.d.ts +169 -0
- package/dist/types/src/controllers/data.d.ts.map +1 -0
- package/dist/types/src/controllers/data_driver.d.ts +161 -0
- package/dist/types/src/controllers/data_driver.d.ts.map +1 -0
- package/dist/types/src/controllers/database_admin.d.ts +12 -0
- package/dist/types/src/controllers/database_admin.d.ts.map +1 -0
- package/dist/types/src/controllers/dialogs_controller.d.ts +37 -0
- package/dist/types/src/controllers/dialogs_controller.d.ts.map +1 -0
- package/dist/types/src/controllers/effective_role.d.ts +5 -0
- package/dist/types/src/controllers/effective_role.d.ts.map +1 -0
- package/dist/types/src/controllers/email.d.ts +35 -0
- package/dist/types/src/controllers/email.d.ts.map +1 -0
- package/dist/types/src/controllers/index.d.ts +19 -0
- package/dist/types/src/controllers/index.d.ts.map +1 -0
- package/dist/types/src/controllers/local_config_persistence.d.ts +21 -0
- package/dist/types/src/controllers/local_config_persistence.d.ts.map +1 -0
- package/dist/types/src/controllers/navigation.d.ts +214 -0
- package/dist/types/src/controllers/navigation.d.ts.map +1 -0
- package/dist/types/src/controllers/registry.d.ts +55 -0
- package/dist/types/src/controllers/registry.d.ts.map +1 -0
- package/dist/types/src/controllers/side_dialogs_controller.d.ts +68 -0
- package/dist/types/src/controllers/side_dialogs_controller.d.ts.map +1 -0
- package/dist/types/src/controllers/side_entity_controller.d.ts +91 -0
- package/dist/types/src/controllers/side_entity_controller.d.ts.map +1 -0
- package/dist/types/src/controllers/snackbar.d.ts +25 -0
- package/dist/types/src/controllers/snackbar.d.ts.map +1 -0
- package/dist/types/src/controllers/storage.d.ts +172 -0
- package/dist/types/src/controllers/storage.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +5 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/rebase_context.d.ts +106 -0
- package/dist/types/src/rebase_context.d.ts.map +1 -0
- package/dist/types/src/types/backend.d.ts +537 -0
- package/dist/types/src/types/backend.d.ts.map +1 -0
- package/dist/types/src/types/builders.d.ts +16 -0
- package/dist/types/src/types/builders.d.ts.map +1 -0
- package/dist/types/src/types/chips.d.ts +6 -0
- package/dist/types/src/types/chips.d.ts.map +1 -0
- package/dist/types/src/types/collections.d.ts +857 -0
- package/dist/types/src/types/collections.d.ts.map +1 -0
- package/dist/types/src/types/cron.d.ts +103 -0
- package/dist/types/src/types/cron.d.ts.map +1 -0
- package/dist/types/src/types/data_source.d.ts +65 -0
- package/dist/types/src/types/data_source.d.ts.map +1 -0
- package/dist/types/src/types/entities.d.ts +146 -0
- package/dist/types/src/types/entities.d.ts.map +1 -0
- package/dist/types/src/types/entity_actions.d.ts +99 -0
- package/dist/types/src/types/entity_actions.d.ts.map +1 -0
- package/dist/types/src/types/entity_callbacks.d.ts +174 -0
- package/dist/types/src/types/entity_callbacks.d.ts.map +1 -0
- package/dist/types/src/types/entity_link_builder.d.ts +8 -0
- package/dist/types/src/types/entity_link_builder.d.ts.map +1 -0
- package/dist/types/src/types/entity_overrides.d.ts +11 -0
- package/dist/types/src/types/entity_overrides.d.ts.map +1 -0
- package/dist/types/src/types/entity_views.d.ts +62 -0
- package/dist/types/src/types/entity_views.d.ts.map +1 -0
- package/dist/types/src/types/export_import.d.ts +22 -0
- package/dist/types/src/types/export_import.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +24 -0
- package/dist/types/src/types/index.d.ts.map +1 -0
- package/dist/types/src/types/locales.d.ts +5 -0
- package/dist/types/src/types/locales.d.ts.map +1 -0
- package/dist/types/src/types/modify_collections.d.ts +6 -0
- package/dist/types/src/types/modify_collections.d.ts.map +1 -0
- package/dist/types/src/types/plugins.d.ts +280 -0
- package/dist/types/src/types/plugins.d.ts.map +1 -0
- package/dist/types/src/types/properties.d.ts +1177 -0
- package/dist/types/src/types/properties.d.ts.map +1 -0
- package/dist/types/src/types/property_config.d.ts +71 -0
- package/dist/types/src/types/property_config.d.ts.map +1 -0
- package/dist/types/src/types/relations.d.ts +337 -0
- package/dist/types/src/types/relations.d.ts.map +1 -0
- package/dist/types/src/types/slots.d.ts +253 -0
- package/dist/types/src/types/slots.d.ts.map +1 -0
- package/dist/types/src/types/translations.d.ts +871 -0
- package/dist/types/src/types/translations.d.ts.map +1 -0
- package/dist/types/src/types/user_management_delegate.d.ts +122 -0
- package/dist/types/src/types/user_management_delegate.d.ts.map +1 -0
- package/dist/types/src/types/websockets.d.ts +79 -0
- package/dist/types/src/types/websockets.d.ts.map +1 -0
- package/dist/types/src/users/index.d.ts +3 -0
- package/dist/types/src/users/index.d.ts.map +1 -0
- package/dist/types/src/users/roles.d.ts +23 -0
- package/dist/types/src/users/roles.d.ts.map +1 -0
- package/dist/types/src/users/user.d.ts +47 -0
- package/dist/types/src/users/user.d.ts.map +1 -0
- package/dist/websocket-BZlPuJrt.js +220 -0
- package/dist/websocket-BZlPuJrt.js.map +1 -0
- package/package.json +79 -0
- package/src/MongoBootstrapper.ts +177 -0
- package/src/auth/ensure-collections.ts +94 -0
- package/src/auth/services.ts +638 -0
- package/src/connection.ts +60 -0
- package/src/db/MongoConditionBuilder.ts +181 -0
- package/src/db/MongoEntityService.ts +350 -0
- package/src/factory.ts +289 -0
- package/src/history/ensure-history-collection.ts +19 -0
- package/src/index.ts +25 -0
- package/src/services/MongoDriver.ts +297 -0
- package/src/services/MongoDriver.ts.backup +266 -0
- package/src/services/MongoHistoryService.ts +154 -0
- package/src/services/MongoRealtimeService.ts +394 -0
- package/src/useMongoDriver.ts +519 -0
- package/src/utils.ts +28 -0
- 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
|
+
}
|