@open-mercato/core 0.5.1-develop.2691.d8a0934b37 → 0.5.1-develop.2699.f8b50c8046
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/dist/modules/api_keys/data/entities.js +1 -1
- package/dist/modules/api_keys/data/entities.js.map +1 -1
- package/dist/modules/api_keys/services/apiKeyService.js +5 -5
- package/dist/modules/api_keys/services/apiKeyService.js.map +2 -2
- package/dist/modules/attachments/api/library/[id]/route.js +1 -1
- package/dist/modules/attachments/api/library/[id]/route.js.map +2 -2
- package/dist/modules/attachments/api/library/route.js +7 -9
- package/dist/modules/attachments/api/library/route.js.map +2 -2
- package/dist/modules/attachments/api/partitions/route.js +3 -3
- package/dist/modules/attachments/api/partitions/route.js.map +2 -2
- package/dist/modules/attachments/api/route.js +6 -5
- package/dist/modules/attachments/api/route.js.map +2 -2
- package/dist/modules/attachments/api/transfer/route.js +1 -1
- package/dist/modules/attachments/api/transfer/route.js.map +2 -2
- package/dist/modules/attachments/data/entities.js +2 -1
- package/dist/modules/attachments/data/entities.js.map +2 -2
- package/dist/modules/attachments/lib/ocrQueue.js +1 -1
- package/dist/modules/attachments/lib/ocrQueue.js.map +2 -2
- package/dist/modules/audit_logs/api/audit-logs/actions/export/route.js.map +2 -2
- package/dist/modules/audit_logs/api/audit-logs/actions/route.js.map +2 -2
- package/dist/modules/audit_logs/data/entities.js +1 -1
- package/dist/modules/audit_logs/data/entities.js.map +1 -1
- package/dist/modules/audit_logs/services/actionLogService.js +77 -70
- package/dist/modules/audit_logs/services/actionLogService.js.map +2 -2
- package/dist/modules/auth/api/roles/acl/route.js +1 -1
- package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
- package/dist/modules/auth/api/users/acl/route.js +2 -2
- package/dist/modules/auth/api/users/acl/route.js.map +2 -2
- package/dist/modules/auth/api/users/resend-invite/route.js +1 -1
- package/dist/modules/auth/api/users/resend-invite/route.js.map +2 -2
- package/dist/modules/auth/cli.js +12 -6
- package/dist/modules/auth/cli.js.map +2 -2
- package/dist/modules/auth/commands/users.js +1 -1
- package/dist/modules/auth/commands/users.js.map +2 -2
- package/dist/modules/auth/data/entities.js +1 -1
- package/dist/modules/auth/data/entities.js.map +2 -2
- package/dist/modules/auth/lib/setup-app.js +3 -3
- package/dist/modules/auth/lib/setup-app.js.map +2 -2
- package/dist/modules/auth/services/authService.js +2 -2
- package/dist/modules/auth/services/authService.js.map +2 -2
- package/dist/modules/business_rules/api/rules/route.js +3 -3
- package/dist/modules/business_rules/api/rules/route.js.map +2 -2
- package/dist/modules/business_rules/api/sets/[id]/members/route.js +7 -4
- package/dist/modules/business_rules/api/sets/[id]/members/route.js.map +2 -2
- package/dist/modules/business_rules/api/sets/route.js +3 -3
- package/dist/modules/business_rules/api/sets/route.js.map +2 -2
- package/dist/modules/business_rules/cli.js +1 -1
- package/dist/modules/business_rules/cli.js.map +2 -2
- package/dist/modules/business_rules/data/entities.js +2 -9
- package/dist/modules/business_rules/data/entities.js.map +2 -2
- package/dist/modules/business_rules/lib/rule-engine.js +1 -1
- package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
- package/dist/modules/catalog/api/option-schemas/route.js +0 -1
- package/dist/modules/catalog/api/option-schemas/route.js.map +2 -2
- package/dist/modules/catalog/data/entities.js +2 -11
- package/dist/modules/catalog/data/entities.js.map +2 -2
- package/dist/modules/configs/data/entities.js +2 -1
- package/dist/modules/configs/data/entities.js.map +2 -2
- package/dist/modules/currencies/commands/fetch-configs.js +3 -3
- package/dist/modules/currencies/commands/fetch-configs.js.map +2 -2
- package/dist/modules/currencies/data/entities.js +1 -1
- package/dist/modules/currencies/data/entities.js.map +2 -2
- package/dist/modules/customer_accounts/api/signup.js +1 -1
- package/dist/modules/customer_accounts/api/signup.js.map +2 -2
- package/dist/modules/customer_accounts/data/entities.js +1 -1
- package/dist/modules/customer_accounts/data/entities.js.map +2 -2
- package/dist/modules/customer_accounts/services/customerInvitationService.js +1 -1
- package/dist/modules/customer_accounts/services/customerInvitationService.js.map +2 -2
- package/dist/modules/customer_accounts/services/customerSessionService.js +1 -1
- package/dist/modules/customer_accounts/services/customerSessionService.js.map +2 -2
- package/dist/modules/customer_accounts/services/customerTokenService.js +12 -7
- package/dist/modules/customer_accounts/services/customerTokenService.js.map +2 -2
- package/dist/modules/customers/api/interactions/conflicts/route.js +19 -17
- package/dist/modules/customers/api/interactions/conflicts/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/counts/route.js +7 -6
- package/dist/modules/customers/api/interactions/counts/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/route.js +28 -42
- package/dist/modules/customers/api/interactions/route.js.map +2 -2
- package/dist/modules/customers/api/utils.js +29 -24
- package/dist/modules/customers/api/utils.js.map +2 -2
- package/dist/modules/customers/cli.js +45 -40
- package/dist/modules/customers/cli.js.map +2 -2
- package/dist/modules/customers/commands/dictionaries.js +1 -1
- package/dist/modules/customers/commands/dictionaries.js.map +2 -2
- package/dist/modules/customers/commands/tags.js +1 -1
- package/dist/modules/customers/commands/tags.js.map +2 -2
- package/dist/modules/customers/data/entities.js +2 -12
- package/dist/modules/customers/data/entities.js.map +2 -2
- package/dist/modules/customers/lib/interactionProjection.js +18 -15
- package/dist/modules/customers/lib/interactionProjection.js.map +2 -2
- package/dist/modules/customers/lib/personCompanyLinkTable.js +6 -8
- package/dist/modules/customers/lib/personCompanyLinkTable.js.map +2 -2
- package/dist/modules/dashboards/api/roles/widgets/route.js +1 -1
- package/dist/modules/dashboards/api/roles/widgets/route.js.map +2 -2
- package/dist/modules/dashboards/api/users/widgets/route.js +1 -1
- package/dist/modules/dashboards/api/users/widgets/route.js.map +2 -2
- package/dist/modules/dashboards/data/entities.js +1 -1
- package/dist/modules/dashboards/data/entities.js.map +1 -1
- package/dist/modules/data_sync/api/mappings/route.js +1 -1
- package/dist/modules/data_sync/api/mappings/route.js.map +2 -2
- package/dist/modules/data_sync/data/entities.js +2 -1
- package/dist/modules/data_sync/data/entities.js.map +2 -2
- package/dist/modules/data_sync/lib/id-mapping.js +1 -1
- package/dist/modules/data_sync/lib/id-mapping.js.map +2 -2
- package/dist/modules/data_sync/lib/sync-run-service.js +1 -1
- package/dist/modules/data_sync/lib/sync-run-service.js.map +2 -2
- package/dist/modules/dictionaries/commands/factory.js +1 -1
- package/dist/modules/dictionaries/commands/factory.js.map +2 -2
- package/dist/modules/dictionaries/data/entities.js +2 -9
- package/dist/modules/dictionaries/data/entities.js.map +2 -2
- package/dist/modules/directory/commands/organizations.js +4 -4
- package/dist/modules/directory/commands/organizations.js.map +2 -2
- package/dist/modules/directory/data/entities.js +2 -1
- package/dist/modules/directory/data/entities.js.map +2 -2
- package/dist/modules/entities/api/definitions.js +2 -2
- package/dist/modules/entities/api/definitions.js.map +2 -2
- package/dist/modules/entities/api/encryption.js +2 -2
- package/dist/modules/entities/api/encryption.js.map +2 -2
- package/dist/modules/entities/api/relations/options.js +2 -2
- package/dist/modules/entities/api/relations/options.js.map +2 -2
- package/dist/modules/entities/cli.js +4 -4
- package/dist/modules/entities/cli.js.map +2 -2
- package/dist/modules/entities/data/entities.js +1 -1
- package/dist/modules/entities/data/entities.js.map +2 -2
- package/dist/modules/entities/lib/field-definitions.js +2 -2
- package/dist/modules/entities/lib/field-definitions.js.map +2 -2
- package/dist/modules/entities/lib/register.js +1 -1
- package/dist/modules/entities/lib/register.js.map +2 -2
- package/dist/modules/feature_toggles/data/entities.js +2 -9
- package/dist/modules/feature_toggles/data/entities.js.map +2 -2
- package/dist/modules/inbox_ops/api/proposals/counts/route.js +3 -6
- package/dist/modules/inbox_ops/api/proposals/counts/route.js.map +2 -2
- package/dist/modules/inbox_ops/data/entities.js +2 -8
- package/dist/modules/inbox_ops/data/entities.js.map +2 -2
- package/dist/modules/inbox_ops/lib/messagesIntegration.js +6 -6
- package/dist/modules/inbox_ops/lib/messagesIntegration.js.map +2 -2
- package/dist/modules/integrations/data/entities.js +2 -1
- package/dist/modules/integrations/data/entities.js.map +2 -2
- package/dist/modules/integrations/lib/credentials-service.js +1 -1
- package/dist/modules/integrations/lib/credentials-service.js.map +2 -2
- package/dist/modules/integrations/lib/log-service.js +1 -1
- package/dist/modules/integrations/lib/log-service.js.map +2 -2
- package/dist/modules/integrations/lib/state-service.js +1 -1
- package/dist/modules/integrations/lib/state-service.js.map +2 -2
- package/dist/modules/messages/api/route.js +90 -93
- package/dist/modules/messages/api/route.js.map +2 -2
- package/dist/modules/messages/api/unread-count/route.js +8 -7
- package/dist/modules/messages/api/unread-count/route.js.map +2 -2
- package/dist/modules/messages/commands/confirmations.js +1 -1
- package/dist/modules/messages/commands/confirmations.js.map +2 -2
- package/dist/modules/messages/commands/messages.js +3 -3
- package/dist/modules/messages/commands/messages.js.map +2 -2
- package/dist/modules/messages/data/entities.js +2 -1
- package/dist/modules/messages/data/entities.js.map +2 -2
- package/dist/modules/messages/lib/email-sender.js +1 -1
- package/dist/modules/messages/lib/email-sender.js.map +2 -2
- package/dist/modules/messages/lib/searchLookup.js +8 -8
- package/dist/modules/messages/lib/searchLookup.js.map +2 -2
- package/dist/modules/messages/lib/tokenConsumption.js +9 -4
- package/dist/modules/messages/lib/tokenConsumption.js.map +2 -2
- package/dist/modules/notifications/data/entities.js +2 -1
- package/dist/modules/notifications/data/entities.js.map +2 -2
- package/dist/modules/notifications/lib/notificationRecipients.js +15 -5
- package/dist/modules/notifications/lib/notificationRecipients.js.map +2 -2
- package/dist/modules/notifications/lib/notificationService.js +39 -34
- package/dist/modules/notifications/lib/notificationService.js.map +2 -2
- package/dist/modules/notifications/workers/create-notification.worker.js +14 -13
- package/dist/modules/notifications/workers/create-notification.worker.js.map +2 -2
- package/dist/modules/payment_gateways/api/transactions/route.js +2 -2
- package/dist/modules/payment_gateways/api/transactions/route.js.map +2 -2
- package/dist/modules/payment_gateways/data/entities.js +2 -1
- package/dist/modules/payment_gateways/data/entities.js.map +2 -2
- package/dist/modules/payment_gateways/lib/gateway-service.js +1 -1
- package/dist/modules/payment_gateways/lib/gateway-service.js.map +2 -2
- package/dist/modules/payment_gateways/lib/webhook-utils.js +2 -2
- package/dist/modules/payment_gateways/lib/webhook-utils.js.map +2 -2
- package/dist/modules/perspectives/data/entities.js +1 -1
- package/dist/modules/perspectives/data/entities.js.map +2 -2
- package/dist/modules/planner/data/entities.js +1 -1
- package/dist/modules/planner/data/entities.js.map +2 -2
- package/dist/modules/progress/data/entities.js +2 -1
- package/dist/modules/progress/data/entities.js.map +2 -2
- package/dist/modules/progress/lib/progressServiceImpl.js +1 -1
- package/dist/modules/progress/lib/progressServiceImpl.js.map +2 -2
- package/dist/modules/query_index/api/status.js +66 -57
- package/dist/modules/query_index/api/status.js.map +2 -2
- package/dist/modules/query_index/cli.js +39 -24
- package/dist/modules/query_index/cli.js.map +2 -2
- package/dist/modules/query_index/data/entities.js +1 -1
- package/dist/modules/query_index/data/entities.js.map +2 -2
- package/dist/modules/query_index/di.js +25 -13
- package/dist/modules/query_index/di.js.map +2 -2
- package/dist/modules/query_index/lib/batch.js +31 -33
- package/dist/modules/query_index/lib/batch.js.map +2 -2
- package/dist/modules/query_index/lib/coverage.js +63 -50
- package/dist/modules/query_index/lib/coverage.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +592 -588
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/query_index/lib/indexer.js +74 -47
- package/dist/modules/query_index/lib/indexer.js.map +2 -2
- package/dist/modules/query_index/lib/jobs.js +37 -24
- package/dist/modules/query_index/lib/jobs.js.map +2 -2
- package/dist/modules/query_index/lib/purge.js +19 -11
- package/dist/modules/query_index/lib/purge.js.map +2 -2
- package/dist/modules/query_index/lib/reindexer.js +47 -44
- package/dist/modules/query_index/lib/reindexer.js.map +2 -2
- package/dist/modules/query_index/lib/search-tokens.js +47 -25
- package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
- package/dist/modules/query_index/lib/stale.js +14 -12
- package/dist/modules/query_index/lib/stale.js.map +2 -2
- package/dist/modules/query_index/lib/subscriber-scope.js +2 -2
- package/dist/modules/query_index/lib/subscriber-scope.js.map +2 -2
- package/dist/modules/query_index/subscribers/delete_one.js +3 -2
- package/dist/modules/query_index/subscribers/delete_one.js.map +2 -2
- package/dist/modules/resources/commands/tag-assignments.js +1 -1
- package/dist/modules/resources/commands/tag-assignments.js.map +2 -2
- package/dist/modules/resources/commands/tags.js +1 -1
- package/dist/modules/resources/commands/tags.js.map +2 -2
- package/dist/modules/resources/data/entities.js +2 -1
- package/dist/modules/resources/data/entities.js.map +2 -2
- package/dist/modules/sales/commands/documentAddresses.js +2 -2
- package/dist/modules/sales/commands/documentAddresses.js.map +2 -2
- package/dist/modules/sales/commands/notes.js.map +2 -2
- package/dist/modules/sales/commands/tags.js +1 -1
- package/dist/modules/sales/commands/tags.js.map +2 -2
- package/dist/modules/sales/data/enrichers.js +9 -8
- package/dist/modules/sales/data/enrichers.js.map +2 -2
- package/dist/modules/sales/data/entities.js +2 -11
- package/dist/modules/sales/data/entities.js.map +2 -2
- package/dist/modules/shipping_carriers/data/entities.js +2 -1
- package/dist/modules/shipping_carriers/data/entities.js.map +2 -2
- package/dist/modules/shipping_carriers/lib/shipping-service.js +1 -1
- package/dist/modules/shipping_carriers/lib/shipping-service.js.map +2 -2
- package/dist/modules/shipping_carriers/lib/webhook-utils.js +2 -2
- package/dist/modules/shipping_carriers/lib/webhook-utils.js.map +2 -2
- package/dist/modules/staff/data/entities.js +1 -1
- package/dist/modules/staff/data/entities.js.map +2 -2
- package/dist/modules/translations/api/[entityType]/[entityId]/route.js +3 -5
- package/dist/modules/translations/api/[entityType]/[entityId]/route.js.map +2 -2
- package/dist/modules/translations/api/context.js +2 -2
- package/dist/modules/translations/api/context.js.map +2 -2
- package/dist/modules/translations/commands/translations.js +46 -39
- package/dist/modules/translations/commands/translations.js.map +2 -2
- package/dist/modules/translations/components/TranslationManager.js +19 -10
- package/dist/modules/translations/components/TranslationManager.js.map +2 -2
- package/dist/modules/translations/data/entities.js +1 -1
- package/dist/modules/translations/data/entities.js.map +2 -2
- package/dist/modules/translations/lib/apply.js +4 -4
- package/dist/modules/translations/lib/apply.js.map +2 -2
- package/dist/modules/translations/lib/batch.js +3 -2
- package/dist/modules/translations/lib/batch.js.map +2 -2
- package/dist/modules/translations/subscribers/cleanup.js +3 -5
- package/dist/modules/translations/subscribers/cleanup.js.map +2 -2
- package/dist/modules/workflows/api/definitions/route.js +1 -1
- package/dist/modules/workflows/api/definitions/route.js.map +2 -2
- package/dist/modules/workflows/cli.js +5 -5
- package/dist/modules/workflows/cli.js.map +2 -2
- package/dist/modules/workflows/data/entities.js +2 -1
- package/dist/modules/workflows/data/entities.js.map +2 -2
- package/dist/modules/workflows/lib/event-logger.js +2 -2
- package/dist/modules/workflows/lib/event-logger.js.map +2 -2
- package/dist/modules/workflows/lib/seeds.js +16 -1
- package/dist/modules/workflows/lib/seeds.js.map +2 -2
- package/dist/modules/workflows/lib/step-handler.js +3 -3
- package/dist/modules/workflows/lib/step-handler.js.map +2 -2
- package/dist/modules/workflows/lib/task-handler.js +1 -1
- package/dist/modules/workflows/lib/task-handler.js.map +2 -2
- package/dist/modules/workflows/lib/transition-handler.js +1 -1
- package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
- package/dist/modules/workflows/lib/workflow-executor.js +2 -2
- package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
- package/jest.config.cjs +4 -2
- package/package.json +3 -3
- package/src/modules/api_keys/data/entities.ts +1 -1
- package/src/modules/api_keys/services/apiKeyService.ts +5 -5
- package/src/modules/attachments/api/library/[id]/route.ts +1 -1
- package/src/modules/attachments/api/library/route.ts +10 -12
- package/src/modules/attachments/api/partitions/route.ts +3 -3
- package/src/modules/attachments/api/route.ts +10 -8
- package/src/modules/attachments/api/transfer/route.ts +1 -1
- package/src/modules/attachments/data/entities.ts +2 -1
- package/src/modules/attachments/lib/ocrQueue.ts +1 -1
- package/src/modules/audit_logs/api/audit-logs/actions/export/route.ts +4 -4
- package/src/modules/audit_logs/api/audit-logs/actions/route.ts +4 -4
- package/src/modules/audit_logs/data/entities.ts +1 -1
- package/src/modules/audit_logs/services/actionLogService.ts +96 -87
- package/src/modules/auth/api/roles/acl/route.ts +1 -1
- package/src/modules/auth/api/users/acl/route.ts +2 -2
- package/src/modules/auth/api/users/resend-invite/route.ts +1 -1
- package/src/modules/auth/cli.ts +46 -40
- package/src/modules/auth/commands/users.ts +1 -1
- package/src/modules/auth/data/entities.ts +1 -1
- package/src/modules/auth/lib/setup-app.ts +3 -3
- package/src/modules/auth/services/authService.ts +2 -2
- package/src/modules/business_rules/api/rules/route.ts +3 -3
- package/src/modules/business_rules/api/sets/[id]/members/route.ts +7 -4
- package/src/modules/business_rules/api/sets/route.ts +3 -3
- package/src/modules/business_rules/cli.ts +1 -1
- package/src/modules/business_rules/data/entities.ts +2 -9
- package/src/modules/business_rules/lib/rule-engine.ts +1 -1
- package/src/modules/catalog/api/option-schemas/route.ts +0 -1
- package/src/modules/catalog/data/entities.ts +2 -11
- package/src/modules/configs/data/entities.ts +2 -1
- package/src/modules/currencies/commands/fetch-configs.ts +3 -3
- package/src/modules/currencies/data/entities.ts +1 -1
- package/src/modules/customer_accounts/api/signup.ts +1 -1
- package/src/modules/customer_accounts/data/entities.ts +1 -1
- package/src/modules/customer_accounts/services/customerInvitationService.ts +1 -1
- package/src/modules/customer_accounts/services/customerSessionService.ts +1 -1
- package/src/modules/customer_accounts/services/customerTokenService.ts +26 -15
- package/src/modules/customers/api/interactions/conflicts/route.ts +26 -23
- package/src/modules/customers/api/interactions/counts/route.ts +13 -11
- package/src/modules/customers/api/interactions/route.ts +32 -44
- package/src/modules/customers/api/utils.ts +45 -37
- package/src/modules/customers/cli.ts +88 -67
- package/src/modules/customers/commands/dictionaries.ts +1 -1
- package/src/modules/customers/commands/tags.ts +1 -1
- package/src/modules/customers/data/entities.ts +2 -12
- package/src/modules/customers/lib/interactionProjection.ts +36 -25
- package/src/modules/customers/lib/personCompanyLinkTable.ts +13 -18
- package/src/modules/dashboards/api/roles/widgets/route.ts +1 -1
- package/src/modules/dashboards/api/users/widgets/route.ts +1 -1
- package/src/modules/dashboards/data/entities.ts +1 -1
- package/src/modules/data_sync/api/mappings/route.ts +1 -1
- package/src/modules/data_sync/data/entities.ts +2 -1
- package/src/modules/data_sync/lib/id-mapping.ts +1 -1
- package/src/modules/data_sync/lib/sync-run-service.ts +1 -1
- package/src/modules/dictionaries/commands/factory.ts +1 -1
- package/src/modules/dictionaries/data/entities.ts +2 -9
- package/src/modules/directory/commands/organizations.ts +4 -4
- package/src/modules/directory/data/entities.ts +2 -1
- package/src/modules/entities/api/definitions.ts +2 -2
- package/src/modules/entities/api/encryption.ts +2 -2
- package/src/modules/entities/api/relations/options.ts +8 -3
- package/src/modules/entities/cli.ts +4 -4
- package/src/modules/entities/data/entities.ts +1 -1
- package/src/modules/entities/lib/field-definitions.ts +2 -2
- package/src/modules/entities/lib/register.ts +1 -1
- package/src/modules/feature_toggles/data/entities.ts +2 -9
- package/src/modules/inbox_ops/api/proposals/counts/route.ts +10 -10
- package/src/modules/inbox_ops/data/entities.ts +2 -8
- package/src/modules/inbox_ops/lib/messagesIntegration.ts +12 -11
- package/src/modules/integrations/data/entities.ts +2 -1
- package/src/modules/integrations/lib/credentials-service.ts +1 -1
- package/src/modules/integrations/lib/log-service.ts +1 -1
- package/src/modules/integrations/lib/state-service.ts +1 -1
- package/src/modules/messages/api/route.ts +134 -123
- package/src/modules/messages/api/unread-count/route.ts +19 -16
- package/src/modules/messages/commands/confirmations.ts +1 -1
- package/src/modules/messages/commands/messages.ts +3 -3
- package/src/modules/messages/data/entities.ts +2 -1
- package/src/modules/messages/lib/email-sender.ts +1 -1
- package/src/modules/messages/lib/searchLookup.ts +16 -13
- package/src/modules/messages/lib/tokenConsumption.ts +16 -8
- package/src/modules/notifications/data/entities.ts +2 -1
- package/src/modules/notifications/lib/notificationRecipients.ts +42 -26
- package/src/modules/notifications/lib/notificationService.ts +53 -42
- package/src/modules/notifications/workers/create-notification.worker.ts +20 -17
- package/src/modules/payment_gateways/api/transactions/route.ts +2 -2
- package/src/modules/payment_gateways/data/entities.ts +2 -1
- package/src/modules/payment_gateways/lib/gateway-service.ts +1 -1
- package/src/modules/payment_gateways/lib/webhook-utils.ts +2 -2
- package/src/modules/perspectives/data/entities.ts +1 -1
- package/src/modules/planner/data/entities.ts +1 -1
- package/src/modules/progress/data/entities.ts +2 -1
- package/src/modules/progress/lib/progressServiceImpl.ts +1 -1
- package/src/modules/query_index/api/status.ts +85 -71
- package/src/modules/query_index/cli.ts +51 -31
- package/src/modules/query_index/data/entities.ts +1 -1
- package/src/modules/query_index/di.ts +41 -16
- package/src/modules/query_index/lib/batch.ts +68 -55
- package/src/modules/query_index/lib/coverage.ts +115 -88
- package/src/modules/query_index/lib/engine.ts +1036 -1096
- package/src/modules/query_index/lib/indexer.ts +115 -79
- package/src/modules/query_index/lib/jobs.ts +51 -31
- package/src/modules/query_index/lib/purge.ts +25 -19
- package/src/modules/query_index/lib/reindexer.ts +97 -84
- package/src/modules/query_index/lib/search-tokens.ts +67 -36
- package/src/modules/query_index/lib/stale.ts +14 -17
- package/src/modules/query_index/lib/subscriber-scope.ts +6 -5
- package/src/modules/query_index/subscribers/delete_one.ts +9 -6
- package/src/modules/resources/commands/tag-assignments.ts +1 -1
- package/src/modules/resources/commands/tags.ts +1 -1
- package/src/modules/resources/data/entities.ts +2 -1
- package/src/modules/sales/commands/documentAddresses.ts +2 -2
- package/src/modules/sales/commands/notes.ts +1 -1
- package/src/modules/sales/commands/tags.ts +1 -1
- package/src/modules/sales/data/enrichers.ts +17 -13
- package/src/modules/sales/data/entities.ts +2 -11
- package/src/modules/shipping_carriers/data/entities.ts +2 -1
- package/src/modules/shipping_carriers/lib/shipping-service.ts +1 -1
- package/src/modules/shipping_carriers/lib/webhook-utils.ts +2 -2
- package/src/modules/staff/data/entities.ts +1 -1
- package/src/modules/translations/api/[entityType]/[entityId]/route.ts +14 -11
- package/src/modules/translations/api/context.ts +4 -4
- package/src/modules/translations/commands/translations.ts +116 -81
- package/src/modules/translations/components/TranslationManager.tsx +23 -14
- package/src/modules/translations/data/entities.ts +1 -1
- package/src/modules/translations/i18n/de.json +1 -0
- package/src/modules/translations/i18n/en.json +1 -0
- package/src/modules/translations/i18n/es.json +1 -0
- package/src/modules/translations/i18n/pl.json +1 -0
- package/src/modules/translations/lib/apply.ts +6 -6
- package/src/modules/translations/lib/batch.ts +9 -7
- package/src/modules/translations/subscribers/cleanup.ts +10 -11
- package/src/modules/workflows/api/definitions/route.ts +1 -1
- package/src/modules/workflows/cli.ts +5 -5
- package/src/modules/workflows/data/entities.ts +2 -1
- package/src/modules/workflows/lib/event-logger.ts +2 -2
- package/src/modules/workflows/lib/seeds.ts +16 -1
- package/src/modules/workflows/lib/step-handler.ts +3 -3
- package/src/modules/workflows/lib/task-handler.ts +1 -1
- package/src/modules/workflows/lib/transition-handler.ts +1 -1
- package/src/modules/workflows/lib/workflow-executor.ts +2 -2
|
@@ -1,36 +1,57 @@
|
|
|
1
1
|
import { resolveEntityTableName } from "@open-mercato/shared/lib/query/engine";
|
|
2
2
|
import { resolveTenantEncryptionService } from "@open-mercato/shared/lib/encryption/customFieldValues";
|
|
3
3
|
import { decryptIndexDocForSearch, encryptIndexDocForStorage } from "@open-mercato/shared/lib/encryption/indexDoc";
|
|
4
|
+
import { sql } from "kysely";
|
|
4
5
|
import { replaceSearchTokensForRecord, deleteSearchTokensForRecord } from "./search-tokens.js";
|
|
5
6
|
import { attachAggregateSearchField } from "./document.js";
|
|
6
7
|
async function buildIndexDoc(em, params) {
|
|
7
|
-
const
|
|
8
|
+
const db = em.getKysely();
|
|
8
9
|
const baseTable = resolveEntityTableName(em, params.entityType);
|
|
9
|
-
const baseRow = await
|
|
10
|
+
const baseRow = await db.selectFrom(baseTable).selectAll().where("id", "=", params.recordId).executeTakeFirst();
|
|
10
11
|
if (!baseRow) return null;
|
|
11
12
|
const docSources = [];
|
|
12
13
|
let parentEntityRow = null;
|
|
13
14
|
if (params.entityType === "customers:customer_person_profile" || params.entityType === "customers:customer_company_profile") {
|
|
14
15
|
const entityId = baseRow.entity_id ?? baseRow.entityId;
|
|
15
16
|
if (entityId) {
|
|
16
|
-
const entityRow = await
|
|
17
|
+
const entityRow = await db.selectFrom("customer_entities").selectAll().where("id", "=", entityId).executeTakeFirst();
|
|
17
18
|
if (entityRow) {
|
|
18
19
|
docSources.push(entityRow);
|
|
19
20
|
parentEntityRow = entityRow;
|
|
20
21
|
}
|
|
21
22
|
}
|
|
22
23
|
}
|
|
24
|
+
void parentEntityRow;
|
|
23
25
|
let doc = {};
|
|
24
26
|
docSources.push(baseRow);
|
|
25
27
|
for (const source of docSources) {
|
|
26
28
|
for (const [k, v] of Object.entries(source)) doc[k] = v;
|
|
27
29
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
let cfQuery = db.selectFrom("custom_field_values").select([
|
|
31
|
+
"field_key",
|
|
32
|
+
"value_text",
|
|
33
|
+
"value_multiline",
|
|
34
|
+
"value_int",
|
|
35
|
+
"value_float",
|
|
36
|
+
"value_bool"
|
|
37
|
+
]).where("entity_id", "=", params.entityType).where("record_id", "=", String(params.recordId));
|
|
38
|
+
if (params.organizationId != null) {
|
|
39
|
+
cfQuery = cfQuery.where((eb) => eb.or([
|
|
40
|
+
eb("organization_id", "=", params.organizationId),
|
|
41
|
+
eb("organization_id", "is", null)
|
|
42
|
+
]));
|
|
43
|
+
} else {
|
|
44
|
+
cfQuery = cfQuery.where("organization_id", "is", null);
|
|
45
|
+
}
|
|
46
|
+
if (params.tenantId != null) {
|
|
47
|
+
cfQuery = cfQuery.where((eb) => eb.or([
|
|
48
|
+
eb("tenant_id", "=", params.tenantId),
|
|
49
|
+
eb("tenant_id", "is", null)
|
|
50
|
+
]));
|
|
51
|
+
} else {
|
|
52
|
+
cfQuery = cfQuery.where("tenant_id", "is", null);
|
|
53
|
+
}
|
|
54
|
+
const cfRows = await cfQuery.execute();
|
|
34
55
|
const cfMap = {};
|
|
35
56
|
for (const r of cfRows) {
|
|
36
57
|
const key = String(r.field_key);
|
|
@@ -43,7 +64,7 @@ async function buildIndexDoc(em, params) {
|
|
|
43
64
|
doc[key] = arr.length <= 1 ? arr[0] : arr;
|
|
44
65
|
}
|
|
45
66
|
try {
|
|
46
|
-
const translationRow = await
|
|
67
|
+
const translationRow = await db.selectFrom("entity_translations").select(["translations"]).where("entity_type", "=", params.entityType).where("entity_id", "=", String(params.recordId)).where(sql`tenant_id is not distinct from ${params.tenantId ?? null}`).where(sql`organization_id is not distinct from ${params.organizationId ?? null}`).executeTakeFirst();
|
|
47
68
|
if (translationRow?.translations && typeof translationRow.translations === "object") {
|
|
48
69
|
for (const [locale, fields] of Object.entries(translationRow.translations)) {
|
|
49
70
|
if (!fields || typeof fields !== "object") continue;
|
|
@@ -69,20 +90,25 @@ async function buildIndexDoc(em, params) {
|
|
|
69
90
|
}
|
|
70
91
|
return doc;
|
|
71
92
|
}
|
|
93
|
+
function scopeEntityIndexes(q, args) {
|
|
94
|
+
let chain = q.where("entity_type", "=", args.entityType);
|
|
95
|
+
chain = chain.where("entity_id", "=", String(args.recordId));
|
|
96
|
+
chain = args.organizationId == null ? chain.where("organization_id", "is", null) : chain.where("organization_id", "=", args.organizationId);
|
|
97
|
+
chain = chain.where(sql`tenant_id is not distinct from ${args.tenantId ?? null}`);
|
|
98
|
+
return chain;
|
|
99
|
+
}
|
|
72
100
|
async function upsertIndexRow(em, args) {
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}).andWhereRaw("tenant_id is not distinct from ?", [args.tenantId ?? null]).first();
|
|
79
|
-
const existing = await baseScopeQuery;
|
|
101
|
+
const db = em.getKysely();
|
|
102
|
+
const existing = await scopeEntityIndexes(
|
|
103
|
+
db.selectFrom("entity_indexes").select(["id", "deleted_at"]),
|
|
104
|
+
args
|
|
105
|
+
).executeTakeFirst();
|
|
80
106
|
const existed = !!existing;
|
|
81
107
|
const wasDeleted = !!existing && existing.deleted_at != null;
|
|
82
108
|
const doc = await buildIndexDoc(em, args);
|
|
83
109
|
if (!doc) {
|
|
84
110
|
try {
|
|
85
|
-
await deleteSearchTokensForRecord(
|
|
111
|
+
await deleteSearchTokensForRecord(db, {
|
|
86
112
|
entityType: args.entityType,
|
|
87
113
|
recordId: args.recordId,
|
|
88
114
|
organizationId: args.organizationId ?? null,
|
|
@@ -91,11 +117,10 @@ async function upsertIndexRow(em, args) {
|
|
|
91
117
|
} catch {
|
|
92
118
|
}
|
|
93
119
|
if (existed) {
|
|
94
|
-
await
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}).andWhereRaw("tenant_id is not distinct from ?", [args.tenantId ?? null]).del();
|
|
120
|
+
await scopeEntityIndexes(
|
|
121
|
+
db.deleteFrom("entity_indexes"),
|
|
122
|
+
args
|
|
123
|
+
).execute();
|
|
99
124
|
}
|
|
100
125
|
return { doc: null, existed, wasDeleted, created: false, revived: false };
|
|
101
126
|
}
|
|
@@ -104,23 +129,27 @@ async function upsertIndexRow(em, args) {
|
|
|
104
129
|
entity_id: String(args.recordId),
|
|
105
130
|
organization_id: args.organizationId ?? null,
|
|
106
131
|
tenant_id: args.tenantId ?? null,
|
|
107
|
-
doc
|
|
132
|
+
doc: sql`${JSON.stringify(doc)}::jsonb`,
|
|
108
133
|
index_version: 1,
|
|
109
|
-
updated_at:
|
|
134
|
+
updated_at: sql`now()`,
|
|
110
135
|
deleted_at: null
|
|
111
136
|
};
|
|
112
137
|
try {
|
|
113
|
-
|
|
114
|
-
|
|
138
|
+
await db.insertInto("entity_indexes").values({ ...payload, created_at: sql`now()` }).onConflict((oc) => oc.columns(["entity_type", "entity_id", "organization_id_coalesced"]).doUpdateSet({
|
|
139
|
+
tenant_id: args.tenantId ?? null,
|
|
140
|
+
doc: sql`${JSON.stringify(doc)}::jsonb`,
|
|
141
|
+
index_version: 1,
|
|
142
|
+
updated_at: sql`now()`,
|
|
143
|
+
deleted_at: null
|
|
144
|
+
})).execute();
|
|
115
145
|
} catch {
|
|
116
|
-
const updated = await
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if (!updated) {
|
|
146
|
+
const updated = await scopeEntityIndexes(
|
|
147
|
+
db.updateTable("entity_indexes").set(payload),
|
|
148
|
+
args
|
|
149
|
+
).executeTakeFirst();
|
|
150
|
+
if (!updated || Number(updated.numUpdatedRows ?? 0) === 0) {
|
|
122
151
|
try {
|
|
123
|
-
await
|
|
152
|
+
await db.insertInto("entity_indexes").values({ ...payload, created_at: sql`now()` }).execute();
|
|
124
153
|
} catch {
|
|
125
154
|
}
|
|
126
155
|
}
|
|
@@ -137,7 +166,7 @@ async function upsertIndexRow(em, args) {
|
|
|
137
166
|
encryption,
|
|
138
167
|
dekKeyCache
|
|
139
168
|
);
|
|
140
|
-
await replaceSearchTokensForRecord(
|
|
169
|
+
await replaceSearchTokensForRecord(db, {
|
|
141
170
|
entityType: args.entityType,
|
|
142
171
|
recordId: args.recordId,
|
|
143
172
|
organizationId: args.organizationId ?? null,
|
|
@@ -149,16 +178,15 @@ async function upsertIndexRow(em, args) {
|
|
|
149
178
|
return { doc, existed, wasDeleted, created, revived };
|
|
150
179
|
}
|
|
151
180
|
async function markDeleted(em, args) {
|
|
152
|
-
const
|
|
153
|
-
const existing = await
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}).andWhereRaw("tenant_id is not distinct from ?", [args.tenantId ?? null]).first();
|
|
181
|
+
const db = em.getKysely();
|
|
182
|
+
const existing = await scopeEntityIndexes(
|
|
183
|
+
db.selectFrom("entity_indexes").select(["deleted_at"]),
|
|
184
|
+
args
|
|
185
|
+
).executeTakeFirst();
|
|
158
186
|
const wasActive = !!existing && existing.deleted_at == null;
|
|
159
187
|
if (existing) {
|
|
160
188
|
try {
|
|
161
|
-
await deleteSearchTokensForRecord(
|
|
189
|
+
await deleteSearchTokensForRecord(db, {
|
|
162
190
|
entityType: args.entityType,
|
|
163
191
|
recordId: args.recordId,
|
|
164
192
|
organizationId: args.organizationId ?? null,
|
|
@@ -166,11 +194,10 @@ async function markDeleted(em, args) {
|
|
|
166
194
|
});
|
|
167
195
|
} catch {
|
|
168
196
|
}
|
|
169
|
-
await
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}).andWhereRaw("tenant_id is not distinct from ?", [args.tenantId ?? null]).del();
|
|
197
|
+
await scopeEntityIndexes(
|
|
198
|
+
db.deleteFrom("entity_indexes"),
|
|
199
|
+
args
|
|
200
|
+
).execute();
|
|
174
201
|
}
|
|
175
202
|
return { wasActive };
|
|
176
203
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/query_index/lib/indexer.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { resolveEntityTableName } from '@open-mercato/shared/lib/query/engine'\nimport { resolveTenantEncryptionService } from '@open-mercato/shared/lib/encryption/customFieldValues'\nimport { decryptIndexDocForSearch, encryptIndexDocForStorage } from '@open-mercato/shared/lib/encryption/indexDoc'\nimport type { Knex } from 'knex'\nimport { replaceSearchTokensForRecord, deleteSearchTokensForRecord } from './search-tokens'\nimport { attachAggregateSearchField } from './document'\n\ntype BuildDocParams = {\n entityType: string // '<module>:<entity>'\n recordId: string\n organizationId?: string | null\n tenantId?: string | null\n}\n\nexport async function buildIndexDoc(em: EntityManager, params: BuildDocParams): Promise<Record<string, any> | null> {\n const knex = (em as any).getConnection().getKnex() as Knex\n const baseTable = resolveEntityTableName(em, params.entityType)\n\n // Fetch base row\n const baseRow = await knex(baseTable)\n .where('id', params.recordId)\n .first()\n if (!baseRow) return null\n const docSources: Array<Record<string, any>> = []\n\n // Attach the core customer entity when indexing customer profiles so search tokens see the combined row\n let parentEntityRow: Record<string, any> | null = null\n if (params.entityType === 'customers:customer_person_profile' || params.entityType === 'customers:customer_company_profile') {\n const entityId = (baseRow as any).entity_id ?? (baseRow as any).entityId\n if (entityId) {\n const entityRow = await knex('customer_entities')\n .where('id', entityId)\n .first()\n if (entityRow) {\n docSources.push(entityRow)\n parentEntityRow = entityRow\n }\n }\n }\n\n // Build base document (snake_case keys as in DB)\n let doc: Record<string, any> = {}\n docSources.push(baseRow)\n for (const source of docSources) {\n for (const [k, v] of Object.entries(source)) doc[k] = v\n }\n\n // Attach custom fields under flat keys 'cf:<key>'\n const cfRows = await knex('custom_field_values')\n .select(['field_key', 'value_text', 'value_multiline', 'value_int', 'value_float', 'value_bool'])\n .where({ entity_id: params.entityType, record_id: String(params.recordId) })\n .modify((qb: any) => {\n if (params.organizationId != null) qb.andWhere((b: any) => b.where({ organization_id: params.organizationId }).orWhereNull('organization_id'))\n else qb.whereNull('organization_id')\n if (params.tenantId != null) qb.andWhere((b: any) => b.where({ tenant_id: params.tenantId }).orWhereNull('tenant_id'))\n else qb.whereNull('tenant_id')\n })\n\n const cfMap: Record<string, any[]> = {}\n for (const r of cfRows) {\n const key = String(r.field_key)\n const cfKey = `cf:${key}`\n const val = r.value_bool ?? r.value_int ?? r.value_float ?? r.value_text ?? r.value_multiline ?? null\n if (!cfMap[cfKey]) cfMap[cfKey] = []\n cfMap[cfKey].push(val)\n }\n for (const [key, arr] of Object.entries(cfMap)) {\n // Store singletons as simple value; multis as array\n doc[key] = arr.length <= 1 ? arr[0] : arr\n }\n\n // Attach translations under flat keys 'l10n:{locale}:{field}'\n try {\n const translationRow = await knex('entity_translations')\n .where({ entity_type: params.entityType, entity_id: String(params.recordId) })\n .andWhereRaw('tenant_id is not distinct from ?', [params.tenantId ?? null])\n .andWhereRaw('organization_id is not distinct from ?', [params.organizationId ?? null])\n .select(['translations'])\n .first()\n\n if (translationRow?.translations && typeof translationRow.translations === 'object') {\n for (const [locale, fields] of Object.entries(translationRow.translations)) {\n if (!fields || typeof fields !== 'object') continue\n for (const [field, value] of Object.entries(fields as Record<string, unknown>)) {\n if (typeof value === 'string' && value.length > 0) {\n doc[`l10n:${locale}:${field}`] = value\n }\n }\n }\n }\n } catch {}\n\n try {\n doc = attachAggregateSearchField(doc)\n const encryption = resolveTenantEncryptionService(em as any)\n doc = await encryptIndexDocForStorage(\n params.entityType,\n doc,\n { tenantId: params.tenantId ?? null, organizationId: params.organizationId ?? null },\n encryption,\n )\n } catch {}\n\n return doc\n}\n\nexport type UpsertIndexResult = {\n doc: Record<string, any> | null\n existed: boolean\n wasDeleted: boolean\n created: boolean\n revived: boolean\n}\n\nexport async function upsertIndexRow(\n em: EntityManager,\n args: { entityType: string; recordId: string; organizationId?: string | null; tenantId?: string | null }\n): Promise<UpsertIndexResult> {\n const knex = (em as any).getConnection().getKnex() as Knex\n const baseScopeQuery = knex('entity_indexes')\n .select(['id', 'deleted_at'])\n .where({\n entity_type: args.entityType,\n entity_id: String(args.recordId),\n organization_id: args.organizationId ?? null,\n })\n .andWhereRaw('tenant_id is not distinct from ?', [args.tenantId ?? null])\n .first<{ id: string; deleted_at: Date | null } | undefined>()\n\n const existing = await baseScopeQuery\n const existed = !!existing\n const wasDeleted = !!existing && existing.deleted_at != null\n\n const doc = await buildIndexDoc(em, args)\n if (!doc) {\n try {\n await deleteSearchTokensForRecord(knex, {\n entityType: args.entityType,\n recordId: args.recordId,\n organizationId: args.organizationId ?? null,\n tenantId: args.tenantId ?? null,\n })\n } catch {}\n if (existed) {\n await knex('entity_indexes')\n .where({\n entity_type: args.entityType,\n entity_id: String(args.recordId),\n organization_id: args.organizationId ?? null,\n })\n .andWhereRaw('tenant_id is not distinct from ?', [args.tenantId ?? null])\n .del()\n }\n return { doc: null, existed, wasDeleted, created: false, revived: false }\n }\n\n const payload = {\n entity_type: args.entityType,\n entity_id: String(args.recordId),\n organization_id: args.organizationId ?? null,\n tenant_id: args.tenantId ?? null,\n doc,\n index_version: 1,\n updated_at: knex.fn.now(),\n deleted_at: null,\n }\n // Prefer modern upsert keyed by coalesced org id when available; fallback to update-then-insert\n try {\n const insertQ = knex('entity_indexes').insert({ ...payload, created_at: knex.fn.now() })\n await insertQ\n .onConflict(['entity_type', 'entity_id', 'organization_id_coalesced'])\n .merge(payload)\n } catch {\n // Fallback for schemas without organization_id_coalesced column/index\n const updated = await knex('entity_indexes')\n .where({\n entity_type: args.entityType,\n entity_id: String(args.recordId),\n organization_id: args.organizationId ?? null,\n })\n .andWhereRaw('tenant_id is not distinct from ?', [args.tenantId ?? null])\n .update(payload)\n if (!updated) {\n try { await knex('entity_indexes').insert({ ...payload, created_at: knex.fn.now() }) } catch {}\n }\n }\n\n const created = !existed\n const revived = existed && wasDeleted\n try {\n const encryption = resolveTenantEncryptionService(em as any)\n const dekKeyCache = new Map<string | null, string | null>()\n const tokenDoc = await decryptIndexDocForSearch(\n args.entityType,\n doc,\n { tenantId: args.tenantId ?? null, organizationId: args.organizationId ?? null },\n encryption,\n dekKeyCache,\n )\n await replaceSearchTokensForRecord(knex, {\n entityType: args.entityType,\n recordId: args.recordId,\n organizationId: args.organizationId ?? null,\n tenantId: args.tenantId ?? null,\n doc: tokenDoc,\n })\n } catch {}\n return { doc, existed, wasDeleted, created, revived }\n}\n\nexport async function markDeleted(\n em: EntityManager,\n args: { entityType: string; recordId: string; organizationId?: string | null; tenantId?: string | null }\n): Promise<{ wasActive: boolean }> {\n const knex = (em as any).getConnection().getKnex() as Knex\n const existing = await knex('entity_indexes')\n .select(['deleted_at'])\n .where({\n entity_type: args.entityType,\n entity_id: String(args.recordId),\n organization_id: args.organizationId ?? null,\n })\n .andWhereRaw('tenant_id is not distinct from ?', [args.tenantId ?? null])\n .first<{ deleted_at: Date | null } | undefined>()\n\n const wasActive = !!existing && existing.deleted_at == null\n\n if (existing) {\n try {\n await deleteSearchTokensForRecord(knex, {\n entityType: args.entityType,\n recordId: args.recordId,\n organizationId: args.organizationId ?? null,\n tenantId: args.tenantId ?? null,\n })\n } catch {}\n await knex('entity_indexes')\n .where({\n entity_type: args.entityType,\n entity_id: String(args.recordId),\n organization_id: args.organizationId ?? null,\n })\n .andWhereRaw('tenant_id is not distinct from ?', [args.tenantId ?? null])\n .del()\n }\n\n return { wasActive }\n}\n"],
|
|
5
|
-
"mappings": "AACA,SAAS,8BAA8B;AACvC,SAAS,sCAAsC;AAC/C,SAAS,0BAA0B,iCAAiC;
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { resolveEntityTableName } from '@open-mercato/shared/lib/query/engine'\nimport { resolveTenantEncryptionService } from '@open-mercato/shared/lib/encryption/customFieldValues'\nimport { decryptIndexDocForSearch, encryptIndexDocForStorage } from '@open-mercato/shared/lib/encryption/indexDoc'\nimport { sql } from 'kysely'\nimport { replaceSearchTokensForRecord, deleteSearchTokensForRecord } from './search-tokens'\nimport { attachAggregateSearchField } from './document'\n\ntype BuildDocParams = {\n entityType: string // '<module>:<entity>'\n recordId: string\n organizationId?: string | null\n tenantId?: string | null\n}\n\nexport async function buildIndexDoc(em: EntityManager, params: BuildDocParams): Promise<Record<string, any> | null> {\n const db = (em as any).getKysely()\n const baseTable = resolveEntityTableName(em, params.entityType)\n\n // Fetch base row\n const baseRow = await db\n .selectFrom(baseTable as any)\n .selectAll()\n .where('id' as any, '=', params.recordId)\n .executeTakeFirst() as Record<string, any> | undefined\n if (!baseRow) return null\n const docSources: Array<Record<string, any>> = []\n\n // Attach the core customer entity when indexing customer profiles so search tokens see the combined row\n let parentEntityRow: Record<string, any> | null = null\n if (params.entityType === 'customers:customer_person_profile' || params.entityType === 'customers:customer_company_profile') {\n const entityId = (baseRow as any).entity_id ?? (baseRow as any).entityId\n if (entityId) {\n const entityRow = await db\n .selectFrom('customer_entities' as any)\n .selectAll()\n .where('id' as any, '=', entityId)\n .executeTakeFirst() as Record<string, any> | undefined\n if (entityRow) {\n docSources.push(entityRow)\n parentEntityRow = entityRow\n }\n }\n }\n void parentEntityRow\n\n // Build base document (snake_case keys as in DB)\n let doc: Record<string, any> = {}\n docSources.push(baseRow)\n for (const source of docSources) {\n for (const [k, v] of Object.entries(source)) doc[k] = v\n }\n\n // Attach custom fields under flat keys 'cf:<key>'\n let cfQuery = db\n .selectFrom('custom_field_values' as any)\n .select([\n 'field_key' as any,\n 'value_text' as any,\n 'value_multiline' as any,\n 'value_int' as any,\n 'value_float' as any,\n 'value_bool' as any,\n ])\n .where('entity_id' as any, '=', params.entityType)\n .where('record_id' as any, '=', String(params.recordId))\n\n if (params.organizationId != null) {\n cfQuery = cfQuery.where((eb: any) => eb.or([\n eb('organization_id' as any, '=', params.organizationId),\n eb('organization_id' as any, 'is', null),\n ]))\n } else {\n cfQuery = cfQuery.where('organization_id' as any, 'is', null)\n }\n\n if (params.tenantId != null) {\n cfQuery = cfQuery.where((eb: any) => eb.or([\n eb('tenant_id' as any, '=', params.tenantId),\n eb('tenant_id' as any, 'is', null),\n ]))\n } else {\n cfQuery = cfQuery.where('tenant_id' as any, 'is', null)\n }\n\n const cfRows = await cfQuery.execute() as Array<Record<string, any>>\n\n const cfMap: Record<string, any[]> = {}\n for (const r of cfRows) {\n const key = String(r.field_key)\n const cfKey = `cf:${key}`\n const val = r.value_bool ?? r.value_int ?? r.value_float ?? r.value_text ?? r.value_multiline ?? null\n if (!cfMap[cfKey]) cfMap[cfKey] = []\n cfMap[cfKey].push(val)\n }\n for (const [key, arr] of Object.entries(cfMap)) {\n // Store singletons as simple value; multis as array\n doc[key] = arr.length <= 1 ? arr[0] : arr\n }\n\n // Attach translations under flat keys 'l10n:{locale}:{field}'\n try {\n const translationRow = await db\n .selectFrom('entity_translations' as any)\n .select(['translations' as any])\n .where('entity_type' as any, '=', params.entityType)\n .where('entity_id' as any, '=', String(params.recordId))\n .where(sql`tenant_id is not distinct from ${params.tenantId ?? null}`)\n .where(sql`organization_id is not distinct from ${params.organizationId ?? null}`)\n .executeTakeFirst() as { translations: Record<string, Record<string, unknown>> | null } | undefined\n\n if (translationRow?.translations && typeof translationRow.translations === 'object') {\n for (const [locale, fields] of Object.entries(translationRow.translations)) {\n if (!fields || typeof fields !== 'object') continue\n for (const [field, value] of Object.entries(fields as Record<string, unknown>)) {\n if (typeof value === 'string' && value.length > 0) {\n doc[`l10n:${locale}:${field}`] = value\n }\n }\n }\n }\n } catch {}\n\n try {\n doc = attachAggregateSearchField(doc)\n const encryption = resolveTenantEncryptionService(em as any)\n doc = await encryptIndexDocForStorage(\n params.entityType,\n doc,\n { tenantId: params.tenantId ?? null, organizationId: params.organizationId ?? null },\n encryption,\n )\n } catch {}\n\n return doc\n}\n\nexport type UpsertIndexResult = {\n doc: Record<string, any> | null\n existed: boolean\n wasDeleted: boolean\n created: boolean\n revived: boolean\n}\n\nfunction scopeEntityIndexes<QB extends { where: (...args: any[]) => QB }>(\n q: QB,\n args: { entityType: string; recordId: string; organizationId?: string | null; tenantId?: string | null },\n): QB {\n let chain = q.where('entity_type' as any, '=', args.entityType)\n chain = chain.where('entity_id' as any, '=', String(args.recordId))\n chain = args.organizationId == null\n ? chain.where('organization_id' as any, 'is', null as any)\n : chain.where('organization_id' as any, '=', args.organizationId)\n chain = chain.where(sql`tenant_id is not distinct from ${args.tenantId ?? null}`)\n return chain\n}\n\nexport async function upsertIndexRow(\n em: EntityManager,\n args: { entityType: string; recordId: string; organizationId?: string | null; tenantId?: string | null }\n): Promise<UpsertIndexResult> {\n const db = (em as any).getKysely()\n\n const existing = await scopeEntityIndexes(\n db.selectFrom('entity_indexes' as any).select(['id' as any, 'deleted_at' as any]),\n args,\n ).executeTakeFirst() as { id: string; deleted_at: Date | null } | undefined\n\n const existed = !!existing\n const wasDeleted = !!existing && existing.deleted_at != null\n\n const doc = await buildIndexDoc(em, args)\n if (!doc) {\n try {\n await deleteSearchTokensForRecord(db, {\n entityType: args.entityType,\n recordId: args.recordId,\n organizationId: args.organizationId ?? null,\n tenantId: args.tenantId ?? null,\n })\n } catch {}\n if (existed) {\n await scopeEntityIndexes(\n db.deleteFrom('entity_indexes' as any) as any,\n args,\n ).execute()\n }\n return { doc: null, existed, wasDeleted, created: false, revived: false }\n }\n\n const payload = {\n entity_type: args.entityType,\n entity_id: String(args.recordId),\n organization_id: args.organizationId ?? null,\n tenant_id: args.tenantId ?? null,\n doc: sql`${JSON.stringify(doc)}::jsonb`,\n index_version: 1,\n updated_at: sql`now()`,\n deleted_at: null,\n }\n\n // Prefer modern upsert keyed by coalesced org id when available; fallback to update-then-insert\n try {\n await db\n .insertInto('entity_indexes' as any)\n .values({ ...payload, created_at: sql`now()` } as any)\n .onConflict((oc: any) => oc\n .columns(['entity_type', 'entity_id', 'organization_id_coalesced'])\n .doUpdateSet({\n tenant_id: args.tenantId ?? null,\n doc: sql`${JSON.stringify(doc)}::jsonb`,\n index_version: 1,\n updated_at: sql`now()`,\n deleted_at: null,\n } as any))\n .execute()\n } catch {\n // Fallback for schemas without organization_id_coalesced column/index\n const updated = await scopeEntityIndexes(\n db.updateTable('entity_indexes' as any).set(payload as any) as any,\n args,\n ).executeTakeFirst() as { numUpdatedRows?: bigint | number } | undefined\n if (!updated || Number(updated.numUpdatedRows ?? 0) === 0) {\n try {\n await db\n .insertInto('entity_indexes' as any)\n .values({ ...payload, created_at: sql`now()` } as any)\n .execute()\n } catch {}\n }\n }\n\n const created = !existed\n const revived = existed && wasDeleted\n try {\n const encryption = resolveTenantEncryptionService(em as any)\n const dekKeyCache = new Map<string | null, string | null>()\n const tokenDoc = await decryptIndexDocForSearch(\n args.entityType,\n doc,\n { tenantId: args.tenantId ?? null, organizationId: args.organizationId ?? null },\n encryption,\n dekKeyCache,\n )\n await replaceSearchTokensForRecord(db, {\n entityType: args.entityType,\n recordId: args.recordId,\n organizationId: args.organizationId ?? null,\n tenantId: args.tenantId ?? null,\n doc: tokenDoc,\n })\n } catch {}\n return { doc, existed, wasDeleted, created, revived }\n}\n\nexport async function markDeleted(\n em: EntityManager,\n args: { entityType: string; recordId: string; organizationId?: string | null; tenantId?: string | null }\n): Promise<{ wasActive: boolean }> {\n const db = (em as any).getKysely()\n const existing = await scopeEntityIndexes(\n db.selectFrom('entity_indexes' as any).select(['deleted_at' as any]),\n args,\n ).executeTakeFirst() as { deleted_at: Date | null } | undefined\n\n const wasActive = !!existing && existing.deleted_at == null\n\n if (existing) {\n try {\n await deleteSearchTokensForRecord(db, {\n entityType: args.entityType,\n recordId: args.recordId,\n organizationId: args.organizationId ?? null,\n tenantId: args.tenantId ?? null,\n })\n } catch {}\n await scopeEntityIndexes(\n db.deleteFrom('entity_indexes' as any) as any,\n args,\n ).execute()\n }\n\n return { wasActive }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,46 +1,59 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { sql } from "kysely";
|
|
2
|
+
function applyScopeWhere(builder, scope) {
|
|
3
|
+
let q = builder.where("entity_type", "=", scope.entityType);
|
|
4
|
+
q = q.where(sql`organization_id is not distinct from ${scope.organizationId ?? null}`);
|
|
5
|
+
q = q.where(sql`tenant_id is not distinct from ${scope.tenantId ?? null}`);
|
|
6
|
+
q = q.where(sql`partition_index is not distinct from ${scope.partitionIndex ?? null}`);
|
|
7
|
+
q = q.where(sql`partition_count is not distinct from ${scope.partitionCount ?? null}`);
|
|
8
|
+
return q;
|
|
8
9
|
}
|
|
9
|
-
async function prepareJob(
|
|
10
|
+
async function prepareJob(db, scope, status, options = {}) {
|
|
10
11
|
const base = {
|
|
11
12
|
organization_id: scope.organizationId ?? null,
|
|
12
13
|
tenant_id: scope.tenantId ?? null,
|
|
13
14
|
partition_index: scope.partitionIndex ?? null,
|
|
14
15
|
partition_count: scope.partitionCount ?? null,
|
|
15
16
|
status,
|
|
16
|
-
started_at:
|
|
17
|
+
started_at: sql`now()`,
|
|
17
18
|
finished_at: null,
|
|
18
|
-
heartbeat_at:
|
|
19
|
+
heartbeat_at: sql`now()`,
|
|
19
20
|
processed_count: 0,
|
|
20
21
|
total_count: options.totalCount ?? null
|
|
21
22
|
};
|
|
22
|
-
const existing = await
|
|
23
|
+
const existing = await applyScopeWhere(
|
|
24
|
+
db.selectFrom("entity_index_jobs").select(["id"]),
|
|
25
|
+
scope
|
|
26
|
+
).executeTakeFirst();
|
|
23
27
|
if (existing) {
|
|
24
|
-
await
|
|
28
|
+
await applyScopeWhere(
|
|
29
|
+
db.updateTable("entity_index_jobs").set(base),
|
|
30
|
+
scope
|
|
31
|
+
).execute();
|
|
25
32
|
return existing.id;
|
|
26
33
|
}
|
|
27
|
-
const inserted = await
|
|
34
|
+
const inserted = await db.insertInto("entity_index_jobs").values({
|
|
28
35
|
entity_type: scope.entityType,
|
|
29
36
|
...base
|
|
30
|
-
}).returning("id");
|
|
37
|
+
}).returning(["id"]).execute();
|
|
31
38
|
return inserted?.[0]?.id ?? null;
|
|
32
39
|
}
|
|
33
|
-
async function updateJobProgress(
|
|
34
|
-
await
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
async function updateJobProgress(db, scope, processedDelta) {
|
|
41
|
+
await applyScopeWhere(
|
|
42
|
+
db.updateTable("entity_index_jobs").set({
|
|
43
|
+
processed_count: sql`coalesce(processed_count, 0) + ${Math.max(0, processedDelta)}`,
|
|
44
|
+
heartbeat_at: sql`now()`
|
|
45
|
+
}),
|
|
46
|
+
scope
|
|
47
|
+
).execute();
|
|
38
48
|
}
|
|
39
|
-
async function finalizeJob(
|
|
40
|
-
await
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
49
|
+
async function finalizeJob(db, scope) {
|
|
50
|
+
await applyScopeWhere(
|
|
51
|
+
db.updateTable("entity_index_jobs").set({
|
|
52
|
+
finished_at: sql`now()`,
|
|
53
|
+
heartbeat_at: sql`now()`
|
|
54
|
+
}),
|
|
55
|
+
scope
|
|
56
|
+
).execute();
|
|
44
57
|
}
|
|
45
58
|
export {
|
|
46
59
|
finalizeJob,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/query_index/lib/jobs.ts"],
|
|
4
|
-
"sourcesContent": ["import type
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import { type Kysely, sql } from 'kysely'\n\nexport type JobScope = {\n entityType: string\n organizationId?: string | null\n tenantId?: string | null\n partitionIndex?: number | null\n partitionCount?: number | null\n}\n\nfunction applyScopeWhere<QB extends { where: (...args: any[]) => QB }>(\n builder: QB,\n scope: JobScope,\n): QB {\n let q = builder.where('entity_type' as any, '=', scope.entityType)\n q = q.where(sql`organization_id is not distinct from ${scope.organizationId ?? null}`)\n q = q.where(sql`tenant_id is not distinct from ${scope.tenantId ?? null}`)\n q = q.where(sql`partition_index is not distinct from ${scope.partitionIndex ?? null}`)\n q = q.where(sql`partition_count is not distinct from ${scope.partitionCount ?? null}`)\n return q\n}\n\nexport async function prepareJob(\n db: Kysely<any>,\n scope: JobScope,\n status: 'reindexing' | 'purging',\n options: { totalCount?: number | null } = {},\n): Promise<string | null> {\n const base = {\n organization_id: scope.organizationId ?? null,\n tenant_id: scope.tenantId ?? null,\n partition_index: scope.partitionIndex ?? null,\n partition_count: scope.partitionCount ?? null,\n status,\n started_at: sql`now()`,\n finished_at: null,\n heartbeat_at: sql`now()`,\n processed_count: 0,\n total_count: options.totalCount ?? null,\n }\n\n const existing = await applyScopeWhere(\n db.selectFrom('entity_index_jobs' as any).select(['id' as any]),\n scope,\n ).executeTakeFirst() as { id: string } | undefined\n\n if (existing) {\n await applyScopeWhere(\n db.updateTable('entity_index_jobs' as any).set(base as any) as any,\n scope,\n ).execute()\n return existing.id\n }\n\n const inserted = await db\n .insertInto('entity_index_jobs' as any)\n .values({\n entity_type: scope.entityType,\n ...base,\n } as any)\n .returning(['id' as any])\n .execute() as Array<{ id: string }>\n\n return inserted?.[0]?.id ?? null\n}\n\nexport async function updateJobProgress(\n db: Kysely<any>,\n scope: JobScope,\n processedDelta: number,\n): Promise<void> {\n await applyScopeWhere(\n db.updateTable('entity_index_jobs' as any).set({\n processed_count: sql`coalesce(processed_count, 0) + ${Math.max(0, processedDelta)}`,\n heartbeat_at: sql`now()`,\n } as any) as any,\n scope,\n ).execute()\n}\n\nexport async function finalizeJob(\n db: Kysely<any>,\n scope: JobScope,\n): Promise<void> {\n await applyScopeWhere(\n db.updateTable('entity_index_jobs' as any).set({\n finished_at: sql`now()`,\n heartbeat_at: sql`now()`,\n } as any) as any,\n scope,\n ).execute()\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAsB,WAAW;AAUjC,SAAS,gBACP,SACA,OACI;AACJ,MAAI,IAAI,QAAQ,MAAM,eAAsB,KAAK,MAAM,UAAU;AACjE,MAAI,EAAE,MAAM,2CAA2C,MAAM,kBAAkB,IAAI,EAAE;AACrF,MAAI,EAAE,MAAM,qCAAqC,MAAM,YAAY,IAAI,EAAE;AACzE,MAAI,EAAE,MAAM,2CAA2C,MAAM,kBAAkB,IAAI,EAAE;AACrF,MAAI,EAAE,MAAM,2CAA2C,MAAM,kBAAkB,IAAI,EAAE;AACrF,SAAO;AACT;AAEA,eAAsB,WACpB,IACA,OACA,QACA,UAA0C,CAAC,GACnB;AACxB,QAAM,OAAO;AAAA,IACX,iBAAiB,MAAM,kBAAkB;AAAA,IACzC,WAAW,MAAM,YAAY;AAAA,IAC7B,iBAAiB,MAAM,kBAAkB;AAAA,IACzC,iBAAiB,MAAM,kBAAkB;AAAA,IACzC;AAAA,IACA,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,aAAa,QAAQ,cAAc;AAAA,EACrC;AAEA,QAAM,WAAW,MAAM;AAAA,IACrB,GAAG,WAAW,mBAA0B,EAAE,OAAO,CAAC,IAAW,CAAC;AAAA,IAC9D;AAAA,EACF,EAAE,iBAAiB;AAEnB,MAAI,UAAU;AACZ,UAAM;AAAA,MACJ,GAAG,YAAY,mBAA0B,EAAE,IAAI,IAAW;AAAA,MAC1D;AAAA,IACF,EAAE,QAAQ;AACV,WAAO,SAAS;AAAA,EAClB;AAEA,QAAM,WAAW,MAAM,GACpB,WAAW,mBAA0B,EACrC,OAAO;AAAA,IACN,aAAa,MAAM;AAAA,IACnB,GAAG;AAAA,EACL,CAAQ,EACP,UAAU,CAAC,IAAW,CAAC,EACvB,QAAQ;AAEX,SAAO,WAAW,CAAC,GAAG,MAAM;AAC9B;AAEA,eAAsB,kBACpB,IACA,OACA,gBACe;AACf,QAAM;AAAA,IACJ,GAAG,YAAY,mBAA0B,EAAE,IAAI;AAAA,MAC7C,iBAAiB,qCAAqC,KAAK,IAAI,GAAG,cAAc,CAAC;AAAA,MACjF,cAAc;AAAA,IAChB,CAAQ;AAAA,IACR;AAAA,EACF,EAAE,QAAQ;AACZ;AAEA,eAAsB,YACpB,IACA,OACe;AACf,QAAM;AAAA,IACJ,GAAG,YAAY,mBAA0B,EAAE,IAAI;AAAA,MAC7C,aAAa;AAAA,MACb,cAAc;AAAA,IAChB,CAAQ;AAAA,IACR;AAAA,EACF,EAAE,QAAQ;AACZ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { sql } from "kysely";
|
|
1
2
|
import { prepareJob, updateJobProgress, finalizeJob } from "./jobs.js";
|
|
2
3
|
async function purgeIndexScope(em, options) {
|
|
3
|
-
const
|
|
4
|
+
const db = em.getKysely();
|
|
4
5
|
const scope = {
|
|
5
6
|
entityType: options.entityType,
|
|
6
7
|
organizationId: options.organizationId ?? null,
|
|
@@ -8,24 +9,31 @@ async function purgeIndexScope(em, options) {
|
|
|
8
9
|
partitionIndex: null,
|
|
9
10
|
partitionCount: null
|
|
10
11
|
};
|
|
11
|
-
const
|
|
12
|
+
const applyScope = (q) => {
|
|
13
|
+
let chain = q.where("entity_type", "=", options.entityType);
|
|
12
14
|
if (options.organizationId !== void 0) {
|
|
13
|
-
|
|
15
|
+
chain = chain.where(sql`organization_id is not distinct from ${options.organizationId ?? null}`);
|
|
14
16
|
}
|
|
15
17
|
if (options.tenantId !== void 0) {
|
|
16
|
-
|
|
18
|
+
chain = chain.where(sql`tenant_id is not distinct from ${options.tenantId ?? null}`);
|
|
17
19
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
return chain;
|
|
21
|
+
};
|
|
22
|
+
const totalRow = await applyScope(
|
|
23
|
+
db.selectFrom("entity_indexes").select(sql`count(*)`.as("count"))
|
|
24
|
+
).executeTakeFirst();
|
|
20
25
|
const total = totalRow ? Number(totalRow.count) || 0 : 0;
|
|
21
|
-
await prepareJob(
|
|
26
|
+
await prepareJob(db, scope, "purging", { totalCount: total });
|
|
22
27
|
if (total > 0) {
|
|
23
|
-
const
|
|
24
|
-
|
|
28
|
+
const result = await applyScope(
|
|
29
|
+
db.deleteFrom("entity_indexes")
|
|
30
|
+
).executeTakeFirst();
|
|
31
|
+
const removed = Number(result?.numDeletedRows ?? 0);
|
|
32
|
+
await updateJobProgress(db, scope, removed || total);
|
|
25
33
|
} else {
|
|
26
|
-
await updateJobProgress(
|
|
34
|
+
await updateJobProgress(db, scope, 0);
|
|
27
35
|
}
|
|
28
|
-
await finalizeJob(
|
|
36
|
+
await finalizeJob(db, scope);
|
|
29
37
|
}
|
|
30
38
|
export {
|
|
31
39
|
purgeIndexScope
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/query_index/lib/purge.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { sql } from 'kysely'\nimport { prepareJob, updateJobProgress, finalizeJob, type JobScope } from './jobs'\n\nexport type PurgeOptions = {\n entityType: string\n organizationId?: string | null\n tenantId?: string | null\n}\n\nexport async function purgeIndexScope(\n em: EntityManager,\n options: PurgeOptions,\n): Promise<void> {\n const db = em.getKysely<any>()\n const scope: JobScope = {\n entityType: options.entityType,\n organizationId: options.organizationId ?? null,\n tenantId: options.tenantId ?? null,\n partitionIndex: null,\n partitionCount: null,\n }\n\n const applyScope = <QB extends { where: (...args: any[]) => QB }>(q: QB): QB => {\n let chain = q.where('entity_type' as any, '=', options.entityType)\n if (options.organizationId !== undefined) {\n chain = chain.where(sql`organization_id is not distinct from ${options.organizationId ?? null}`)\n }\n if (options.tenantId !== undefined) {\n chain = chain.where(sql`tenant_id is not distinct from ${options.tenantId ?? null}`)\n }\n return chain\n }\n\n const totalRow = await applyScope(\n db.selectFrom('entity_indexes' as any).select(sql`count(*)`.as('count')),\n ).executeTakeFirst() as { count: unknown } | undefined\n\n const total = totalRow ? Number(totalRow.count) || 0 : 0\n\n await prepareJob(db, scope, 'purging', { totalCount: total })\n\n if (total > 0) {\n const result = await applyScope(\n db.deleteFrom('entity_indexes' as any) as any,\n ).executeTakeFirst() as { numDeletedRows?: bigint | number } | undefined\n const removed = Number(result?.numDeletedRows ?? 0)\n await updateJobProgress(db, scope, removed || total)\n } else {\n await updateJobProgress(db, scope, 0)\n }\n\n await finalizeJob(db, scope)\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,WAAW;AACpB,SAAS,YAAY,mBAAmB,mBAAkC;AAQ1E,eAAsB,gBACpB,IACA,SACe;AACf,QAAM,KAAK,GAAG,UAAe;AAC7B,QAAM,QAAkB;AAAA,IACtB,YAAY,QAAQ;AAAA,IACpB,gBAAgB,QAAQ,kBAAkB;AAAA,IAC1C,UAAU,QAAQ,YAAY;AAAA,IAC9B,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,EAClB;AAEA,QAAM,aAAa,CAA+C,MAAc;AAC9E,QAAI,QAAQ,EAAE,MAAM,eAAsB,KAAK,QAAQ,UAAU;AACjE,QAAI,QAAQ,mBAAmB,QAAW;AACxC,cAAQ,MAAM,MAAM,2CAA2C,QAAQ,kBAAkB,IAAI,EAAE;AAAA,IACjG;AACA,QAAI,QAAQ,aAAa,QAAW;AAClC,cAAQ,MAAM,MAAM,qCAAqC,QAAQ,YAAY,IAAI,EAAE;AAAA,IACrF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,MAAM;AAAA,IACrB,GAAG,WAAW,gBAAuB,EAAE,OAAO,cAAc,GAAG,OAAO,CAAC;AAAA,EACzE,EAAE,iBAAiB;AAEnB,QAAM,QAAQ,WAAW,OAAO,SAAS,KAAK,KAAK,IAAI;AAEvD,QAAM,WAAW,IAAI,OAAO,WAAW,EAAE,YAAY,MAAM,CAAC;AAE5D,MAAI,QAAQ,GAAG;AACb,UAAM,SAAS,MAAM;AAAA,MACnB,GAAG,WAAW,gBAAuB;AAAA,IACvC,EAAE,iBAAiB;AACnB,UAAM,UAAU,OAAO,QAAQ,kBAAkB,CAAC;AAClD,UAAM,kBAAkB,IAAI,OAAO,WAAW,KAAK;AAAA,EACrD,OAAO;AACL,UAAM,kBAAkB,IAAI,OAAO,CAAC;AAAA,EACtC;AAEA,QAAM,YAAY,IAAI,KAAK;AAC7B;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|