diff --git a/common/changes/@boostercloud/framework-core/upgrade_nedb_seald_2023-07-28-14-42.json b/common/changes/@boostercloud/framework-core/upgrade_nedb_seald_2023-07-28-14-42.json new file mode 100644 index 000000000..1d1105f42 --- /dev/null +++ b/common/changes/@boostercloud/framework-core/upgrade_nedb_seald_2023-07-28-14-42.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@boostercloud/framework-core", + "comment": "replace nedb with seald", + "type": "minor" + } + ], + "packageName": "@boostercloud/framework-core" +} \ No newline at end of file diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 36f3ee19e..b66bf2407 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -8,8 +8,8 @@ importers: ../../packages/application-tester: specifiers: '@apollo/client': 3.7.13 - '@boostercloud/eslint-config': workspace:^2.7.0 - '@boostercloud/framework-types': workspace:^2.7.0 + '@boostercloud/eslint-config': workspace:^2.8.0 + '@boostercloud/framework-types': workspace:^2.8.0 '@effect-ts/core': ^0.60.4 '@types/jsonwebtoken': 9.0.1 '@types/node': ^18.18.2 @@ -70,10 +70,10 @@ importers: ../../packages/cli: specifiers: - '@boostercloud/application-tester': workspace:^2.7.0 - '@boostercloud/eslint-config': workspace:^2.7.0 - '@boostercloud/framework-core': workspace:^2.7.0 - '@boostercloud/framework-types': workspace:^2.7.0 + '@boostercloud/application-tester': workspace:^2.8.0 + '@boostercloud/eslint-config': workspace:^2.8.0 + '@boostercloud/framework-core': workspace:^2.8.0 + '@boostercloud/framework-types': workspace:^2.8.0 '@effect-ts/core': ^0.60.4 '@oclif/core': ^3.9.0 '@oclif/plugin-help': ^5 @@ -183,8 +183,8 @@ importers: ../../packages/framework-common-helpers: specifiers: - '@boostercloud/eslint-config': workspace:^2.7.0 - '@boostercloud/framework-types': workspace:^2.7.0 + '@boostercloud/eslint-config': workspace:^2.8.0 + '@boostercloud/framework-types': workspace:^2.8.0 '@effect-ts/core': ^0.60.4 '@types/chai': 4.2.18 '@types/chai-as-promised': 7.1.4 @@ -254,10 +254,10 @@ importers: ../../packages/framework-core: specifiers: - '@boostercloud/eslint-config': workspace:^2.7.0 - '@boostercloud/framework-common-helpers': workspace:^2.7.0 - '@boostercloud/framework-types': workspace:^2.7.0 - '@boostercloud/metadata-booster': workspace:^2.7.0 + '@boostercloud/eslint-config': workspace:^2.8.0 + '@boostercloud/framework-common-helpers': workspace:^2.8.0 + '@boostercloud/framework-types': workspace:^2.8.0 + '@boostercloud/metadata-booster': workspace:^2.8.0 '@effect/cli': ^0.35.2 '@effect/platform': ^0.48.3 '@effect/platform-node': ^0.45.5 @@ -374,19 +374,19 @@ importers: ../../packages/framework-integration-tests: specifiers: '@apollo/client': 3.7.13 - '@boostercloud/application-tester': workspace:^2.7.0 - '@boostercloud/cli': workspace:^2.7.0 - '@boostercloud/eslint-config': workspace:^2.7.0 - '@boostercloud/framework-common-helpers': workspace:^2.7.0 - '@boostercloud/framework-core': workspace:^2.7.0 - '@boostercloud/framework-provider-aws': workspace:^2.7.0 - '@boostercloud/framework-provider-aws-infrastructure': workspace:^2.7.0 - '@boostercloud/framework-provider-azure': workspace:^2.7.0 - '@boostercloud/framework-provider-azure-infrastructure': workspace:^2.7.0 - '@boostercloud/framework-provider-local': workspace:^2.7.0 - '@boostercloud/framework-provider-local-infrastructure': workspace:^2.7.0 - '@boostercloud/framework-types': workspace:^2.7.0 - '@boostercloud/metadata-booster': workspace:^2.7.0 + '@boostercloud/application-tester': workspace:^2.8.0 + '@boostercloud/cli': workspace:^2.8.0 + '@boostercloud/eslint-config': workspace:^2.8.0 + '@boostercloud/framework-common-helpers': workspace:^2.8.0 + '@boostercloud/framework-core': workspace:^2.8.0 + '@boostercloud/framework-provider-aws': workspace:^2.8.0 + '@boostercloud/framework-provider-aws-infrastructure': workspace:^2.8.0 + '@boostercloud/framework-provider-azure': workspace:^2.8.0 + '@boostercloud/framework-provider-azure-infrastructure': workspace:^2.8.0 + '@boostercloud/framework-provider-local': workspace:^2.8.0 + '@boostercloud/framework-provider-local-infrastructure': workspace:^2.8.0 + '@boostercloud/framework-types': workspace:^2.8.0 + '@boostercloud/metadata-booster': workspace:^2.8.0 '@effect-ts/core': ^0.60.4 '@effect/cli': ^0.35.2 '@effect/platform': ^0.48.3 @@ -395,6 +395,7 @@ importers: '@effect/printer-ansi': ^0.32.13 '@effect/schema': ^0.64.2 '@effect/typeclass': ^0.23.4 + '@seald-io/nedb': 4.0.2 '@types/aws-lambda': 8.10.48 '@types/chai': 4.2.18 '@types/chai-arrays': 2.0.0 @@ -423,6 +424,7 @@ importers: eslint-plugin-import: ^2.26.0 eslint-plugin-prettier: 3.4.0 eslint-plugin-unicorn: ~44.0.2 + express: ^4.17.1 express-unless: 2.1.3 faker: 5.1.0 fast-check: ^3.13.2 @@ -433,7 +435,6 @@ importers: jwks-rsa: 3.0.1 mocha: 10.2.0 mocha-skip-if: 0.0.3 - nedb: ^1.8.0 nyc: ^15.1.0 prettier: 2.3.0 react: ^17.0.0 @@ -465,6 +466,7 @@ importers: '@effect/typeclass': 0.23.4_effect@2.4.6 aws-sdk: 2.853.0 effect: 2.4.6 + express: 4.18.2 express-unless: 2.1.3 fast-check: 3.15.1 graphql: 16.8.1 @@ -479,6 +481,7 @@ importers: '@boostercloud/framework-provider-azure-infrastructure': link:../framework-provider-azure-infrastructure '@boostercloud/framework-provider-local-infrastructure': link:../framework-provider-local-infrastructure '@boostercloud/metadata-booster': link:../metadata-booster + '@seald-io/nedb': 4.0.2 '@types/aws-lambda': 8.10.48 '@types/chai': 4.2.18 '@types/chai-arrays': 2.0.0 @@ -512,7 +515,6 @@ importers: jwks-rsa: 3.0.1 mocha: 10.2.0 mocha-skip-if: 0.0.3 - nedb: 1.8.0 nyc: 15.1.0 prettier: 2.3.0 react: 17.0.2 @@ -528,9 +530,9 @@ importers: ../../packages/framework-provider-aws: specifiers: - '@boostercloud/eslint-config': workspace:^2.7.0 - '@boostercloud/framework-common-helpers': workspace:^2.7.0 - '@boostercloud/framework-types': workspace:^2.7.0 + '@boostercloud/eslint-config': workspace:^2.8.0 + '@boostercloud/framework-common-helpers': workspace:^2.8.0 + '@boostercloud/framework-types': workspace:^2.8.0 '@effect-ts/core': ^0.60.4 '@types/aws-lambda': 8.10.48 '@types/chai': 4.2.18 @@ -624,10 +626,10 @@ importers: '@aws-cdk/core': ^1.170.0 '@aws-cdk/custom-resources': ^1.170.0 '@aws-cdk/cx-api': ^1.170.0 - '@boostercloud/eslint-config': workspace:^2.7.0 - '@boostercloud/framework-common-helpers': workspace:^2.7.0 - '@boostercloud/framework-provider-aws': workspace:^2.7.0 - '@boostercloud/framework-types': workspace:^2.7.0 + '@boostercloud/eslint-config': workspace:^2.8.0 + '@boostercloud/framework-common-helpers': workspace:^2.8.0 + '@boostercloud/framework-provider-aws': workspace:^2.8.0 + '@boostercloud/framework-types': workspace:^2.8.0 '@effect-ts/core': ^0.60.4 '@types/archiver': 5.1.0 '@types/aws-lambda': 8.10.48 @@ -741,9 +743,9 @@ importers: '@azure/functions': ^1.2.2 '@azure/identity': ~2.1.0 '@azure/web-pubsub': ~1.1.0 - '@boostercloud/eslint-config': workspace:^2.7.0 - '@boostercloud/framework-common-helpers': workspace:^2.7.0 - '@boostercloud/framework-types': workspace:^2.7.0 + '@boostercloud/eslint-config': workspace:^2.8.0 + '@boostercloud/framework-common-helpers': workspace:^2.8.0 + '@boostercloud/framework-types': workspace:^2.8.0 '@effect-ts/core': ^0.60.4 '@types/chai': 4.2.18 '@types/chai-as-promised': 7.1.4 @@ -815,11 +817,11 @@ importers: '@azure/arm-resources': ^5.0.1 '@azure/cosmos': ^4.0.0 '@azure/identity': ~2.1.0 - '@boostercloud/eslint-config': workspace:^2.7.0 - '@boostercloud/framework-common-helpers': workspace:^2.7.0 - '@boostercloud/framework-core': workspace:^2.7.0 - '@boostercloud/framework-provider-azure': workspace:^2.7.0 - '@boostercloud/framework-types': workspace:^2.7.0 + '@boostercloud/eslint-config': workspace:^2.8.0 + '@boostercloud/framework-common-helpers': workspace:^2.8.0 + '@boostercloud/framework-core': workspace:^2.8.0 + '@boostercloud/framework-provider-azure': workspace:^2.8.0 + '@boostercloud/framework-types': workspace:^2.8.0 '@cdktf/provider-azurerm': 11.2.0 '@cdktf/provider-time': 9.0.2 '@effect-ts/core': ^0.60.4 @@ -926,16 +928,16 @@ importers: ../../packages/framework-provider-local: specifiers: - '@boostercloud/eslint-config': workspace:^2.7.0 - '@boostercloud/framework-common-helpers': workspace:^2.7.0 - '@boostercloud/framework-types': workspace:^2.7.0 + '@boostercloud/eslint-config': workspace:^2.8.0 + '@boostercloud/framework-common-helpers': workspace:^2.8.0 + '@boostercloud/framework-types': workspace:^2.8.0 '@effect-ts/core': ^0.60.4 + '@seald-io/nedb': 4.0.2 '@types/chai': 4.2.18 '@types/chai-as-promised': 7.1.4 '@types/express': ^4.17.13 '@types/faker': 5.1.5 '@types/mocha': 10.0.1 - '@types/nedb': ^1.8.12 '@types/node': ^18.18.2 '@types/sinon': 10.0.0 '@types/sinon-chai': 3.2.5 @@ -953,7 +955,6 @@ importers: express: ^4.17.1 faker: 5.1.0 mocha: 10.2.0 - nedb: ^1.8.0 nyc: ^15.1.0 prettier: 2.3.0 rimraf: ^5.0.0 @@ -968,8 +969,7 @@ importers: '@boostercloud/framework-common-helpers': link:../framework-common-helpers '@boostercloud/framework-types': link:../framework-types '@effect-ts/core': 0.60.5 - '@types/nedb': 1.8.16 - nedb: 1.8.0 + '@seald-io/nedb': 4.0.2 tslib: 2.6.2 ws: 8.12.0 devDependencies: @@ -1007,10 +1007,10 @@ importers: ../../packages/framework-provider-local-infrastructure: specifiers: - '@boostercloud/eslint-config': workspace:^2.7.0 - '@boostercloud/framework-common-helpers': workspace:^2.7.0 - '@boostercloud/framework-provider-local': workspace:^2.7.0 - '@boostercloud/framework-types': workspace:^2.7.0 + '@boostercloud/eslint-config': workspace:^2.8.0 + '@boostercloud/framework-common-helpers': workspace:^2.8.0 + '@boostercloud/framework-provider-local': workspace:^2.8.0 + '@boostercloud/framework-types': workspace:^2.8.0 '@effect-ts/core': ^0.60.4 '@types/chai': 4.2.18 '@types/chai-as-promised': 7.1.4 @@ -1090,8 +1090,8 @@ importers: ../../packages/framework-types: specifiers: - '@boostercloud/eslint-config': workspace:^2.7.0 - '@boostercloud/metadata-booster': workspace:^2.7.0 + '@boostercloud/eslint-config': workspace:^2.8.0 + '@boostercloud/metadata-booster': workspace:^2.8.0 '@effect-ts/core': ^0.60.4 '@effect-ts/node': ~0.39.0 '@effect/cli': ^0.35.2 @@ -1175,7 +1175,7 @@ importers: ../../packages/metadata-booster: specifiers: - '@boostercloud/eslint-config': workspace:^2.7.0 + '@boostercloud/eslint-config': workspace:^2.8.0 '@effect-ts/core': ^0.60.4 '@types/node': ^18.18.2 '@typescript-eslint/eslint-plugin': ^5.0.0 @@ -1386,7 +1386,7 @@ packages: '@aws-cdk/aws-cloudwatch': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm '@aws-cdk/aws-cognito': 1.204.0_jhanj7vnhseo3o4cwsyzgiowqa '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a - '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_duidta2ijoio5sg5x7jqysldja + '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_xbmlyikxd4zabyotfrt4oo4gli '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-lambda': 1.204.0_afnjft5qr3fswieaeg3dwwhnvm '@aws-cdk/aws-logs': 1.204.0_l4ztnfmrjykhsbk6ow7yhidayu @@ -1516,7 +1516,7 @@ packages: '@aws-cdk/aws-cloudwatch': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a '@aws-cdk/aws-elasticloadbalancing': 1.204.0_s2iwowsvskkmujjbrmx4g5hlsi - '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_duidta2ijoio5sg5x7jqysldja + '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_xbmlyikxd4zabyotfrt4oo4gli '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-sns': 1.204.0_bi2u42js5xhxqcsg5gqefde4xi '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam @@ -1929,17 +1929,17 @@ packages: '@aws-cdk/aws-ecr': 1.204.0_4bnk2gpayjo75fecjckge2dkni '@aws-cdk/aws-ecr-assets': 1.204.0_scjupxxta56mdpzkdveav52ufq '@aws-cdk/aws-elasticloadbalancing': 1.204.0_s2iwowsvskkmujjbrmx4g5hlsi - '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_duidta2ijoio5sg5x7jqysldja + '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_xbmlyikxd4zabyotfrt4oo4gli '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-kms': 1.204.0_cttdkzy7hngahjug7jmkfylr2y '@aws-cdk/aws-lambda': 1.204.0_afnjft5qr3fswieaeg3dwwhnvm '@aws-cdk/aws-logs': 1.204.0_l4ztnfmrjykhsbk6ow7yhidayu '@aws-cdk/aws-route53': 1.204.0_i3vim6rlintxrbha4iep76yf5u - '@aws-cdk/aws-route53-targets': 1.204.0_yvzacxtkufuieelzdl2p47lu74 + '@aws-cdk/aws-route53-targets': 1.204.0_2eviprr3zwoouaslbumtdekrhi '@aws-cdk/aws-s3': 1.204.0_bi2u42js5xhxqcsg5gqefde4xi '@aws-cdk/aws-s3-assets': 1.204.0_l4ztnfmrjykhsbk6ow7yhidayu '@aws-cdk/aws-secretsmanager': 1.204.0_336juigttbrwz7tyvm6a6wfpy4 - '@aws-cdk/aws-servicediscovery': 1.204.0_duidta2ijoio5sg5x7jqysldja + '@aws-cdk/aws-servicediscovery': 1.204.0_nu23nesxfni464wb5cy4ehgagi '@aws-cdk/aws-sns': 1.204.0_bi2u42js5xhxqcsg5gqefde4xi '@aws-cdk/aws-sqs': 1.204.0_cttdkzy7hngahjug7jmkfylr2y '@aws-cdk/aws-ssm': 1.204.0_cttdkzy7hngahjug7jmkfylr2y @@ -2000,7 +2000,7 @@ packages: constructs: 3.4.344 dev: false - /@aws-cdk/aws-elasticloadbalancingv2/1.204.0_duidta2ijoio5sg5x7jqysldja: + /@aws-cdk/aws-elasticloadbalancingv2/1.204.0_xbmlyikxd4zabyotfrt4oo4gli: resolution: {integrity: sha512-/43kzUTU3w9jimPuD5QZxoBN74+9QnOdhAcqIMVCFLPMkVLAxx3vg5g5MWWG+3j6rUoSecrtrP1AP7thZuo5wA==} engines: {node: '>= 14.15.0'} deprecated: |- @@ -2018,6 +2018,7 @@ packages: dependencies: '@aws-cdk/aws-certificatemanager': 1.204.0_xtqk4litqxecxsqs3sd6ajo2ja '@aws-cdk/aws-cloudwatch': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm + '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-lambda': 1.204.0_afnjft5qr3fswieaeg3dwwhnvm '@aws-cdk/aws-route53': 1.204.0_i3vim6rlintxrbha4iep76yf5u @@ -2028,7 +2029,7 @@ packages: '@aws-cdk/region-info': 1.204.0 constructs: 3.4.344 transitivePeerDependencies: - - '@aws-cdk/aws-ec2' + - '@aws-cdk/assets' - '@aws-cdk/aws-logs' - '@aws-cdk/custom-resources' dev: false @@ -2317,7 +2318,7 @@ packages: - '@aws-cdk/aws-s3' dev: false - /@aws-cdk/aws-route53-targets/1.204.0_yvzacxtkufuieelzdl2p47lu74: + /@aws-cdk/aws-route53-targets/1.204.0_2eviprr3zwoouaslbumtdekrhi: resolution: {integrity: sha512-JyILJz/HGRMilpFxrDk/VXv+TN24DoG5Gfdfh8SJoJpptokowN8blaQ2ibf6N0JnFqWSBrs7gMMWB2dR/sXoTQ==} engines: {node: '>= 14.15.0'} deprecated: |- @@ -2339,7 +2340,7 @@ packages: '@aws-cdk/aws-cognito': 1.204.0_jhanj7vnhseo3o4cwsyzgiowqa '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a '@aws-cdk/aws-elasticloadbalancing': 1.204.0_s2iwowsvskkmujjbrmx4g5hlsi - '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_duidta2ijoio5sg5x7jqysldja + '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_xbmlyikxd4zabyotfrt4oo4gli '@aws-cdk/aws-globalaccelerator': 1.204.0_u3bt2hwm6nh6yzg6d6qalghehq '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-route53': 1.204.0_i3vim6rlintxrbha4iep76yf5u @@ -2348,6 +2349,7 @@ packages: '@aws-cdk/region-info': 1.204.0 constructs: 3.4.344 transitivePeerDependencies: + - '@aws-cdk/assets' - '@aws-cdk/aws-lambda' - '@aws-cdk/aws-logs' - '@aws-cdk/custom-resources' @@ -2530,7 +2532,7 @@ packages: constructs: 3.4.344 dev: false - /@aws-cdk/aws-servicediscovery/1.204.0_duidta2ijoio5sg5x7jqysldja: + /@aws-cdk/aws-servicediscovery/1.204.0_nu23nesxfni464wb5cy4ehgagi: resolution: {integrity: sha512-K1ckza6oAj3DntEAYmolm2JafkxJ0ekWb+DCl9hkm9l+546j28Qpb4cm8VkgGteNBN4JYACxrIuIxVC2zBLsCg==} engines: {node: '>= 14.15.0'} deprecated: |- @@ -2544,11 +2546,12 @@ packages: constructs: ^3.3.69 dependencies: '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a - '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_duidta2ijoio5sg5x7jqysldja + '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_xbmlyikxd4zabyotfrt4oo4gli '@aws-cdk/aws-route53': 1.204.0_i3vim6rlintxrbha4iep76yf5u '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam constructs: 3.4.344 transitivePeerDependencies: + - '@aws-cdk/assets' - '@aws-cdk/aws-iam' - '@aws-cdk/aws-lambda' - '@aws-cdk/aws-logs' @@ -3977,6 +3980,16 @@ packages: requiresBuild: true optional: true + /@seald-io/binary-search-tree/1.0.3: + resolution: {integrity: sha512-qv3jnwoakeax2razYaMsGI/luWdliBLHTdC6jU55hQt1hcFqzauH/HsBollQ7IR4ySTtYhT+xyHoijpA16C+tA==} + + /@seald-io/nedb/4.0.2: + resolution: {integrity: sha512-gJ91fT1sgh2cLXYVcTSh7khZ8LdemI8+SojCdpZ5wy+DUQ4fSrEwGqOwbdV49NDs2BBO6GeBpSb8CnhG2IW1rw==} + dependencies: + '@seald-io/binary-search-tree': 1.0.3 + localforage: 1.10.0 + util: 0.12.5 + /@sentry-internal/tracing/7.90.0: resolution: {integrity: sha512-74jEtpdio9aRkiVBcrY1ZJXek0oFMqxDJK6BkJNCA+aUK1z96V9viehANRk3Nbxm01rWjmH1U4e1siuo9FhjuQ==} engines: {node: '>=8'} @@ -4385,6 +4398,7 @@ packages: resolution: {integrity: sha512-ND+uzwAZk7ZI9byOvHGOcZe2R9XUcLF698yDJKn00trFvh+GaemkX3gQKCSKtObjDpv8Uuou+k8v4x4scPr4TA==} dependencies: '@types/node': 18.19.3 + dev: true /@types/needle/2.5.3: resolution: {integrity: sha512-RwgTwMRaedfyCBe5SSWMpm1Yqzc5UPZEMw0eAd09OSyV93nLRj9/evMGZmgFeHKzUOd4xxtHvgtc+rjcBjI1Qg==} @@ -4967,9 +4981,6 @@ packages: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} - /async/0.2.10: - resolution: {integrity: sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==} - /async/3.2.5: resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} @@ -5054,11 +5065,6 @@ packages: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} - /binary-search-tree/0.2.5: - resolution: {integrity: sha512-CvNVKS6iXagL1uGwLagSXz1hzSMezxOuGnFi5FHGKqaTO3nPPWrAbyALUzK640j+xOTVm7lzD9YP8W1f/gvUdw==} - dependencies: - underscore: 1.4.4 - /bl/1.2.3: resolution: {integrity: sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==} dependencies: @@ -6116,7 +6122,7 @@ packages: dependencies: semver: 7.5.4 shelljs: 0.8.5 - typescript: 5.5.0-dev.20240314 + typescript: 5.5.0-dev.20240321 /duration/0.2.2: resolution: {integrity: sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg==} @@ -8852,6 +8858,7 @@ packages: hasBin: true dependencies: minimist: 1.2.8 + dev: true /mkdirp/1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} @@ -8983,15 +8990,6 @@ packages: resolution: {integrity: sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==} hasBin: true - /nedb/1.8.0: - resolution: {integrity: sha512-ip7BJdyb5m+86ZbSb4y10FCCW9g35+U8bDRrZlAfCI6m4dKwEsQ5M52grcDcVK4Vm/vnPlDLywkyo3GliEkb5A==} - dependencies: - async: 0.2.10 - binary-search-tree: 0.2.5 - localforage: 1.10.0 - mkdirp: 0.5.6 - underscore: 1.4.4 - /needle/2.9.1: resolution: {integrity: sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==} engines: {node: '>= 4.4.x'} @@ -11199,8 +11197,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - /typescript/5.5.0-dev.20240314: - resolution: {integrity: sha512-8yyAVbLSgGrydN7CZWeP+GZ5zkEBh45r0LswVPgxNDjBuDx9VuKtp+ws+Ri122iwfy8vGr5b486IjeeVM49Crw==} + /typescript/5.5.0-dev.20240321: + resolution: {integrity: sha512-QEUqMB18VAUQBHtHlq8BfjxGZzFkavH5fhZn+I97N67mDZTa86n1S8kiRKmrbxVwPAdvn3DYtJzcGq5OvdWkmQ==} engines: {node: '>=14.17'} hasBin: true @@ -11219,9 +11217,6 @@ packages: through: 2.3.8 dev: true - /underscore/1.4.4: - resolution: {integrity: sha512-ZqGrAgaqqZM7LGRzNjLnw5elevWb5M8LEoDMadxIW3OWbcv72wMMgKdwOKpd5Fqxe8choLD8HN3iSj3TUh/giQ==} - /undici-types/5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} diff --git a/packages/framework-integration-tests/integration/provider-specific/local/commands.integration.ts b/packages/framework-integration-tests/integration/provider-specific/local/commands.integration.ts index 15ddbeda1..16048be4c 100644 --- a/packages/framework-integration-tests/integration/provider-specific/local/commands.integration.ts +++ b/packages/framework-integration-tests/integration/provider-specific/local/commands.integration.ts @@ -2,19 +2,19 @@ import { ApolloClient, NormalizedCacheObject } from '@apollo/client' import { changeCartItem, graphQLClient } from './utils' import { random } from 'faker' import { expect } from 'chai' -import * as DataStore from 'nedb' +import Datastore from '@seald-io/nedb' import { sandboxPath } from './constants' import * as util from 'util' import * as path from 'path' import { waitForIt } from '../../helper/sleep' describe('commands', () => { - let events: DataStore + let events: Datastore let client: ApolloClient before(async () => { - events = new DataStore(path.join(sandboxPath, '.booster', 'events.json')) + events = new Datastore(path.join(sandboxPath, '.booster', 'events.json')) client = await graphQLClient() }) diff --git a/packages/framework-integration-tests/integration/provider-specific/local/read-models.integration.ts b/packages/framework-integration-tests/integration/provider-specific/local/read-models.integration.ts index 0655a06ae..5837c6569 100644 --- a/packages/framework-integration-tests/integration/provider-specific/local/read-models.integration.ts +++ b/packages/framework-integration-tests/integration/provider-specific/local/read-models.integration.ts @@ -2,18 +2,18 @@ import { ApolloClient, NormalizedCacheObject } from '@apollo/client' import { changeCartItem, graphQLClient } from './utils' import { random } from 'faker' import { expect } from 'chai' -import * as DataStore from 'nedb' +import Datastore from '@seald-io/nedb' import { sandboxPath } from './constants' import * as path from 'path' import { waitForIt } from '../../helper/sleep' describe('read-models', () => { - let readModels: DataStore + let readModels: Datastore let client: ApolloClient before(async () => { - readModels = new DataStore(path.join(sandboxPath, '.booster', 'read_models.json')) + readModels = new Datastore(path.join(sandboxPath, '.booster', 'read_models.json')) client = await graphQLClient() }) diff --git a/packages/framework-integration-tests/integration/provider-specific/local/start/setup.ts b/packages/framework-integration-tests/integration/provider-specific/local/start/setup.ts index d737347ad..e39fba167 100644 --- a/packages/framework-integration-tests/integration/provider-specific/local/start/setup.ts +++ b/packages/framework-integration-tests/integration/provider-specific/local/start/setup.ts @@ -27,6 +27,6 @@ before(async () => { throw new Error('Pid not found') } storePIDFor(sandboxPath, serverProcess.pid) //store pid to kill process on stop - await sleep(2000) + await sleep(10000) console.log('local server ready') }) diff --git a/packages/framework-integration-tests/integration/provider-unaware/end-to-end/commands.integration.ts b/packages/framework-integration-tests/integration/provider-unaware/end-to-end/commands.integration.ts index 4fbb2dd29..ecfe4d5fe 100644 --- a/packages/framework-integration-tests/integration/provider-unaware/end-to-end/commands.integration.ts +++ b/packages/framework-integration-tests/integration/provider-unaware/end-to-end/commands.integration.ts @@ -1,6 +1,6 @@ import { ApolloClient, NormalizedCacheObject, gql } from '@apollo/client' import { commerce, finance, random } from 'faker' -import { expect } from 'chai' +import { expect } from '../../helper/expect' import { applicationUnderTest } from './setup' describe('Commands end-to-end tests', () => { diff --git a/packages/framework-integration-tests/integration/provider-unaware/end-to-end/entities.integration.ts b/packages/framework-integration-tests/integration/provider-unaware/end-to-end/entities.integration.ts index f9c76b6bc..3c765df62 100644 --- a/packages/framework-integration-tests/integration/provider-unaware/end-to-end/entities.integration.ts +++ b/packages/framework-integration-tests/integration/provider-unaware/end-to-end/entities.integration.ts @@ -1,14 +1,12 @@ import { ApolloClient, NormalizedCacheObject, gql } from '@apollo/client' import { random, commerce, finance, lorem, internet } from 'faker' import { expect } from 'chai' -import { sleep, waitForIt } from '../../helper/sleep' +import { waitForIt } from '../../helper/sleep' import { applicationUnderTest } from './setup' import { UUID } from '@boostercloud/framework-types' import { NEW_CART_IDS, QUANTITY_AFTER_DATA_MIGRATION_V2, QUANTITY_TO_MIGRATE_DATA } from '../../../src/constants' import { ProductType } from '../../../src/entities/product' -const secs = 10 - describe('Entities end-to-end tests', () => { let client: ApolloClient let userToken: string @@ -147,9 +145,6 @@ describe('Entities end-to-end tests', () => { `, }) - console.log(`Waiting ${secs} second${secs > 1 ? 's' : ''} for deletion to complete...`) - await sleep(secs * 1000) - client = applicationUnderTest.graphql.client(userToken) // Retrieve updated entity const queryResult = await waitForIt( @@ -178,7 +173,7 @@ describe('Entities end-to-end tests', () => { `, }) }, - () => true + (result) => !result?.data?.ProductReadModel ) const productData = queryResult.data.ProductReadModel @@ -331,10 +326,9 @@ describe('Entities end-to-end tests', () => { }) }, (result) => { - const resultReadModels = result?.data?.ListDataMigrationsReadModels - const count = resultReadModels?.count + const count = result?.data?.ListDataMigrationsReadModels?.count if (count < 2) { - return `Waiting for at least 2 migrations. Done ${count} migrations. ${JSON.stringify(resultReadModels)}` + return `Waiting for ${count} migrations. Done ${count} migrations` } return true } diff --git a/packages/framework-integration-tests/integration/provider-unaware/end-to-end/read-models.integration.ts b/packages/framework-integration-tests/integration/provider-unaware/end-to-end/read-models.integration.ts index 13df283e6..7ec8c5829 100644 --- a/packages/framework-integration-tests/integration/provider-unaware/end-to-end/read-models.integration.ts +++ b/packages/framework-integration-tests/integration/provider-unaware/end-to-end/read-models.integration.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ import { ApolloClient, NormalizedCacheObject, gql } from '@apollo/client' import { commerce, finance, internet, lorem, random } from 'faker' -import { expect } from 'chai' +import { expect } from '../../helper/expect' import { waitForIt } from '../../helper/sleep' import { CartItem } from '../../../src/common/cart-item' import { applicationUnderTest } from './setup' @@ -179,12 +179,7 @@ describe('Read models end-to-end tests', () => { await Promise.all(changeCartPromises) }) - // TODO this test is failing in local because of local provider doesn't provides optimistic concurrency control - // TODO Remove condition when it will be fixed it('should retrieve expected cart', async () => { - if (process.env.TESTED_PROVIDER === 'LOCAL') { - return - } const queryResult = await waitForIt( () => { return client.query({ diff --git a/packages/framework-integration-tests/integration/provider-unaware/end-to-end/subscriptions.integration.ts b/packages/framework-integration-tests/integration/provider-unaware/functionality/subscriptions.integration.ts similarity index 99% rename from packages/framework-integration-tests/integration/provider-unaware/end-to-end/subscriptions.integration.ts rename to packages/framework-integration-tests/integration/provider-unaware/functionality/subscriptions.integration.ts index 92508833d..fc6915b97 100644 --- a/packages/framework-integration-tests/integration/provider-unaware/end-to-end/subscriptions.integration.ts +++ b/packages/framework-integration-tests/integration/provider-unaware/functionality/subscriptions.integration.ts @@ -257,7 +257,7 @@ describe('subscriptions', () => { }) }) }) - + context('with a user without the required role', () => { let loggedClient: DisconnectableApolloClient diff --git a/packages/framework-integration-tests/package.json b/packages/framework-integration-tests/package.json index 01cd8a281..8309c991e 100644 --- a/packages/framework-integration-tests/package.json +++ b/packages/framework-integration-tests/package.json @@ -20,6 +20,7 @@ "tslib": "^2.4.0", "@effect-ts/core": "^0.60.4", "express-unless": "2.1.3", + "express": "^4.17.1", "effect": "^2.4.6", "@effect/platform": "^0.48.3", "@effect/schema": "^0.64.2", @@ -73,7 +74,7 @@ "jwks-rsa": "3.0.1", "mocha": "10.2.0", "mocha-skip-if": "0.0.3", - "nedb": "^1.8.0", + "@seald-io/nedb": "4.0.2", "nyc": "^15.1.0", "prettier": "2.3.0", "rimraf": "^5.0.0", @@ -110,7 +111,7 @@ "integration/aws-end-to-end": "echo 'Skipping integration tests.' # TODO 'Enable it again when AWS Provider will be upgrade it' TS_NODE_PROJECT=\"./tsconfig.integration.json\" TESTED_PROVIDER=AWS AWS_SDK_LOAD_CONFIG=true BOOSTER_ENV=production mocha --forbid-only --exit --config \"integration/provider-unaware/end-to-end/.mocharc.yml\" \"integration/provider-unaware/end-to-end/**/*.integration.ts\"", "integration/aws-load": "echo 'Skipping integration tests.' # TS_NODE_PROJECT=\"./tsconfig.integration.json\" TESTED_PROVIDER=AWS AWS_SDK_LOAD_CONFIG=true BOOSTER_ENV=production mocha --forbid-only --exit --config \"integration/provider-unaware/load/.mocharc.yml\" \"integration/provider-unaware/load/**/*.load.ts\"", "integration/aws-nuke": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" AWS_SDK_LOAD_CONFIG=true BOOSTER_ENV=production mocha --forbid-only --exit --config \"integration/provider-specific/aws/nuke/.mocharc.yml\" \"integration/provider-specific/aws/nuke/**/*.integration.ts\"", - "integration/local": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" BOOSTER_ENV=local mocha --forbid-only --exit --config \"integration/provider-specific/local/.mocharc.yml\" \"integration/provider-specific/local/**/*.integration.ts\"", + "integration/local": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" npm run integration/local-start && npm run integration/local-end-to-end && npm run integration/local-stop", "integration/local-ongoing": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" npm run integration/local-start && npm run integration/local-stop", "integration/local-start": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" BOOSTER_ENV=local mocha --forbid-only --exit --config \"integration/provider-specific/local/start/.mocharc.yml\" \"integration/provider-specific/local/start/*.integration.ts\"", "integration/local-func": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" TESTED_PROVIDER=LOCAL BOOSTER_ENV=local mocha --forbid-only --exit --config \"integration/provider-unaware/functionality/.mocharc.yml\" \"integration/provider-unaware/functionality/**/*.integration.ts\"", diff --git a/packages/framework-provider-local/package.json b/packages/framework-provider-local/package.json index a60eee975..a5572e446 100644 --- a/packages/framework-provider-local/package.json +++ b/packages/framework-provider-local/package.json @@ -25,8 +25,7 @@ "dependencies": { "@boostercloud/framework-common-helpers": "workspace:^2.8.0", "@boostercloud/framework-types": "workspace:^2.8.0", - "@types/nedb": "^1.8.12", - "nedb": "^1.8.0", + "@seald-io/nedb": "4.0.2", "tslib": "^2.4.0", "@effect-ts/core": "^0.60.4", "ws": "8.12.0" diff --git a/packages/framework-provider-local/src/library/health-adapter.ts b/packages/framework-provider-local/src/library/health-adapter.ts index 7005bb51c..8cdfcfdfd 100644 --- a/packages/framework-provider-local/src/library/health-adapter.ts +++ b/packages/framework-provider-local/src/library/health-adapter.ts @@ -1,22 +1,17 @@ -import * as DataStore from 'nedb' import { EventRegistry, ReadModelRegistry } from '../services' import { eventsDatabase, readModelsDatabase } from '../paths' import { boosterLocalPort, HealthEnvelope, UUID } from '@boostercloud/framework-types' import { existsSync } from 'fs' import * as express from 'express' import { request } from '@boostercloud/framework-common-helpers' +import Nedb from '@seald-io/nedb' export async function databaseUrl(): Promise> { return [eventsDatabase, readModelsDatabase] } -export async function countAll(database: DataStore): Promise { - const count = await new Promise((resolve, reject) => { - database.count({}, (err, docs) => { - if (err) reject(err) - else resolve(docs) - }) - }) +export async function countAll(database: Nedb): Promise { + const count = await database.countAsync({}) return count ?? 0 } diff --git a/packages/framework-provider-local/src/services/event-registry.ts b/packages/framework-provider-local/src/services/event-registry.ts index 9da556e7f..0a3f9f3e9 100644 --- a/packages/framework-provider-local/src/services/event-registry.ts +++ b/packages/framework-provider-local/src/services/event-registry.ts @@ -1,16 +1,26 @@ /* eslint-disable @typescript-eslint/ban-types */ import { EntitySnapshotEnvelope, EventEnvelope, EventStoreEntryEnvelope } from '@boostercloud/framework-types' -import * as DataStore from 'nedb' import { eventsDatabase } from '../paths' +const DataStore = require('@seald-io/nedb') export class EventRegistry { - public readonly events: DataStore = new DataStore(eventsDatabase) + public readonly events + public isLoaded = false + constructor() { - this.events.loadDatabase() + this.events = new DataStore({ filename: eventsDatabase }) + } + + async loadDatabaseIfNeeded(): Promise { + if (!this.isLoaded) { + this.isLoaded = true + await this.events.loadDatabaseAsync() + } } getCursor(query: object, createdAt = 1, projections?: unknown) { - return this.events.find(query, projections).sort({ createdAt: createdAt }) + const cursor = this.events.findAsync(query, projections) + return cursor.sort({ createdAt: createdAt }) } public async query( @@ -19,31 +29,18 @@ export class EventRegistry { limit?: number, projections?: unknown ): Promise { - const cursor = this.getCursor(query, createdAt, projections) + await this.loadDatabaseIfNeeded() + let cursor = this.getCursor(query, createdAt, projections) if (limit) { - cursor.limit(Number(limit)) + cursor = cursor.limit(Number(limit)) } - const queryPromise = await new Promise((resolve, reject) => { - cursor.exec((err, docs) => { - if (err) reject(err) - else resolve(docs) - }) - }) - - return queryPromise + return await cursor.execAsync() } public async queryLatestSnapshot(query: object): Promise { - const results = await new Promise((resolve, reject) => - this.events - .find({ ...query, kind: 'snapshot' }) - .sort({ snapshottedEventCreatedAt: -1 }) // Sort in descending order (newer timestamps first) - .exec((err, docs) => { - if (err) reject(err) - else resolve(docs) - }) - ) - + await this.loadDatabaseIfNeeded() + const cursor = this.events.findAsync({ ...query, kind: 'snapshot' }).sort({ snapshottedEventCreatedAt: -1 }) // Sort in descending order (newer timestamps first) + const results = await cursor.execAsync() if (results.length <= 0) { return undefined } @@ -51,21 +48,17 @@ export class EventRegistry { } public async store(storableObject: EventEnvelope | EntitySnapshotEnvelope): Promise { - return new Promise((resolve, reject) => { - this.events.insert(storableObject, (err) => { - err ? reject(err) : resolve() - }) - }) + await this.loadDatabaseIfNeeded() + await this.events.insertAsync(storableObject) } public async deleteAll(): Promise { - const deletePromise = new Promise((resolve, reject) => - this.events.remove({}, { multi: true }, (err, numRemoved: number) => { - if (err) reject(err) - else resolve(numRemoved) - }) - ) + await this.loadDatabaseIfNeeded() + return await this.events.removeAsync({}, { multi: true }) + } - return (await deletePromise) as number + public async count(query?: object): Promise { + await this.loadDatabaseIfNeeded() + return await this.events.countAsync(query) } } diff --git a/packages/framework-provider-local/src/services/read-model-registry.ts b/packages/framework-provider-local/src/services/read-model-registry.ts index a461cb3f2..3da531d1d 100644 --- a/packages/framework-provider-local/src/services/read-model-registry.ts +++ b/packages/framework-provider-local/src/services/read-model-registry.ts @@ -1,6 +1,6 @@ import { ReadModelEnvelope, SortFor, UUID } from '@boostercloud/framework-types' -import * as DataStore from 'nedb' import { readModelsDatabase } from '../paths' +const DataStore = require('@seald-io/nedb') interface LocalSortedFor { [key: string]: number @@ -11,10 +11,19 @@ export type NedbError = Error & { [key: string | number | symbol]: unknown } export const UNIQUE_VIOLATED_ERROR_TYPE = 'uniqueViolated' export class ReadModelRegistry { - public readonly readModels: DataStore = new DataStore(readModelsDatabase) + public readonly readModels + public isLoaded = false + constructor() { - this.readModels.loadDatabase() - this.readModels.ensureIndex({ fieldName: 'uniqueKey', unique: true, sparse: true }) + this.readModels = new DataStore({ filename: readModelsDatabase }) + } + + async loadDatabaseIfNeeded(): Promise { + if (!this.isLoaded) { + this.isLoaded = true + await this.readModels.loadDatabaseAsync() + await this.readModels.ensureIndexAsync({ fieldName: 'uniqueKey', unique: true, sparse: true }) + } } public async query( @@ -23,7 +32,8 @@ export class ReadModelRegistry { skip?: number, limit?: number ): Promise> { - let cursor = this.readModels.find(query) + await this.loadDatabaseIfNeeded() + let cursor = this.readModels.findAsync(query) const sortByList = this.toLocalSortFor(sortBy) if (sortByList) { cursor = cursor.sort(sortByList) @@ -34,16 +44,11 @@ export class ReadModelRegistry { if (limit) { cursor = cursor.limit(limit) } - const queryPromise = new Promise((resolve, reject) => - cursor.exec((err, docs) => { - if (err) reject(err) - else resolve(docs) - }) - ) - return queryPromise as Promise> + return await cursor.execAsync() } public async store(readModel: ReadModelEnvelope, expectedCurrentVersion: number): Promise { + await this.loadDatabaseIfNeeded() const uniqueReadModel: ReadModelEnvelope & { uniqueKey?: string } = readModel uniqueReadModel.uniqueKey = `${readModel.typeName}_${readModel.value.id}_${readModel.value.boosterMetadata?.version}` if (uniqueReadModel.value.boosterMetadata?.version === 1) { @@ -52,49 +57,36 @@ export class ReadModelRegistry { return this.update(uniqueReadModel, expectedCurrentVersion) } - private insert(readModel: ReadModelEnvelope): Promise { - return new Promise((resolve, reject) => { - this.readModels.insert(readModel, (err: unknown) => { - err ? reject(err) : resolve() - }) - }) + private async insert(readModel: ReadModelEnvelope): Promise { + await this.loadDatabaseIfNeeded() + await this.readModels.insertAsync(readModel) } - private update(readModel: ReadModelEnvelope, expectedCurrentVersion: number): Promise { - return new Promise((resolve, reject) => { - this.readModels.update( - { - typeName: readModel.typeName, - 'value.id': readModel.value.id, - 'value.boosterMetadata.version': expectedCurrentVersion, - }, - readModel, - { upsert: false, returnUpdatedDocs: true }, - (err: unknown, numAffected: number) => { - if (numAffected === 0) { - const error: NedbError = new Error( - `Can't update readModel ${JSON.stringify( - readModel - )} with expectedCurrentVersion = ${expectedCurrentVersion} . Optimistic concurrency error` - ) as NedbError - error.errorType = UNIQUE_VIOLATED_ERROR_TYPE - reject(error) - } - err ? reject(err) : resolve() - } - ) - }) + private async update(readModel: ReadModelEnvelope, expectedCurrentVersion: number): Promise { + await this.loadDatabaseIfNeeded() + const { numAffected } = await this.readModels.updateAsync( + { + typeName: readModel.typeName, + 'value.id': readModel.value.id, + 'value.boosterMetadata.version': expectedCurrentVersion, + }, + readModel, + { upsert: false, returnUpdatedDocs: true } + ) + if (numAffected === 0) { + const error: NedbError = new Error( + `Can't update readModel ${JSON.stringify( + readModel + )} with expectedCurrentVersion = ${expectedCurrentVersion} . Optimistic concurrency error` + ) as NedbError + error.errorType = UNIQUE_VIOLATED_ERROR_TYPE + throw error + } } public async deleteById(id: UUID, typeName: string): Promise { - const deletePromise = new Promise((resolve, reject) => - this.readModels.remove({ typeName: typeName, 'value.id': id }, { multi: false }, (err, numRemoved: number) => { - if (err) reject(err) - else resolve(numRemoved) - }) - ) - - return deletePromise as Promise + await this.loadDatabaseIfNeeded() + return await this.readModels.removeAsync({ typeName: typeName, 'value.id': id }, { multi: false }) } toLocalSortFor( diff --git a/packages/framework-provider-local/src/services/web-socket-registry.ts b/packages/framework-provider-local/src/services/web-socket-registry.ts index c55ce67ae..826452cc8 100644 --- a/packages/framework-provider-local/src/services/web-socket-registry.ts +++ b/packages/framework-provider-local/src/services/web-socket-registry.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/ban-types */ -import * as DataStore from 'nedb' -import { ConnectionDataEnvelope, EventEnvelope, SubscriptionEnvelope, UUID } from '@boostercloud/framework-types' +const DataStore = require('@seald-io/nedb') +import { ConnectionDataEnvelope, SubscriptionEnvelope, UUID } from '@boostercloud/framework-types' export interface ConnectionData extends ConnectionDataEnvelope { connectionID: UUID @@ -9,83 +9,56 @@ export interface ConnectionData extends ConnectionDataEnvelope { export type SimpleRegistryTypes = ConnectionData | SubscriptionEnvelope export class WebSocketRegistry { - public datastore: DataStore + public datastore + public isLoaded = false constructor(connectionsDatabase: string) { - this.datastore = new DataStore(connectionsDatabase) - this.datastore.loadDatabase() - this.addIndexes() + this.datastore = new DataStore({ filename: connectionsDatabase }) } - addIndexes(): void { + async loadDatabaseIfNeeded(): Promise { + if (!this.isLoaded) { + this.isLoaded = true + await this.datastore.loadDatabaseAsync() + await this.addIndexes() + } + } + + async addIndexes(): Promise { const maxDurationInSeconds = 2 * 24 * 60 * 60 // 2 days - this.datastore.ensureIndex({ fieldName: 'expirationTime', expireAfterSeconds: maxDurationInSeconds }) + this.datastore.ensureIndexAsync({ fieldName: 'expirationTime', expireAfterSeconds: maxDurationInSeconds }) } getCursor(query: object, createdAt = 1, projections?: unknown) { - return this.datastore.find(query, projections).sort({ createdAt: createdAt }) + return this.datastore.findAsync(query, projections).sort({ createdAt: createdAt }) } public async query(query: object, createdAt = 1, limit?: number, projections?: unknown): Promise { - const cursor = this.getCursor(query, createdAt, projections) + await this.loadDatabaseIfNeeded() + let cursor = this.getCursor(query, createdAt, projections) if (limit) { - cursor.limit(Number(limit)) - } - const queryPromise = new Promise((resolve, reject) => { - cursor.exec((err, docs) => { - if (err) reject(err) - else resolve(docs) - }) - }) - - return await queryPromise - } - - public async queryLatest(query: object): Promise { - const queryPromise = new Promise((resolve, reject) => - this.datastore - .find(query) - .sort({ createdAt: -1 }) // Sort in descending order (newer timestamps first) - .exec((err, docs) => { - if (err) reject(err) - else resolve(docs) - }) - ) - - const events = (await queryPromise) as Array - if (events.length <= 0) { - return null + cursor = cursor.limit(Number(limit)) } - return events[0] + return await cursor.execAsync() } public async store(envelope: SimpleRegistryTypes): Promise { - return new Promise((resolve, reject) => { - this.datastore.insert(envelope, (err) => { - err ? reject(err) : resolve() - }) - }) + await this.loadDatabaseIfNeeded() + await this.datastore.insertAsync(envelope) } public async delete(query: unknown): Promise { - const deletePromise = new Promise((resolve, reject) => - this.datastore.remove(query, { multi: true }, (err, numRemoved: number) => { - if (err) reject(err) - else resolve(numRemoved) - }) - ) - - return (await deletePromise) as number + await this.loadDatabaseIfNeeded() + return await this.datastore.removeAsync(query, { multi: true }) } public async deleteAll(): Promise { - const deletePromise = new Promise((resolve, reject) => - this.datastore.remove({}, { multi: true }, (err, numRemoved: number) => { - if (err) reject(err) - else resolve(numRemoved) - }) - ) + await this.loadDatabaseIfNeeded() + return await this.datastore.removeAsync({}, { multi: true }) + } - return (await deletePromise) as number + public async count(query?: object): Promise { + await this.loadDatabaseIfNeeded() + return await this.datastore.countAsync(query) } } diff --git a/packages/framework-provider-local/test/services/event-registry.test.ts b/packages/framework-provider-local/test/services/event-registry.test.ts index c4c96d110..58ca02e5a 100644 --- a/packages/framework-provider-local/test/services/event-registry.test.ts +++ b/packages/framework-provider-local/test/services/event-registry.test.ts @@ -1,14 +1,14 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { EventEnvelope, EntitySnapshotEnvelope } from '@boostercloud/framework-types' +import { EntitySnapshotEnvelope, EventEnvelope } from '@boostercloud/framework-types' import { expect } from '../expect' import * as faker from 'faker' -import { stub, restore } from 'sinon' +import { date, random } from 'faker' +import { restore, stub } from 'sinon' import { + createMockEntitySnapshotEnvelope, createMockEventEnvelope, createMockEventEnvelopeForEntity, - createMockEntitySnapshotEnvelope, } from '../helpers/event-helper' -import { date, random } from 'faker' import { EventRegistry } from '../../src/services' describe('the event registry', () => { @@ -155,10 +155,10 @@ describe('the event registry', () => { it('should insert events into the events database', async () => { const mockEvent: EventEnvelope = createMockEventEnvelope() - eventRegistry.events.insert = stub().yields(null, mockEvent) + eventRegistry.events.insertAsync = stub().returns(mockEvent) await eventRegistry.store(mockEvent) - return expect(eventRegistry.events.insert).to.have.been.called + return expect(eventRegistry.events.insertAsync).to.have.been.called }) it('should throw if the database `insert` fails', async () => { @@ -178,9 +178,9 @@ describe('the event registry', () => { const error = new Error(faker.random.words()) - eventRegistry.events.insert = stub().yields(error, null) + eventRegistry.events.insertAsync = stub().throws(error) - return expect(eventRegistry.store(event)).to.be.rejectedWith(error) + await expect(eventRegistry.store(event)).to.be.rejectedWith(error) }) }) }) diff --git a/packages/framework-provider-local/test/services/read-model-registry.test.ts b/packages/framework-provider-local/test/services/read-model-registry.test.ts index 6e7dd57eb..78518b4fc 100644 --- a/packages/framework-provider-local/test/services/read-model-registry.test.ts +++ b/packages/framework-provider-local/test/services/read-model-registry.test.ts @@ -187,12 +187,12 @@ describe('the read model registry', () => { const id = '1' mockReadModelEnvelope.value.id = id - readModelRegistry.readModels.remove = stub().yields(null, mockReadModelEnvelope) + readModelRegistry.readModels.removeAsync = stub().returns(mockReadModelEnvelope) await readModelRegistry.store(mockReadModelEnvelope, 1) await readModelRegistry.deleteById(id, mockReadModelEnvelope.typeName) - expect(readModelRegistry.readModels.remove).to.have.been.calledWith( + expect(readModelRegistry.readModels.removeAsync).to.have.been.calledWith( { typeName: mockReadModelEnvelope.typeName, 'value.id': id }, { multi: false } ) @@ -209,10 +209,10 @@ describe('the read model registry', () => { 'value.boosterMetadata.version': 2, } - readModelRegistry.readModels.update = stub().yields(null, readModel) + readModelRegistry.readModels.updateAsync = stub().returns(readModel) await readModelRegistry.store(readModel, 2) - expect(readModelRegistry.readModels.update).to.have.been.calledWith(expectedQuery, readModel, { + expect(readModelRegistry.readModels.updateAsync).to.have.been.calledWith(expectedQuery, readModel, { upsert: false, returnUpdatedDocs: true, })