@webda/core 4.0.0-beta.1 → 4.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +252 -0
- package/lib/application/application.d.ts +437 -0
- package/lib/application/application.d.ts.map +1 -0
- package/lib/application/application.js +792 -0
- package/lib/application/application.js.map +1 -0
- package/lib/application/hooks.d.ts +34 -0
- package/lib/application/hooks.d.ts.map +1 -0
- package/lib/application/hooks.js +57 -0
- package/lib/application/hooks.js.map +1 -0
- package/lib/application/iapplication.d.ts +43 -0
- package/lib/application/iapplication.d.ts.map +1 -0
- package/lib/application/iapplication.js +2 -0
- package/lib/application/iapplication.js.map +1 -0
- package/lib/application/iconfiguration.d.ts +176 -0
- package/lib/application/iconfiguration.d.ts.map +1 -0
- package/lib/application/iconfiguration.js +8 -0
- package/lib/application/iconfiguration.js.map +1 -0
- package/lib/application/runner.d.ts +8 -0
- package/lib/application/runner.d.ts.map +1 -0
- package/lib/application/runner.js +26 -0
- package/lib/application/runner.js.map +1 -0
- package/lib/application/unpackedapplication.d.ts +104 -0
- package/lib/application/unpackedapplication.d.ts.map +1 -0
- package/lib/application/unpackedapplication.js +492 -0
- package/lib/application/unpackedapplication.js.map +1 -0
- package/lib/bin/cli-phase.d.ts +28 -0
- package/lib/bin/cli-phase.d.ts.map +1 -0
- package/lib/bin/cli-phase.js +44 -0
- package/lib/bin/cli-phase.js.map +1 -0
- package/lib/bin/cli.d.ts +161 -0
- package/lib/bin/cli.d.ts.map +1 -0
- package/lib/bin/cli.js +828 -0
- package/lib/bin/cli.js.map +1 -0
- package/lib/bin/launcher.d.ts +3 -0
- package/lib/bin/launcher.d.ts.map +1 -0
- package/lib/bin/launcher.js +50 -0
- package/lib/bin/launcher.js.map +1 -0
- package/lib/cache/cache.d.ts +33 -0
- package/lib/cache/cache.d.ts.map +1 -0
- package/lib/cache/cache.js +8 -0
- package/lib/cache/cache.js.map +1 -0
- package/lib/{services/configuration.d.ts → configurations/configuration.service.d.ts} +58 -49
- package/lib/configurations/configuration.service.d.ts.map +1 -0
- package/lib/configurations/configuration.service.js +248 -0
- package/lib/configurations/configuration.service.js.map +1 -0
- package/lib/configurations/fileconfiguration.service.d.ts +30 -0
- package/lib/configurations/fileconfiguration.service.d.ts.map +1 -0
- package/lib/configurations/fileconfiguration.service.js +65 -0
- package/lib/configurations/fileconfiguration.service.js.map +1 -0
- package/lib/configurations/kubernetesconfiguration.service.d.ts +43 -0
- package/lib/configurations/kubernetesconfiguration.service.d.ts.map +1 -0
- package/lib/configurations/kubernetesconfiguration.service.js +83 -0
- package/lib/configurations/kubernetesconfiguration.service.js.map +1 -0
- package/lib/contexts/execution.d.ts +33 -0
- package/lib/contexts/execution.d.ts.map +1 -0
- package/lib/contexts/execution.js +73 -0
- package/lib/contexts/execution.js.map +1 -0
- package/lib/contexts/globalcontext.d.ts +29 -0
- package/lib/contexts/globalcontext.d.ts.map +1 -0
- package/lib/contexts/globalcontext.js +38 -0
- package/lib/contexts/globalcontext.js.map +1 -0
- package/lib/{utils → contexts}/httpcontext.d.ts +45 -19
- package/lib/contexts/httpcontext.d.ts.map +1 -0
- package/lib/{utils → contexts}/httpcontext.js +102 -34
- package/lib/contexts/httpcontext.js.map +1 -0
- package/lib/contexts/icontext.d.ts +236 -0
- package/lib/contexts/icontext.d.ts.map +1 -0
- package/lib/contexts/icontext.js +230 -0
- package/lib/contexts/icontext.js.map +1 -0
- package/lib/contexts/operationcontext.d.ts +179 -0
- package/lib/contexts/operationcontext.d.ts.map +1 -0
- package/lib/contexts/operationcontext.js +358 -0
- package/lib/contexts/operationcontext.js.map +1 -0
- package/lib/contexts/simplecontext.d.ts +31 -0
- package/lib/contexts/simplecontext.d.ts.map +1 -0
- package/lib/contexts/simplecontext.js +45 -0
- package/lib/contexts/simplecontext.js.map +1 -0
- package/lib/contexts/webcontext.d.ts +218 -0
- package/lib/contexts/webcontext.d.ts.map +1 -0
- package/lib/contexts/webcontext.js +389 -0
- package/lib/contexts/webcontext.js.map +1 -0
- package/lib/core/authorizer.d.ts +23 -0
- package/lib/core/authorizer.d.ts.map +1 -0
- package/lib/core/authorizer.js +17 -0
- package/lib/core/authorizer.js.map +1 -0
- package/lib/core/core.d.ts +225 -0
- package/lib/core/core.d.ts.map +1 -0
- package/lib/core/core.js +576 -0
- package/lib/core/core.js.map +1 -0
- package/lib/core/hooks.d.ts +72 -0
- package/lib/core/hooks.d.ts.map +1 -0
- package/lib/core/hooks.js +73 -0
- package/lib/core/hooks.js.map +1 -0
- package/lib/core/icore.d.ts +249 -0
- package/lib/core/icore.d.ts.map +1 -0
- package/lib/core/icore.js +15 -0
- package/lib/core/icore.js.map +1 -0
- package/lib/core/instancestorage.d.ts +61 -0
- package/lib/core/instancestorage.d.ts.map +1 -0
- package/lib/core/instancestorage.js +75 -0
- package/lib/core/instancestorage.js.map +1 -0
- package/lib/core/operations.d.ts +181 -0
- package/lib/core/operations.d.ts.map +1 -0
- package/lib/core/operations.js +559 -0
- package/lib/core/operations.js.map +1 -0
- package/lib/errors/errors.d.ts +126 -0
- package/lib/errors/errors.d.ts.map +1 -0
- package/lib/errors/errors.js +165 -0
- package/lib/errors/errors.js.map +1 -0
- package/lib/events/asynceventemitter.d.ts +159 -0
- package/lib/events/asynceventemitter.d.ts.map +1 -0
- package/lib/events/asynceventemitter.js +152 -0
- package/lib/events/asynceventemitter.js.map +1 -0
- package/lib/events/events.d.ts +112 -0
- package/lib/events/events.d.ts.map +1 -0
- package/lib/events/events.js +45 -0
- package/lib/events/events.js.map +1 -0
- package/lib/index.d.ts +84 -51
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +82 -59
- package/lib/index.js.map +1 -1
- package/lib/loggers/console.service.d.ts +24 -0
- package/lib/loggers/console.service.d.ts.map +1 -0
- package/lib/loggers/console.service.js +30 -0
- package/lib/loggers/console.service.js.map +1 -0
- package/lib/loggers/file.service.d.ts +25 -0
- package/lib/loggers/file.service.d.ts.map +1 -0
- package/lib/loggers/file.service.js +33 -0
- package/lib/loggers/file.service.js.map +1 -0
- package/lib/loggers/hooks.d.ts +20 -0
- package/lib/loggers/hooks.d.ts.map +1 -0
- package/lib/loggers/hooks.js +40 -0
- package/lib/loggers/hooks.js.map +1 -0
- package/lib/loggers/ilogger.d.ts +76 -0
- package/lib/loggers/ilogger.d.ts.map +1 -0
- package/lib/loggers/ilogger.js +108 -0
- package/lib/loggers/ilogger.js.map +1 -0
- package/lib/loggers/logger.d.ts +13 -0
- package/lib/loggers/logger.d.ts.map +1 -0
- package/lib/loggers/logger.js +18 -0
- package/lib/loggers/logger.js.map +1 -0
- package/lib/loggers/memory.service.d.ts +18 -0
- package/lib/loggers/memory.service.d.ts.map +1 -0
- package/lib/loggers/memory.service.js +21 -0
- package/lib/loggers/memory.service.js.map +1 -0
- package/lib/loggers/params.d.ts +47 -0
- package/lib/loggers/params.d.ts.map +1 -0
- package/lib/loggers/params.js +56 -0
- package/lib/loggers/params.js.map +1 -0
- package/lib/metrics/metrics.d.ts +25 -0
- package/lib/metrics/metrics.d.ts.map +1 -0
- package/lib/metrics/metrics.js +51 -0
- package/lib/metrics/metrics.js.map +1 -0
- package/lib/models/aclmodel.d.ts +21 -77
- package/lib/models/aclmodel.d.ts.map +1 -0
- package/lib/models/aclmodel.js +27 -204
- package/lib/models/aclmodel.js.map +1 -1
- package/lib/models/coremodel.model.d.ts +5 -0
- package/lib/models/coremodel.model.d.ts.map +1 -0
- package/lib/models/coremodel.model.js +5 -0
- package/lib/models/coremodel.model.js.map +1 -0
- package/lib/models/decorator.d.ts +63 -0
- package/lib/models/decorator.d.ts.map +1 -0
- package/lib/models/decorator.js +63 -0
- package/lib/models/decorator.js.map +1 -0
- package/lib/models/deployment.d.ts +2 -1
- package/lib/models/deployment.d.ts.map +1 -0
- package/lib/models/ident.model.d.ts +89 -0
- package/lib/models/ident.model.d.ts.map +1 -0
- package/lib/models/ident.model.js +115 -0
- package/lib/models/ident.model.js.map +1 -0
- package/lib/models/ownermodel.model.d.ts +68 -0
- package/lib/models/ownermodel.model.d.ts.map +1 -0
- package/lib/models/ownermodel.model.js +112 -0
- package/lib/models/ownermodel.model.js.map +1 -0
- package/lib/models/registry.model.d.ts +76 -0
- package/lib/models/registry.model.d.ts.map +1 -0
- package/lib/models/registry.model.js +104 -0
- package/lib/models/registry.model.js.map +1 -0
- package/lib/models/rolemodel.model.d.ts +28 -0
- package/lib/models/rolemodel.model.d.ts.map +1 -0
- package/lib/models/rolemodel.model.js +53 -0
- package/lib/models/rolemodel.model.js.map +1 -0
- package/lib/models/simpleuser.model.d.ts +78 -0
- package/lib/models/simpleuser.model.d.ts.map +1 -0
- package/lib/models/simpleuser.model.js +123 -0
- package/lib/models/simpleuser.model.js.map +1 -0
- package/lib/models/types.d.ts +113 -0
- package/lib/models/types.d.ts.map +1 -0
- package/lib/models/types.js +2 -0
- package/lib/models/types.js.map +1 -0
- package/lib/models/user.model.d.ts +103 -0
- package/lib/models/user.model.d.ts.map +1 -0
- package/lib/models/user.model.js +125 -0
- package/lib/models/user.model.js.map +1 -0
- package/lib/queues/memoryqueue.service.d.ts +72 -0
- package/lib/queues/memoryqueue.service.d.ts.map +1 -0
- package/lib/queues/memoryqueue.service.js +136 -0
- package/lib/queues/memoryqueue.service.js.map +1 -0
- package/lib/queues/pubsubservice.d.ts +9 -6
- package/lib/queues/pubsubservice.d.ts.map +1 -0
- package/lib/queues/pubsubservice.js +5 -4
- package/lib/queues/pubsubservice.js.map +1 -1
- package/lib/queues/queueservice.d.ts +10 -11
- package/lib/queues/queueservice.d.ts.map +1 -0
- package/lib/queues/queueservice.js +48 -20
- package/lib/queues/queueservice.js.map +1 -1
- package/lib/rest/hooks.d.ts +8 -0
- package/lib/rest/hooks.d.ts.map +1 -0
- package/lib/rest/hooks.js +10 -0
- package/lib/rest/hooks.js.map +1 -0
- package/lib/rest/irest.d.ts +212 -0
- package/lib/rest/irest.d.ts.map +1 -0
- package/lib/rest/irest.js +39 -0
- package/lib/rest/irest.js.map +1 -0
- package/lib/rest/originfilter.d.ts +38 -0
- package/lib/rest/originfilter.d.ts.map +1 -0
- package/lib/rest/originfilter.js +61 -0
- package/lib/rest/originfilter.js.map +1 -0
- package/lib/rest/restoperationstransport.service.d.ts +193 -0
- package/lib/rest/restoperationstransport.service.d.ts.map +1 -0
- package/lib/rest/restoperationstransport.service.js +780 -0
- package/lib/rest/restoperationstransport.service.js.map +1 -0
- package/lib/rest/router.service.d.ts +244 -0
- package/lib/rest/router.service.d.ts.map +1 -0
- package/lib/rest/router.service.js +843 -0
- package/lib/rest/router.service.js.map +1 -0
- package/lib/schemas/hooks.d.ts +48 -0
- package/lib/schemas/hooks.d.ts.map +1 -0
- package/lib/schemas/hooks.js +152 -0
- package/lib/schemas/hooks.js.map +1 -0
- package/lib/services/audit.model.d.ts +208 -0
- package/lib/services/audit.model.d.ts.map +1 -0
- package/lib/services/audit.model.js +431 -0
- package/lib/services/audit.model.js.map +1 -0
- package/lib/services/{authentication.d.ts → authentication.service.d.ts} +140 -58
- package/lib/services/authentication.service.d.ts.map +1 -0
- package/lib/services/authentication.service.js +932 -0
- package/lib/services/authentication.service.js.map +1 -0
- package/lib/services/binary.service.d.ts +808 -0
- package/lib/services/binary.service.d.ts.map +1 -0
- package/lib/services/binary.service.js +1365 -0
- package/lib/services/binary.service.js.map +1 -0
- package/lib/services/cloudbinary.d.ts +19 -13
- package/lib/services/cloudbinary.d.ts.map +1 -0
- package/lib/services/cloudbinary.js +24 -18
- package/lib/services/cloudbinary.js.map +1 -1
- package/lib/services/command.d.ts +118 -0
- package/lib/services/command.d.ts.map +1 -0
- package/lib/services/command.js +97 -0
- package/lib/services/command.js.map +1 -0
- package/lib/services/cron.service.d.ts +142 -0
- package/lib/services/cron.service.d.ts.map +1 -0
- package/lib/services/cron.service.js +291 -0
- package/lib/services/cron.service.js.map +1 -0
- package/lib/services/{cryptoservice.d.ts → cryptoservice.service.d.ts} +77 -142
- package/lib/services/cryptoservice.service.d.ts.map +1 -0
- package/lib/services/cryptoservice.service.js +527 -0
- package/lib/services/cryptoservice.service.js.map +1 -0
- package/lib/services/debugmailer.service.d.ts +49 -0
- package/lib/services/debugmailer.service.d.ts.map +1 -0
- package/lib/services/debugmailer.service.js +66 -0
- package/lib/services/debugmailer.service.js.map +1 -0
- package/lib/services/domainservice.service.d.ts +203 -0
- package/lib/services/domainservice.service.d.ts.map +1 -0
- package/lib/services/domainservice.service.js +600 -0
- package/lib/services/domainservice.service.js.map +1 -0
- package/lib/services/httpserver.service.d.ts +248 -0
- package/lib/services/httpserver.service.d.ts.map +1 -0
- package/lib/services/httpserver.service.js +673 -0
- package/lib/services/httpserver.service.js.map +1 -0
- package/lib/services/iauthentication.d.ts +9 -0
- package/lib/services/iauthentication.d.ts.map +1 -0
- package/lib/services/iauthentication.js +2 -0
- package/lib/services/iauthentication.js.map +1 -0
- package/lib/services/icryptoservice.d.ts +127 -0
- package/lib/services/icryptoservice.d.ts.map +1 -0
- package/lib/services/icryptoservice.js +68 -0
- package/lib/services/icryptoservice.js.map +1 -0
- package/lib/services/imailer.d.ts +17 -0
- package/lib/services/imailer.d.ts.map +1 -0
- package/lib/services/imailer.js +2 -0
- package/lib/services/imailer.js.map +1 -0
- package/lib/services/iservice.d.ts +104 -0
- package/lib/services/iservice.d.ts.map +1 -0
- package/lib/services/iservice.js +63 -0
- package/lib/services/iservice.js.map +1 -0
- package/lib/services/mailer.service.d.ts +220 -0
- package/lib/services/mailer.service.d.ts.map +1 -0
- package/lib/services/mailer.service.js +251 -0
- package/lib/services/mailer.service.js.map +1 -0
- package/lib/services/{notificationservice.d.ts → notificationservice.service.d.ts} +10 -10
- package/lib/services/notificationservice.service.d.ts.map +1 -0
- package/lib/services/{notificationservice.js → notificationservice.service.js} +24 -12
- package/lib/services/notificationservice.service.js.map +1 -0
- package/lib/services/oauth.d.ts +58 -31
- package/lib/services/oauth.d.ts.map +1 -0
- package/lib/services/oauth.js +365 -251
- package/lib/services/oauth.js.map +1 -1
- package/lib/services/operationstransport.d.ts +65 -0
- package/lib/services/operationstransport.d.ts.map +1 -0
- package/lib/services/operationstransport.js +103 -0
- package/lib/services/operationstransport.js.map +1 -0
- package/lib/services/{prometheus.d.ts → prometheus.service.d.ts} +13 -11
- package/lib/services/prometheus.service.d.ts.map +1 -0
- package/lib/services/prometheus.service.js +203 -0
- package/lib/services/prometheus.service.js.map +1 -0
- package/lib/services/resource.service.d.ts +121 -0
- package/lib/services/resource.service.d.ts.map +1 -0
- package/lib/services/resource.service.js +301 -0
- package/lib/services/resource.service.js.map +1 -0
- package/lib/services/service.d.ts +88 -189
- package/lib/services/service.d.ts.map +1 -0
- package/lib/services/service.js +407 -432
- package/lib/services/service.js.map +1 -1
- package/lib/services/servicecommands.d.ts +99 -0
- package/lib/services/servicecommands.d.ts.map +1 -0
- package/lib/services/servicecommands.js +165 -0
- package/lib/services/servicecommands.js.map +1 -0
- package/lib/services/serviceparameters.d.ts +33 -0
- package/lib/services/serviceparameters.d.ts.map +1 -0
- package/lib/services/serviceparameters.js +79 -0
- package/lib/services/serviceparameters.js.map +1 -0
- package/lib/{utils → session}/cookie.d.ts +32 -18
- package/lib/session/cookie.d.ts.map +1 -0
- package/lib/{utils → session}/cookie.js +76 -23
- package/lib/session/cookie.js.map +1 -0
- package/lib/session/manager.model.d.ts +71 -0
- package/lib/session/manager.model.d.ts.map +1 -0
- package/lib/session/manager.model.js +155 -0
- package/lib/session/manager.model.js.map +1 -0
- package/lib/session/session.d.ts +57 -0
- package/lib/session/session.d.ts.map +1 -0
- package/lib/session/session.js +126 -0
- package/lib/session/session.js.map +1 -0
- package/lib/stores/istore.d.ts +99 -0
- package/lib/stores/istore.d.ts.map +1 -0
- package/lib/stores/istore.js +26 -0
- package/lib/stores/istore.js.map +1 -0
- package/lib/stores/memory.service.d.ts +114 -0
- package/lib/stores/memory.service.d.ts.map +1 -0
- package/lib/stores/memory.service.js +343 -0
- package/lib/stores/memory.service.js.map +1 -0
- package/lib/stores/store.d.ts +127 -768
- package/lib/stores/store.d.ts.map +1 -0
- package/lib/stores/store.js +258 -1718
- package/lib/stores/store.js.map +1 -1
- package/lib/templates/templates.d.ts +39 -0
- package/lib/templates/templates.d.ts.map +1 -0
- package/lib/templates/templates.js +92 -0
- package/lib/templates/templates.js.map +1 -0
- package/lib/test/application.d.ts +174 -0
- package/lib/test/application.d.ts.map +1 -0
- package/lib/test/application.js +288 -0
- package/lib/test/application.js.map +1 -0
- package/lib/test/asyncstorage.d.ts +16 -0
- package/lib/test/asyncstorage.d.ts.map +1 -0
- package/lib/test/asyncstorage.js +32 -0
- package/lib/test/asyncstorage.js.map +1 -0
- package/lib/test/core.d.ts +63 -0
- package/lib/test/core.d.ts.map +1 -0
- package/lib/test/core.js +190 -0
- package/lib/test/core.js.map +1 -0
- package/lib/test/index.d.ts +7 -0
- package/lib/test/index.d.ts.map +1 -0
- package/lib/test/index.js +8 -0
- package/lib/test/index.js.map +1 -0
- package/lib/test/internal.d.ts +34 -0
- package/lib/test/internal.d.ts.map +1 -0
- package/lib/test/internal.js +156 -0
- package/lib/test/internal.js.map +1 -0
- package/lib/test/objects.d.ts +318 -0
- package/lib/test/objects.d.ts.map +1 -0
- package/lib/test/objects.js +443 -0
- package/lib/test/objects.js.map +1 -0
- package/lib/utils/abstractdeployer.d.ts +5 -2
- package/lib/utils/abstractdeployer.d.ts.map +1 -0
- package/lib/utils/abstractdeployer.js +3 -0
- package/lib/utils/abstractdeployer.js.map +1 -1
- package/package.json +85 -56
- package/test/cachedapp/webda.config.json +1 -5
- package/test/config-cached.json +1 -5
- package/test/config.json +6 -99
- package/test/data/.env +1 -0
- package/test/my-cnf.json +9 -0
- package/webda.module.json +3462 -2231
- package/lib/application.d.ts +0 -876
- package/lib/application.js +0 -741
- package/lib/application.js.map +0 -1
- package/lib/application.spec.d.ts +0 -1
- package/lib/application.spec.js +0 -234
- package/lib/application.spec.js.map +0 -1
- package/lib/core.d.ts +0 -740
- package/lib/core.js +0 -1310
- package/lib/core.js.map +0 -1
- package/lib/core.spec.d.ts +0 -1
- package/lib/core.spec.js +0 -761
- package/lib/core.spec.js.map +0 -1
- package/lib/errors.d.ts +0 -65
- package/lib/errors.js +0 -113
- package/lib/errors.js.map +0 -1
- package/lib/errors.spec.d.ts +0 -1
- package/lib/errors.spec.js +0 -33
- package/lib/errors.spec.js.map +0 -1
- package/lib/models/aclmodel.spec.d.ts +0 -1
- package/lib/models/aclmodel.spec.js +0 -187
- package/lib/models/aclmodel.spec.js.map +0 -1
- package/lib/models/coremodel.d.ts +0 -887
- package/lib/models/coremodel.js +0 -1208
- package/lib/models/coremodel.js.map +0 -1
- package/lib/models/coremodel.spec.d.ts +0 -1
- package/lib/models/coremodel.spec.js +0 -462
- package/lib/models/coremodel.spec.js.map +0 -1
- package/lib/models/ident.d.ts +0 -53
- package/lib/models/ident.js +0 -40
- package/lib/models/ident.js.map +0 -1
- package/lib/models/ident.spec.d.ts +0 -1
- package/lib/models/ident.spec.js +0 -43
- package/lib/models/ident.spec.js.map +0 -1
- package/lib/models/ownermodel.d.ts +0 -50
- package/lib/models/ownermodel.js +0 -65
- package/lib/models/ownermodel.js.map +0 -1
- package/lib/models/ownermodel.spec.d.ts +0 -1
- package/lib/models/ownermodel.spec.js +0 -191
- package/lib/models/ownermodel.spec.js.map +0 -1
- package/lib/models/relations.d.ts +0 -181
- package/lib/models/relations.js +0 -157
- package/lib/models/relations.js.map +0 -1
- package/lib/models/relations.spec.d.ts +0 -12
- package/lib/models/relations.spec.js +0 -224
- package/lib/models/relations.spec.js.map +0 -1
- package/lib/models/rolemodel.d.ts +0 -10
- package/lib/models/rolemodel.js +0 -35
- package/lib/models/rolemodel.js.map +0 -1
- package/lib/models/rolemodel.spec.d.ts +0 -1
- package/lib/models/rolemodel.spec.js +0 -86
- package/lib/models/rolemodel.spec.js.map +0 -1
- package/lib/models/user.d.ts +0 -100
- package/lib/models/user.js +0 -157
- package/lib/models/user.js.map +0 -1
- package/lib/models/user.spec.d.ts +0 -1
- package/lib/models/user.spec.js +0 -88
- package/lib/models/user.spec.js.map +0 -1
- package/lib/queues/filequeue.d.ts +0 -58
- package/lib/queues/filequeue.js +0 -131
- package/lib/queues/filequeue.js.map +0 -1
- package/lib/queues/filequeue.spec.d.ts +0 -1
- package/lib/queues/filequeue.spec.js +0 -78
- package/lib/queues/filequeue.spec.js.map +0 -1
- package/lib/queues/memoryqueue.d.ts +0 -45
- package/lib/queues/memoryqueue.js +0 -81
- package/lib/queues/memoryqueue.js.map +0 -1
- package/lib/queues/memoryqueue.spec.d.ts +0 -1
- package/lib/queues/memoryqueue.spec.js +0 -192
- package/lib/queues/memoryqueue.spec.js.map +0 -1
- package/lib/queues/queue.spec.d.ts +0 -5
- package/lib/queues/queue.spec.js +0 -55
- package/lib/queues/queue.spec.js.map +0 -1
- package/lib/router.d.ts +0 -172
- package/lib/router.js +0 -419
- package/lib/router.js.map +0 -1
- package/lib/router.spec.d.ts +0 -1
- package/lib/router.spec.js +0 -229
- package/lib/router.spec.js.map +0 -1
- package/lib/services/asyncevents.d.ts +0 -151
- package/lib/services/asyncevents.js +0 -217
- package/lib/services/asyncevents.js.map +0 -1
- package/lib/services/asyncevents.spec.d.ts +0 -1
- package/lib/services/asyncevents.spec.js +0 -118
- package/lib/services/asyncevents.spec.js.map +0 -1
- package/lib/services/authentication.js +0 -772
- package/lib/services/authentication.js.map +0 -1
- package/lib/services/authentication.spec.d.ts +0 -1
- package/lib/services/authentication.spec.js +0 -458
- package/lib/services/authentication.spec.js.map +0 -1
- package/lib/services/binary.d.ts +0 -549
- package/lib/services/binary.js +0 -986
- package/lib/services/binary.js.map +0 -1
- package/lib/services/binary.spec.d.ts +0 -44
- package/lib/services/binary.spec.js +0 -438
- package/lib/services/binary.spec.js.map +0 -1
- package/lib/services/cloudbinary.spec.d.ts +0 -13
- package/lib/services/cloudbinary.spec.js +0 -192
- package/lib/services/cloudbinary.spec.js.map +0 -1
- package/lib/services/configuration.js +0 -178
- package/lib/services/configuration.js.map +0 -1
- package/lib/services/configuration.spec.d.ts +0 -1
- package/lib/services/configuration.spec.js +0 -87
- package/lib/services/configuration.spec.js.map +0 -1
- package/lib/services/cron.d.ts +0 -73
- package/lib/services/cron.js +0 -141
- package/lib/services/cron.js.map +0 -1
- package/lib/services/cron.spec.d.ts +0 -1
- package/lib/services/cron.spec.js +0 -76
- package/lib/services/cron.spec.js.map +0 -1
- package/lib/services/cryptoservice.js +0 -434
- package/lib/services/cryptoservice.js.map +0 -1
- package/lib/services/cryptoservice.spec.d.ts +0 -1
- package/lib/services/cryptoservice.spec.js +0 -177
- package/lib/services/cryptoservice.spec.js.map +0 -1
- package/lib/services/debugmailer.d.ts +0 -36
- package/lib/services/debugmailer.js +0 -52
- package/lib/services/debugmailer.js.map +0 -1
- package/lib/services/debugmailer.spec.d.ts +0 -1
- package/lib/services/debugmailer.spec.js +0 -29
- package/lib/services/debugmailer.spec.js.map +0 -1
- package/lib/services/domainservice.d.ts +0 -152
- package/lib/services/domainservice.js +0 -881
- package/lib/services/domainservice.js.map +0 -1
- package/lib/services/domainservice.spec.d.ts +0 -1
- package/lib/services/domainservice.spec.js +0 -401
- package/lib/services/domainservice.spec.js.map +0 -1
- package/lib/services/filebinary.d.ts +0 -133
- package/lib/services/filebinary.js +0 -371
- package/lib/services/filebinary.js.map +0 -1
- package/lib/services/filebinary.spec.d.ts +0 -21
- package/lib/services/filebinary.spec.js +0 -415
- package/lib/services/filebinary.spec.js.map +0 -1
- package/lib/services/fileconfiguration.d.ts +0 -22
- package/lib/services/fileconfiguration.js +0 -48
- package/lib/services/fileconfiguration.js.map +0 -1
- package/lib/services/fileconfiguration.spec.d.ts +0 -1
- package/lib/services/fileconfiguration.spec.js +0 -177
- package/lib/services/fileconfiguration.spec.js.map +0 -1
- package/lib/services/invitationservice.d.ts +0 -222
- package/lib/services/invitationservice.js +0 -526
- package/lib/services/invitationservice.js.map +0 -1
- package/lib/services/invitationservice.spec.d.ts +0 -1
- package/lib/services/invitationservice.spec.js +0 -516
- package/lib/services/invitationservice.spec.js.map +0 -1
- package/lib/services/kubernetesconfiguration.d.ts +0 -26
- package/lib/services/kubernetesconfiguration.js +0 -54
- package/lib/services/kubernetesconfiguration.js.map +0 -1
- package/lib/services/kubernetesconfiguration.spec.d.ts +0 -1
- package/lib/services/kubernetesconfiguration.spec.js +0 -147
- package/lib/services/kubernetesconfiguration.spec.js.map +0 -1
- package/lib/services/mailer.d.ts +0 -165
- package/lib/services/mailer.js +0 -176
- package/lib/services/mailer.js.map +0 -1
- package/lib/services/mailer.spec.d.ts +0 -1
- package/lib/services/mailer.spec.js +0 -144
- package/lib/services/mailer.spec.js.map +0 -1
- package/lib/services/notificationservice.js.map +0 -1
- package/lib/services/notificationservice.spec.d.ts +0 -1
- package/lib/services/notificationservice.spec.js +0 -78
- package/lib/services/notificationservice.spec.js.map +0 -1
- package/lib/services/oauth.spec.d.ts +0 -1
- package/lib/services/oauth.spec.js +0 -184
- package/lib/services/oauth.spec.js.map +0 -1
- package/lib/services/prometheus.js +0 -160
- package/lib/services/prometheus.js.map +0 -1
- package/lib/services/prometheus.spec.d.ts +0 -1
- package/lib/services/prometheus.spec.js +0 -57
- package/lib/services/prometheus.spec.js.map +0 -1
- package/lib/services/resource.d.ts +0 -87
- package/lib/services/resource.js +0 -156
- package/lib/services/resource.js.map +0 -1
- package/lib/services/resource.spec.d.ts +0 -1
- package/lib/services/resource.spec.js +0 -122
- package/lib/services/resource.spec.js.map +0 -1
- package/lib/services/service.spec.d.ts +0 -1
- package/lib/services/service.spec.js +0 -268
- package/lib/services/service.spec.js.map +0 -1
- package/lib/stores/aggregator.d.ts +0 -41
- package/lib/stores/aggregator.js +0 -80
- package/lib/stores/aggregator.js.map +0 -1
- package/lib/stores/aliasstore.d.ts +0 -108
- package/lib/stores/aliasstore.js +0 -168
- package/lib/stores/aliasstore.js.map +0 -1
- package/lib/stores/aliasstore.spec.d.ts +0 -11
- package/lib/stores/aliasstore.spec.js +0 -89
- package/lib/stores/aliasstore.spec.js.map +0 -1
- package/lib/stores/file.d.ts +0 -107
- package/lib/stores/file.js +0 -188
- package/lib/stores/file.js.map +0 -1
- package/lib/stores/file.spec.d.ts +0 -19
- package/lib/stores/file.spec.js +0 -232
- package/lib/stores/file.spec.js.map +0 -1
- package/lib/stores/mapper.d.ts +0 -149
- package/lib/stores/mapper.js +0 -293
- package/lib/stores/mapper.js.map +0 -1
- package/lib/stores/mapper.spec.d.ts +0 -1
- package/lib/stores/mapper.spec.js +0 -160
- package/lib/stores/mapper.spec.js.map +0 -1
- package/lib/stores/memory.d.ts +0 -151
- package/lib/stores/memory.js +0 -371
- package/lib/stores/memory.js.map +0 -1
- package/lib/stores/memory.spec.d.ts +0 -20
- package/lib/stores/memory.spec.js +0 -328
- package/lib/stores/memory.spec.js.map +0 -1
- package/lib/stores/modelmapper.d.ts +0 -61
- package/lib/stores/modelmapper.js +0 -199
- package/lib/stores/modelmapper.js.map +0 -1
- package/lib/stores/store.spec.d.ts +0 -65
- package/lib/stores/store.spec.js +0 -906
- package/lib/stores/store.spec.js.map +0 -1
- package/lib/test.d.ts +0 -162
- package/lib/test.js +0 -399
- package/lib/test.js.map +0 -1
- package/lib/unpackedapplication.d.ts +0 -76
- package/lib/unpackedapplication.js +0 -299
- package/lib/unpackedapplication.js.map +0 -1
- package/lib/utils/abstractdeployer.spec.d.ts +0 -1
- package/lib/utils/abstractdeployer.spec.js +0 -21
- package/lib/utils/abstractdeployer.spec.js.map +0 -1
- package/lib/utils/case.d.ts +0 -7
- package/lib/utils/case.js +0 -43
- package/lib/utils/case.js.map +0 -1
- package/lib/utils/case.spec.d.ts +0 -1
- package/lib/utils/case.spec.js +0 -50
- package/lib/utils/case.spec.js.map +0 -1
- package/lib/utils/context.d.ts +0 -462
- package/lib/utils/context.js +0 -732
- package/lib/utils/context.js.map +0 -1
- package/lib/utils/context.spec.d.ts +0 -9
- package/lib/utils/context.spec.js +0 -372
- package/lib/utils/context.spec.js.map +0 -1
- package/lib/utils/cookie.js.map +0 -1
- package/lib/utils/cookie.spec.d.ts +0 -1
- package/lib/utils/cookie.spec.js +0 -78
- package/lib/utils/cookie.spec.js.map +0 -1
- package/lib/utils/esm.d.ts +0 -13
- package/lib/utils/esm.js +0 -19
- package/lib/utils/esm.js.map +0 -1
- package/lib/utils/httpcontext.js.map +0 -1
- package/lib/utils/httpcontext.spec.d.ts +0 -4
- package/lib/utils/httpcontext.spec.js +0 -77
- package/lib/utils/httpcontext.spec.js.map +0 -1
- package/lib/utils/logger.d.ts +0 -91
- package/lib/utils/logger.js +0 -121
- package/lib/utils/logger.js.map +0 -1
- package/lib/utils/logger.spec.d.ts +0 -1
- package/lib/utils/logger.spec.js +0 -48
- package/lib/utils/logger.spec.js.map +0 -1
- package/lib/utils/serializers.d.ts +0 -161
- package/lib/utils/serializers.js +0 -420
- package/lib/utils/serializers.js.map +0 -1
- package/lib/utils/serializers.spec.d.ts +0 -1
- package/lib/utils/serializers.spec.js +0 -313
- package/lib/utils/serializers.spec.js.map +0 -1
- package/lib/utils/session.d.ts +0 -126
- package/lib/utils/session.js +0 -166
- package/lib/utils/session.js.map +0 -1
- package/lib/utils/session.spec.d.ts +0 -1
- package/lib/utils/session.spec.js +0 -71
- package/lib/utils/session.spec.js.map +0 -1
- package/lib/utils/throttler.d.ts +0 -102
- package/lib/utils/throttler.js +0 -168
- package/lib/utils/throttler.js.map +0 -1
- package/lib/utils/throttler.spec.d.ts +0 -1
- package/lib/utils/throttler.spec.js +0 -55
- package/lib/utils/throttler.spec.js.map +0 -1
- package/lib/utils/waiter.d.ts +0 -93
- package/lib/utils/waiter.js +0 -148
- package/lib/utils/waiter.js.map +0 -1
- package/lib/utils/waiter.spec.d.ts +0 -1
- package/lib/utils/waiter.spec.js +0 -98
- package/lib/utils/waiter.spec.js.map +0 -1
- package/test/config-file-missing-file-no-default.json +0 -44
- package/test/config-file-missing-file.json +0 -55
- package/test/config-file-no-reload.json +0 -69
- package/test/config-file-reload.json +0 -68
- package/test/config-invitation.json +0 -63
- package/test/config-kube-reload.json +0 -68
- package/test/config-reload.json +0 -66
- package/test/config.old.json +0 -152
- package/test/jsonutils/mdocs.yaml +0 -56
- package/test/jsonutils/test.json +0 -3
- package/test/jsonutils/test.yml +0 -5
- package/test/moddas/annotatedservice.js +0 -23
- package/test/moddas/debugmailer.js +0 -13
- package/test/moddas/fakeservice.js +0 -4
- package/test/moddas/voidstore.js +0 -66
- package/test/models/ident.js +0 -36
- package/test/models/task.js +0 -42
package/lib/stores/store.js
CHANGED
|
@@ -1,70 +1,129 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
};
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
import { Route, Service, ServiceParameters } from "../services/service.js";
|
|
11
|
-
import * as WebdaQL from "@webda/ql";
|
|
1
|
+
import { Counter, Histogram } from "../metrics/metrics.js";
|
|
2
|
+
import * as WebdaError from "../errors/errors.js";
|
|
3
|
+
import { registerRepository } from "@webda/models";
|
|
4
|
+
import { ServiceParameters } from "../services/serviceparameters.js";
|
|
5
|
+
import { Service } from "../services/service.js";
|
|
6
|
+
import { useApplication, useModel, useModelId } from "../application/hooks.js";
|
|
7
|
+
import { useLog } from "../loggers/hooks.js";
|
|
8
|
+
import { useCore, useModelMetadata } from "../core/hooks.js";
|
|
9
|
+
/** Error thrown when an item is not found in a store */
|
|
12
10
|
export class StoreNotFoundError extends WebdaError.CodeError {
|
|
11
|
+
/** Create a new StoreNotFoundError
|
|
12
|
+
* @param uuid - the item primary key
|
|
13
|
+
* @param storeName - the store name
|
|
14
|
+
*/
|
|
13
15
|
constructor(uuid, storeName) {
|
|
14
16
|
super("STORE_NOTFOUND", `Item not found ${uuid} Store(${storeName})`);
|
|
15
17
|
}
|
|
16
18
|
}
|
|
19
|
+
/** Error thrown when a conditional update fails due to a version/condition mismatch */
|
|
17
20
|
export class UpdateConditionFailError extends WebdaError.CodeError {
|
|
21
|
+
/** Create a new UpdateConditionFailError
|
|
22
|
+
* @param uuid - the item primary key
|
|
23
|
+
* @param conditionField - the condition field name
|
|
24
|
+
* @param condition - the expected condition value
|
|
25
|
+
*/
|
|
18
26
|
constructor(uuid, conditionField, condition) {
|
|
19
27
|
super("STORE_UPDATE_CONDITION_FAILED", `UpdateCondition not met on ${uuid}.${conditionField} === ${condition instanceof Date ? condition.toISOString() : condition}`);
|
|
20
28
|
}
|
|
21
29
|
}
|
|
22
30
|
/**
|
|
23
31
|
* Store parameter
|
|
32
|
+
*
|
|
33
|
+
* @internal — Store configuration schema. Authored in `webda.config`/deployment
|
|
34
|
+
* files; not consumed by app code directly.
|
|
24
35
|
*/
|
|
25
36
|
export class StoreParameters extends ServiceParameters {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Models managed by this Store.
|
|
39
|
+
*
|
|
40
|
+
* @default ["Webda/RegistryEntry"]
|
|
41
|
+
*/
|
|
42
|
+
models;
|
|
43
|
+
/**
|
|
44
|
+
* Allow to load object that does not have the type data
|
|
45
|
+
*
|
|
46
|
+
* If set to true, then the Store will only managed the defined _model and no
|
|
47
|
+
* model extending this one
|
|
48
|
+
*
|
|
49
|
+
* @default false
|
|
50
|
+
*/
|
|
51
|
+
strict;
|
|
52
|
+
/**
|
|
53
|
+
* When __type model not found, use the model
|
|
54
|
+
* If strict is setup this parameter is not used
|
|
55
|
+
*
|
|
56
|
+
* @default true
|
|
57
|
+
*/
|
|
58
|
+
defaultModel;
|
|
59
|
+
/**
|
|
60
|
+
* If set, Store will ignore the __type
|
|
61
|
+
*
|
|
62
|
+
* @default false
|
|
63
|
+
*/
|
|
64
|
+
forceModel;
|
|
65
|
+
/**
|
|
66
|
+
* Slow query threshold
|
|
67
|
+
*
|
|
68
|
+
* @default 30000
|
|
69
|
+
*/
|
|
70
|
+
slowQueryThreshold;
|
|
71
|
+
/**
|
|
72
|
+
* Model Aliases to allow easier rename of Model
|
|
73
|
+
*/
|
|
74
|
+
modelAliases;
|
|
75
|
+
/**
|
|
76
|
+
* Disable default memory cache
|
|
77
|
+
*/
|
|
78
|
+
noCache;
|
|
79
|
+
/**
|
|
80
|
+
* Load store parameters with defaults for model type, strict mode, and aliases
|
|
81
|
+
* @param params - the service parameters
|
|
82
|
+
* @returns the result
|
|
83
|
+
*/
|
|
84
|
+
load(params) {
|
|
85
|
+
// REFACTOR >= 5
|
|
86
|
+
if (params.expose) {
|
|
87
|
+
throw new Error("Expose is not supported anymore, use DomainService instead");
|
|
42
88
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
89
|
+
// END_REFACTOR
|
|
90
|
+
super.load(params);
|
|
91
|
+
// Deprecation mapping: model + additionalModels → models[]
|
|
92
|
+
const hasModels = Array.isArray(params.models);
|
|
93
|
+
const hasModel = typeof params.model === "string";
|
|
94
|
+
// Presence check (not length) used for the conflict guard so that
|
|
95
|
+
// `{ models: [...], additionalModels: [] }` is still detected as ambiguous.
|
|
96
|
+
const hasAdditionalKey = Array.isArray(params.additionalModels);
|
|
97
|
+
// Length check used for the deprecation branch: an empty additionalModels
|
|
98
|
+
// alongside a bare `model` is unambiguous and should not warn on its own.
|
|
99
|
+
const hasAdditional = hasAdditionalKey && params.additionalModels.length > 0;
|
|
100
|
+
if (hasModels && (hasModel || hasAdditionalKey)) {
|
|
101
|
+
throw new Error("StoreParameters: `models` and `model`/`additionalModels` are mutually exclusive — ambiguous configuration");
|
|
48
102
|
}
|
|
49
|
-
if (
|
|
50
|
-
|
|
103
|
+
if (hasModels) {
|
|
104
|
+
this.models = [...params.models];
|
|
51
105
|
}
|
|
52
|
-
if (
|
|
53
|
-
|
|
106
|
+
else if (hasModel || hasAdditional) {
|
|
107
|
+
useLog("WARN", `StoreParameters: \`model\` and \`additionalModels\` are deprecated. Use \`models: [...]\` instead.`);
|
|
108
|
+
this.models = [params.model ?? "Webda/RegistryEntry", ...(params.additionalModels ?? [])];
|
|
54
109
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
110
|
+
else {
|
|
111
|
+
this.models = ["Webda/RegistryEntry"];
|
|
112
|
+
}
|
|
113
|
+
// When the caller passed `models[]` (or nothing at all), backfill the deprecated
|
|
114
|
+
// fields from the canonical `models[]` so any code still reading `parameters.model`
|
|
115
|
+
// or `parameters.additionalModels` keeps working. In the legacy-input branch
|
|
116
|
+
// `super.load(params)` already set both via Object.assign, so the `??=` is a no-op.
|
|
117
|
+
this.strict ??= false;
|
|
118
|
+
this.defaultModel ??= true;
|
|
119
|
+
this.forceModel ??= false;
|
|
120
|
+
this.slowQueryThreshold ??= 30000;
|
|
121
|
+
this.modelAliases ??= {};
|
|
122
|
+
return this;
|
|
61
123
|
}
|
|
62
124
|
}
|
|
63
125
|
/**
|
|
64
126
|
* This class handle NoSQL storage and mapping (duplication) between NoSQL object
|
|
65
|
-
* TODO Create the mapping documentation
|
|
66
|
-
*
|
|
67
|
-
* It use basic CRUD, and can expose those 4 to through HTTP
|
|
68
127
|
*
|
|
69
128
|
* It emits events :
|
|
70
129
|
* Store.Save: Before saving the object
|
|
@@ -77,106 +136,162 @@ export class StoreParameters extends ServiceParameters {
|
|
|
77
136
|
* Store.Action: When an action will be done on an object
|
|
78
137
|
* Store.Actioned: When an action has been done on an object
|
|
79
138
|
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* Parameters
|
|
84
|
-
*
|
|
85
|
-
* map: { ... }
|
|
86
|
-
* expose: { // Enable the HTTP exposure
|
|
87
|
-
* url: '', // The url to expose to by default it is service name in lowercase ( users for example )
|
|
88
|
-
* restrict: {
|
|
89
|
-
* create: true, // Don't expose the POST /users
|
|
90
|
-
* update: true, // Don't expose the PUT /users/{uuid}
|
|
91
|
-
* delete: true, // Don't expose the DELETE /users/{uuid}
|
|
92
|
-
* get: true // Don't expose the GET /users/{uuid}
|
|
93
|
-
* }
|
|
94
|
-
* }
|
|
139
|
+
* @internal — Subclassed by store packages only. App code never references a
|
|
140
|
+
* Store directly: use `useRepository(Model)` or static model methods
|
|
141
|
+
* (`Model.create()`, `Model.query()`, `Model.ref()`).
|
|
95
142
|
* @category CoreServices
|
|
96
143
|
*/
|
|
97
144
|
class Store extends Service {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
145
|
+
/** All model classes managed by this store. Index 0 is the legacy "primary" model. */
|
|
146
|
+
_models = [];
|
|
147
|
+
/** Metadata for each model in `_models`, keyed by Identifier. */
|
|
148
|
+
_modelMetadatas = new Map();
|
|
149
|
+
/** Store the manager hierarchy with their depth */
|
|
150
|
+
_modelsHierarchy = {};
|
|
151
|
+
/**
|
|
152
|
+
* Override the resolved model class for this store at runtime. Used by
|
|
153
|
+
* the abstract `StoreTest` harness so test fixtures can substitute a
|
|
154
|
+
* subclass with extra fields in place of the configured model. In
|
|
155
|
+
* production this is a no-op the framework never calls.
|
|
156
|
+
* @param model - the substitute model class
|
|
157
|
+
*/
|
|
158
|
+
setModelDefinitionHelper(model) {
|
|
159
|
+
this._models[0] = model;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Compute and register repositories for all known models based on available stores.
|
|
163
|
+
*
|
|
164
|
+
* Called from `Store.init()` so each store's init triggers a recompute.
|
|
165
|
+
* Cannot be cached: the FIRST store to init (typically `Registry`) would
|
|
166
|
+
* claim every model with its fallback repository, and subsequent
|
|
167
|
+
* stores wouldn't get a chance to claim their configured models.
|
|
168
|
+
* Re-running is idempotent — `registerRepository` overwrites map entries
|
|
169
|
+
* in place, and the resolution loop is deterministic per current
|
|
170
|
+
* service/model state.
|
|
171
|
+
*/
|
|
172
|
+
static computeStores() {
|
|
173
|
+
// Gather all stores and register Repository
|
|
174
|
+
const stores = Object.values(useCore().getServices()).filter(s => s instanceof Store);
|
|
175
|
+
const models = Object.values(useApplication().getModels());
|
|
176
|
+
const registry = useCore().getService("Registry");
|
|
177
|
+
// Check each available models
|
|
178
|
+
for (const model of models) {
|
|
179
|
+
// Model can be null?
|
|
180
|
+
if (!model)
|
|
181
|
+
continue;
|
|
182
|
+
if (!model.Metadata || !Array.isArray(model.Metadata.PrimaryKey)) {
|
|
183
|
+
useLog("WARN", `${useModelId(model)} does not have Metadata or PrimaryKey defined`);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
let currentValue = -1;
|
|
187
|
+
let currentStore = undefined;
|
|
188
|
+
for (const store of stores) {
|
|
189
|
+
const value = store.handleModel(model);
|
|
190
|
+
if (value < 0 || (value > currentValue && currentValue !== -1)) {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
currentValue = value;
|
|
194
|
+
currentStore = store;
|
|
195
|
+
}
|
|
196
|
+
if (!currentStore) {
|
|
197
|
+
useLog("TRACE", `${useModelId(model)} fallback to Registry store`);
|
|
198
|
+
currentStore = registry;
|
|
199
|
+
}
|
|
200
|
+
// Register the repository
|
|
201
|
+
registerRepository(model, currentStore.getRepository(model));
|
|
202
|
+
useLog("DEBUG", `${useModelId(model)} using store ${currentStore.getName()}`);
|
|
203
|
+
}
|
|
112
204
|
}
|
|
113
205
|
/**
|
|
114
|
-
* Retrieve the
|
|
206
|
+
* Retrieve the Models and build the models hierarchy map.
|
|
115
207
|
*
|
|
116
|
-
*
|
|
208
|
+
* Walks `parameters.models[]` (the canonical flat list introduced in Task 1).
|
|
209
|
+
* If the list is empty or contains only the default "Webda/RegistryEntry"
|
|
210
|
+
* fallback, the hierarchy stays empty and the store will not claim any model
|
|
211
|
+
* — preserving the pre-migration fallback behaviour for test-only or
|
|
212
|
+
* misconfigured stores.
|
|
117
213
|
*/
|
|
118
214
|
computeParameters() {
|
|
119
215
|
super.computeParameters();
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (!this.parameters.noCache) {
|
|
126
|
-
this._cacheStore = new MemoryStore(this._webda, `_${this.getName()}_cache`, {
|
|
127
|
-
model: this.parameters.model
|
|
128
|
-
});
|
|
129
|
-
this._cacheStore.computeParameters();
|
|
130
|
-
this._cacheStore.initMetrics();
|
|
131
|
-
this.cacheStorePatchException();
|
|
216
|
+
const ids = this.parameters.models ?? [];
|
|
217
|
+
// Empty / default RegistryEntry → leave hierarchy empty (preserves test-only / fallback behaviour).
|
|
218
|
+
const isOnlyDefault = ids.length === 1 && ids[0] === "Webda/RegistryEntry";
|
|
219
|
+
if (ids.length === 0 || isOnlyDefault) {
|
|
220
|
+
return;
|
|
132
221
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
222
|
+
this._models = [];
|
|
223
|
+
this._modelMetadatas = new Map();
|
|
224
|
+
this._modelsHierarchy = {};
|
|
225
|
+
// Subclasses in ModelMetadata are resolved to ModelClass objects at runtime
|
|
226
|
+
// (see Application.setModelMetadata). Accept both string IDs and ModelClass
|
|
227
|
+
// references so the hierarchy is keyed by string identifier throughout.
|
|
228
|
+
const recursive = (subclasses, depth) => {
|
|
229
|
+
for (const entry of subclasses) {
|
|
230
|
+
let subModel;
|
|
231
|
+
let subId;
|
|
232
|
+
if (typeof entry === "string") {
|
|
233
|
+
subId = entry;
|
|
234
|
+
try {
|
|
235
|
+
subModel = useModel(entry);
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
subModel = entry;
|
|
243
|
+
subId = useModelId(subModel);
|
|
244
|
+
}
|
|
245
|
+
if (!subId || !subModel)
|
|
246
|
+
continue;
|
|
247
|
+
this._modelsHierarchy[subId] = Math.min(depth, this._modelsHierarchy[subId] ?? depth);
|
|
248
|
+
const subMeta = useModelMetadata(subModel);
|
|
249
|
+
if (!subMeta)
|
|
250
|
+
continue;
|
|
251
|
+
recursive(subMeta.Subclasses ?? [], depth + 1);
|
|
140
252
|
}
|
|
141
253
|
};
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (!this.parameters.strict) {
|
|
147
|
-
recursive(this._model.getHierarchy().children, 1);
|
|
148
|
-
}
|
|
149
|
-
// Add additional models
|
|
150
|
-
if (this.parameters.additionalModels.length) {
|
|
151
|
-
// Strict mode is to only allow one model per store
|
|
152
|
-
if (this.parameters.strict) {
|
|
153
|
-
this.log("ERROR", "Cannot add additional models in strict mode");
|
|
254
|
+
for (const id of ids) {
|
|
255
|
+
let model;
|
|
256
|
+
try {
|
|
257
|
+
model = useModel(id);
|
|
154
258
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
259
|
+
catch {
|
|
260
|
+
model = undefined;
|
|
261
|
+
}
|
|
262
|
+
if (!model) {
|
|
263
|
+
useLog("TRACE", `Store ${this.getName?.() ?? "unknown"}: model not found: ${id}`);
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
const meta = useModelMetadata(model);
|
|
267
|
+
if (!meta) {
|
|
268
|
+
useLog("WARN", `Store ${this.getName?.() ?? "unknown"}: model metadata not found for ${id}`);
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
this._models.push(model);
|
|
272
|
+
this._modelMetadatas.set(meta.Identifier, meta);
|
|
273
|
+
this._modelsHierarchy[meta.Identifier] = 0;
|
|
274
|
+
if (!this.parameters.strict) {
|
|
275
|
+
recursive(meta.Subclasses ?? [], 1);
|
|
162
276
|
}
|
|
163
|
-
}
|
|
164
|
-
if (this.getParameters().expose) {
|
|
165
|
-
this.log("WARN", "Exposing a store is not recommended, use a DomainService instead to expose all your CoreModel");
|
|
166
277
|
}
|
|
167
278
|
}
|
|
279
|
+
/**
|
|
280
|
+
* Log a slow query (placeholder for future implementation)
|
|
281
|
+
* @param _query - the query to execute
|
|
282
|
+
* @param _reason - the reason
|
|
283
|
+
* @param _time - the time
|
|
284
|
+
*/
|
|
168
285
|
logSlowQuery(_query, _reason, _time) {
|
|
169
286
|
// TODO Need to implement: https://github.com/loopingz/webda.io/issues/202
|
|
170
287
|
}
|
|
171
288
|
/**
|
|
172
|
-
*
|
|
173
|
-
* @
|
|
289
|
+
* Initialize the store
|
|
290
|
+
* @returns this for chaining
|
|
174
291
|
*/
|
|
175
|
-
async
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
await this._cacheStore.delete(uid, undefined, undefined, true);
|
|
179
|
-
}
|
|
292
|
+
async init() {
|
|
293
|
+
Store.computeStores();
|
|
294
|
+
return super.init();
|
|
180
295
|
}
|
|
181
296
|
/**
|
|
182
297
|
* @override
|
|
@@ -192,1619 +307,44 @@ class Store extends Service {
|
|
|
192
307
|
name: "slow_queries",
|
|
193
308
|
help: "Number of slow queries encountered"
|
|
194
309
|
});
|
|
195
|
-
this.metrics.cache_invalidations = this.getMetric(Counter, {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
});
|
|
199
|
-
this.metrics.cache_hits = this.getMetric(Counter, {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
});
|
|
310
|
+
// this.metrics.cache_invalidations = this.getMetric(Counter, {
|
|
311
|
+
// name: "cache_invalidations",
|
|
312
|
+
// help: "Number of cache invalidation encountered"
|
|
313
|
+
// });
|
|
314
|
+
// this.metrics.cache_hits = this.getMetric(Counter, {
|
|
315
|
+
// name: "cache_hits",
|
|
316
|
+
// help: "Number of cache hits"
|
|
317
|
+
// });
|
|
203
318
|
this.metrics.queries = this.getMetric(Histogram, {
|
|
204
319
|
name: "queries",
|
|
205
320
|
help: "Query duration"
|
|
206
321
|
});
|
|
207
322
|
}
|
|
208
323
|
/**
|
|
209
|
-
*
|
|
210
|
-
* @returns
|
|
324
|
+
* All models managed by this store.
|
|
325
|
+
* @returns the array of model classes managed by this store
|
|
211
326
|
*/
|
|
212
|
-
|
|
213
|
-
return this.
|
|
327
|
+
getModels() {
|
|
328
|
+
return this._models;
|
|
214
329
|
}
|
|
215
330
|
/**
|
|
216
331
|
* Return if a model is handled by the store
|
|
217
|
-
* @param model
|
|
332
|
+
* @param model - the model to use
|
|
218
333
|
* @return distance from the managed class -1 means not managed, 0 manage exactly this model, >0 manage an ancestor model
|
|
219
334
|
*
|
|
335
|
+
* @returns the result number
|
|
220
336
|
*/
|
|
221
337
|
handleModel(model) {
|
|
222
|
-
const name =
|
|
338
|
+
const name = useModelId(model);
|
|
223
339
|
return this._modelsHierarchy[name] ?? -1;
|
|
224
340
|
}
|
|
225
341
|
/**
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
* @param raiseIfNotFound
|
|
229
|
-
* @returns
|
|
230
|
-
*/
|
|
231
|
-
async _getFromCache(uuid, raiseIfNotFound = false) {
|
|
232
|
-
let res = await this._cacheStore?._get(uuid);
|
|
233
|
-
if (!res) {
|
|
234
|
-
res = await this._get(uuid, raiseIfNotFound);
|
|
235
|
-
if (res) {
|
|
236
|
-
await this._cacheStore?._save(res);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
else {
|
|
240
|
-
this.metrics.cache_hits.inc();
|
|
241
|
-
res.__store = this;
|
|
242
|
-
}
|
|
243
|
-
return res;
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* Get object from store
|
|
247
|
-
* @param uid
|
|
248
|
-
* @returns
|
|
249
|
-
*/
|
|
250
|
-
async getObject(uid) {
|
|
251
|
-
this.metrics.operations_total.inc({ operation: "get" });
|
|
252
|
-
return this._getFromCache(uid);
|
|
253
|
-
}
|
|
254
|
-
/**
|
|
255
|
-
* @override
|
|
256
|
-
*/
|
|
257
|
-
getUrl(url, methods) {
|
|
258
|
-
// If url is absolute
|
|
259
|
-
if (url.startsWith("/")) {
|
|
260
|
-
return url;
|
|
261
|
-
}
|
|
262
|
-
// Parent url to find here
|
|
263
|
-
const expose = this.parameters.expose;
|
|
264
|
-
if (!expose.url ||
|
|
265
|
-
(url === "." && methods.includes("POST") && expose.restrict.create) ||
|
|
266
|
-
(url === "./{uuid}" && methods.includes("DELETE") && expose.restrict.delete) ||
|
|
267
|
-
(url === "./{uuid}" && methods.includes("PATCH") && expose.restrict.update) ||
|
|
268
|
-
(url === "./{uuid}" && methods.includes("PUT") && expose.restrict.update) ||
|
|
269
|
-
(url === "./{uuid}" && methods.includes("GET") && expose.restrict.get) ||
|
|
270
|
-
(url === ".{?q}" && methods.includes("GET") && expose.restrict.query) ||
|
|
271
|
-
(url === "." && methods.includes("PUT") && expose.restrict.query)) {
|
|
272
|
-
return undefined;
|
|
273
|
-
}
|
|
274
|
-
return super.getUrl(url, methods);
|
|
275
|
-
}
|
|
276
|
-
static getOpenAPI() { }
|
|
277
|
-
/**
|
|
278
|
-
* @inheritdoc
|
|
279
|
-
*/
|
|
280
|
-
initRoutes() {
|
|
281
|
-
if (!this.parameters.expose) {
|
|
282
|
-
return;
|
|
283
|
-
}
|
|
284
|
-
super.initRoutes();
|
|
285
|
-
// We enforce ExposeParameters within the constructor
|
|
286
|
-
const expose = this.parameters.expose;
|
|
287
|
-
this.getWebda().getRouter().registerModelUrl(this.parameters.model, expose.url);
|
|
288
|
-
// Query endpoint
|
|
289
|
-
if (!expose.restrict.query) {
|
|
290
|
-
let requestBody;
|
|
291
|
-
if (expose.queryMethod === "PUT") {
|
|
292
|
-
requestBody = {
|
|
293
|
-
content: {
|
|
294
|
-
"application/json": {
|
|
295
|
-
schema: {
|
|
296
|
-
properties: {
|
|
297
|
-
q: {
|
|
298
|
-
type: "string"
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
this.addRoute(expose.queryMethod === "GET" ? `.{?q}` : ".", [expose.queryMethod], this.httpQuery, {
|
|
307
|
-
model: this.parameters.model,
|
|
308
|
-
[expose.queryMethod.toLowerCase()]: {
|
|
309
|
-
description: `Query on ${this.parameters.model} model with WebdaQL`,
|
|
310
|
-
summary: "Query " + this.parameters.model,
|
|
311
|
-
operationId: `query${this._model.name}`,
|
|
312
|
-
requestBody,
|
|
313
|
-
responses: {
|
|
314
|
-
"200": {
|
|
315
|
-
description: `Retrieve models ${this._model.name}`,
|
|
316
|
-
content: {
|
|
317
|
-
"application/json": {
|
|
318
|
-
schema: {
|
|
319
|
-
properties: {
|
|
320
|
-
continuationToken: {
|
|
321
|
-
type: "string"
|
|
322
|
-
},
|
|
323
|
-
results: {
|
|
324
|
-
type: "array",
|
|
325
|
-
items: {
|
|
326
|
-
$ref: `#/components/schemas/${this._model.name}`
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
},
|
|
334
|
-
"400": {
|
|
335
|
-
description: "Query is invalid"
|
|
336
|
-
},
|
|
337
|
-
"403": {
|
|
338
|
-
description: "You don't have permissions"
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
});
|
|
343
|
-
}
|
|
344
|
-
// Model actions
|
|
345
|
-
if (this._model && this._model.getActions) {
|
|
346
|
-
let actions = this._model.getActions();
|
|
347
|
-
Object.keys(actions).forEach(name => {
|
|
348
|
-
let action = actions[name];
|
|
349
|
-
action.method ?? (action.method = name);
|
|
350
|
-
if (!action.methods) {
|
|
351
|
-
action.methods = ["PUT"];
|
|
352
|
-
}
|
|
353
|
-
let executer;
|
|
354
|
-
if (action.global) {
|
|
355
|
-
// By default will grab the object and then call the action
|
|
356
|
-
if (!this._model[action.method]) {
|
|
357
|
-
throw Error("Action static method " + action.method + " does not exist");
|
|
358
|
-
}
|
|
359
|
-
executer = this.httpGlobalAction;
|
|
360
|
-
this.addRoute(`./${name}`, action.methods, executer, action.openapi);
|
|
361
|
-
}
|
|
362
|
-
else {
|
|
363
|
-
// By default will grab the object and then call the action
|
|
364
|
-
if (!this._model.prototype[action.method]) {
|
|
365
|
-
throw Error("Action method " + action.method + " does not exist");
|
|
366
|
-
}
|
|
367
|
-
executer = ctx => this.httpAction(ctx, action.method);
|
|
368
|
-
this.addRoute(`./{uuid}/${name}`, action.methods, executer, action.openapi);
|
|
369
|
-
}
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
/**
|
|
374
|
-
* OVerwrite the model
|
|
375
|
-
* Used mainly in test
|
|
376
|
-
*/
|
|
377
|
-
setModel(model) {
|
|
378
|
-
this._model = model;
|
|
379
|
-
this._cacheStore?.setModel(model);
|
|
380
|
-
this.parameters.strict = false;
|
|
381
|
-
}
|
|
382
|
-
/**
|
|
383
|
-
* We should ignore exception from the store
|
|
384
|
-
*/
|
|
385
|
-
cacheStorePatchException() {
|
|
386
|
-
const replacer = original => {
|
|
387
|
-
return (...args) => {
|
|
388
|
-
return original
|
|
389
|
-
.bind(this._cacheStore, ...args)()
|
|
390
|
-
.catch(err => {
|
|
391
|
-
this.log("TRACE", `Ignoring cache exception ${this._name}: ${err.message}`);
|
|
392
|
-
});
|
|
393
|
-
};
|
|
394
|
-
};
|
|
395
|
-
for (let i of [
|
|
396
|
-
"_get",
|
|
397
|
-
"_patch",
|
|
398
|
-
"_update",
|
|
399
|
-
"_delete",
|
|
400
|
-
"_incrementAttributes",
|
|
401
|
-
"_upsertItemToCollection",
|
|
402
|
-
"_deleteItemFromCollection",
|
|
403
|
-
"_removeAttribute"
|
|
404
|
-
]) {
|
|
405
|
-
this._cacheStore[i] = replacer(this._cacheStore[i]);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
/**
|
|
409
|
-
* Init a model from the current stored data
|
|
410
|
-
*
|
|
411
|
-
* Initial the reverse map as well
|
|
412
|
-
*
|
|
413
|
-
* @param object
|
|
414
|
-
* @returns
|
|
415
|
-
*/
|
|
416
|
-
initModel(object = {}) {
|
|
417
|
-
var _a;
|
|
418
|
-
object.__type ?? (object.__type = this.getWebda().getApplication().getModelFromInstance(object) || this._modelType);
|
|
419
|
-
// Make sure to send a model object
|
|
420
|
-
if (!(object instanceof this._model)) {
|
|
421
|
-
// Dynamic load type
|
|
422
|
-
if (object.__type && !this.getParameters().forceModel) {
|
|
423
|
-
try {
|
|
424
|
-
const modelType = this.getWebda()
|
|
425
|
-
.getApplication()
|
|
426
|
-
.getModel(this.parameters.modelAliases[object.__type] || object.__type);
|
|
427
|
-
object = new modelType().load(object, true);
|
|
428
|
-
}
|
|
429
|
-
catch (err) {
|
|
430
|
-
if (!this.parameters.defaultModel) {
|
|
431
|
-
throw new Error(`Unknown model ${object.__type} found for Store(${this.getName()})`);
|
|
432
|
-
}
|
|
433
|
-
object = this._model.factory(object);
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
else {
|
|
437
|
-
object = this._model.factory(object);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
if (!object.getUuid()) {
|
|
441
|
-
object.setUuid(object.generateUid(object));
|
|
442
|
-
}
|
|
443
|
-
object.__store = this;
|
|
444
|
-
for (let i in this._reverseMap) {
|
|
445
|
-
object[_a = this._reverseMap[i].property] ?? (object[_a] = []);
|
|
446
|
-
for (let j in object[this._reverseMap[i].property]) {
|
|
447
|
-
if (object[this._reverseMap[i].property][j] instanceof ModelMapLoaderImplementation) {
|
|
448
|
-
continue;
|
|
449
|
-
}
|
|
450
|
-
// Use Partial
|
|
451
|
-
object[this._reverseMap[i].property][j] = this._reverseMap[i].mapper.newModel(object[this._reverseMap[i].property][j]);
|
|
452
|
-
object[this._reverseMap[i].property][j].setContext(object.getContext());
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
return object;
|
|
456
|
-
}
|
|
457
|
-
/**
|
|
458
|
-
* Get a new model with this data preloaded
|
|
459
|
-
* @param object
|
|
460
|
-
* @returns
|
|
461
|
-
*/
|
|
462
|
-
newModel(object = {}) {
|
|
463
|
-
let result = this.initModel(object);
|
|
464
|
-
Object.keys(object).forEach(k => result.__dirty.add(k));
|
|
465
|
-
return result;
|
|
466
|
-
}
|
|
467
|
-
/**
|
|
468
|
-
* Add reverse map information
|
|
469
|
-
*
|
|
470
|
-
* @param prop
|
|
471
|
-
* @param cascade
|
|
472
|
-
* @param store
|
|
473
|
-
*/
|
|
474
|
-
addReverseMap(prop, store) {
|
|
475
|
-
this._reverseMap.push({
|
|
476
|
-
property: prop,
|
|
477
|
-
mapper: store
|
|
478
|
-
});
|
|
479
|
-
}
|
|
480
|
-
/**
|
|
481
|
-
* Increment attributes of an object
|
|
482
|
-
*
|
|
483
|
-
* @param uid
|
|
484
|
-
* @param info
|
|
485
|
-
* @returns
|
|
486
|
-
*/
|
|
487
|
-
async incrementAttributes(uid, info) {
|
|
488
|
-
let params = info.filter(i => i.value !== 0);
|
|
489
|
-
// If value === 0 no need to update anything
|
|
490
|
-
if (params.length === 0) {
|
|
491
|
-
return;
|
|
492
|
-
}
|
|
493
|
-
let updateDate = new Date();
|
|
494
|
-
this.metrics.operations_total.inc({ operation: "increment" });
|
|
495
|
-
await this._incrementAttributes(uid, params, updateDate);
|
|
496
|
-
const evt = {
|
|
497
|
-
object_id: uid,
|
|
498
|
-
store: this,
|
|
499
|
-
updateDate,
|
|
500
|
-
partial_update: {
|
|
501
|
-
increments: params
|
|
502
|
-
}
|
|
503
|
-
};
|
|
504
|
-
await this.emitStoreEvent("Store.PartialUpdated", evt);
|
|
505
|
-
return updateDate;
|
|
506
|
-
}
|
|
507
|
-
/**
|
|
508
|
-
* Helper function that call incrementAttributes
|
|
509
|
-
* @param uid
|
|
510
|
-
* @param prop
|
|
511
|
-
* @param value
|
|
512
|
-
* @returns
|
|
513
|
-
*/
|
|
514
|
-
async incrementAttribute(uid, prop, value) {
|
|
515
|
-
return this.incrementAttributes(uid, [{ property: prop, value }]);
|
|
516
|
-
}
|
|
517
|
-
/**
|
|
518
|
-
* Add or update an item to an array in the model
|
|
519
|
-
*
|
|
520
|
-
* @param uid of the model
|
|
521
|
-
* @param prop of the model to add in
|
|
522
|
-
* @param item to add in the array
|
|
523
|
-
* @param index if specified update item in this index
|
|
524
|
-
* @param itemWriteCondition value of the condition to test (in case of update)
|
|
525
|
-
* @param itemWriteConditionField field to read the condition from (in case of update)
|
|
526
|
-
*/
|
|
527
|
-
async upsertItemToCollection(uid, prop, item, index = undefined, itemWriteCondition = undefined, itemWriteConditionField = this._uuidField) {
|
|
528
|
-
let updateDate = new Date();
|
|
529
|
-
this.metrics.operations_total.inc({ operation: "collectionUpsert" });
|
|
530
|
-
await this._upsertItemToCollection(uid, prop, item, index, itemWriteCondition, itemWriteConditionField, updateDate);
|
|
531
|
-
await this.emitStoreEvent("Store.PartialUpdated", {
|
|
532
|
-
object_id: uid,
|
|
533
|
-
store: this,
|
|
534
|
-
updateDate,
|
|
535
|
-
partial_update: {
|
|
536
|
-
addItem: {
|
|
537
|
-
value: item,
|
|
538
|
-
property: prop,
|
|
539
|
-
index: index
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
});
|
|
543
|
-
return updateDate;
|
|
544
|
-
}
|
|
545
|
-
/**
|
|
546
|
-
* Remove an item from an array in the model
|
|
547
|
-
*
|
|
548
|
-
* @param uid of the model
|
|
549
|
-
* @param prop of the model to remove from
|
|
550
|
-
* @param index of the item to remove in the array
|
|
551
|
-
* @param itemWriteCondition value of the condition
|
|
552
|
-
* @param itemWriteConditionField field to read the condition from
|
|
553
|
-
*/
|
|
554
|
-
async deleteItemFromCollection(uid, prop, index, itemWriteCondition, itemWriteConditionField = this._uuidField) {
|
|
555
|
-
let updateDate = new Date();
|
|
556
|
-
this.metrics.operations_total.inc({ operation: "collectionDelete" });
|
|
557
|
-
await this._deleteItemFromCollection(uid, prop, index, itemWriteCondition, itemWriteConditionField, updateDate);
|
|
558
|
-
await this.emitStoreEvent("Store.PartialUpdated", {
|
|
559
|
-
object_id: uid,
|
|
560
|
-
store: this,
|
|
561
|
-
updateDate,
|
|
562
|
-
partial_update: {
|
|
563
|
-
deleteItem: {
|
|
564
|
-
property: prop,
|
|
565
|
-
index: index
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
});
|
|
569
|
-
return updateDate;
|
|
570
|
-
}
|
|
571
|
-
/**
|
|
572
|
-
* Iterate through the results
|
|
573
|
-
*
|
|
574
|
-
* This can be resource consuming
|
|
575
|
-
*
|
|
576
|
-
* @param query
|
|
577
|
-
* @param context
|
|
578
|
-
*/
|
|
579
|
-
async *iterate(query = "", context) {
|
|
580
|
-
if (query.includes("OFFSET")) {
|
|
581
|
-
throw new Error("Cannot contain an OFFSET for iterate method");
|
|
582
|
-
}
|
|
583
|
-
let continuationToken;
|
|
584
|
-
do {
|
|
585
|
-
let q = query + (continuationToken !== undefined ? ` OFFSET "${continuationToken}"` : "");
|
|
586
|
-
let page = await this.query(q, context);
|
|
587
|
-
for (let item of page.results) {
|
|
588
|
-
yield item;
|
|
589
|
-
}
|
|
590
|
-
continuationToken = page.continuationToken;
|
|
591
|
-
} while (continuationToken);
|
|
592
|
-
}
|
|
593
|
-
// REFACTOR . >= 4
|
|
594
|
-
/**
|
|
595
|
-
* Query all the results
|
|
596
|
-
*
|
|
597
|
-
*
|
|
598
|
-
* @param query
|
|
599
|
-
* @param context
|
|
600
|
-
* @returns
|
|
601
|
-
* @deprecated use iterate instead
|
|
602
|
-
*/
|
|
603
|
-
async queryAll(query, context) {
|
|
604
|
-
let res = [];
|
|
605
|
-
for await (let item of this.iterate(query, context)) {
|
|
606
|
-
res.push(item);
|
|
607
|
-
}
|
|
608
|
-
return res;
|
|
609
|
-
}
|
|
610
|
-
// END_REFACTOR
|
|
611
|
-
/**
|
|
612
|
-
* Check that __type Comparison is only used with = and CONTAINS
|
|
613
|
-
* If CONTAINS is used, move __type to __types
|
|
614
|
-
* If __type = store._model, remove it
|
|
615
|
-
*/
|
|
616
|
-
queryTypeUpdater(query) {
|
|
617
|
-
return query;
|
|
618
|
-
}
|
|
619
|
-
/**
|
|
620
|
-
* Query store with WebdaQL
|
|
621
|
-
* @param query
|
|
622
|
-
* @param context to apply permission
|
|
623
|
-
*/
|
|
624
|
-
async query(query, context) {
|
|
625
|
-
let permissionQuery = this._model.getPermissionQuery(context);
|
|
626
|
-
let partialPermission = true;
|
|
627
|
-
let fullQuery = query;
|
|
628
|
-
if (permissionQuery) {
|
|
629
|
-
partialPermission = permissionQuery.partial;
|
|
630
|
-
fullQuery = WebdaQL.PrependCondition(query, permissionQuery.query);
|
|
631
|
-
}
|
|
632
|
-
let queryValidator = new WebdaQL.QueryValidator(fullQuery);
|
|
633
|
-
let offset = queryValidator.getOffset();
|
|
634
|
-
const limit = queryValidator.getLimit();
|
|
635
|
-
const parsedQuery = this.queryTypeUpdater(queryValidator.getQuery());
|
|
636
|
-
parsedQuery.limit = limit;
|
|
637
|
-
// __type is a special field to filter on the type of the object
|
|
638
|
-
// Emit the default event
|
|
639
|
-
await this.emitSync("Store.Query", {
|
|
640
|
-
query,
|
|
641
|
-
parsedQuery,
|
|
642
|
-
store: this,
|
|
643
|
-
context
|
|
644
|
-
});
|
|
645
|
-
const result = {
|
|
646
|
-
results: [],
|
|
647
|
-
continuationToken: undefined
|
|
648
|
-
};
|
|
649
|
-
/*
|
|
650
|
-
Offset are split in two with _
|
|
651
|
-
|
|
652
|
-
MainOffset is the database offset, retrieving a page from the database
|
|
653
|
-
SubOffset is the offset within the page
|
|
654
|
-
|
|
655
|
-
As we filter through the page, for additional filters or permissions, the page cut
|
|
656
|
-
by database does not endup being our final page cut, so we need a page offset to
|
|
657
|
-
abstract this completely
|
|
658
|
-
*/
|
|
659
|
-
let [mainOffset, subOffset] = offset.split("_");
|
|
660
|
-
let secondOffset = parseInt(subOffset || "0");
|
|
661
|
-
let duration = Date.now();
|
|
662
|
-
this.metrics.operations_total.inc({ operation: "query" });
|
|
663
|
-
while (result.results.length < limit) {
|
|
664
|
-
let tmpResults = await this.find({
|
|
665
|
-
...parsedQuery,
|
|
666
|
-
continuationToken: mainOffset
|
|
667
|
-
});
|
|
668
|
-
// If no filter is returned assume it is by mistake and apply filtering
|
|
669
|
-
if (tmpResults.filter === undefined) {
|
|
670
|
-
tmpResults.filter = queryValidator.getExpression();
|
|
671
|
-
this.log("WARN", `Store '${this.getName()}' postquery full filtering`);
|
|
672
|
-
}
|
|
673
|
-
let subOffsetCount = 0;
|
|
674
|
-
for (let item of tmpResults.results) {
|
|
675
|
-
item.setContext(context);
|
|
676
|
-
// Because of dynamic filter and permission we need to suboffset the pagination
|
|
677
|
-
subOffsetCount++;
|
|
678
|
-
if (subOffsetCount <= secondOffset) {
|
|
679
|
-
continue;
|
|
680
|
-
}
|
|
681
|
-
if (tmpResults.filter !== true && !tmpResults.filter.eval(item)) {
|
|
682
|
-
continue;
|
|
683
|
-
}
|
|
684
|
-
if (context && partialPermission && (await item.canAct(context, "get")) !== true) {
|
|
685
|
-
continue;
|
|
686
|
-
}
|
|
687
|
-
result.results.push(item);
|
|
688
|
-
if (result.results.length >= limit) {
|
|
689
|
-
if (subOffsetCount === tmpResults.results.length) {
|
|
690
|
-
result.continuationToken = tmpResults.continuationToken;
|
|
691
|
-
}
|
|
692
|
-
else {
|
|
693
|
-
result.continuationToken = `${mainOffset}_${subOffsetCount}`;
|
|
694
|
-
}
|
|
695
|
-
break;
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
// Update both offset
|
|
699
|
-
mainOffset = tmpResults.continuationToken;
|
|
700
|
-
// Fresh new query so we do not need to skip
|
|
701
|
-
secondOffset = 0;
|
|
702
|
-
if (mainOffset === undefined || result.results.length >= limit) {
|
|
703
|
-
break;
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
duration = Date.now() - duration;
|
|
707
|
-
this.metrics.queries.observe(duration / 1000);
|
|
708
|
-
if (duration > this.parameters.slowQueryThreshold) {
|
|
709
|
-
this.logSlowQuery(query, "", duration);
|
|
710
|
-
this.metrics.slow_queries_total.inc();
|
|
711
|
-
}
|
|
712
|
-
await this.emitSync("Store.Queried", {
|
|
713
|
-
query,
|
|
714
|
-
parsedQuery: parsedQuery,
|
|
715
|
-
store: this,
|
|
716
|
-
continuationToken: result.continuationToken,
|
|
717
|
-
results: result.results,
|
|
718
|
-
context
|
|
719
|
-
});
|
|
720
|
-
return result;
|
|
721
|
-
}
|
|
722
|
-
/**
|
|
723
|
-
* Expose query to http
|
|
724
|
-
*/
|
|
725
|
-
async httpQuery(ctx) {
|
|
726
|
-
let query;
|
|
727
|
-
if (ctx.getHttpContext().getMethod() === "GET") {
|
|
728
|
-
query = ctx.getParameters().q;
|
|
729
|
-
}
|
|
730
|
-
else {
|
|
731
|
-
query = WebdaQL.unsanitize((await ctx.getRequestBody()).q);
|
|
732
|
-
}
|
|
733
|
-
try {
|
|
734
|
-
ctx.write(await this.query(query, ctx));
|
|
735
|
-
}
|
|
736
|
-
catch (err) {
|
|
737
|
-
if (err instanceof SyntaxError) {
|
|
738
|
-
this.log("INFO", "Query syntax error");
|
|
739
|
-
throw new WebdaError.BadRequest("Query syntax error");
|
|
740
|
-
}
|
|
741
|
-
throw err;
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
/**
|
|
745
|
-
* Handle StoreEvent and update cache based on it
|
|
746
|
-
* Then emit the event, it allows the cache to be updated
|
|
747
|
-
* before listeners are called
|
|
748
|
-
*
|
|
749
|
-
* @param event
|
|
750
|
-
* @param data
|
|
751
|
-
*/
|
|
752
|
-
async emitStoreEvent(event, data) {
|
|
753
|
-
if (event === "Store.Deleted") {
|
|
754
|
-
await this._cacheStore?._delete(data.object_id);
|
|
755
|
-
}
|
|
756
|
-
else if (event === "Store.PartialUpdated") {
|
|
757
|
-
const partialEvent = data;
|
|
758
|
-
if (partialEvent.partial_update.increments) {
|
|
759
|
-
await this._cacheStore?._incrementAttributes(partialEvent.object_id, partialEvent.partial_update.increments, partialEvent.updateDate);
|
|
760
|
-
}
|
|
761
|
-
else if (partialEvent.partial_update.deleteAttribute) {
|
|
762
|
-
await this._cacheStore?._removeAttribute(partialEvent.object_id, partialEvent.partial_update.deleteAttribute, partialEvent.updateDate);
|
|
763
|
-
}
|
|
764
|
-
else if (partialEvent.partial_update.addItem) {
|
|
765
|
-
await this._cacheStore?._upsertItemToCollection(partialEvent.object_id, partialEvent.partial_update.addItem.property, partialEvent.partial_update.addItem.value, partialEvent.partial_update.addItem.index, undefined, undefined, partialEvent.updateDate);
|
|
766
|
-
}
|
|
767
|
-
else if (partialEvent.partial_update.deleteItem) {
|
|
768
|
-
await this._cacheStore?._deleteItemFromCollection(partialEvent.object_id, partialEvent.partial_update.deleteItem.property, partialEvent.partial_update.deleteItem.index, undefined, undefined, partialEvent.updateDate);
|
|
769
|
-
}
|
|
770
|
-
else if (partialEvent.partial_update.patch) {
|
|
771
|
-
await this._cacheStore?._patch(partialEvent.partial_update.patch, partialEvent.object_id);
|
|
772
|
-
}
|
|
773
|
-
else {
|
|
774
|
-
await this.invalidateCache(partialEvent.object_id);
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
else if (event === "Store.Updated") {
|
|
778
|
-
await this._cacheStore?._update(data.update, data.object_id);
|
|
779
|
-
}
|
|
780
|
-
else if (event === "Store.PatchUpdated") {
|
|
781
|
-
await this._cacheStore?._patch(data.object, data.object_id);
|
|
782
|
-
}
|
|
783
|
-
await this.emitSync(event, data);
|
|
784
|
-
}
|
|
785
|
-
/**
|
|
786
|
-
* Save an object
|
|
787
|
-
*
|
|
788
|
-
* @param {Object} Object to save
|
|
789
|
-
* @param {String} Uuid to use, if not specified take the object.uuid or generate one if not found
|
|
790
|
-
* @return {Promise} with saved object
|
|
791
|
-
*
|
|
792
|
-
* Might want to rename to create
|
|
793
|
-
*/
|
|
794
|
-
async save(object, ctx = undefined) {
|
|
795
|
-
if (object instanceof this._model && object._creationDate !== undefined && object._lastUpdate !== undefined) {
|
|
796
|
-
if (ctx) {
|
|
797
|
-
object.setContext(ctx);
|
|
798
|
-
}
|
|
799
|
-
return await object.save();
|
|
800
|
-
}
|
|
801
|
-
return this.create(object, ctx);
|
|
802
|
-
}
|
|
803
|
-
/**
|
|
804
|
-
*
|
|
805
|
-
* @param object
|
|
806
|
-
* @param ctx
|
|
807
|
-
* @returns
|
|
808
|
-
*/
|
|
809
|
-
async create(object, ctx = undefined) {
|
|
810
|
-
object = this.initModel(object);
|
|
811
|
-
// Dates should be store by the Store
|
|
812
|
-
if (!object._creationDate) {
|
|
813
|
-
object._creationDate = object._lastUpdate = new Date();
|
|
814
|
-
}
|
|
815
|
-
else {
|
|
816
|
-
object._lastUpdate = new Date();
|
|
817
|
-
}
|
|
818
|
-
const ancestors = this.getWebda().getApplication().getModelHierarchy(object.__type).ancestors;
|
|
819
|
-
object.__types = [object.__type, ...ancestors].filter(i => i !== "Webda/CoreModel" && i !== "CoreModel");
|
|
820
|
-
if (ctx) {
|
|
821
|
-
object.setContext(ctx);
|
|
822
|
-
}
|
|
823
|
-
// Handle object auto listener
|
|
824
|
-
const evt = {
|
|
825
|
-
object: object,
|
|
826
|
-
object_id: object.getUuid(),
|
|
827
|
-
store: this,
|
|
828
|
-
context: ctx
|
|
829
|
-
};
|
|
830
|
-
await Promise.all([
|
|
831
|
-
this.emitSync("Store.Save", evt),
|
|
832
|
-
object?.__class.emitSync("Store.Save", evt),
|
|
833
|
-
object._onSave()
|
|
834
|
-
]);
|
|
835
|
-
this.metrics.operations_total.inc({ operation: "save" });
|
|
836
|
-
let res = await this._save(object);
|
|
837
|
-
await this._cacheStore?._save(object);
|
|
838
|
-
object = this.initModel(res);
|
|
839
|
-
const evtSaved = {
|
|
840
|
-
object: object,
|
|
841
|
-
object_id: object.getUuid(),
|
|
842
|
-
store: this,
|
|
843
|
-
context: ctx
|
|
844
|
-
};
|
|
845
|
-
await Promise.all([
|
|
846
|
-
this.emitSync("Store.Saved", evtSaved),
|
|
847
|
-
object?.__class.emitSync("Store.Saved", evtSaved),
|
|
848
|
-
object._onSaved()
|
|
849
|
-
]);
|
|
850
|
-
return object;
|
|
851
|
-
}
|
|
852
|
-
/**
|
|
853
|
-
* Patch an object
|
|
854
|
-
*
|
|
855
|
-
* @param object
|
|
856
|
-
* @param reverseMap
|
|
857
|
-
* @returns
|
|
858
|
-
*/
|
|
859
|
-
async patch(object, reverseMap = true, conditionField, conditionValue) {
|
|
860
|
-
return this.update(object, reverseMap, true, conditionField, conditionValue);
|
|
861
|
-
}
|
|
862
|
-
/**
|
|
863
|
-
* Check if an UpdateCondition is met
|
|
864
|
-
* @param model
|
|
865
|
-
* @param conditionField
|
|
866
|
-
* @param condition
|
|
867
|
-
* @param uid
|
|
342
|
+
* Check that keys are valid
|
|
343
|
+
* All keys of model stored in a Store must have the same type of primary key
|
|
868
344
|
*/
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
// Add toString to manage Date object
|
|
872
|
-
if (model[conditionField].toString() !== condition.toString()) {
|
|
873
|
-
throw new UpdateConditionFailError(uid ? uid : model.getUuid(), conditionField, condition);
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
/**
|
|
878
|
-
* Check if an UpdateCondition is met
|
|
879
|
-
* @param model
|
|
880
|
-
* @param conditionField
|
|
881
|
-
* @param condition
|
|
882
|
-
* @param uid
|
|
883
|
-
*/
|
|
884
|
-
checkCollectionUpdateCondition(model, collection, conditionField, condition, index) {
|
|
885
|
-
// No index so addition to collection
|
|
886
|
-
if (index === null) {
|
|
887
|
-
// The condition must be length of the collection
|
|
888
|
-
if (!model[collection] || model[collection].length !== condition) {
|
|
889
|
-
throw new UpdateConditionFailError(model.getUuid(), collection, condition);
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
else if (condition && model[collection][index][conditionField] !== condition) {
|
|
893
|
-
throw new UpdateConditionFailError(model.getUuid(), `${collection}[${index}].${conditionField}`, condition);
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
/**
|
|
897
|
-
* Update conditionally
|
|
898
|
-
* @param uuid
|
|
899
|
-
* @param updates
|
|
900
|
-
* @param conditionField
|
|
901
|
-
* @param condition
|
|
902
|
-
*/
|
|
903
|
-
async conditionalPatch(uuid, updates, conditionField, condition) {
|
|
904
|
-
try {
|
|
905
|
-
await this._patch(updates, uuid, condition, conditionField);
|
|
906
|
-
// CoreModel should also emit this one but cannot do within this context
|
|
907
|
-
await this.emitStoreEvent("Store.PartialUpdated", {
|
|
908
|
-
object_id: uuid,
|
|
909
|
-
partial_update: {
|
|
910
|
-
patch: updates
|
|
911
|
-
},
|
|
912
|
-
store: this
|
|
913
|
-
});
|
|
914
|
-
return true;
|
|
915
|
-
}
|
|
916
|
-
catch (err) {
|
|
917
|
-
if (err instanceof UpdateConditionFailError) {
|
|
918
|
-
return false;
|
|
919
|
-
}
|
|
920
|
-
throw err;
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
/**
|
|
924
|
-
*
|
|
925
|
-
* @param model
|
|
926
|
-
* @param prop
|
|
927
|
-
* @param item
|
|
928
|
-
* @param index
|
|
929
|
-
* @param itemWriteCondition
|
|
930
|
-
* @param itemWriteConditionField
|
|
931
|
-
* @param updateDate
|
|
932
|
-
*/
|
|
933
|
-
async simulateUpsertItemToCollection(model, prop, item, updateDate, index, itemWriteCondition, itemWriteConditionField) {
|
|
934
|
-
if (prop === "__proto__") {
|
|
935
|
-
throw new Error("Cannot update __proto__: js/prototype-polluting-assignment");
|
|
936
|
-
}
|
|
937
|
-
this.checkCollectionUpdateCondition(model, prop, itemWriteConditionField, itemWriteCondition, index);
|
|
938
|
-
if (index === undefined) {
|
|
939
|
-
if (model[prop] === undefined) {
|
|
940
|
-
model[prop] = [item];
|
|
941
|
-
}
|
|
942
|
-
else {
|
|
943
|
-
model[prop].push(item);
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
else {
|
|
947
|
-
model[prop][index] = item;
|
|
948
|
-
}
|
|
949
|
-
model._lastUpdate = updateDate;
|
|
950
|
-
await this._save(model);
|
|
951
|
-
}
|
|
952
|
-
/**
|
|
953
|
-
* Update an object
|
|
954
|
-
*
|
|
955
|
-
* If no attribute can be updated then return undefined
|
|
956
|
-
*
|
|
957
|
-
* @param {Object} Object to save
|
|
958
|
-
* @param {Boolean} reverseMap internal use only, for disable map resolution
|
|
959
|
-
* @return {Promise} with saved object
|
|
960
|
-
*/
|
|
961
|
-
async update(object, reverseMap = true, partial = false, conditionField, conditionValue) {
|
|
962
|
-
/** @ignore */
|
|
963
|
-
let saved;
|
|
964
|
-
let loaded;
|
|
965
|
-
// Dont allow to update collections from map
|
|
966
|
-
if (this._reverseMap != undefined && reverseMap) {
|
|
967
|
-
for (let i in this._reverseMap) {
|
|
968
|
-
if (object[this._reverseMap[i].property] != undefined) {
|
|
969
|
-
delete object[this._reverseMap[i].property];
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
if (Object.keys(object).length < 2) {
|
|
974
|
-
return undefined;
|
|
975
|
-
}
|
|
976
|
-
object._lastUpdate = new Date();
|
|
977
|
-
this.metrics.operations_total.inc({ operation: "get" });
|
|
978
|
-
const uuid = object.getUuid ? object.getUuid() : object[this._uuidField];
|
|
979
|
-
let load = await this._getFromCache(uuid, true);
|
|
980
|
-
if (load.__type !== this._modelType && this.parameters.strict) {
|
|
981
|
-
this.log("WARN", `Object '${uuid}' was not created by this store ${load.__type}:${this._modelType}`);
|
|
982
|
-
throw new StoreNotFoundError(uuid, this.getName());
|
|
983
|
-
}
|
|
984
|
-
loaded = this.initModel(load);
|
|
985
|
-
if (object instanceof CoreModel) {
|
|
986
|
-
loaded.setContext(object.getContext());
|
|
987
|
-
}
|
|
988
|
-
const update = object;
|
|
989
|
-
const evt = {
|
|
990
|
-
object: loaded,
|
|
991
|
-
object_id: loaded.getUuid(),
|
|
992
|
-
store: this,
|
|
993
|
-
update
|
|
994
|
-
};
|
|
995
|
-
await Promise.all([
|
|
996
|
-
this.emitSync(partial ? `Store.PatchUpdate` : `Store.Update`, evt),
|
|
997
|
-
object?.__class?.emitSync(partial ? `Store.PatchUpdate` : `Store.Update`, evt),
|
|
998
|
-
loaded._onUpdate(object)
|
|
999
|
-
]);
|
|
1000
|
-
let res;
|
|
1001
|
-
if (conditionField !== null) {
|
|
1002
|
-
conditionField ?? (conditionField = "_lastUpdate");
|
|
1003
|
-
conditionValue ?? (conditionValue = load[conditionField]);
|
|
1004
|
-
}
|
|
1005
|
-
if (partial) {
|
|
1006
|
-
this.metrics.operations_total.inc({ operation: "partialUpdate" });
|
|
1007
|
-
await this._patch(object, uuid, conditionValue, conditionField);
|
|
1008
|
-
res = object;
|
|
1009
|
-
}
|
|
1010
|
-
else {
|
|
1011
|
-
// Copy back the mappers
|
|
1012
|
-
for (let i in this._reverseMap) {
|
|
1013
|
-
object[this._reverseMap[i].property] = loaded[this._reverseMap[i].property];
|
|
1014
|
-
}
|
|
1015
|
-
object = this.initModel(object);
|
|
1016
|
-
this.metrics.operations_total.inc({ operation: "update" });
|
|
1017
|
-
res = await this._update(object, uuid, conditionValue, conditionField);
|
|
1018
|
-
}
|
|
1019
|
-
// Reinit save
|
|
1020
|
-
saved = this.initModel({
|
|
1021
|
-
...loaded,
|
|
1022
|
-
...res
|
|
1023
|
-
});
|
|
1024
|
-
const evtUpdated = {
|
|
1025
|
-
object: saved,
|
|
1026
|
-
object_id: saved.getUuid(),
|
|
1027
|
-
store: this,
|
|
1028
|
-
update,
|
|
1029
|
-
previous: loaded
|
|
1030
|
-
};
|
|
1031
|
-
await Promise.all([
|
|
1032
|
-
this.emitStoreEvent(partial ? `Store.PatchUpdated` : `Store.Updated`, evtUpdated),
|
|
1033
|
-
saved?.__class.emitSync(partial ? `Store.PatchUpdated` : `Store.Updated`, evtUpdated),
|
|
1034
|
-
saved._onUpdated()
|
|
1035
|
-
]);
|
|
1036
|
-
return saved;
|
|
1037
|
-
}
|
|
1038
|
-
/**
|
|
1039
|
-
* Manage the store migration for __type case sensitivity
|
|
1040
|
-
*/
|
|
1041
|
-
async v3Migration() {
|
|
1042
|
-
// Compute case for all object
|
|
1043
|
-
await this.recomputeTypeCase();
|
|
1044
|
-
// Compute all __types
|
|
1045
|
-
await this.recomputeTypes();
|
|
1046
|
-
// We do not move to short id as it is not compatible with v2
|
|
1047
|
-
}
|
|
1048
|
-
/**
|
|
1049
|
-
*
|
|
1050
|
-
*/
|
|
1051
|
-
async recomputeTypeShortId() {
|
|
1052
|
-
this.log("INFO", "Ensuring __type is using its short id form");
|
|
1053
|
-
const app = this.getWebda().getApplication();
|
|
1054
|
-
// We need to be laxist for migration
|
|
1055
|
-
this.parameters.strict = false;
|
|
1056
|
-
await this.migration("typesShortId", async (item) => {
|
|
1057
|
-
if (item.__type !== undefined && item.__type.includes("/")) {
|
|
1058
|
-
const model = app.getWebdaObject("models", item.__type);
|
|
1059
|
-
const name = app.getShortId(app.getModelName(model));
|
|
1060
|
-
if (name !== item.__type) {
|
|
1061
|
-
this.log("INFO", "Migrating type " + item.__type + " to " + name);
|
|
1062
|
-
return {
|
|
1063
|
-
__type: name
|
|
1064
|
-
};
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
1067
|
-
});
|
|
1068
|
-
}
|
|
1069
|
-
/**
|
|
1070
|
-
* Ensure model aliases are not used in this store
|
|
1071
|
-
*
|
|
1072
|
-
* So alias can be cleaned
|
|
1073
|
-
*/
|
|
1074
|
-
async cleanModelAliases() {
|
|
1075
|
-
this.log("INFO", "Ensuring __type is not using any aliases");
|
|
1076
|
-
// We need to be laxist for migration
|
|
1077
|
-
this.parameters.strict = false;
|
|
1078
|
-
await this.migration("cleanAliases", async (item) => {
|
|
1079
|
-
if (this.parameters.modelAliases[item.__type]) {
|
|
1080
|
-
this.log("INFO", "Migrating type " + item.__type + " to " + this.parameters.modelAliases[item.__type]);
|
|
1081
|
-
return {
|
|
1082
|
-
__type: this.parameters.modelAliases[item.__type]
|
|
1083
|
-
};
|
|
1084
|
-
}
|
|
1085
|
-
});
|
|
1086
|
-
}
|
|
1087
|
-
/**
|
|
1088
|
-
* Recompute type case
|
|
1089
|
-
*/
|
|
1090
|
-
async recomputeTypeCase() {
|
|
1091
|
-
this.log("INFO", "Ensuring __type is case sensitive from migration from v2.x");
|
|
1092
|
-
const app = this.getWebda().getApplication();
|
|
1093
|
-
// We need to be laxist for migration
|
|
1094
|
-
this.parameters.strict = false;
|
|
1095
|
-
await this.migration("typesCase", async (item) => {
|
|
1096
|
-
if (item.__type !== undefined) {
|
|
1097
|
-
if (!app.hasWebdaObject("models", item.__type, true) && app.hasWebdaObject("models", item.__type, false)) {
|
|
1098
|
-
const model = app.getWebdaObject("models", item.__type, false);
|
|
1099
|
-
const name = app.getModelName(model);
|
|
1100
|
-
if (model) {
|
|
1101
|
-
this.log("INFO", "Migrating type " + item.__type + " to " + name);
|
|
1102
|
-
return {
|
|
1103
|
-
__type: name
|
|
1104
|
-
};
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
}
|
|
1108
|
-
});
|
|
1109
|
-
}
|
|
1110
|
-
/**
|
|
1111
|
-
* Recompute the __types for all objects (storeMigration.Registry.typesCompute)
|
|
1112
|
-
*/
|
|
1113
|
-
async recomputeTypes() {
|
|
1114
|
-
this.log("INFO", "Ensuring __types is correct from migration from v2.x");
|
|
1115
|
-
// Update __types for each __type will be more efficient
|
|
1116
|
-
await this.migration("typesCompute", async (item) => {
|
|
1117
|
-
let __types = this.getWebda().getApplication().getModelTypes(item);
|
|
1118
|
-
if (!item.__types ||
|
|
1119
|
-
item.__types.length !== __types.length ||
|
|
1120
|
-
!__types.every((element, index) => element === item.__types[index])) {
|
|
1121
|
-
this.log("INFO", "Migrating types " + JSON.stringify(item.__types) + " to " + JSON.stringify(__types), "for", item.__type, item.getUuid());
|
|
1122
|
-
return {
|
|
1123
|
-
__types
|
|
1124
|
-
};
|
|
1125
|
-
}
|
|
1126
|
-
});
|
|
1127
|
-
}
|
|
1128
|
-
/**
|
|
1129
|
-
* Delete a migration
|
|
1130
|
-
* @param name
|
|
1131
|
-
*/
|
|
1132
|
-
async cancelMigration(name) {
|
|
1133
|
-
await this.getWebda().getRegistry().delete(`storeMigration.${this.getName()}.${name}`);
|
|
1134
|
-
}
|
|
1135
|
-
/**
|
|
1136
|
-
* Get a migration
|
|
1137
|
-
* @param name
|
|
1138
|
-
*/
|
|
1139
|
-
async getMigration(name) {
|
|
1140
|
-
return await this.getWebda().getRegistry().get(`storeMigration.${this.getName()}.${name}`);
|
|
1141
|
-
}
|
|
1142
|
-
/**
|
|
1143
|
-
* Add a migration mechanism to store
|
|
1144
|
-
* @param name
|
|
1145
|
-
* @param patcher
|
|
1146
|
-
*/
|
|
1147
|
-
async migration(name, patcher, batchSize = 500) {
|
|
1148
|
-
let status = await this.getWebda().getRegistry().get(`storeMigration.${this.getName()}.${name}`, undefined, {});
|
|
1149
|
-
status.count ?? (status.count = 0);
|
|
1150
|
-
status.updated ?? (status.updated = 0);
|
|
1151
|
-
const worker = new Throttler(20);
|
|
1152
|
-
do {
|
|
1153
|
-
const res = await this.query(status.continuationToken ? `LIMIT ${batchSize} OFFSET "${status.continuationToken}"` : `LIMIT ${batchSize}`);
|
|
1154
|
-
status.count += res.results.length;
|
|
1155
|
-
for (let item of res.results) {
|
|
1156
|
-
let updated = await patcher(item);
|
|
1157
|
-
if (updated !== undefined) {
|
|
1158
|
-
status.updated++;
|
|
1159
|
-
if (typeof updated === "function") {
|
|
1160
|
-
worker.queue(updated);
|
|
1161
|
-
}
|
|
1162
|
-
else {
|
|
1163
|
-
worker.queue(async () => {
|
|
1164
|
-
await item.patch(updated, null);
|
|
1165
|
-
});
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
|
-
}
|
|
1169
|
-
this.log("INFO", `storeMigration.${this.getName()}.${name}: Migrated ${status.count} items: ${status.updated} updated`);
|
|
1170
|
-
status.continuationToken = res.continuationToken;
|
|
1171
|
-
await worker.wait();
|
|
1172
|
-
await status.save();
|
|
1173
|
-
} while (status.continuationToken);
|
|
1174
|
-
}
|
|
1175
|
-
/**
|
|
1176
|
-
* Remove an attribute from an object
|
|
1177
|
-
*
|
|
1178
|
-
* @param uuid
|
|
1179
|
-
* @param attribute
|
|
1180
|
-
* @returns
|
|
1181
|
-
*/
|
|
1182
|
-
async removeAttribute(uuid, attribute, itemWriteCondition, itemWriteConditionField) {
|
|
1183
|
-
this.metrics.operations_total.inc({ operation: "attributeDelete" });
|
|
1184
|
-
await this._removeAttribute(uuid, attribute, itemWriteCondition, itemWriteConditionField);
|
|
1185
|
-
await this.emitStoreEvent("Store.PartialUpdated", {
|
|
1186
|
-
object_id: uuid,
|
|
1187
|
-
partial_update: {
|
|
1188
|
-
deleteAttribute: attribute
|
|
1189
|
-
},
|
|
1190
|
-
store: this
|
|
1191
|
-
});
|
|
1192
|
-
}
|
|
1193
|
-
/**
|
|
1194
|
-
* Cascade delete a related object
|
|
1195
|
-
*
|
|
1196
|
-
* @param obj
|
|
1197
|
-
* @param uuid
|
|
1198
|
-
* @returns
|
|
1199
|
-
*/
|
|
1200
|
-
async cascadeDelete(obj, _uuid) {
|
|
1201
|
-
// We dont need uuid but Binary store will need it
|
|
1202
|
-
return this.delete(obj.getUuid());
|
|
1203
|
-
}
|
|
1204
|
-
/**
|
|
1205
|
-
* Delete an object from the store without condition nor async
|
|
1206
|
-
* @param uid to delete
|
|
1207
|
-
* @returns
|
|
1208
|
-
*/
|
|
1209
|
-
async forceDelete(uid) {
|
|
1210
|
-
return this.delete(uid, undefined, undefined, true);
|
|
1211
|
-
}
|
|
1212
|
-
/**
|
|
1213
|
-
* Delete an object
|
|
1214
|
-
*
|
|
1215
|
-
* @param {String} uuid to delete
|
|
1216
|
-
* @param {Boolean} delete sync even if asyncDelete is active
|
|
1217
|
-
* @return {Promise} the deletion promise
|
|
1218
|
-
*/
|
|
1219
|
-
async delete(uid, writeCondition, writeConditionField, sync = false) {
|
|
1220
|
-
/** @ignore */
|
|
1221
|
-
let to_delete;
|
|
1222
|
-
// Allow full object or just its uuid
|
|
1223
|
-
if (typeof uid === "object") {
|
|
1224
|
-
to_delete = uid;
|
|
1225
|
-
}
|
|
1226
|
-
else {
|
|
1227
|
-
this.metrics.operations_total.inc({ operation: "get" });
|
|
1228
|
-
to_delete = await this._getFromCache(uid);
|
|
1229
|
-
if (to_delete === undefined) {
|
|
1230
|
-
return;
|
|
1231
|
-
}
|
|
1232
|
-
if (to_delete.__type !== this._modelType && this.parameters.strict) {
|
|
1233
|
-
this.log("WARN", `Object '${uid}' was not created by this store ${to_delete.__type}:${this._modelType}`);
|
|
1234
|
-
return;
|
|
1235
|
-
}
|
|
1236
|
-
to_delete = this.initModel(to_delete);
|
|
1237
|
-
}
|
|
1238
|
-
// Check condition as we have the object
|
|
1239
|
-
if (writeCondition) {
|
|
1240
|
-
if (to_delete[writeConditionField] !== writeCondition) {
|
|
1241
|
-
throw new UpdateConditionFailError(to_delete.getUuid(), writeConditionField, writeCondition);
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
const evt = {
|
|
1245
|
-
object: to_delete,
|
|
1246
|
-
object_id: to_delete.getUuid(),
|
|
1247
|
-
store: this
|
|
1248
|
-
};
|
|
1249
|
-
// Send preevent
|
|
1250
|
-
await Promise.all([
|
|
1251
|
-
this.emitSync("Store.Delete", evt),
|
|
1252
|
-
to_delete?.__class.emitSync("Store.Delete", evt),
|
|
1253
|
-
to_delete._onDelete()
|
|
1254
|
-
]);
|
|
1255
|
-
// If async we just tag the object as deleted
|
|
1256
|
-
if (this.parameters.asyncDelete && !sync) {
|
|
1257
|
-
this.metrics.operations_total.inc({ operation: "partialUpdate" });
|
|
1258
|
-
await this._patch({
|
|
1259
|
-
__deleted: true
|
|
1260
|
-
}, to_delete.getUuid());
|
|
1261
|
-
await this._cacheStore?._patch({
|
|
1262
|
-
__deleted: true
|
|
1263
|
-
}, to_delete.getUuid());
|
|
1264
|
-
}
|
|
1265
|
-
else {
|
|
1266
|
-
this.metrics.operations_total.inc({ operation: "delete" });
|
|
1267
|
-
// Delete from the DB for real
|
|
1268
|
-
await this._delete(to_delete.getUuid(), writeCondition, writeConditionField);
|
|
1269
|
-
await this._cacheStore?._delete(to_delete.getUuid(), writeCondition, writeConditionField);
|
|
1270
|
-
}
|
|
1271
|
-
// Send post event
|
|
1272
|
-
const evtDeleted = {
|
|
1273
|
-
object: to_delete,
|
|
1274
|
-
object_id: to_delete.getUuid(),
|
|
1275
|
-
store: this
|
|
1276
|
-
};
|
|
1277
|
-
await Promise.all([
|
|
1278
|
-
this.emitStoreEvent("Store.Deleted", evtDeleted),
|
|
1279
|
-
to_delete.__class.emitSync("Store.Deleted", evtDeleted),
|
|
1280
|
-
to_delete._onDeleted()
|
|
1281
|
-
]);
|
|
1282
|
-
}
|
|
1283
|
-
/**
|
|
1284
|
-
* By default we cannot know if the store will trigger or not
|
|
1285
|
-
*
|
|
1286
|
-
* @param id
|
|
1287
|
-
* @param callback
|
|
1288
|
-
*/
|
|
1289
|
-
canTriggerConfiguration(_id, _callback) {
|
|
1290
|
-
return false;
|
|
1291
|
-
}
|
|
1292
|
-
/**
|
|
1293
|
-
* Provide a way to store configuration in store
|
|
1294
|
-
* @param {string} id
|
|
1295
|
-
* @returns {Promise<Map<string, any>>}
|
|
1296
|
-
*/
|
|
1297
|
-
async getConfiguration(id) {
|
|
1298
|
-
this.metrics.operations_total.inc({ operation: "get" });
|
|
1299
|
-
let object = await this._getFromCache(id);
|
|
1300
|
-
if (!object) {
|
|
1301
|
-
return undefined;
|
|
1302
|
-
}
|
|
1303
|
-
let result = {};
|
|
1304
|
-
for (let i in object) {
|
|
1305
|
-
if (i === this._uuidField || i === "_lastUpdate" || i.startsWith("_")) {
|
|
1306
|
-
continue;
|
|
1307
|
-
}
|
|
1308
|
-
result[i] = object[i];
|
|
1309
|
-
}
|
|
1310
|
-
return result;
|
|
1311
|
-
}
|
|
1312
|
-
/**
|
|
1313
|
-
* Upsert the uuid object
|
|
1314
|
-
* @param uuid
|
|
1315
|
-
* @param data
|
|
1316
|
-
*/
|
|
1317
|
-
async put(uuid, data) {
|
|
1318
|
-
if (await this.exists(uuid)) {
|
|
1319
|
-
return this.update({ ...data, uuid });
|
|
1320
|
-
}
|
|
1321
|
-
return this.save(data instanceof CoreModel ? data.setUuid(uuid) : { ...data, uuid });
|
|
1322
|
-
}
|
|
1323
|
-
/**
|
|
1324
|
-
* Get an object
|
|
1325
|
-
*
|
|
1326
|
-
* @param {String} uuid to get
|
|
1327
|
-
* @return {Promise} the object retrieved ( can be undefined if not found )
|
|
1328
|
-
*/
|
|
1329
|
-
async get(uid, ctx = undefined, defaultValue = undefined) {
|
|
1330
|
-
/** @ignore */
|
|
1331
|
-
if (!uid) {
|
|
1332
|
-
return undefined;
|
|
1333
|
-
}
|
|
1334
|
-
this.metrics.operations_total.inc({ operation: "get" });
|
|
1335
|
-
let object = await this._getFromCache(uid);
|
|
1336
|
-
if (!object) {
|
|
1337
|
-
return defaultValue ? this.initModel(defaultValue).setUuid(uid) : undefined;
|
|
1338
|
-
}
|
|
1339
|
-
if (object.__type !== this._modelType && this.parameters.strict) {
|
|
1340
|
-
this.log("WARN", `Object '${uid}' was not created by this store ${object.__type}:${this._modelType}`);
|
|
1341
|
-
return undefined;
|
|
1342
|
-
}
|
|
1343
|
-
object = this.initModel(object);
|
|
1344
|
-
object.setContext(ctx);
|
|
1345
|
-
const evt = {
|
|
1346
|
-
object: object,
|
|
1347
|
-
object_id: object.getUuid(),
|
|
1348
|
-
store: this,
|
|
1349
|
-
context: ctx
|
|
1350
|
-
};
|
|
1351
|
-
await Promise.all([this.emitSync("Store.Get", evt), object.__class.emitSync("Store.Get", evt), object._onGet()]);
|
|
1352
|
-
return object;
|
|
1353
|
-
}
|
|
1354
|
-
/**
|
|
1355
|
-
* Set one attribute in an object
|
|
1356
|
-
*
|
|
1357
|
-
* this is an helper function that calls patch
|
|
1358
|
-
*
|
|
1359
|
-
* @param uid of the object
|
|
1360
|
-
* @param property to update1
|
|
1361
|
-
* @param value new value
|
|
1362
|
-
* @returns
|
|
1363
|
-
*/
|
|
1364
|
-
async setAttribute(uid, property, value) {
|
|
1365
|
-
let patch = {};
|
|
1366
|
-
patch[property] = value;
|
|
1367
|
-
patch[this.getUuidField()] = uid;
|
|
1368
|
-
await this.patch(patch);
|
|
1369
|
-
}
|
|
1370
|
-
/**
|
|
1371
|
-
* @override
|
|
1372
|
-
*/
|
|
1373
|
-
async simulateFind(query, uuids) {
|
|
1374
|
-
let result = {
|
|
1375
|
-
results: [],
|
|
1376
|
-
continuationToken: undefined,
|
|
1377
|
-
filter: true
|
|
1378
|
-
};
|
|
1379
|
-
let count = 0;
|
|
1380
|
-
let limit = query.limit;
|
|
1381
|
-
let offset = parseInt(query.continuationToken || "0");
|
|
1382
|
-
let originalOffset = offset;
|
|
1383
|
-
if (query.orderBy && query.orderBy.length) {
|
|
1384
|
-
offset = 0;
|
|
1385
|
-
// We need to retrieve everything to orderBy after
|
|
1386
|
-
limit = Number.MAX_SAFE_INTEGER;
|
|
1387
|
-
}
|
|
1388
|
-
// Need to transfert to Array
|
|
1389
|
-
for (let uuid of uuids) {
|
|
1390
|
-
count++;
|
|
1391
|
-
// Offset start
|
|
1392
|
-
if (offset >= count) {
|
|
1393
|
-
continue;
|
|
1394
|
-
}
|
|
1395
|
-
let obj = await this._getFromCache(uuid);
|
|
1396
|
-
if (obj && query.filter.eval(obj)) {
|
|
1397
|
-
result.results.push(obj);
|
|
1398
|
-
if (result.results.length >= limit) {
|
|
1399
|
-
result.continuationToken = count.toString();
|
|
1400
|
-
return result;
|
|
1401
|
-
}
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
|
-
// Order by
|
|
1405
|
-
if (query.orderBy && query.orderBy.length) {
|
|
1406
|
-
// Sorting the results
|
|
1407
|
-
result.results.sort((a, b) => {
|
|
1408
|
-
let valA, valB;
|
|
1409
|
-
for (let orderBy of query.orderBy) {
|
|
1410
|
-
let invert = orderBy.direction === "ASC" ? 1 : -1;
|
|
1411
|
-
valA = WebdaQL.ComparisonExpression.getAttributeValue(a, orderBy.field.split("."));
|
|
1412
|
-
valB = WebdaQL.ComparisonExpression.getAttributeValue(b, orderBy.field.split("."));
|
|
1413
|
-
if (valA === valB) {
|
|
1414
|
-
continue;
|
|
1415
|
-
}
|
|
1416
|
-
if (typeof valA === "string") {
|
|
1417
|
-
return valA.localeCompare(valB) * invert;
|
|
1418
|
-
}
|
|
1419
|
-
return (valA < valB ? -1 : 1) * invert;
|
|
1420
|
-
}
|
|
1421
|
-
return -1;
|
|
1422
|
-
});
|
|
1423
|
-
result.results = result.results.slice(originalOffset, query.limit + originalOffset);
|
|
1424
|
-
if (result.results.length >= query.limit) {
|
|
1425
|
-
result.continuationToken = (query.limit + originalOffset).toString();
|
|
1426
|
-
}
|
|
1427
|
-
}
|
|
1428
|
-
return result;
|
|
1429
|
-
}
|
|
1430
|
-
getOpenApiReplacements() {
|
|
1431
|
-
return {
|
|
1432
|
-
modelName: this._model.name
|
|
1433
|
-
};
|
|
1434
|
-
}
|
|
1435
|
-
/**
|
|
1436
|
-
* Handle POST
|
|
1437
|
-
* @param ctx
|
|
1438
|
-
*/
|
|
1439
|
-
async httpCreate(ctx) {
|
|
1440
|
-
return this.operationCreate(ctx, this.parameters.model);
|
|
1441
|
-
}
|
|
1442
|
-
/**
|
|
1443
|
-
* Create a new object based on the context
|
|
1444
|
-
* @param ctx
|
|
1445
|
-
* @param model
|
|
1446
|
-
*/
|
|
1447
|
-
async operationCreate(ctx, model) {
|
|
1448
|
-
let body = await ctx.getInput();
|
|
1449
|
-
const modelPrototype = this.getWebda().getApplication().getModel(model);
|
|
1450
|
-
let object = modelPrototype.factory(body, ctx);
|
|
1451
|
-
object._creationDate = new Date();
|
|
1452
|
-
await object.checkAct(ctx, "create");
|
|
1453
|
-
try {
|
|
1454
|
-
await object.validate(ctx, body);
|
|
1455
|
-
}
|
|
1456
|
-
catch (err) {
|
|
1457
|
-
this.log("INFO", "Object is not valid", err);
|
|
1458
|
-
throw new WebdaError.BadRequest("Object is not valid");
|
|
1459
|
-
}
|
|
1460
|
-
if (object[this._uuidField] && (await this.exists(object[this._uuidField]))) {
|
|
1461
|
-
throw new WebdaError.Conflict("Object already exists");
|
|
1462
|
-
}
|
|
1463
|
-
await this.save(object, ctx);
|
|
1464
|
-
ctx.write(object);
|
|
1465
|
-
const evt = {
|
|
1466
|
-
context: ctx,
|
|
1467
|
-
values: body,
|
|
1468
|
-
object: object,
|
|
1469
|
-
object_id: object.getUuid(),
|
|
1470
|
-
store: this
|
|
1471
|
-
};
|
|
1472
|
-
await Promise.all([object.__class.emitSync("Store.WebCreate", evt), this.emitSync("Store.WebCreate", evt)]);
|
|
1473
|
-
}
|
|
1474
|
-
/**
|
|
1475
|
-
* Handle obect action
|
|
1476
|
-
* @param ctx
|
|
1477
|
-
*/
|
|
1478
|
-
async httpAction(ctx, actionMethod) {
|
|
1479
|
-
let action = ctx.getHttpContext().getUrl().split("/").pop();
|
|
1480
|
-
actionMethod ?? (actionMethod = action);
|
|
1481
|
-
let object = await this.get(ctx.parameter("uuid"), ctx);
|
|
1482
|
-
if (object === undefined || object.__deleted) {
|
|
1483
|
-
throw new WebdaError.NotFound("Object not found or is deleted");
|
|
1484
|
-
}
|
|
1485
|
-
const inputSchema = `${object.__class.getIdentifier(false)}.${action}.input`;
|
|
1486
|
-
if (this.getWebda().getApplication().hasSchema(inputSchema)) {
|
|
1487
|
-
const input = await ctx.getInput();
|
|
1488
|
-
try {
|
|
1489
|
-
this.getWebda().validateSchema(inputSchema, input);
|
|
1490
|
-
}
|
|
1491
|
-
catch (err) {
|
|
1492
|
-
this.log("INFO", "Object invalid", err);
|
|
1493
|
-
this.log("INFO", "Object invalid", inputSchema, input, this.getWebda().getApplication().getSchema(inputSchema));
|
|
1494
|
-
throw new WebdaError.BadRequest("Body is invalid");
|
|
1495
|
-
}
|
|
1496
|
-
}
|
|
1497
|
-
await object.checkAct(ctx, action);
|
|
1498
|
-
const evt = {
|
|
1499
|
-
action: action,
|
|
1500
|
-
object: object,
|
|
1501
|
-
store: this,
|
|
1502
|
-
context: ctx
|
|
1503
|
-
};
|
|
1504
|
-
await Promise.all([this.emitSync("Store.Action", evt), object.__class.emitSync("Store.Action", evt)]);
|
|
1505
|
-
const res = await object[actionMethod](ctx);
|
|
1506
|
-
if (res) {
|
|
1507
|
-
ctx.write(res);
|
|
1508
|
-
}
|
|
1509
|
-
const evtActioned = {
|
|
1510
|
-
action: action,
|
|
1511
|
-
object: object,
|
|
1512
|
-
store: this,
|
|
1513
|
-
context: ctx,
|
|
1514
|
-
result: res
|
|
1515
|
-
};
|
|
1516
|
-
await Promise.all([
|
|
1517
|
-
this.emitSync("Store.Actioned", evtActioned),
|
|
1518
|
-
object?.__class.emitSync("Store.Actioned", evtActioned)
|
|
1519
|
-
]);
|
|
1520
|
-
}
|
|
1521
|
-
/**
|
|
1522
|
-
* Handle collection action
|
|
1523
|
-
* @param ctx
|
|
1524
|
-
*/
|
|
1525
|
-
async httpGlobalAction(ctx, model = this._model) {
|
|
1526
|
-
let action = ctx.getHttpContext().getUrl().split("/").pop();
|
|
1527
|
-
const evt = {
|
|
1528
|
-
action: action,
|
|
1529
|
-
store: this,
|
|
1530
|
-
context: ctx,
|
|
1531
|
-
model
|
|
1532
|
-
};
|
|
1533
|
-
await Promise.all([this.emitSync("Store.Action", evt), model.emitSync("Store.Action", evt)]);
|
|
1534
|
-
const res = await model[action](ctx);
|
|
1535
|
-
if (res) {
|
|
1536
|
-
ctx.write(res);
|
|
1537
|
-
}
|
|
1538
|
-
const evtActioned = {
|
|
1539
|
-
action: action,
|
|
1540
|
-
store: this,
|
|
1541
|
-
context: ctx,
|
|
1542
|
-
result: res,
|
|
1543
|
-
model
|
|
1544
|
-
};
|
|
1545
|
-
await Promise.all([this.emitSync("Store.Actioned", evtActioned), model?.emitSync("Store.Actioned", evtActioned)]);
|
|
1546
|
-
}
|
|
1547
|
-
/**
|
|
1548
|
-
* Handle HTTP Update for an object
|
|
1549
|
-
*
|
|
1550
|
-
* @param ctx context of the request
|
|
1551
|
-
*/
|
|
1552
|
-
async httpUpdate(ctx) {
|
|
1553
|
-
const { uuid } = ctx.getParameters();
|
|
1554
|
-
const body = await ctx.getInput();
|
|
1555
|
-
body[this._uuidField] = uuid;
|
|
1556
|
-
let object = await this.get(uuid, ctx);
|
|
1557
|
-
if (!object || object.__deleted)
|
|
1558
|
-
throw new WebdaError.NotFound("Object not found or is deleted");
|
|
1559
|
-
await object.checkAct(ctx, "update");
|
|
1560
|
-
if (ctx.getHttpContext().getMethod() === "PATCH") {
|
|
1561
|
-
try {
|
|
1562
|
-
await object.validate(ctx, body, true);
|
|
1563
|
-
}
|
|
1564
|
-
catch (err) {
|
|
1565
|
-
this.log("INFO", "Object invalid", err, object);
|
|
1566
|
-
throw new WebdaError.BadRequest("Object is not valid");
|
|
1567
|
-
}
|
|
1568
|
-
let updateObject = new this._model();
|
|
1569
|
-
// Clean any default attributes from the model
|
|
1570
|
-
Object.keys(updateObject)
|
|
1571
|
-
.filter(i => i !== "__class")
|
|
1572
|
-
.forEach(i => {
|
|
1573
|
-
delete updateObject[i];
|
|
1574
|
-
});
|
|
1575
|
-
updateObject.setContext(ctx);
|
|
1576
|
-
updateObject.setUuid(uuid);
|
|
1577
|
-
updateObject.load(body, false, false);
|
|
1578
|
-
await this.patch(updateObject);
|
|
1579
|
-
object = undefined;
|
|
1580
|
-
}
|
|
1581
|
-
else {
|
|
1582
|
-
let updateObject = new this._model();
|
|
1583
|
-
updateObject.setContext(ctx);
|
|
1584
|
-
updateObject.load(body);
|
|
1585
|
-
// Copy back the _ attributes
|
|
1586
|
-
Object.keys(object)
|
|
1587
|
-
.filter(i => i.startsWith("_"))
|
|
1588
|
-
.forEach(i => {
|
|
1589
|
-
updateObject[i] = object[i];
|
|
1590
|
-
});
|
|
1591
|
-
try {
|
|
1592
|
-
await updateObject.validate(ctx, body);
|
|
1593
|
-
}
|
|
1594
|
-
catch (err) {
|
|
1595
|
-
this.log("INFO", "Object invalid", err);
|
|
1596
|
-
throw new WebdaError.BadRequest("Object is not valid");
|
|
1597
|
-
}
|
|
1598
|
-
// Add mappers back to
|
|
1599
|
-
object = await this.update(updateObject);
|
|
1600
|
-
}
|
|
1601
|
-
ctx.write(object);
|
|
1602
|
-
const evt = {
|
|
1603
|
-
context: ctx,
|
|
1604
|
-
updates: body,
|
|
1605
|
-
object: object,
|
|
1606
|
-
store: this,
|
|
1607
|
-
method: ctx.getHttpContext().getMethod()
|
|
1608
|
-
};
|
|
1609
|
-
await Promise.all([object?.__class.emitSync("Store.WebUpdate", evt), this.emitSync("Store.WebUpdate", evt)]);
|
|
1610
|
-
}
|
|
1611
|
-
/**
|
|
1612
|
-
* Handle GET on object
|
|
1613
|
-
*
|
|
1614
|
-
* @param ctx context of the request
|
|
1615
|
-
*/
|
|
1616
|
-
async httpGet(ctx) {
|
|
1617
|
-
let uuid = ctx.parameter("uuid");
|
|
1618
|
-
let object = await this.get(uuid, ctx);
|
|
1619
|
-
await this.emitSync("Store.WebGetNotFound", {
|
|
1620
|
-
context: ctx,
|
|
1621
|
-
uuid,
|
|
1622
|
-
store: this
|
|
1623
|
-
});
|
|
1624
|
-
if (object === undefined || object.__deleted) {
|
|
1625
|
-
throw new WebdaError.NotFound("Object not found or is deleted");
|
|
1626
|
-
}
|
|
1627
|
-
await object.checkAct(ctx, "get");
|
|
1628
|
-
ctx.write(object);
|
|
1629
|
-
const evt = {
|
|
1630
|
-
context: ctx,
|
|
1631
|
-
object: object,
|
|
1632
|
-
store: this
|
|
1633
|
-
};
|
|
1634
|
-
await Promise.all([this.emitSync("Store.WebGet", evt), object.__class.emitSync("Store.WebGet", evt)]);
|
|
1635
|
-
ctx.write(object);
|
|
1636
|
-
}
|
|
1637
|
-
/**
|
|
1638
|
-
* Handle HTTP request
|
|
1639
|
-
*
|
|
1640
|
-
* @param ctx context of the request
|
|
1641
|
-
* @returns
|
|
1642
|
-
*/
|
|
1643
|
-
async httpDelete(ctx) {
|
|
1644
|
-
let uuid = ctx.parameter("uuid");
|
|
1645
|
-
let object = await this.get(uuid, ctx);
|
|
1646
|
-
if (!object || object.__deleted)
|
|
1647
|
-
throw new WebdaError.NotFound("Object not found or is deleted");
|
|
1648
|
-
await object.checkAct(ctx, "delete");
|
|
1649
|
-
// http://stackoverflow.com/questions/28684209/huge-delay-on-delete-requests-with-204-response-and-no-content-in-objectve-c#
|
|
1650
|
-
// IOS don't handle 204 with Content-Length != 0 it seems
|
|
1651
|
-
// Might still run into: Have trouble to handle the Content-Length on API Gateway so returning an empty object for now
|
|
1652
|
-
ctx.writeHead(204, { "Content-Length": "0" });
|
|
1653
|
-
await this.delete(uuid);
|
|
1654
|
-
const evt = {
|
|
1655
|
-
context: ctx,
|
|
1656
|
-
object_id: uuid,
|
|
1657
|
-
store: this
|
|
1658
|
-
};
|
|
1659
|
-
await Promise.all([this.emitSync("Store.WebDelete", evt), object.__class.emitSync("Store.WebDelete", evt)]);
|
|
1660
|
-
}
|
|
1661
|
-
/**
|
|
1662
|
-
* Return the model uuid field
|
|
1663
|
-
*/
|
|
1664
|
-
getUuidField() {
|
|
1665
|
-
return this._uuidField;
|
|
1666
|
-
}
|
|
1667
|
-
/**
|
|
1668
|
-
* Check if an object exists
|
|
1669
|
-
* @abstract
|
|
1670
|
-
* @params {String} uuid of the object or the object
|
|
1671
|
-
*/
|
|
1672
|
-
async exists(uid) {
|
|
1673
|
-
if (typeof uid !== "string") {
|
|
1674
|
-
uid = uid.getUuid();
|
|
1675
|
-
}
|
|
1676
|
-
return this._exists(uid);
|
|
345
|
+
checkKeys() {
|
|
346
|
+
// TODO Implement
|
|
1677
347
|
}
|
|
1678
348
|
}
|
|
1679
|
-
__decorate([
|
|
1680
|
-
Route(".", ["POST"], {
|
|
1681
|
-
post: {
|
|
1682
|
-
description: "The way to create a new ${modelName} model",
|
|
1683
|
-
summary: "Create a new ${modelName}",
|
|
1684
|
-
operationId: "create${modelName}",
|
|
1685
|
-
requestBody: {
|
|
1686
|
-
content: {
|
|
1687
|
-
"application/json": {
|
|
1688
|
-
schema: {
|
|
1689
|
-
$ref: "#/components/schemas/${modelName}"
|
|
1690
|
-
}
|
|
1691
|
-
}
|
|
1692
|
-
}
|
|
1693
|
-
},
|
|
1694
|
-
responses: {
|
|
1695
|
-
"200": {
|
|
1696
|
-
description: "Retrieve model",
|
|
1697
|
-
content: {
|
|
1698
|
-
"application/json": {
|
|
1699
|
-
schema: {
|
|
1700
|
-
$ref: "#/components/schemas/${modelName}"
|
|
1701
|
-
}
|
|
1702
|
-
}
|
|
1703
|
-
}
|
|
1704
|
-
},
|
|
1705
|
-
"400": {
|
|
1706
|
-
description: "Object is invalid"
|
|
1707
|
-
},
|
|
1708
|
-
"403": {
|
|
1709
|
-
description: "You don't have permissions"
|
|
1710
|
-
},
|
|
1711
|
-
"409": {
|
|
1712
|
-
description: "Object already exists"
|
|
1713
|
-
}
|
|
1714
|
-
}
|
|
1715
|
-
}
|
|
1716
|
-
})
|
|
1717
|
-
], Store.prototype, "httpCreate", null);
|
|
1718
|
-
__decorate([
|
|
1719
|
-
Route("./{uuid}", ["PUT", "PATCH"], {
|
|
1720
|
-
put: {
|
|
1721
|
-
description: "Update a ${modelName} if the permissions allow",
|
|
1722
|
-
summary: "Update a ${modelName}",
|
|
1723
|
-
operationId: "update${modelName}",
|
|
1724
|
-
schemas: {
|
|
1725
|
-
input: "${modelName}",
|
|
1726
|
-
output: "${modelName}"
|
|
1727
|
-
},
|
|
1728
|
-
responses: {
|
|
1729
|
-
"200": {},
|
|
1730
|
-
"400": {
|
|
1731
|
-
description: "Object is invalid"
|
|
1732
|
-
},
|
|
1733
|
-
"403": {
|
|
1734
|
-
description: "You don't have permissions"
|
|
1735
|
-
},
|
|
1736
|
-
"404": {
|
|
1737
|
-
description: "Unknown object"
|
|
1738
|
-
}
|
|
1739
|
-
}
|
|
1740
|
-
},
|
|
1741
|
-
patch: {
|
|
1742
|
-
description: "Patch a ${modelName} if the permissions allow",
|
|
1743
|
-
summary: "Patch a ${modelName}",
|
|
1744
|
-
operationId: "partialUpdatet${modelName}",
|
|
1745
|
-
schemas: {
|
|
1746
|
-
input: "${modelName}"
|
|
1747
|
-
},
|
|
1748
|
-
responses: {
|
|
1749
|
-
"204": {
|
|
1750
|
-
description: ""
|
|
1751
|
-
},
|
|
1752
|
-
"400": {
|
|
1753
|
-
description: "Object is invalid"
|
|
1754
|
-
},
|
|
1755
|
-
"403": {
|
|
1756
|
-
description: "You don't have permissions"
|
|
1757
|
-
},
|
|
1758
|
-
"404": {
|
|
1759
|
-
description: "Unknown object"
|
|
1760
|
-
}
|
|
1761
|
-
}
|
|
1762
|
-
}
|
|
1763
|
-
})
|
|
1764
|
-
], Store.prototype, "httpUpdate", null);
|
|
1765
|
-
__decorate([
|
|
1766
|
-
Route("./{uuid}", ["GET"], {
|
|
1767
|
-
get: {
|
|
1768
|
-
description: "Retrieve ${modelName} model if permissions allow",
|
|
1769
|
-
summary: "Retrieve a ${modelName}",
|
|
1770
|
-
operationId: "get${modelName}",
|
|
1771
|
-
schemas: {
|
|
1772
|
-
output: "${modelName}"
|
|
1773
|
-
},
|
|
1774
|
-
responses: {
|
|
1775
|
-
"200": {},
|
|
1776
|
-
"400": {
|
|
1777
|
-
description: "Object is invalid"
|
|
1778
|
-
},
|
|
1779
|
-
"403": {
|
|
1780
|
-
description: "You don't have permissions"
|
|
1781
|
-
},
|
|
1782
|
-
"404": {
|
|
1783
|
-
description: "Unknown object"
|
|
1784
|
-
}
|
|
1785
|
-
}
|
|
1786
|
-
}
|
|
1787
|
-
})
|
|
1788
|
-
], Store.prototype, "httpGet", null);
|
|
1789
|
-
__decorate([
|
|
1790
|
-
Route("./{uuid}", ["DELETE"], {
|
|
1791
|
-
delete: {
|
|
1792
|
-
operationId: "delete${modelName}",
|
|
1793
|
-
description: "Delete ${modelName} if the permissions allow",
|
|
1794
|
-
summary: "Delete a ${modelName}",
|
|
1795
|
-
responses: {
|
|
1796
|
-
"204": {
|
|
1797
|
-
description: ""
|
|
1798
|
-
},
|
|
1799
|
-
"403": {
|
|
1800
|
-
description: "You don't have permissions"
|
|
1801
|
-
},
|
|
1802
|
-
"404": {
|
|
1803
|
-
description: "Unknown object"
|
|
1804
|
-
}
|
|
1805
|
-
}
|
|
1806
|
-
}
|
|
1807
|
-
})
|
|
1808
|
-
], Store.prototype, "httpDelete", null);
|
|
1809
349
|
export { Store };
|
|
1810
350
|
//# sourceMappingURL=store.js.map
|