@nocobase/database 0.5.0-alpha.38 → 0.7.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -21
- package/esm/collection-importer.d.ts +7 -0
- package/esm/collection-importer.js +49 -0
- package/esm/collection-importer.js.map +1 -0
- package/esm/collection.d.ts +73 -0
- package/esm/collection.js +224 -0
- package/esm/collection.js.map +1 -0
- package/esm/database.d.ts +101 -0
- package/esm/database.js +275 -0
- package/esm/database.js.map +1 -0
- package/esm/fields/array-field.d.ts +11 -0
- package/esm/fields/array-field.js +26 -0
- package/esm/fields/array-field.js.map +1 -0
- package/esm/fields/belongs-to-field.d.ts +12 -0
- package/esm/fields/belongs-to-field.js +57 -0
- package/esm/fields/belongs-to-field.js.map +1 -0
- package/esm/fields/belongs-to-many-field.d.ts +11 -0
- package/esm/fields/belongs-to-many-field.js +55 -0
- package/esm/fields/belongs-to-many-field.js.map +1 -0
- package/esm/fields/boolean-field.d.ts +8 -0
- package/esm/fields/boolean-field.js +8 -0
- package/esm/fields/boolean-field.js.map +1 -0
- package/esm/fields/context-field.d.ts +13 -0
- package/esm/fields/context-field.js +43 -0
- package/esm/fields/context-field.js.map +1 -0
- package/esm/fields/date-field.d.ts +8 -0
- package/esm/fields/date-field.js +8 -0
- package/esm/fields/date-field.js.map +1 -0
- package/esm/fields/field.d.ts +37 -0
- package/esm/fields/field.js +74 -0
- package/esm/fields/field.js.map +1 -0
- package/esm/fields/has-inverse-field.d.ts +4 -0
- package/esm/fields/has-inverse-field.js +2 -0
- package/esm/fields/has-inverse-field.js.map +1 -0
- package/esm/fields/has-many-field.d.ts +64 -0
- package/esm/fields/has-many-field.js +58 -0
- package/esm/fields/has-many-field.js.map +1 -0
- package/esm/fields/has-one-field.d.ts +64 -0
- package/esm/fields/has-one-field.js +57 -0
- package/esm/fields/has-one-field.js.map +1 -0
- package/esm/fields/index.d.ts +40 -0
- package/esm/fields/index.js +21 -0
- package/esm/fields/index.js.map +1 -0
- package/esm/fields/json-field.d.ts +14 -0
- package/esm/fields/json-field.js +17 -0
- package/esm/fields/json-field.js.map +1 -0
- package/esm/fields/number-field.d.ts +32 -0
- package/esm/fields/number-field.js +28 -0
- package/esm/fields/number-field.js.map +1 -0
- package/esm/fields/password-field.d.ts +21 -0
- package/esm/fields/password-field.js +71 -0
- package/esm/fields/password-field.js.map +1 -0
- package/esm/fields/radio-field.d.ts +14 -0
- package/esm/fields/radio-field.js +49 -0
- package/esm/fields/radio-field.js.map +1 -0
- package/esm/fields/relation-field.d.ts +20 -0
- package/esm/fields/relation-field.js +27 -0
- package/esm/fields/relation-field.js.map +1 -0
- package/esm/fields/sort-field.d.ts +16 -0
- package/esm/fields/sort-field.js +90 -0
- package/esm/fields/sort-field.js.map +1 -0
- package/esm/fields/string-field.d.ts +8 -0
- package/esm/fields/string-field.js +8 -0
- package/esm/fields/string-field.js.map +1 -0
- package/esm/fields/text-field.d.ts +8 -0
- package/esm/fields/text-field.js +8 -0
- package/esm/fields/text-field.js.map +1 -0
- package/esm/fields/time-field.d.ts +8 -0
- package/esm/fields/time-field.js +8 -0
- package/esm/fields/time-field.js.map +1 -0
- package/esm/fields/uid-field.d.ts +10 -0
- package/esm/fields/uid-field.js +27 -0
- package/esm/fields/uid-field.js.map +1 -0
- package/esm/fields/virtual-field.d.ts +8 -0
- package/esm/fields/virtual-field.js +8 -0
- package/esm/fields/virtual-field.js.map +1 -0
- package/esm/filter-parser.d.ts +27 -0
- package/esm/filter-parser.js +185 -0
- package/esm/filter-parser.js.map +1 -0
- package/esm/index.d.ts +15 -0
- package/esm/index.js +16 -0
- package/esm/index.js.map +1 -0
- package/esm/magic-attribute-model.d.ts +7 -0
- package/esm/magic-attribute-model.js +70 -0
- package/esm/magic-attribute-model.js.map +1 -0
- package/esm/mock-database.d.ts +22 -0
- package/esm/mock-database.js +34 -0
- package/esm/mock-database.js.map +1 -0
- package/esm/model-hook.d.ts +12 -0
- package/esm/model-hook.js +61 -0
- package/esm/model-hook.js.map +1 -0
- package/esm/model.d.ts +15 -0
- package/esm/model.js +80 -0
- package/esm/model.js.map +1 -0
- package/esm/operators/array.d.ts +26 -0
- package/esm/operators/array.js +105 -0
- package/esm/operators/array.js.map +1 -0
- package/esm/operators/association.d.ts +10 -0
- package/esm/operators/association.js +14 -0
- package/esm/operators/association.js.map +1 -0
- package/esm/operators/date.d.ts +34 -0
- package/esm/operators/date.js +35 -0
- package/esm/operators/date.js.map +1 -0
- package/esm/operators/empty.d.ts +28 -0
- package/esm/operators/empty.js +58 -0
- package/esm/operators/empty.js.map +1 -0
- package/esm/operators/index.d.ts +2 -0
- package/esm/operators/index.js +2 -0
- package/esm/operators/index.js.map +1 -0
- package/esm/operators/ne.d.ts +10 -0
- package/esm/operators/ne.js +12 -0
- package/esm/operators/ne.js.map +1 -0
- package/esm/operators/string.d.ts +21 -0
- package/esm/operators/string.js +35 -0
- package/esm/operators/string.js.map +1 -0
- package/esm/operators/utils.d.ts +4 -0
- package/esm/operators/utils.js +11 -0
- package/esm/operators/utils.js.map +1 -0
- package/esm/options-parser.d.ts +31 -0
- package/esm/options-parser.js +225 -0
- package/esm/options-parser.js.map +1 -0
- package/esm/playground.d.ts +1 -0
- package/esm/playground.js +53 -0
- package/esm/playground.js.map +1 -0
- package/esm/relation-repository/belongs-to-many-repository.d.ts +36 -0
- package/esm/relation-repository/belongs-to-many-repository.js +199 -0
- package/esm/relation-repository/belongs-to-many-repository.js.map +1 -0
- package/esm/relation-repository/belongs-to-repository.d.ts +17 -0
- package/esm/relation-repository/belongs-to-repository.js +4 -0
- package/esm/relation-repository/belongs-to-repository.js.map +1 -0
- package/esm/relation-repository/hasmany-repository.d.ts +23 -0
- package/esm/relation-repository/hasmany-repository.js +125 -0
- package/esm/relation-repository/hasmany-repository.js.map +1 -0
- package/esm/relation-repository/hasone-repository.d.ts +17 -0
- package/esm/relation-repository/hasone-repository.js +4 -0
- package/esm/relation-repository/hasone-repository.js.map +1 -0
- package/esm/relation-repository/multiple-relation-repository.d.ts +23 -0
- package/esm/relation-repository/multiple-relation-repository.js +149 -0
- package/esm/relation-repository/multiple-relation-repository.js.map +1 -0
- package/esm/relation-repository/relation-repository.d.ts +32 -0
- package/esm/relation-repository/relation-repository.js +93 -0
- package/esm/relation-repository/relation-repository.js.map +1 -0
- package/esm/relation-repository/single-relation-repository.d.ts +23 -0
- package/esm/relation-repository/single-relation-repository.js +96 -0
- package/esm/relation-repository/single-relation-repository.js.map +1 -0
- package/esm/relation-repository/types.d.ts +7 -0
- package/esm/relation-repository/types.js +2 -0
- package/esm/relation-repository/types.js.map +1 -0
- package/esm/repository.d.ts +165 -0
- package/esm/repository.js +276 -0
- package/esm/repository.js.map +1 -0
- package/esm/transaction-decorator.d.ts +1 -0
- package/esm/transaction-decorator.js +63 -0
- package/esm/transaction-decorator.js.map +1 -0
- package/esm/update-associations.d.ts +60 -0
- package/esm/update-associations.js +362 -0
- package/esm/update-associations.js.map +1 -0
- package/esm/update-guard.d.ts +26 -0
- package/esm/update-guard.js +122 -0
- package/esm/update-guard.js.map +1 -0
- package/lib/collection-importer.d.ts +7 -0
- package/lib/collection-importer.js +75 -0
- package/lib/collection-importer.js.map +1 -0
- package/lib/collection.d.ts +73 -0
- package/lib/collection.js +231 -0
- package/lib/collection.js.map +1 -0
- package/lib/database.d.ts +93 -43
- package/lib/database.js +277 -471
- package/lib/database.js.map +1 -1
- package/lib/fields/array-field.d.ts +11 -0
- package/lib/fields/array-field.js +30 -0
- package/lib/fields/array-field.js.map +1 -0
- package/lib/fields/belongs-to-field.d.ts +12 -0
- package/lib/fields/belongs-to-field.js +61 -0
- package/lib/fields/belongs-to-field.js.map +1 -0
- package/lib/fields/belongs-to-many-field.d.ts +11 -0
- package/lib/fields/belongs-to-many-field.js +59 -0
- package/lib/fields/belongs-to-many-field.js.map +1 -0
- package/lib/fields/boolean-field.d.ts +8 -0
- package/lib/fields/boolean-field.js +12 -0
- package/lib/fields/boolean-field.js.map +1 -0
- package/lib/fields/context-field.d.ts +13 -0
- package/lib/fields/context-field.js +50 -0
- package/lib/fields/context-field.js.map +1 -0
- package/lib/fields/date-field.d.ts +8 -0
- package/lib/fields/date-field.js +12 -0
- package/lib/fields/date-field.js.map +1 -0
- package/lib/fields/field.d.ts +37 -0
- package/lib/fields/field.js +81 -0
- package/lib/fields/field.js.map +1 -0
- package/lib/fields/has-inverse-field.d.ts +4 -0
- package/lib/fields/has-inverse-field.js +3 -0
- package/lib/fields/has-inverse-field.js.map +1 -0
- package/lib/fields/has-many-field.d.ts +64 -0
- package/lib/fields/has-many-field.js +62 -0
- package/lib/fields/has-many-field.js.map +1 -0
- package/lib/fields/has-one-field.d.ts +64 -0
- package/lib/fields/has-one-field.js +61 -0
- package/lib/fields/has-one-field.js.map +1 -0
- package/lib/fields/index.d.ts +40 -10
- package/lib/fields/index.js +31 -138
- package/lib/fields/index.js.map +1 -1
- package/lib/fields/json-field.d.ts +14 -0
- package/lib/fields/json-field.js +22 -0
- package/lib/fields/json-field.js.map +1 -0
- package/lib/fields/number-field.d.ts +32 -0
- package/lib/fields/number-field.js +36 -0
- package/lib/fields/number-field.js.map +1 -0
- package/lib/fields/password-field.d.ts +21 -0
- package/lib/fields/password-field.js +78 -0
- package/lib/fields/password-field.js.map +1 -0
- package/lib/fields/radio-field.d.ts +14 -0
- package/lib/fields/radio-field.js +53 -0
- package/lib/fields/radio-field.js.map +1 -0
- package/lib/fields/relation-field.d.ts +20 -0
- package/lib/fields/relation-field.js +31 -0
- package/lib/fields/relation-field.js.map +1 -0
- package/lib/fields/sort-field.d.ts +16 -0
- package/lib/fields/sort-field.js +94 -0
- package/lib/fields/sort-field.js.map +1 -0
- package/lib/fields/string-field.d.ts +8 -0
- package/lib/fields/string-field.js +12 -0
- package/lib/fields/string-field.js.map +1 -0
- package/lib/fields/text-field.d.ts +8 -0
- package/lib/fields/text-field.js +12 -0
- package/lib/fields/text-field.js.map +1 -0
- package/lib/fields/time-field.d.ts +8 -0
- package/lib/fields/time-field.js +12 -0
- package/lib/fields/time-field.js.map +1 -0
- package/lib/fields/uid-field.d.ts +10 -0
- package/lib/fields/uid-field.js +31 -0
- package/lib/fields/uid-field.js.map +1 -0
- package/lib/fields/virtual-field.d.ts +8 -0
- package/lib/fields/virtual-field.js +12 -0
- package/lib/fields/virtual-field.js.map +1 -0
- package/lib/filter-parser.d.ts +27 -0
- package/lib/filter-parser.js +191 -0
- package/lib/filter-parser.js.map +1 -0
- package/lib/index.d.ts +13 -6
- package/lib/index.js +27 -60
- package/lib/index.js.map +1 -1
- package/lib/magic-attribute-model.d.ts +7 -0
- package/lib/magic-attribute-model.js +77 -0
- package/lib/magic-attribute-model.js.map +1 -0
- package/lib/mock-database.d.ts +22 -0
- package/lib/mock-database.js +40 -0
- package/lib/mock-database.js.map +1 -0
- package/lib/model-hook.d.ts +12 -0
- package/lib/model-hook.js +68 -0
- package/lib/model-hook.js.map +1 -0
- package/lib/model.d.ts +11 -45
- package/lib/model.js +76 -452
- package/lib/model.js.map +1 -1
- package/lib/operators/array.d.ts +26 -0
- package/lib/operators/array.js +107 -0
- package/lib/operators/array.js.map +1 -0
- package/lib/operators/association.d.ts +10 -0
- package/lib/operators/association.js +16 -0
- package/lib/operators/association.js.map +1 -0
- package/lib/operators/date.d.ts +34 -0
- package/lib/operators/date.js +40 -0
- package/lib/operators/date.js.map +1 -0
- package/lib/operators/empty.d.ts +28 -0
- package/lib/operators/empty.js +82 -0
- package/lib/operators/empty.js.map +1 -0
- package/lib/operators/index.d.ts +2 -0
- package/lib/operators/index.js +4 -0
- package/lib/operators/index.js.map +1 -0
- package/lib/operators/ne.d.ts +10 -0
- package/lib/operators/ne.js +14 -0
- package/lib/operators/ne.js.map +1 -0
- package/lib/operators/string.d.ts +21 -0
- package/lib/operators/string.js +37 -0
- package/lib/operators/string.js.map +1 -0
- package/lib/operators/utils.d.ts +4 -0
- package/lib/operators/utils.js +16 -0
- package/lib/operators/utils.js.map +1 -0
- package/lib/options-parser.d.ts +31 -0
- package/lib/options-parser.js +232 -0
- package/lib/options-parser.js.map +1 -0
- package/lib/playground.d.ts +1 -0
- package/lib/playground.js +55 -0
- package/lib/playground.js.map +1 -0
- package/lib/relation-repository/belongs-to-many-repository.d.ts +36 -0
- package/lib/relation-repository/belongs-to-many-repository.js +206 -0
- package/lib/relation-repository/belongs-to-many-repository.js.map +1 -0
- package/lib/relation-repository/belongs-to-repository.d.ts +17 -0
- package/lib/relation-repository/belongs-to-repository.js +8 -0
- package/lib/relation-repository/belongs-to-repository.js.map +1 -0
- package/lib/relation-repository/hasmany-repository.d.ts +23 -0
- package/lib/relation-repository/hasmany-repository.js +129 -0
- package/lib/relation-repository/hasmany-repository.js.map +1 -0
- package/lib/relation-repository/hasone-repository.d.ts +17 -0
- package/lib/relation-repository/hasone-repository.js +8 -0
- package/lib/relation-repository/hasone-repository.js.map +1 -0
- package/lib/relation-repository/multiple-relation-repository.d.ts +23 -0
- package/lib/relation-repository/multiple-relation-repository.js +153 -0
- package/lib/relation-repository/multiple-relation-repository.js.map +1 -0
- package/lib/relation-repository/relation-repository.d.ts +32 -0
- package/lib/relation-repository/relation-repository.js +100 -0
- package/lib/relation-repository/relation-repository.js.map +1 -0
- package/lib/relation-repository/single-relation-repository.d.ts +23 -0
- package/lib/relation-repository/single-relation-repository.js +103 -0
- package/lib/relation-repository/single-relation-repository.js.map +1 -0
- package/lib/relation-repository/types.d.ts +7 -0
- package/lib/relation-repository/types.js +3 -0
- package/lib/relation-repository/types.js.map +1 -0
- package/lib/repository.d.ts +165 -0
- package/lib/repository.js +302 -0
- package/lib/repository.js.map +1 -0
- package/lib/transaction-decorator.d.ts +1 -0
- package/lib/transaction-decorator.js +70 -0
- package/lib/transaction-decorator.js.map +1 -0
- package/lib/update-associations.d.ts +60 -0
- package/lib/update-associations.js +374 -0
- package/lib/update-associations.js.map +1 -0
- package/lib/update-guard.d.ts +26 -0
- package/lib/update-guard.js +129 -0
- package/lib/update-guard.js.map +1 -0
- package/package.json +17 -5
- package/src/__tests__/collection-importer.test.ts +21 -0
- package/src/__tests__/collection.sortable.test.ts +65 -0
- package/src/__tests__/collection.test.ts +218 -0
- package/src/__tests__/database.import.test.ts +33 -0
- package/src/__tests__/database.test.ts +229 -0
- package/src/__tests__/field-options/hidden.test.ts +302 -0
- package/src/__tests__/field-options/sort-by.test.ts +220 -0
- package/src/__tests__/fields/belongs-to-field.test.ts +162 -0
- package/src/__tests__/fields/belongs-to-many-field.test.ts +61 -0
- package/src/__tests__/fields/context-field.test.ts +140 -0
- package/src/__tests__/fields/has-many-field.test.ts +152 -0
- package/src/__tests__/fields/has-one-field.test.ts +67 -0
- package/src/__tests__/fields/password-field.test.ts +30 -0
- package/src/__tests__/fields/sort-field.test.ts +133 -0
- package/src/__tests__/fields/string-field.test.ts +77 -0
- package/src/__tests__/filter-parser.test.ts +104 -0
- package/src/__tests__/fixtures/c0/a.ts +6 -0
- package/src/__tests__/fixtures/c1/b.ts +6 -0
- package/src/__tests__/fixtures/c2/a.ts +6 -0
- package/src/__tests__/fixtures/collections/delay-extend.ts +6 -0
- package/src/__tests__/fixtures/collections/delay-extend2.ts +6 -0
- package/src/__tests__/fixtures/collections/extend.ts +6 -0
- package/src/__tests__/fixtures/collections/extend2.ts +6 -0
- package/src/__tests__/fixtures/collections/posts.ts +4 -0
- package/src/__tests__/fixtures/collections/tags.js +4 -0
- package/src/__tests__/fixtures/collections/test.jpg +0 -0
- package/src/__tests__/fixtures/collections/user.json +9 -0
- package/src/__tests__/index.ts +1 -0
- package/src/__tests__/magic-attribute-model.test.ts +103 -0
- package/src/__tests__/model.test.ts +60 -0
- package/src/__tests__/operator/array-operator.test.ts +268 -0
- package/src/__tests__/operator/association-operator.test.ts +263 -0
- package/src/__tests__/operator/date-operator.test.ts +165 -0
- package/src/__tests__/operator/empty-operator.test.ts +77 -0
- package/src/__tests__/operator/ne.test.ts +33 -0
- package/src/__tests__/operator/string-operator.test.ts +62 -0
- package/src/__tests__/option-parser.test.ts +185 -0
- package/src/__tests__/relation-repository/belongs-to-many-repository.test.ts +697 -0
- package/src/__tests__/relation-repository/has-many-repository.test.ts +414 -0
- package/src/__tests__/relation-repository/hasone-repository.test.ts +77 -0
- package/src/__tests__/repository/count.test.ts +180 -0
- package/src/__tests__/repository/create.test.ts +163 -0
- package/src/__tests__/repository/destroy.test.ts +196 -0
- package/src/__tests__/repository/find.test.ts +247 -0
- package/src/__tests__/repository/update.test.ts +60 -0
- package/src/__tests__/repository.test.ts +438 -0
- package/src/__tests__/update-associations.test.ts +412 -0
- package/src/__tests__/update-guard.test.ts +376 -0
- package/src/collection-importer.ts +49 -0
- package/src/collection.ts +282 -0
- package/src/database.ts +340 -0
- package/src/fields/array-field.ts +35 -0
- package/src/fields/belongs-to-field.ts +76 -0
- package/src/fields/belongs-to-many-field.ts +77 -0
- package/src/fields/boolean-field.ts +12 -0
- package/src/fields/context-field.ts +45 -0
- package/src/fields/date-field.ts +12 -0
- package/src/fields/field.ts +105 -0
- package/src/fields/has-inverse-field.ts +5 -0
- package/src/fields/has-many-field.ts +143 -0
- package/src/fields/has-one-field.ts +136 -0
- package/src/fields/index.ts +72 -0
- package/src/fields/json-field.ts +25 -0
- package/src/fields/number-field.ts +52 -0
- package/src/fields/password-field.ts +72 -0
- package/src/fields/radio-field.ts +50 -0
- package/src/fields/relation-field.ts +37 -0
- package/src/fields/sort-field.ts +96 -0
- package/src/fields/string-field.ts +12 -0
- package/src/fields/text-field.ts +12 -0
- package/src/fields/time-field.ts +12 -0
- package/src/fields/uid-field.ts +24 -0
- package/src/fields/virtual-field.ts +12 -0
- package/src/filter-parser.ts +243 -0
- package/src/index.ts +16 -0
- package/src/magic-attribute-model.ts +62 -0
- package/src/mock-database.ts +42 -0
- package/src/model-hook.ts +69 -0
- package/src/model.ts +114 -0
- package/src/operators/array.ts +145 -0
- package/src/operators/association.ts +14 -0
- package/src/operators/date.ts +41 -0
- package/src/operators/empty.ts +75 -0
- package/src/operators/index.ts +8 -0
- package/src/operators/ne.ts +12 -0
- package/src/operators/string.ts +40 -0
- package/src/operators/utils.ts +13 -0
- package/src/options-parser.ts +285 -0
- package/src/playground.ts +52 -0
- package/src/relation-repository/belongs-to-many-repository.ts +240 -0
- package/src/relation-repository/belongs-to-repository.ts +23 -0
- package/src/relation-repository/hasmany-repository.ts +145 -0
- package/src/relation-repository/hasone-repository.ts +23 -0
- package/src/relation-repository/multiple-relation-repository.ts +198 -0
- package/src/relation-repository/relation-repository.ts +114 -0
- package/src/relation-repository/single-relation-repository.ts +99 -0
- package/src/relation-repository/types.ts +15 -0
- package/src/repository.ts +478 -0
- package/src/transaction-decorator.ts +58 -0
- package/src/update-associations.ts +478 -0
- package/src/update-guard.ts +167 -0
- package/tsconfig.build.json +9 -0
- package/tsconfig.json +5 -0
- package/examples/index.ts +0 -125
- package/examples/plugins/db-driven/index.ts +0 -25
- package/examples/plugins/db-driven/tables/fields.ts +0 -78
- package/examples/plugins/db-driven/tables/tables.ts +0 -53
- package/examples/tables/bar.js +0 -26
- package/examples/tables/comments.ts +0 -19
- package/examples/tables/foo.json +0 -3
- package/examples/tables/posts.ts +0 -28
- package/examples/tables/profiles.ts +0 -23
- package/examples/tables/tags.ts +0 -15
- package/examples/tables/users.ts +0 -34
- package/lib/database.d.ts.map +0 -1
- package/lib/fields/field-types.d.ts +0 -419
- package/lib/fields/field-types.d.ts.map +0 -1
- package/lib/fields/field-types.js +0 -1222
- package/lib/fields/field-types.js.map +0 -1
- package/lib/fields/index.d.ts.map +0 -1
- package/lib/fields/option-types.d.ts +0 -105
- package/lib/fields/option-types.d.ts.map +0 -1
- package/lib/fields/option-types.js +0 -18
- package/lib/fields/option-types.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/model.d.ts.map +0 -1
- package/lib/op.d.ts +0 -45
- package/lib/op.d.ts.map +0 -1
- package/lib/op.js +0 -225
- package/lib/op.js.map +0 -1
- package/lib/table.d.ts +0 -56
- package/lib/table.d.ts.map +0 -1
- package/lib/table.js +0 -456
- package/lib/table.js.map +0 -1
- package/lib/utils.d.ts +0 -26
- package/lib/utils.d.ts.map +0 -1
- package/lib/utils.js +0 -438
- package/lib/utils.js.map +0 -1
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import lodash from 'lodash';
|
|
2
|
+
|
|
3
|
+
export function transactionWrapperBuilder(transactionGenerator) {
|
|
4
|
+
return function transaction(transactionInjector?) {
|
|
5
|
+
return (target, name, descriptor) => {
|
|
6
|
+
const oldValue = descriptor.value;
|
|
7
|
+
|
|
8
|
+
descriptor.value = async function () {
|
|
9
|
+
let transaction;
|
|
10
|
+
let newTransaction = false;
|
|
11
|
+
|
|
12
|
+
if (arguments.length > 0 && typeof arguments[0] === 'object') {
|
|
13
|
+
transaction = arguments[0]['transaction'];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (!transaction) {
|
|
17
|
+
transaction = await transactionGenerator.apply(this);
|
|
18
|
+
newTransaction = true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// 需要将 newTransaction 注入到被装饰函数参数内
|
|
22
|
+
if (newTransaction) {
|
|
23
|
+
try {
|
|
24
|
+
let callArguments;
|
|
25
|
+
if (lodash.isPlainObject(arguments[0])) {
|
|
26
|
+
callArguments = {
|
|
27
|
+
...arguments[0],
|
|
28
|
+
transaction,
|
|
29
|
+
};
|
|
30
|
+
} else if (transactionInjector) {
|
|
31
|
+
callArguments = transactionInjector(arguments, transaction);
|
|
32
|
+
} else if (lodash.isNull(arguments[0]) || lodash.isUndefined(arguments[0])) {
|
|
33
|
+
callArguments = {
|
|
34
|
+
transaction,
|
|
35
|
+
};
|
|
36
|
+
} else {
|
|
37
|
+
throw new Error(`please provide transactionInjector for ${name} call`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const results = await oldValue.apply(this, [callArguments]);
|
|
41
|
+
|
|
42
|
+
await transaction.commit();
|
|
43
|
+
|
|
44
|
+
return results;
|
|
45
|
+
} catch (err) {
|
|
46
|
+
console.error({ err });
|
|
47
|
+
await transaction.rollback();
|
|
48
|
+
throw err;
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
return oldValue.apply(this, arguments);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return descriptor;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Association,
|
|
3
|
+
BelongsTo,
|
|
4
|
+
BelongsToMany,
|
|
5
|
+
HasMany,
|
|
6
|
+
HasOne,
|
|
7
|
+
Hookable,
|
|
8
|
+
ModelCtor,
|
|
9
|
+
Transactionable,
|
|
10
|
+
} from 'sequelize';
|
|
11
|
+
import { Model } from './model';
|
|
12
|
+
import { TransactionAble } from './repository';
|
|
13
|
+
import { UpdateGuard } from './update-guard';
|
|
14
|
+
|
|
15
|
+
function isUndefinedOrNull(value: any) {
|
|
16
|
+
return typeof value === 'undefined' || value === null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function isStringOrNumber(value: any) {
|
|
20
|
+
return typeof value === 'string' || typeof value === 'number';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function getKeysByPrefix(keys: string[], prefix: string) {
|
|
24
|
+
return keys.filter((key) => key.startsWith(`${prefix}.`)).map((key) => key.substring(prefix.length + 1));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function modelAssociations(instance: Model) {
|
|
28
|
+
return (<typeof Model>instance.constructor).associations;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function belongsToManyAssociations(instance: Model): Array<BelongsToMany> {
|
|
32
|
+
const associations = modelAssociations(instance);
|
|
33
|
+
return Object.entries(associations)
|
|
34
|
+
.filter((entry) => {
|
|
35
|
+
const [key, association] = entry;
|
|
36
|
+
return association.associationType == 'BelongsToMany';
|
|
37
|
+
})
|
|
38
|
+
.map((association) => {
|
|
39
|
+
return <BelongsToMany>association[1];
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function modelAssociationByKey(instance: Model, key: string): Association {
|
|
44
|
+
return modelAssociations(instance)[key] as Association;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
type UpdateValue = { [key: string]: any };
|
|
48
|
+
|
|
49
|
+
interface UpdateOptions extends TransactionAble {
|
|
50
|
+
filter?: any;
|
|
51
|
+
filterByTk?: number | string;
|
|
52
|
+
// 字段白名单
|
|
53
|
+
whitelist?: string[];
|
|
54
|
+
// 字段黑名单
|
|
55
|
+
blacklist?: string[];
|
|
56
|
+
// 关系数据默认会新建并建立关联处理,如果是已存在的数据只关联,但不更新关系数据
|
|
57
|
+
// 如果需要更新关联数据,可以通过 updateAssociationValues 指定
|
|
58
|
+
updateAssociationValues?: string[];
|
|
59
|
+
sanitized?: boolean;
|
|
60
|
+
sourceModel?: Model;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface UpdateAssociationOptions extends Transactionable, Hookable {
|
|
64
|
+
updateAssociationValues?: string[];
|
|
65
|
+
sourceModel?: Model;
|
|
66
|
+
context?: any;
|
|
67
|
+
associationContext?: any;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export async function updateModelByValues(instance: Model, values: UpdateValue, options?: UpdateOptions) {
|
|
71
|
+
if (!options?.sanitized) {
|
|
72
|
+
const guard = new UpdateGuard();
|
|
73
|
+
//@ts-ignore
|
|
74
|
+
guard.setModel(instance.constructor);
|
|
75
|
+
guard.setBlackList(options.blacklist);
|
|
76
|
+
guard.setWhiteList(options.whitelist);
|
|
77
|
+
guard.setAssociationKeysToBeUpdate(options.updateAssociationValues);
|
|
78
|
+
values = guard.sanitize(values);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
await instance.update(values, options);
|
|
82
|
+
await updateAssociations(instance, values, options);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export async function updateThroughTableValue(
|
|
86
|
+
instance: Model,
|
|
87
|
+
throughName: string,
|
|
88
|
+
throughValues: any,
|
|
89
|
+
source: Model,
|
|
90
|
+
transaction = null,
|
|
91
|
+
) {
|
|
92
|
+
// update through table values
|
|
93
|
+
for (const belongsToMany of belongsToManyAssociations(instance)) {
|
|
94
|
+
// @ts-ignore
|
|
95
|
+
const throughModel = belongsToMany.through.model;
|
|
96
|
+
const throughModelName = throughModel.name;
|
|
97
|
+
|
|
98
|
+
if (throughModelName === throughModelName) {
|
|
99
|
+
const where = {
|
|
100
|
+
[belongsToMany.foreignKey]: instance.get(belongsToMany.sourceKey),
|
|
101
|
+
[belongsToMany.otherKey]: source.get(belongsToMany.targetKey),
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
return await throughModel.update(throughValues, {
|
|
105
|
+
where,
|
|
106
|
+
transaction,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* update association of instance by values
|
|
114
|
+
* @param instance
|
|
115
|
+
* @param values
|
|
116
|
+
* @param options
|
|
117
|
+
*/
|
|
118
|
+
export async function updateAssociations(instance: Model, values: any, options: UpdateAssociationOptions = {}) {
|
|
119
|
+
// if no values set, return
|
|
120
|
+
if (!values) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
let newTransaction = false;
|
|
125
|
+
let transaction = options.transaction;
|
|
126
|
+
|
|
127
|
+
if (!transaction) {
|
|
128
|
+
newTransaction = true;
|
|
129
|
+
transaction = await instance.sequelize.transaction();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const keys = Object.keys(values);
|
|
133
|
+
|
|
134
|
+
for (const key of Object.keys(modelAssociations(instance))) {
|
|
135
|
+
if (keys.includes(key)) {
|
|
136
|
+
await updateAssociation(instance, key, values[key], {
|
|
137
|
+
...options,
|
|
138
|
+
transaction,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// update through table values
|
|
144
|
+
for (const belongsToMany of belongsToManyAssociations(instance)) {
|
|
145
|
+
// @ts-ignore
|
|
146
|
+
const throughModel = belongsToMany.through.model;
|
|
147
|
+
const throughModelName = throughModel.name;
|
|
148
|
+
|
|
149
|
+
if (values[throughModelName] && options.sourceModel) {
|
|
150
|
+
const where = {
|
|
151
|
+
[belongsToMany.foreignKey]: instance.get(belongsToMany.sourceKey),
|
|
152
|
+
[belongsToMany.otherKey]: options.sourceModel.get(belongsToMany.targetKey),
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
await throughModel.update(values[throughModel.name], {
|
|
156
|
+
where,
|
|
157
|
+
context: options.context,
|
|
158
|
+
transaction,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (newTransaction) {
|
|
164
|
+
await transaction.commit();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function isReverseAssociationPair(a: any, b: any) {
|
|
169
|
+
const typeSet = new Set();
|
|
170
|
+
typeSet.add(a.associationType);
|
|
171
|
+
typeSet.add(b.associationType);
|
|
172
|
+
|
|
173
|
+
if (typeSet.size == 1 && typeSet.has('BelongsToMany')) {
|
|
174
|
+
return (
|
|
175
|
+
a.through.tableName === b.through.tableName &&
|
|
176
|
+
a.target.name === b.source.name &&
|
|
177
|
+
b.target.name === a.source.name &&
|
|
178
|
+
a.foreignKey === b.otherKey &&
|
|
179
|
+
a.sourceKey === b.targetKey &&
|
|
180
|
+
a.otherKey === b.foreignKey &&
|
|
181
|
+
a.targetKey === b.sourceKey
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if ((typeSet.has('HasOne') && typeSet.has('BelongsTo')) || (typeSet.has('HasMany') && typeSet.has('BelongsTo'))) {
|
|
186
|
+
const sourceAssoc = a.associationType == 'BelongsTo' ? b : a;
|
|
187
|
+
const targetAssoc = sourceAssoc == a ? b : a;
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
sourceAssoc.source.name === targetAssoc.target.name &&
|
|
191
|
+
sourceAssoc.foreignKey === targetAssoc.foreignKey &&
|
|
192
|
+
sourceAssoc.sourceKey === targetAssoc.targetKey
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* update model association by key
|
|
201
|
+
* @param instance
|
|
202
|
+
* @param key
|
|
203
|
+
* @param value
|
|
204
|
+
* @param options
|
|
205
|
+
*/
|
|
206
|
+
export async function updateAssociation(
|
|
207
|
+
instance: Model,
|
|
208
|
+
key: string,
|
|
209
|
+
value: any,
|
|
210
|
+
options: UpdateAssociationOptions = {},
|
|
211
|
+
) {
|
|
212
|
+
const association = modelAssociationByKey(instance, key);
|
|
213
|
+
|
|
214
|
+
if (!association) {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (options.associationContext && isReverseAssociationPair(association, options.associationContext)) {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
switch (association.associationType) {
|
|
223
|
+
case 'HasOne':
|
|
224
|
+
case 'BelongsTo':
|
|
225
|
+
return updateSingleAssociation(instance, key, value, options);
|
|
226
|
+
case 'HasMany':
|
|
227
|
+
case 'BelongsToMany':
|
|
228
|
+
return updateMultipleAssociation(instance, key, value, options);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* update belongsTo and HasOne
|
|
234
|
+
* @param model
|
|
235
|
+
* @param key
|
|
236
|
+
* @param value
|
|
237
|
+
* @param options
|
|
238
|
+
*/
|
|
239
|
+
export async function updateSingleAssociation(
|
|
240
|
+
model: Model,
|
|
241
|
+
key: string,
|
|
242
|
+
value: any,
|
|
243
|
+
options: UpdateAssociationOptions = {},
|
|
244
|
+
) {
|
|
245
|
+
const association = <HasOne | BelongsTo>modelAssociationByKey(model, key);
|
|
246
|
+
|
|
247
|
+
if (!association) {
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (!['undefined', 'string', 'number', 'object'].includes(typeof value)) {
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const { context, updateAssociationValues = [], transaction = await model.sequelize.transaction() } = options;
|
|
256
|
+
const keys = getKeysByPrefix(updateAssociationValues, key);
|
|
257
|
+
|
|
258
|
+
try {
|
|
259
|
+
// set method of association
|
|
260
|
+
const setAccessor = association.accessors.set;
|
|
261
|
+
|
|
262
|
+
const removeAssociation = async () => {
|
|
263
|
+
await model[setAccessor](null, { transaction });
|
|
264
|
+
model.setDataValue(key, null);
|
|
265
|
+
if (!options.transaction) {
|
|
266
|
+
await transaction.commit();
|
|
267
|
+
}
|
|
268
|
+
return true;
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
if (isUndefinedOrNull(value)) {
|
|
272
|
+
return await removeAssociation();
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (isStringOrNumber(value)) {
|
|
276
|
+
await model[setAccessor](value, { context, transaction });
|
|
277
|
+
if (!options.transaction) {
|
|
278
|
+
await transaction.commit();
|
|
279
|
+
}
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (value instanceof Model) {
|
|
284
|
+
await model[setAccessor](value, { context, transaction });
|
|
285
|
+
model.setDataValue(key, value);
|
|
286
|
+
|
|
287
|
+
if (!options.transaction) {
|
|
288
|
+
await transaction.commit();
|
|
289
|
+
}
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const createAccessor = association.accessors.create;
|
|
294
|
+
let dataKey: string;
|
|
295
|
+
let M: ModelCtor<Model>;
|
|
296
|
+
if (association.associationType === 'BelongsTo') {
|
|
297
|
+
M = association.target as ModelCtor<Model>;
|
|
298
|
+
// @ts-ignore
|
|
299
|
+
dataKey = association.targetKey;
|
|
300
|
+
} else {
|
|
301
|
+
M = association.source as ModelCtor<Model>;
|
|
302
|
+
dataKey = M.primaryKeyAttribute;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (isStringOrNumber(value[dataKey])) {
|
|
306
|
+
let instance: any = await M.findOne({
|
|
307
|
+
where: {
|
|
308
|
+
[dataKey]: value[dataKey],
|
|
309
|
+
},
|
|
310
|
+
transaction,
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
if (instance) {
|
|
314
|
+
await model[setAccessor](instance, { context, transaction });
|
|
315
|
+
|
|
316
|
+
if (updateAssociationValues.includes(key)) {
|
|
317
|
+
await instance.update(value, { ...options, transaction });
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
await updateAssociations(instance, value, {
|
|
321
|
+
...options,
|
|
322
|
+
transaction,
|
|
323
|
+
associationContext: association,
|
|
324
|
+
updateAssociationValues: keys,
|
|
325
|
+
});
|
|
326
|
+
model.setDataValue(key, instance);
|
|
327
|
+
if (!options.transaction) {
|
|
328
|
+
await transaction.commit();
|
|
329
|
+
}
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const instance = await model[createAccessor](value, { context, transaction });
|
|
335
|
+
await updateAssociations(instance, value, {
|
|
336
|
+
...options,
|
|
337
|
+
transaction,
|
|
338
|
+
associationContext: association,
|
|
339
|
+
updateAssociationValues: keys,
|
|
340
|
+
});
|
|
341
|
+
model.setDataValue(key, instance);
|
|
342
|
+
// @ts-ignore
|
|
343
|
+
if (association.targetKey) {
|
|
344
|
+
model.setDataValue(association.foreignKey, instance[dataKey]);
|
|
345
|
+
}
|
|
346
|
+
if (!options.transaction) {
|
|
347
|
+
await transaction.commit();
|
|
348
|
+
}
|
|
349
|
+
} catch (error) {
|
|
350
|
+
if (!options.transaction) {
|
|
351
|
+
await transaction.rollback();
|
|
352
|
+
}
|
|
353
|
+
throw error;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* update multiple association of model by value
|
|
359
|
+
* @param model
|
|
360
|
+
* @param key
|
|
361
|
+
* @param value
|
|
362
|
+
* @param options
|
|
363
|
+
*/
|
|
364
|
+
export async function updateMultipleAssociation(
|
|
365
|
+
model: Model,
|
|
366
|
+
key: string,
|
|
367
|
+
value: any,
|
|
368
|
+
options: UpdateAssociationOptions = {},
|
|
369
|
+
) {
|
|
370
|
+
const association = <BelongsToMany | HasMany>modelAssociationByKey(model, key);
|
|
371
|
+
|
|
372
|
+
if (!association) {
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (!['undefined', 'string', 'number', 'object'].includes(typeof value)) {
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const { context, updateAssociationValues = [], transaction = await model.sequelize.transaction() } = options;
|
|
381
|
+
const keys = getKeysByPrefix(updateAssociationValues, key);
|
|
382
|
+
|
|
383
|
+
try {
|
|
384
|
+
const setAccessor = association.accessors.set;
|
|
385
|
+
|
|
386
|
+
const createAccessor = association.accessors.create;
|
|
387
|
+
if (isUndefinedOrNull(value)) {
|
|
388
|
+
await model[setAccessor](null, { transaction, context });
|
|
389
|
+
model.setDataValue(key, null);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (isStringOrNumber(value)) {
|
|
394
|
+
await model[setAccessor](value, { transaction, context });
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (!Array.isArray(value)) {
|
|
399
|
+
value = [value];
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const list1 = []; // to be setted
|
|
403
|
+
const list2 = []; // to be added
|
|
404
|
+
for (const item of value) {
|
|
405
|
+
if (isUndefinedOrNull(item)) {
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
if (isStringOrNumber(item)) {
|
|
409
|
+
list1.push(item);
|
|
410
|
+
} else if (item instanceof Model) {
|
|
411
|
+
list1.push(item);
|
|
412
|
+
} else if (item.sequelize) {
|
|
413
|
+
list1.push(item);
|
|
414
|
+
} else if (typeof item === 'object') {
|
|
415
|
+
list2.push(item);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// associate targets in lists1
|
|
420
|
+
await model[setAccessor](list1, { transaction, context });
|
|
421
|
+
|
|
422
|
+
const list3 = [];
|
|
423
|
+
for (const item of list2) {
|
|
424
|
+
const pk = association.target.primaryKeyAttribute;
|
|
425
|
+
|
|
426
|
+
const through = (<any>association).through ? (<any>association).through.model.name : null;
|
|
427
|
+
|
|
428
|
+
const accessorOptions = {
|
|
429
|
+
context,
|
|
430
|
+
transaction,
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
const throughValue = item[through];
|
|
434
|
+
|
|
435
|
+
if (throughValue) {
|
|
436
|
+
accessorOptions['through'] = throughValue;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (isUndefinedOrNull(item[pk])) {
|
|
440
|
+
// create new record
|
|
441
|
+
const instance = await model[createAccessor](item, accessorOptions);
|
|
442
|
+
await updateAssociations(instance, item, {
|
|
443
|
+
...options,
|
|
444
|
+
transaction,
|
|
445
|
+
associationContext: association,
|
|
446
|
+
updateAssociationValues: keys,
|
|
447
|
+
});
|
|
448
|
+
list3.push(instance);
|
|
449
|
+
} else {
|
|
450
|
+
// set & update record
|
|
451
|
+
const instance = await association.target.findByPk<any>(item[pk], {
|
|
452
|
+
transaction,
|
|
453
|
+
});
|
|
454
|
+
const addAccessor = association.accessors.add;
|
|
455
|
+
|
|
456
|
+
await model[addAccessor](item[pk], accessorOptions);
|
|
457
|
+
if (updateAssociationValues.includes(key)) {
|
|
458
|
+
await instance.update(item, { ...options, transaction });
|
|
459
|
+
}
|
|
460
|
+
await updateAssociations(instance, item, {
|
|
461
|
+
...options,
|
|
462
|
+
transaction,
|
|
463
|
+
associationContext: association,
|
|
464
|
+
updateAssociationValues: keys,
|
|
465
|
+
});
|
|
466
|
+
list3.push(instance);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
model.setDataValue(key, list1.concat(list3));
|
|
471
|
+
if (!options.transaction) {
|
|
472
|
+
await transaction.commit();
|
|
473
|
+
}
|
|
474
|
+
} catch (error) {
|
|
475
|
+
await transaction.rollback();
|
|
476
|
+
throw error;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import lodash from 'lodash';
|
|
2
|
+
import { ModelCtor } from 'sequelize';
|
|
3
|
+
import { Model } from './model';
|
|
4
|
+
import { AssociationKeysToBeUpdate, BlackList, WhiteList } from './repository';
|
|
5
|
+
|
|
6
|
+
type UpdateValueItem = string | number | UpdateValues;
|
|
7
|
+
|
|
8
|
+
type UpdateValues = {
|
|
9
|
+
[key: string]: UpdateValueItem | Array<UpdateValueItem>;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
type UpdateAction = 'create' | 'update';
|
|
13
|
+
export class UpdateGuard {
|
|
14
|
+
model: ModelCtor<any>;
|
|
15
|
+
action: UpdateAction;
|
|
16
|
+
private associationKeysToBeUpdate: AssociationKeysToBeUpdate;
|
|
17
|
+
private blackList: BlackList;
|
|
18
|
+
private whiteList: WhiteList;
|
|
19
|
+
|
|
20
|
+
setAction(action: UpdateAction) {
|
|
21
|
+
this.action = action;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
setModel(model: ModelCtor<any>) {
|
|
25
|
+
this.model = model;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
setAssociationKeysToBeUpdate(associationKeysToBeUpdate: AssociationKeysToBeUpdate) {
|
|
29
|
+
if (this.action == 'create') {
|
|
30
|
+
this.associationKeysToBeUpdate = Object.keys(this.model.associations);
|
|
31
|
+
} else {
|
|
32
|
+
this.associationKeysToBeUpdate = associationKeysToBeUpdate;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
setWhiteList(whiteList: WhiteList) {
|
|
37
|
+
this.whiteList = whiteList;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
setBlackList(blackList: BlackList) {
|
|
41
|
+
this.blackList = blackList;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Sanitize values by whitelist blacklist
|
|
46
|
+
* @param values
|
|
47
|
+
*/
|
|
48
|
+
sanitize(values: UpdateValues) {
|
|
49
|
+
values = lodash.clone(values);
|
|
50
|
+
|
|
51
|
+
if (!this.model) {
|
|
52
|
+
throw new Error('please set model first');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const associations = this.model.associations;
|
|
56
|
+
const associationsValues = lodash.pick(values, Object.keys(associations));
|
|
57
|
+
|
|
58
|
+
// build params of association update guard
|
|
59
|
+
const listOfAssociation = (list, association) => {
|
|
60
|
+
if (list) {
|
|
61
|
+
list = list
|
|
62
|
+
.filter((whiteListKey) => whiteListKey.startsWith(`${association}.`))
|
|
63
|
+
.map((whiteListKey) => whiteListKey.replace(`${association}.`, ''));
|
|
64
|
+
|
|
65
|
+
if (list.length == 0) {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return list;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return undefined;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// sanitize association values
|
|
76
|
+
Object.keys(associationsValues).forEach((association) => {
|
|
77
|
+
let associationValues = associationsValues[association];
|
|
78
|
+
|
|
79
|
+
const filterAssociationToBeUpdate = (value) => {
|
|
80
|
+
const associationKeysToBeUpdate = this.associationKeysToBeUpdate || [];
|
|
81
|
+
|
|
82
|
+
if (associationKeysToBeUpdate.includes(association)) {
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const associationObj = associations[association];
|
|
87
|
+
|
|
88
|
+
const associationKeyName =
|
|
89
|
+
associationObj.associationType == 'BelongsTo' || associationObj.associationType == 'HasOne'
|
|
90
|
+
? (<any>associationObj).targetKey
|
|
91
|
+
: associationObj.target.primaryKeyAttribute;
|
|
92
|
+
|
|
93
|
+
if (value[associationKeyName]) {
|
|
94
|
+
return lodash.pick(value, [associationKeyName, ...Object.keys(associationObj.target.associations)]);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return value;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const sanitizeValue = (value) => {
|
|
101
|
+
const associationUpdateGuard = new UpdateGuard();
|
|
102
|
+
associationUpdateGuard.setModel(associations[association].target);
|
|
103
|
+
|
|
104
|
+
['whiteList', 'blackList', 'associationKeysToBeUpdate'].forEach((optionKey) => {
|
|
105
|
+
associationUpdateGuard[`set${lodash.upperFirst(optionKey)}`](listOfAssociation(this[optionKey], association));
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
return associationUpdateGuard.sanitize(filterAssociationToBeUpdate(value));
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
if (Array.isArray(associationValues)) {
|
|
112
|
+
associationValues = associationValues.map((value) => {
|
|
113
|
+
if (typeof value == 'string' || typeof value == 'number') {
|
|
114
|
+
return value;
|
|
115
|
+
} else {
|
|
116
|
+
return sanitizeValue(value);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
} else if (typeof associationValues === 'object' && associationValues !== null) {
|
|
120
|
+
associationValues = sanitizeValue(associationValues);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// set association values to sanitized value
|
|
124
|
+
values[association] = associationValues;
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
if (values instanceof Model) {
|
|
128
|
+
return values;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let valuesKeys = Object.keys(values || {});
|
|
132
|
+
|
|
133
|
+
// handle whitelist
|
|
134
|
+
if (this.whiteList) {
|
|
135
|
+
valuesKeys = valuesKeys.filter((valueKey) => {
|
|
136
|
+
return (
|
|
137
|
+
this.whiteList.findIndex((whiteKey) => {
|
|
138
|
+
const keyPaths = whiteKey.split('.');
|
|
139
|
+
return keyPaths[0] === valueKey;
|
|
140
|
+
}) !== -1
|
|
141
|
+
);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// handle blacklist
|
|
146
|
+
if (this.blackList) {
|
|
147
|
+
valuesKeys = valuesKeys.filter((valueKey) => !this.blackList.includes(valueKey));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const result = valuesKeys.reduce((obj, key) => {
|
|
151
|
+
lodash.set(obj, key, values[key]);
|
|
152
|
+
return obj;
|
|
153
|
+
}, {});
|
|
154
|
+
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
static fromOptions(model, options) {
|
|
159
|
+
const guard = new UpdateGuard();
|
|
160
|
+
guard.setModel(model);
|
|
161
|
+
guard.setWhiteList(options.whitelist);
|
|
162
|
+
guard.setBlackList(options.blacklist);
|
|
163
|
+
guard.setAction(lodash.get(options, 'action', 'update'));
|
|
164
|
+
guard.setAssociationKeysToBeUpdate(options.updateAssociationValues);
|
|
165
|
+
return guard;
|
|
166
|
+
}
|
|
167
|
+
}
|