diff --git a/.changeset/real-ears-cheat.md b/.changeset/real-ears-cheat.md index 5aaa32d9053..ef1dc9d4646 100644 --- a/.changeset/real-ears-cheat.md +++ b/.changeset/real-ears-cheat.md @@ -1,6 +1,5 @@ --- '@keystone-next/fields': major -'@keystone-next/adapter-mongoose-legacy': major '@keystone-next/fields-legacy': major --- diff --git a/.changeset/tame-points-provide.md b/.changeset/tame-points-provide.md new file mode 100644 index 00000000000..524e1174449 --- /dev/null +++ b/.changeset/tame-points-provide.md @@ -0,0 +1,13 @@ +--- +'@keystone-next/example-ecommerce': patch +'@keystone-next/example-roles': patch +'@keystone-next/admin-ui': patch +'@keystone-next/fields': patch +'@keystone-next/keystone': patch +'@keystone-next/fields-legacy': patch +'@keystone-next/test-utils-legacy': patch +'@keystone-next/api-tests-legacy': patch +'@keystone-next/benchmarks-legacy': patch +--- + +Removed the `adapters-mongoose-legacy` packages dependency. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 569fb6c5e7f..3bfd28d5829 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -57,11 +57,11 @@ While not every changeset is going to need a huge amount of detail, a good idea - WHY the change was made - HOW a consumer should update their code -An example, if you generate a changeset that includes `adapter-mongoose` as a patch, and `keystone` as a minor, you can merge your PR, and the next time the `version-packages` command is run, these will both be updated. +An example, if you generate a changeset that includes `adapter-prisma` as a patch, and `keystone` as a minor, you can merge your PR, and the next time the `version-packages` command is run, these will both be updated. ```md --- -'@keystone-next/adapter-mongoose-legacy': patch +'@keystone-next/adapter-prisma-legacy': patch '@keystone-next/keystone-legacy': minor --- diff --git a/STYLE_GUIDE.md b/STYLE_GUIDE.md index 6a97c04642e..d3cc710fb0c 100644 --- a/STYLE_GUIDE.md +++ b/STYLE_GUIDE.md @@ -33,7 +33,7 @@ Also, it should go without saying: - Ensure correct spelling; spell-check documents before committing. (We _favour_ UK/Australian spelling.) -- Ensure correct capitalisation, inc. product names and acronyms (eg: JavaScript, URL, Node.js, MongoDB). +- Ensure correct capitalisation, inc. product names and acronyms (eg: JavaScript, URL, Node.js). Note, _abbreviations_ like "etc.", "ie." and "eg." are not acronyms; they should only be capitalised if at the start of a sentence. - Ensure correct English grammar (or Miss Willings will come for you 👩🏼‍🏫). diff --git a/examples-next/README.md b/examples-next/README.md index 50732202260..5dae80a2288 100644 --- a/examples-next/README.md +++ b/examples-next/README.md @@ -12,7 +12,6 @@ To run the projects locally: - Clone this repo - Run `yarn` in the root (this repo is a monorepo and uses yarn workspaces, so that will install everything you'll need) -- Make sure you have a local mongo server up and running on the default port - Open one of the example project folders in your terminal and run `yarn dev` If everything works 🤞 the GraphQL Server and Admin UI will start on [localhost:3000](http://localhost:3000) diff --git a/examples-next/ecommerce/README.md b/examples-next/ecommerce/README.md index fdd93ce9517..863113f1cd7 100644 --- a/examples-next/ecommerce/README.md +++ b/examples-next/ecommerce/README.md @@ -14,7 +14,6 @@ To run the project locally: - Clone this repo - Run `yarn` in the root (this repo is a monorepo and uses yarn workspaces, so that will install everything you'll need) -- Make sure you have a local mongo server up and running on the default port - Open this folder in your terminal and run `yarn dev` If everything works 🤞 the GraphQL Server and Admin UI will start on [localhost:3000](http://localhost:3000) diff --git a/examples-next/roles/README.md b/examples-next/roles/README.md index 6a10a0391bf..babc4d3dec2 100644 --- a/examples-next/roles/README.md +++ b/examples-next/roles/README.md @@ -16,7 +16,6 @@ To run the project locally: - Clone this repo - Run `yarn` in the root (this repo is a monorepo and uses yarn workspaces, so that will install everything you'll need) -- Make sure you have a local mongo server up and running on the default port - Open this folder in your terminal and run `yarn dev` If everything works 🤞 the GraphQL Server and Admin UI will start on [localhost:3000](http://localhost:3000) diff --git a/packages-next/admin-ui/TODO.md b/packages-next/admin-ui/TODO.md index 7ee08f5355c..4ed0e6e9459 100644 --- a/packages-next/admin-ui/TODO.md +++ b/packages-next/admin-ui/TODO.md @@ -12,7 +12,6 @@ - [ ] Add an example that implements custom fields - [x] `idField` option - [x] autoIncrement in fields package - - [x] mongoId in fields package - [x] `idField` option - [x] disallow `id` field in fields object - [x] default `idField` to `autoIncrement` for Prisma with fieldMode: 'hidden' for itemView and createView diff --git a/packages-next/fields/src/types/autoIncrement/tests/test-fixtures.ts b/packages-next/fields/src/types/autoIncrement/tests/test-fixtures.ts index a5040f18fab..ceb87286c84 100644 --- a/packages-next/fields/src/types/autoIncrement/tests/test-fixtures.ts +++ b/packages-next/fields/src/types/autoIncrement/tests/test-fixtures.ts @@ -15,8 +15,7 @@ export const fieldName = 'orderNumber'; export const skipCreateTest = false; export const skipUpdateTest = true; -// `AutoIncrement` field type is not supported by `mongoose`. So, we need to filter it out while performing `API` tests. -export const unSupportedAdapterList = ['mongoose', 'prisma_sqlite']; +export const unSupportedAdapterList = ['prisma_sqlite']; // Be default, `AutoIncrement` are read-only. But for `isRequired` test purpose, we need to bypass these restrictions. export const fieldConfig = (matrixValue: MatrixValue) => ({ diff --git a/packages-next/keystone/package.json b/packages-next/keystone/package.json index 337d888463b..24a977a362c 100644 --- a/packages-next/keystone/package.json +++ b/packages-next/keystone/package.json @@ -27,7 +27,6 @@ "@types/express": "^4.17.11", "@types/fs-extra": "^9.0.9", "@types/graphql-upload": "^8.0.4", - "@types/keystonejs__adapter-mongoose": "^5.1.2", "@types/keystonejs__keystone": "^7.0.1", "@types/pluralize": "^0.0.29", "@types/prettier": "^2.2.3", diff --git a/packages/adapter-mongoose/.npmignore b/packages/adapter-mongoose/.npmignore deleted file mode 100644 index 851b108d115..00000000000 --- a/packages/adapter-mongoose/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -**/*.md -**/*.test.js diff --git a/packages/adapter-mongoose/CHANGELOG.md b/packages/adapter-mongoose/CHANGELOG.md deleted file mode 100644 index 7456493350c..00000000000 --- a/packages/adapter-mongoose/CHANGELOG.md +++ /dev/null @@ -1,870 +0,0 @@ -# @keystonejs/adapter-mongoose - -## 11.1.3 - -### Patch Changes - -- Updated dependencies [[`e944b1ebb`](https://github.com/keystonejs/keystone/commit/e944b1ebbede95500b06028c591ee8947278a479), [`ca1be4156`](https://github.com/keystonejs/keystone/commit/ca1be415663dd822b3adda1e073bd7a1d4a9b97b), [`7ae452ad1`](https://github.com/keystonejs/keystone/commit/7ae452ad144d1186225e94ff39be0eaf9983f585), [`97609a623`](https://github.com/keystonejs/keystone/commit/97609a623334fd8d7b9e24dd099abda2e2a37853), [`45272d0b1`](https://github.com/keystonejs/keystone/commit/45272d0b1dc68e6ae8dbc4cfda790b3a50cf1b25), [`ade638de0`](https://github.com/keystonejs/keystone/commit/ade638de07142e8ecd0c3bf6c805eed76fd89878), [`2a1fc416e`](https://github.com/keystonejs/keystone/commit/2a1fc416e8f0a83e108a72fcec81b380c601f3ef), [`9e78d8818`](https://github.com/keystonejs/keystone/commit/9e78d88187d8d789e5f080fd4529742f54ff1ddd), [`5510ae33f`](https://github.com/keystonejs/keystone/commit/5510ae33fb18d42e378a00f1f78b803fb01b3fad), [`4d405390c`](https://github.com/keystonejs/keystone/commit/4d405390c0f8dcc37e6fe4da7ce3866c699088f3), [`b36758a12`](https://github.com/keystonejs/keystone/commit/b36758a121c096e8776420949c77a5304957a969), [`fe9fc5e0d`](https://github.com/keystonejs/keystone/commit/fe9fc5e0de8cefb889624e43bc281ac408bcd3b8), [`b8cd13fdf`](https://github.com/keystonejs/keystone/commit/b8cd13fdfcec645140a06b0331b240583eace061), [`32578f01e`](https://github.com/keystonejs/keystone/commit/32578f01e70ea972d438a29fa1e3793c1e02750b)]: - - @keystone-next/keystone-legacy@22.0.0 - - @keystone-next/utils-legacy@8.0.0 - - @keystone-next/fields-mongoid-legacy@10.0.0 - -## 11.1.2 - -### Patch Changes - -- [#5150](https://github.com/keystonejs/keystone/pull/5150) [`3a9d20ce1`](https://github.com/keystonejs/keystone/commit/3a9d20ce11463e7f73f6b6325375cdcee17d63ed) Thanks [@timleslie](https://github.com/timleslie)! - Applied eslint `import/order` rule. - -- Updated dependencies [[`8e9b04ecd`](https://github.com/keystonejs/keystone/commit/8e9b04ecd07d9c5d0e6aead4705e7a655498ae05), [`3a9d20ce1`](https://github.com/keystonejs/keystone/commit/3a9d20ce11463e7f73f6b6325375cdcee17d63ed), [`2bccf71b1`](https://github.com/keystonejs/keystone/commit/2bccf71b152a9be65a2df6a9751f1d7a382041ae), [`a4002b045`](https://github.com/keystonejs/keystone/commit/a4002b045b3e783971c382f9373159c04845beeb), [`4ac9148a0`](https://github.com/keystonejs/keystone/commit/4ac9148a0fa5b302d50e0ca4293206e2ef3616b7), [`bafdcb7bd`](https://github.com/keystonejs/keystone/commit/bafdcb7bdcba641bb8a00689a2bcefed10f4d890)]: - - @keystone-next/keystone-legacy@21.0.0 - - @keystone-next/fields-mongoid-legacy@9.1.7 - -## 11.1.1 - -### Patch Changes - -- Updated dependencies [[`b44f07b6a`](https://github.com/keystonejs/keystone/commit/b44f07b6a7ce1eef6d41513096eadea5aa2be5f7), [`c45cbb9b1`](https://github.com/keystonejs/keystone/commit/c45cbb9b14010b3ced7ea012f3502998ba2ec393), [`b4b276cf6`](https://github.com/keystonejs/keystone/commit/b4b276cf66f90dce2d711c144c0d99c4752f1f5e), [`ab14e7043`](https://github.com/keystonejs/keystone/commit/ab14e70435ef89cf702d407c90396eca53bc3f4d), [`7ad7430dc`](https://github.com/keystonejs/keystone/commit/7ad7430dc377f79f7ad4024879ec2966ba0d185f)]: - - @keystone-next/utils-legacy@7.0.0 - - @keystone-next/keystone-legacy@20.0.0 - - @keystone-next/fields-mongoid-legacy@9.1.6 - -## 11.1.0 - -### Minor Changes - -- [`5d565ea57`](https://github.com/keystonejs/keystone/commit/5d565ea57853713458329b823bde7a38776b02bc) [#4892](https://github.com/keystonejs/keystone/pull/4892) Thanks [@timleslie](https://github.com/timleslie)! - Added support for configuring the field to use for `search` filtering via the `searchField` list adapter config option. - -### Patch Changes - -- [`f4e4498c6`](https://github.com/keystonejs/keystone/commit/f4e4498c6e4c7301288f23048f4aad3c492985c7) [#5018](https://github.com/keystonejs/keystone/pull/5018) Thanks [@bladey](https://github.com/bladey)! - Updated legacy packages to the @keystone-next namespace. - -- Updated dependencies [[`f4e4498c6`](https://github.com/keystonejs/keystone/commit/f4e4498c6e4c7301288f23048f4aad3c492985c7), [`6f985acc7`](https://github.com/keystonejs/keystone/commit/6f985acc775d6037ac69a01215f962285de78c75), [`4eb4753e4`](https://github.com/keystonejs/keystone/commit/4eb4753e45e5a6ca37bdc756aef7adda7f551da4), [`891cd490a`](https://github.com/keystonejs/keystone/commit/891cd490a17026f4af29f0ed9b9ca411747d1d63), [`a16d2cbff`](https://github.com/keystonejs/keystone/commit/a16d2cbffd9aa57d0cbdd783ff5ff0c699ff2d8b), [`5d565ea57`](https://github.com/keystonejs/keystone/commit/5d565ea57853713458329b823bde7a38776b02bc)]: - - @keystone-next/fields-mongoid-legacy@9.1.5 - - @keystone-next/keystone-legacy@19.3.0 - - @keystone-next/utils-legacy@6.0.2 - -## 11.0.1 - -### Patch Changes - -- [`a0931858e`](https://github.com/keystonejs/keystone/commit/a0931858e499d9504e4e822b850dcf89c3cdac60) [#4768](https://github.com/keystonejs/keystone/pull/4768) Thanks [@kschingiz](https://github.com/kschingiz)! - Created indexes for relation adjacency collection fields - -- Updated dependencies [[`4035218df`](https://github.com/keystonejs/keystone/commit/4035218df390beff3d42c0d3fc21335230d8a60d), [`8d0be8a89`](https://github.com/keystonejs/keystone/commit/8d0be8a89e2d9b89826365f81f47b8d8863b93d0)]: - - @keystonejs/keystone@19.2.0 - - @keystonejs/fields-mongoid@9.1.4 - -## 11.0.0 - -### Major Changes - -- [`749d1c86c`](https://github.com/keystonejs/keystone/commit/749d1c86c89690ef10014a4a0a12641eb24bfe1d) [#4709](https://github.com/keystonejs/keystone/pull/4709) Thanks [@timleslie](https://github.com/timleslie)! - Database adapters no longer support custom `ListAdapter` classes via the `listAdapterClass` option of `adapterConfig` in `createList()`. - -### Patch Changes - -- Updated dependencies [[`749d1c86c`](https://github.com/keystonejs/keystone/commit/749d1c86c89690ef10014a4a0a12641eb24bfe1d), [`588be9ea1`](https://github.com/keystonejs/keystone/commit/588be9ea16ab5fb6e74f844b917ca8aeb91a9ac9), [`94c8d349d`](https://github.com/keystonejs/keystone/commit/94c8d349d3795cd9abec407f78752417623ee56f)]: - - @keystonejs/keystone@19.0.0 - - @keystonejs/utils@6.0.1 - - @keystonejs/fields-mongoid@9.1.3 - -## 10.1.2 - -### Patch Changes - -- Updated dependencies [[`3b7a056bb`](https://github.com/keystonejs/keystone/commit/3b7a056bb835482ceb408a70bf97300741552d19), [`b76241695`](https://github.com/keystonejs/keystone/commit/b7624169554b01dba2185ef43856a223d32f12be), [`4768fbf83`](https://github.com/keystonejs/keystone/commit/4768fbf831ffff648e540c479a1954ae40e05aaa), [`74a8528ea`](https://github.com/keystonejs/keystone/commit/74a8528ea0dad739f4f16af32fe4f8926a188b61)]: - - @keystonejs/keystone@18.1.0 - - @keystonejs/utils@6.0.0 - -## 10.1.1 - -### Patch Changes - -- [`cf2819544`](https://github.com/keystonejs/keystone/commit/cf2819544426def260ada5eb18fdc9b8a01e9438) [#4591](https://github.com/keystonejs/keystone/pull/4591) Thanks [@timleslie](https://github.com/timleslie)! - Reverted query optimisations which introduced regressions in `10.1.0`. - -- Updated dependencies [[`1200c3562`](https://github.com/keystonejs/keystone/commit/1200c356272ae8deea9da4267ce62c1449498e95), [`1200c3562`](https://github.com/keystonejs/keystone/commit/1200c356272ae8deea9da4267ce62c1449498e95)]: - - @keystonejs/keystone@18.0.0 - -## 10.1.0 - -### Minor Changes - -- [`364ac9254`](https://github.com/keystonejs/keystone/commit/364ac9254735befd2d4804789bb62464bb51ee5b) [#4516](https://github.com/keystonejs/keystone/pull/4516) Thanks [@renovate](https://github.com/apps/renovate)! - Updated dependency mongoose to `^5.11.5`. - -* [`d329f07a5`](https://github.com/keystonejs/keystone/commit/d329f07a5ce7ebf5d658a7f90334ba4372a2a72d) [#4536](https://github.com/keystonejs/keystone/pull/4536) Thanks [@timleslie](https://github.com/timleslie)! - Improved performance of generated queries. Thanks to @enhancers for the code contribution and @gautamsi for leading the discussion. - -### Patch Changes - -- Updated dependencies []: - - @keystonejs/fields-mongoid@9.1.1 - -## 10.0.1 - -### Patch Changes - -- [`2d660b2a1`](https://github.com/keystonejs/keystone/commit/2d660b2a1dd013787e022cad3a0c70dbe08c60da) [#3580](https://github.com/keystonejs/keystone/pull/3580) Thanks [@renovate](https://github.com/apps/renovate)! - Updated dependency `mongoose` to `^5.10.11`. - -- Updated dependencies [[`3dd5c570a`](https://github.com/keystonejs/keystone/commit/3dd5c570a27d0795a689407d96fc9623c90a66df)]: - - @keystonejs/keystone@17.1.1 - - @keystonejs/fields-mongoid@9.0.1 - -## 10.0.0 - -### Major Changes - -- [`e5efd0ef3`](https://github.com/keystonejs/keystone/commit/e5efd0ef3d6943534cb6c728afe5dbf0caf43e74) [#3684](https://github.com/keystonejs/keystone/pull/3684) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Make `id` field on GraphQL output type non-nullable when using the default id field type - -### Patch Changes - -- Updated dependencies [[`e5efd0ef3`](https://github.com/keystonejs/keystone/commit/e5efd0ef3d6943534cb6c728afe5dbf0caf43e74)]: - - @keystonejs/fields-mongoid@9.0.0 - -## 9.0.8 - -### Patch Changes - -- [`966b5bc70`](https://github.com/keystonejs/keystone/commit/966b5bc7003e0f580528c4dcd46647cc4124b592) [#3737](https://github.com/keystonejs/keystone/pull/3737) Thanks [@renovate](https://github.com/apps/renovate)! - Updated dependency `mongodb-memory-server-core` to `^6.8.0`. - -* [`cc56990f2`](https://github.com/keystonejs/keystone/commit/cc56990f2e9a4ecf0c112362e8d472b9286f76bc) [#3596](https://github.com/keystonejs/keystone/pull/3596) Thanks [@renovate](https://github.com/apps/renovate)! - Updated dev dependency `pluralize` to `^8.0.0`. - -* Updated dependencies [[`f70c9f1ba`](https://github.com/keystonejs/keystone/commit/f70c9f1ba7452b54a15ab71943a3777d5b6dade4), [`df0687184`](https://github.com/keystonejs/keystone/commit/df068718456d23819a7cae491870be4560b2010d), [`cc56990f2`](https://github.com/keystonejs/keystone/commit/cc56990f2e9a4ecf0c112362e8d472b9286f76bc)]: - - @keystonejs/fields-mongoid@8.0.0 - - @keystonejs/keystone@17.0.0 - -## 9.0.7 - -### Patch Changes - -- [`06dffc42b`](https://github.com/keystonejs/keystone/commit/06dffc42b08062e3166880146c8fb606493ead12) [#3682](https://github.com/keystonejs/keystone/pull/3682) Thanks [@renovate](https://github.com/apps/renovate)! - Updated dependency `mongodb-memory-server-core` to `^6.7.6`. - -* [`7a1f8bbdc`](https://github.com/keystonejs/keystone/commit/7a1f8bbdcdf68c9579e17db77fa826e811abcab4) [#3645](https://github.com/keystonejs/keystone/pull/3645) Thanks [@timleslie](https://github.com/timleslie)! - Removed dependency on `@keystonejs/mongo-join-builder`, which is no longer maintained. - -- [`6f42b0a9d`](https://github.com/keystonejs/keystone/commit/6f42b0a9d231049f9e7523eb78ec621d9c9d6df9) [#3678](https://github.com/keystonejs/keystone/pull/3678) Thanks [@timleslie](https://github.com/timleslie)! - Converted `pluralize` into a `devDependency` as it's only used for testing. - -* [`5c1e55721`](https://github.com/keystonejs/keystone/commit/5c1e5572134fa93c9aefbb537676e30cafd0e7d9) [#3651](https://github.com/keystonejs/keystone/pull/3651) Thanks [@renovate](https://github.com/apps/renovate)! - Updated dependency `mongodb` to `^3.6.2`. - -- [`7956d5da0`](https://github.com/keystonejs/keystone/commit/7956d5da00197dc11f5d54f7870b8fa72c05a3c0) [#3653](https://github.com/keystonejs/keystone/pull/3653) Thanks [@renovate](https://github.com/apps/renovate)! - Updated dependency `mongodb-memory-server-core` to `^6.7.5`. - -- Updated dependencies [[`83007be79`](https://github.com/keystonejs/keystone/commit/83007be798ebd751d7eb708cde366dc35999af72), [`38e3ad9c3`](https://github.com/keystonejs/keystone/commit/38e3ad9c3e7124d06f11c7046821c857cf7f9ad2), [`304701d7c`](https://github.com/keystonejs/keystone/commit/304701d7c23e98c8dc40c0f3f5512a0370107c06), [`7a1f8bbdc`](https://github.com/keystonejs/keystone/commit/7a1f8bbdcdf68c9579e17db77fa826e811abcab4), [`d95010eea`](https://github.com/keystonejs/keystone/commit/d95010eea35f40274f412dad5c2fed6b16ae6c60), [`104232785`](https://github.com/keystonejs/keystone/commit/104232785aac856be6a3ba55f8fa0fd8357237ed)]: - - @keystonejs/keystone@16.0.0 - -## 9.0.6 - -### Patch Changes - -- Updated dependencies [[`4f6883dc3`](https://github.com/keystonejs/keystone/commit/4f6883dc38962805f96256f9fdf42fb77bb3326a), [`d7eac6629`](https://github.com/keystonejs/keystone/commit/d7eac662956fc2dffd9ea5cfedf60e51ecc1b80d), [`65ecf8c98`](https://github.com/keystonejs/keystone/commit/65ecf8c9821abe42fd3714e182d8a79bb8e129aa), [`77aa2d7d1`](https://github.com/keystonejs/keystone/commit/77aa2d7d156a83759a7f3c26e8c5bd019966b054), [`d07f6bfb6`](https://github.com/keystonejs/keystone/commit/d07f6bfb6b3bd65036c2030d2758abdf4eca1a9e), [`74ad0cf7a`](https://github.com/keystonejs/keystone/commit/74ad0cf7a1a08d7665575c13da9cfb0e5a692f22)]: - - @keystonejs/fields-mongoid@7.0.3 - - @keystonejs/keystone@15.0.0 - - @keystonejs/mongo-join-builder@8.0.0 - -## 9.0.5 - -### Patch Changes - -- [`b3aa85031`](https://github.com/keystonejs/keystone/commit/b3aa850311cbc1622568f69f9cb4b9f46ab9db22) [#3519](https://github.com/keystonejs/keystone/pull/3519) Thanks [@renovate](https://github.com/apps/renovate)! - Updated dependency `mongoose` to `~5.9.29`. - -* [`16fba3b98`](https://github.com/keystonejs/keystone/commit/16fba3b98271410e570a370f610da7cd0686f294) [#3550](https://github.com/keystonejs/keystone/pull/3550) Thanks [@timleslie](https://github.com/timleslie)! - Removed unused dependencies. - -* Updated dependencies [[`cd15192cd`](https://github.com/keystonejs/keystone/commit/cd15192cdae5e476f64a257c196ca569a9440d5a), [`7bfdb79ee`](https://github.com/keystonejs/keystone/commit/7bfdb79ee43235418f098e5fe7412968dcf6c397), [`6c97a5534`](https://github.com/keystonejs/keystone/commit/6c97a5534e8a18d15aeac8b0471810fdd4d04f80), [`2498cf010`](https://github.com/keystonejs/keystone/commit/2498cf010adc4c707b69637cc2f3fa6a29c8ae29), [`2e6a06202`](https://github.com/keystonejs/keystone/commit/2e6a06202299b36c36fd3efd895f2280479eac31), [`3b619327b`](https://github.com/keystonejs/keystone/commit/3b619327b3801501b96b9af04ec6ca90e9ad9469), [`d71f98791`](https://github.com/keystonejs/keystone/commit/d71f987917509a206b1e0a994dbc6641a7cf4e06), [`28b88abd3`](https://github.com/keystonejs/keystone/commit/28b88abd369f0df12eae72107db7c24323eda4b5)]: - - @keystonejs/keystone@14.0.2 - - @keystonejs/fields-mongoid@7.0.2 - - @keystonejs/mongo-join-builder@7.1.3 - -## 9.0.4 - -### Patch Changes - -- [`6cb4476ff`](https://github.com/keystonejs/keystone/commit/6cb4476ff15923933862c1cd7d4b1ade794106c6) [#3481](https://github.com/keystonejs/keystone/pull/3481) Thanks [@Noviny](https://github.com/Noviny)! - Updated dependencies through a major version - this shouldn't require change by consumers. - -- Updated dependencies [[`6cb4476ff`](https://github.com/keystonejs/keystone/commit/6cb4476ff15923933862c1cd7d4b1ade794106c6), [`5935b89f8`](https://github.com/keystonejs/keystone/commit/5935b89f8862b36f14d09da68f056f759a860f3e), [`64eba4894`](https://github.com/keystonejs/keystone/commit/64eba4894175360b269104276a8ee5da7f8b5bc3), [`877a5a90d`](https://github.com/keystonejs/keystone/commit/877a5a90d608f0a13b6c0ea103cb96e3ac2caacc), [`483b20ec5`](https://github.com/keystonejs/keystone/commit/483b20ec53ff89f1d026c0495fdae5df60a7cf59), [`ea367f759`](https://github.com/keystonejs/keystone/commit/ea367f7594f47efc3528d9917cce010b3a16bf4d), [`7f04d9dd2`](https://github.com/keystonejs/keystone/commit/7f04d9dd21ad792b540d9e0a5d83356c091597ad)]: - - @keystonejs/keystone@14.0.1 - - @keystonejs/utils@5.4.3 - - @keystonejs/fields-mongoid@7.0.1 - -## 9.0.3 - -### Patch Changes - -- Updated dependencies [[`25f50dadc`](https://github.com/keystonejs/keystone/commit/25f50dadc07d888de18d485244c84d17462dce2e), [`d38c9174f`](https://github.com/keystonejs/keystone/commit/d38c9174f8146ad6e268be87cf5d54d5074bc593), [`f714ac1e2`](https://github.com/keystonejs/keystone/commit/f714ac1e2c49ef44d756e35042bdb7da6db589a7), [`c243839c1`](https://github.com/keystonejs/keystone/commit/c243839c12abc8cffe8ff788fe57dcb880dc3a41)]: - - @keystonejs/keystone@14.0.0 - - @keystonejs/fields-mongoid@7.0.0 - -## 9.0.2 - -### Patch Changes - -- [`7e78ffdaa`](https://github.com/keystonejs/keystone/commit/7e78ffdaa96050e49e8e2678a3c4f1897fedae4f) [#3400](https://github.com/keystonejs/keystone/pull/3400) Thanks [@timleslie](https://github.com/timleslie)! - Restricted `mongoose` to the version range `~5.9.11` to avoid a [bug](https://github.com/keystonejs/keystone/issues/3397) in `5.10.0`. - -- Updated dependencies [[`0369985e3`](https://github.com/keystonejs/keystone/commit/0369985e320afd6112f2664f8a8edc1ed7167130)]: - - @keystonejs/keystone@13.1.1 - -## 9.0.1 - -### Patch Changes - -- Updated dependencies [[`af5171563`](https://github.com/keystonejs/keystone/commit/af51715637433bcdd2538835c98ac71a8eb86122), [`271f1a40b`](https://github.com/keystonejs/keystone/commit/271f1a40b97e03aaa00ce920a6515b8f18669428), [`22b4a5c1a`](https://github.com/keystonejs/keystone/commit/22b4a5c1a13c3cca47190467be9d56e836f180f1), [`7da9d67d7`](https://github.com/keystonejs/keystone/commit/7da9d67d7d481c44a81406c6b34540a3f0a8340d), [`afe661e60`](https://github.com/keystonejs/keystone/commit/afe661e607539df13584d460e1016ba0fa883cb8), [`04f9be03d`](https://github.com/keystonejs/keystone/commit/04f9be03de7fe82035205379208511c6e49890b3), [`ef7074977`](https://github.com/keystonejs/keystone/commit/ef70749775ce1565eafd7f94c3d7438c8ebd474e), [`e07c42d4e`](https://github.com/keystonejs/keystone/commit/e07c42d4ec75d5703bec4a2e419a42d18bed90ca), [`5a3849806`](https://github.com/keystonejs/keystone/commit/5a3849806d00e62b722461d02f6e4639bc45c1eb), [`086b6baec`](https://github.com/keystonejs/keystone/commit/086b6baecdb8730bd7ae7001a96ae881fb13bac2)]: - - @keystonejs/keystone@13.0.0 - - @keystonejs/mongo-join-builder@7.1.2 - - @keystonejs/fields-mongoid@6.0.3 - -## 9.0.0 - -### Major Changes - -- [`c9ca62876`](https://github.com/keystonejs/keystone/commit/c9ca628765f1ecb599c8556de2d31567ddf12504) [#3223](https://github.com/keystonejs/keystone/pull/3223) Thanks [@timleslie](https://github.com/timleslie)! - Adapters must now be explicitly configured with a connection string. A default based on the project name is no longer used. See the docs for [`adapter-knex`](/packages/adapter-knex/README.md) and [`adapter-mongoose`](/packages/adapter-mongoose/README.md). - -### Patch Changes - -- Updated dependencies [[`5ad84ccd8`](https://github.com/keystonejs/keystone/commit/5ad84ccd8d008188e293629e90a4d7e7fde55333), [`61cdafe20`](https://github.com/keystonejs/keystone/commit/61cdafe20e0a22b5a1f9b6a2dcc4aefa45a26902), [`8480f889a`](https://github.com/keystonejs/keystone/commit/8480f889a492d83ee805f19877d49fd112117939), [`49984caae`](https://github.com/keystonejs/keystone/commit/49984caaec803ed86b027c9634ac6b3f671e9ba7), [`02f069f0b`](https://github.com/keystonejs/keystone/commit/02f069f0b6e28ccfe6d5cdeb59ab01bde27a655e), [`e114894d1`](https://github.com/keystonejs/keystone/commit/e114894d1bbcea8940cf14486fc336aa8d112da7), [`5fc97cbf4`](https://github.com/keystonejs/keystone/commit/5fc97cbf4489587a3a8cb38c04ba81fc2cb1fc5a), [`56e1798d6`](https://github.com/keystonejs/keystone/commit/56e1798d6815723cfba01e6d7dc6b4fe73d4447b), [`06f86c6f5`](https://github.com/keystonejs/keystone/commit/06f86c6f5c573411f0efda565a269d1d7ccb3c66), [`283839cfb`](https://github.com/keystonejs/keystone/commit/283839cfb84f80818dd85699e011eee4775e550d), [`81b4df318`](https://github.com/keystonejs/keystone/commit/81b4df3182fc63c583e3fae5c05c528b678cab95), [`e6909b003`](https://github.com/keystonejs/keystone/commit/e6909b0037c9d3dc4fc6131da7968a424ce02be9), [`3ce644d5f`](https://github.com/keystonejs/keystone/commit/3ce644d5f2b6e674adb2f155c0e729536079347a), [`622cc7d69`](https://github.com/keystonejs/keystone/commit/622cc7d6976ecb71f5b135c931ac0fcb4afdb1c7)]: - - @keystonejs/keystone@12.0.0 - - @keystonejs/mongo-join-builder@7.1.1 - - @keystonejs/fields-mongoid@6.0.2 - -## 8.1.3 - -### Patch Changes - -- [`835866e1a`](https://github.com/keystonejs/keystone/commit/835866e1a2954113d809c9f0bac186485ac6212b) [#3133](https://github.com/keystonejs/keystone/pull/3133) Thanks [@timleslie](https://github.com/timleslie)! - Fixed bug with deleting items in lists with a one-to-many one-sided relationship. - -- Updated dependencies [[`8df24d2ab`](https://github.com/keystonejs/keystone/commit/8df24d2ab4bed8a7fc1a856c20a571781dd7c04e), [`33046a66f`](https://github.com/keystonejs/keystone/commit/33046a66f33a82cf099880303b44d9736344667d), [`7c38e2671`](https://github.com/keystonejs/keystone/commit/7c38e267143491f38699326f02764f40f337d416)]: - - @keystonejs/keystone@11.0.0 - -## 8.1.2 - -### Patch Changes - -- Updated dependencies [[`4104e1f15`](https://github.com/keystonejs/keystone/commit/4104e1f15c545c05f680e8d16413862e875ca57a), [`ea9608342`](https://github.com/keystonejs/keystone/commit/ea960834262cec66f52fa39c1b3b07b702b3cd4d), [`cbfc67470`](https://github.com/keystonejs/keystone/commit/cbfc6747011329f7210e79ebe228f44ed8607321), [`aacc4a7f8`](https://github.com/keystonejs/keystone/commit/aacc4a7f8f88c242ae4bd784330d25056842d3fb), [`3204ae785`](https://github.com/keystonejs/keystone/commit/3204ae78576b0ab5649d5f5ae9cfbb1def347af1), [`4b06157be`](https://github.com/keystonejs/keystone/commit/4b06157be6cffde2d88969823f7c410fefd82317), [`839666e25`](https://github.com/keystonejs/keystone/commit/839666e25d8bffefd034e6344e11d72dd43b925b), [`64c0d68ac`](https://github.com/keystonejs/keystone/commit/64c0d68acb1ee969097a8fe59b5c296473790c5c), [`b696b2acb`](https://github.com/keystonejs/keystone/commit/b696b2acbf7def8dba41f46ccef5ff852703b95a), [`d970580e1`](https://github.com/keystonejs/keystone/commit/d970580e14904ba2f2ac5e969257e71f77ab67d7)]: - - @keystonejs/keystone@10.0.0 - - @keystonejs/fields-mongoid@6.0.0 - - @keystonejs/logger@5.1.2 - -## 8.1.1 - -### Patch Changes - -- [`63e00d80`](https://github.com/keystonejs/keystone/commit/63e00d805f3653863002befdaeda74c711f36f6b) [#2973](https://github.com/keystonejs/keystone/pull/2973) Thanks [@timleslie](https://github.com/timleslie)! - Fixed a bug which could lead to data loss (knex adapter only) when deleting items from a list which was the `1` side of a `1:N` relationship. - -## 8.1.0 - -### Minor Changes - -- [`9bad0e5f`](https://github.com/keystonejs/keystone/commit/9bad0e5fe67d2379537f4cb145058c6c809b3533) [#2660](https://github.com/keystonejs/keystone/pull/2660) Thanks [@Vultraz](https://github.com/Vultraz)! - Added new `sortBy` query argument. - - Each list now has an additional `SortBy` enum type that represents the valid sorting options for all orderable fields in the list. `sortBy` takes one or more of these enum types, allowing for multi-field/column sorting. - -### Patch Changes - -- [`e765ad20`](https://github.com/keystonejs/keystone/commit/e765ad20abae9838f64b72b7d43767ec87db336a) [#2866](https://github.com/keystonejs/keystone/pull/2866) Thanks [@Vultraz](https://github.com/Vultraz)! - Updated mongodb and mongoose dependencies to latest version. - -- Updated dependencies [[`12126788`](https://github.com/keystonejs/keystone/commit/121267885eb3e279eb5b6d035568f547323dd245), [`e0e3e30a`](https://github.com/keystonejs/keystone/commit/e0e3e30a9051741de3f5a0c12ba00f2238d54800), [`c8e52f3b`](https://github.com/keystonejs/keystone/commit/c8e52f3ba892269922c1ed3af0c2114f07387704), [`2a1e4f49`](https://github.com/keystonejs/keystone/commit/2a1e4f49d7f234c49e5b04440ff786ddf3e9e7ed), [`9e2e0071`](https://github.com/keystonejs/keystone/commit/9e2e00715aff50f2ddfedf3dbc14f390275ff23b), [`b5c44934`](https://github.com/keystonejs/keystone/commit/b5c4493442c5e4cfeba23c058a9a6819c628aab9), [`0fbc5b98`](https://github.com/keystonejs/keystone/commit/0fbc5b989a9f96248d1bd7f2f589fe77cb1d8f7d), [`da1359df`](https://github.com/keystonejs/keystone/commit/da1359dfc1bff7e27505eff876efe3a0865bae2d), [`60e2c7eb`](https://github.com/keystonejs/keystone/commit/60e2c7eb2298a016c68a19a056040a3b45beab2a), [`9bad0e5f`](https://github.com/keystonejs/keystone/commit/9bad0e5fe67d2379537f4cb145058c6c809b3533), [`e765ad20`](https://github.com/keystonejs/keystone/commit/e765ad20abae9838f64b72b7d43767ec87db336a)]: - - @keystonejs/keystone@9.0.0 - - @keystonejs/utils@5.4.1 - - @keystonejs/fields-mongoid@5.1.9 - - @keystonejs/mongo-join-builder@7.1.0 - -## 8.0.2 - -### Patch Changes - -- [`875aa0ed`](https://github.com/keystonejs/keystone/commit/875aa0ed787d901061aa0409160a360546014df3) [#2796](https://github.com/keystonejs/keystone/pull/2796) Thanks [@timleslie](https://github.com/timleslie)! - Fixed a bug with updating one-to-one relationship values. - -- Updated dependencies [[`78fda9d7`](https://github.com/keystonejs/keystone/commit/78fda9d7b9a090240c946553cc42ba0bf6b8a88c)]: - - @keystonejs/fields-mongoid@5.1.7 - -## 8.0.1 - -### Patch Changes - -- [`c1345884`](https://github.com/keystonejs/keystone/commit/c134588491c73fabbd5186df1787bce5aec5c7c7) [#2666](https://github.com/keystonejs/keystone/pull/2666) Thanks [@timleslie](https://github.com/timleslie)! - Removed a stray `console.log()`. - -## 8.0.0 - -### Major Changes - -- [`fd685241`](https://github.com/keystonejs/keystone/commit/fd68524135025e4d800b4a98932916736dd50e9d) [#2000](https://github.com/keystonejs/keystone/pull/2000) Thanks [@timleslie](https://github.com/timleslie)! - ## Release - Arcade - - This release introduces a **new and improved data schema** for Keystone. - The new data schema simplifies the way your data is stored and will unlock the development of new functionality within Keystone. - - > **Important:** You will need to make changes to your database to take advantage of the new data schema. Please read the full [release notes](https://www.keystonejs.com/discussions/new-data-schema) for instructions on updating your database. - -### Patch Changes - -- Updated dependencies [[`fd685241`](https://github.com/keystonejs/keystone/commit/fd68524135025e4d800b4a98932916736dd50e9d)]: - - @keystonejs/keystone@8.0.0 - - @keystonejs/mongo-join-builder@7.0.0 - - @keystonejs/fields-mongoid@5.1.6 - -## 7.0.0 - -### Major Changes - -- [`2ae2bd47`](https://github.com/keystonejs/keystone/commit/2ae2bd47eb54a816cfd4c8cd178c460729cbc258) [#2623](https://github.com/keystonejs/keystone/pull/2623) Thanks [@maryam-mv](https://github.com/maryam-mv)! - Updated @sindresorhus/slugify to fix a problem where it was producing unexpected output, eg. adding unexpected underscores: 'NAME1 Website' => 'nam_e1_website'. The slugify output for db name may be different with this change. For the above example, the output will now be 'name_1_website' for the same string. - - If your database name changes unexpectedly, you can add an environment variable called `DATABASE_URL` with a full path to the database. For more information on configuring database connections read the documentation for the [Knex adapter](https://v5.keystonejs.com/keystonejs/adapter-knex/#knexoptions) or [Mongoose adapter](https://v5.keystonejs.com/keystonejs/adapter-mongoose/#mongoose-database-adapter). - - If you are using the `Slug` field type, in some edge-cases, slugs may change when saved after this update. You can use the `generate` option on the slug field for [custom slug generation](https://v5.keystonejs.com/keystonejs/fields/src/types/slug/#custom-generate-method) if required. - -### Patch Changes - -- [`c08c28d2`](https://github.com/keystonejs/keystone/commit/c08c28d22f2c6a2bfa73ab0ea347c9e0da8a9063) [#2593](https://github.com/keystonejs/keystone/pull/2593) Thanks [@jossmac](https://github.com/jossmac)! - Applied a more consistent voice throughout documentation. - -- Updated dependencies [[`4a7d1eab`](https://github.com/keystonejs/keystone/commit/4a7d1eabf9b44fac7e16dfe20afdce409986e8dc), [`cef28dfd`](https://github.com/keystonejs/keystone/commit/cef28dfdad332cf185a577b06600acc3d8ba4888), [`c08c28d2`](https://github.com/keystonejs/keystone/commit/c08c28d22f2c6a2bfa73ab0ea347c9e0da8a9063), [`2cbd38b0`](https://github.com/keystonejs/keystone/commit/2cbd38b05adc98cface11a8767f66b48a1cb0bbf), [`3407fa68`](https://github.com/keystonejs/keystone/commit/3407fa68b91d7ebb3e7288c7e95631013fe12535), [`c2b1b725`](https://github.com/keystonejs/keystone/commit/c2b1b725a9474348964a4ac2e0f5b4aaf1a7f486)]: - - @keystonejs/keystone@7.1.0 - - @keystonejs/fields-mongoid@5.1.5 - -## 6.0.0 - -### Major Changes - -- [`cec7ba5e`](https://github.com/keystonejs/keystone/commit/cec7ba5e2061280eff2a1d989054ecb02760e36d) [#2544](https://github.com/keystonejs/keystone/pull/2544) Thanks [@timleslie](https://github.com/timleslie)! - Removed the `prepareFieldAdapter()` method of `BaseListAdapter`, `MongooseAdapter` and `KnexListAdapter`. No action is required unless you were explicitly using this method in your code. - -### Minor Changes - -- [`ca28681c`](https://github.com/keystonejs/keystone/commit/ca28681ca23c74bc57041fa36c20b93a4520e762) [#2543](https://github.com/keystonejs/keystone/pull/2543) Thanks [@timleslie](https://github.com/timleslie)! - `BaseKeystoneAdapter.connect` and `BaseKeystoneAdapter.postConnect` both now accept a `rels` argument, which provides information about the relationships in the system. - -### Patch Changes - -- Updated dependencies [[`b6a555c2`](https://github.com/keystonejs/keystone/commit/b6a555c28296394908757f7404b72bc6b828b52a), [`ca28681c`](https://github.com/keystonejs/keystone/commit/ca28681ca23c74bc57041fa36c20b93a4520e762), [`68be8f45`](https://github.com/keystonejs/keystone/commit/68be8f452909100fbddec431d6fe60c20a06a700), [`61a70503`](https://github.com/keystonejs/keystone/commit/61a70503f6c184a8f0f5440466399f12e6d7fa41), [`cec7ba5e`](https://github.com/keystonejs/keystone/commit/cec7ba5e2061280eff2a1d989054ecb02760e36d), [`663ae7b4`](https://github.com/keystonejs/keystone/commit/663ae7b453f450f077795fbbc6c9f138e6b27f52)]: - - @keystonejs/keystone@7.0.0 - - @keystonejs/utils@5.4.0 - - @keystonejs/fields-mongoid@5.1.4 - -## 5.2.2 - -### Patch Changes - -- [`83bdf743`](https://github.com/keystonejs/keystone/commit/83bdf743748e39d1ea73eff2c8e3576cc713c624) [#2538](https://github.com/keystonejs/keystone/pull/2538) Thanks [@Vultraz](https://github.com/Vultraz)! - Updated mongo dependencies to latest version. - -- Updated dependencies [[`51546e41`](https://github.com/keystonejs/keystone/commit/51546e4142fb8c66cfc413479c671a59618f885b), [`83bdf743`](https://github.com/keystonejs/keystone/commit/83bdf743748e39d1ea73eff2c8e3576cc713c624), [`d30b7498`](https://github.com/keystonejs/keystone/commit/d30b74984b21ae9fc2a3b39850f674639fbac074), [`8f22ab5e`](https://github.com/keystonejs/keystone/commit/8f22ab5eefc034f9fef4fd0f9ec2c2583fc5514f), [`599c0929`](https://github.com/keystonejs/keystone/commit/599c0929b213ebd4beb79e3ccaa685b92348ca81), [`fb510d67`](https://github.com/keystonejs/keystone/commit/fb510d67ab124d8c1bda1884fa2a0d48262b5e4d)]: - - @keystonejs/utils@5.3.0 - - @keystonejs/keystone@6.0.2 - - @keystonejs/mongo-join-builder@6.1.3 - -## 5.2.1 - -### Patch Changes - -- [`5ba330b8`](https://github.com/keystonejs/keystone/commit/5ba330b8b2609ea0033a636daf9a215a5a192c20) [#2487](https://github.com/keystonejs/keystone/pull/2487) Thanks [@Noviny](https://github.com/Noviny)! - Small changes to package.json (mostly adding a repository field) - -- Updated dependencies [[`10e88dc3`](https://github.com/keystonejs/keystone/commit/10e88dc3d81f5e021db0bfb31f7547852c602c14), [`e46f0adf`](https://github.com/keystonejs/keystone/commit/e46f0adf97141e1f1205787453173a0585df5bc3), [`6975f169`](https://github.com/keystonejs/keystone/commit/6975f16959bde3fe0e861977471c94a8c9f2c0b0), [`42497b8e`](https://github.com/keystonejs/keystone/commit/42497b8ebbaeaf0f4d7881dbb76c6abafde4cace), [`97fb01fe`](https://github.com/keystonejs/keystone/commit/97fb01fe5a32f5003a084c1fd357852fc28f74e4), [`6111e065`](https://github.com/keystonejs/keystone/commit/6111e06554a6aa6db0f7df1a6c16f9da8e81fce4), [`2d1069f1`](https://github.com/keystonejs/keystone/commit/2d1069f11f5f8941b0a18e482541043c853ebb4f), [`949f2f6a`](https://github.com/keystonejs/keystone/commit/949f2f6a3889492015281ffba45a8b3d37e6d888), [`6b353eff`](https://github.com/keystonejs/keystone/commit/6b353effc8b617137a3978b2c845e01403889722), [`5ba330b8`](https://github.com/keystonejs/keystone/commit/5ba330b8b2609ea0033a636daf9a215a5a192c20)]: - - @keystonejs/keystone@6.0.0 - - @keystonejs/fields-mongoid@5.1.2 - - @keystonejs/logger@5.1.1 - - @keystonejs/mongo-join-builder@6.1.2 - - @keystonejs/utils@5.2.2 - -## 5.2.0 - -### Minor Changes - -- [`517b23e4`](https://github.com/keystonejs/keystone/commit/517b23e4b17414ed1807e8d7af1e67377ba3b7bf) [#2391](https://github.com/keystonejs/keystone/pull/2391) Thanks [@timleslie](https://github.com/timleslie)! - Removed support for Node 8.x, as it is [no longer in maintenance mode](https://nodejs.org/en/about/releases/). - -### Patch Changes - -- Updated dependencies [[`517b23e4`](https://github.com/keystonejs/keystone/commit/517b23e4b17414ed1807e8d7af1e67377ba3b7bf)]: - - @keystonejs/fields-mongoid@5.1.0 - - @keystonejs/keystone@5.5.0 - - @keystonejs/logger@5.1.0 - - @keystonejs/mongo-join-builder@6.1.0 - - @keystonejs/utils@5.2.0 - -## 5.1.5 - -### Patch Changes - -- [`a34f1f72`](https://github.com/keystonejs/keystone/commit/a34f1f72613d1b7c79309ffe04fae0a79baa7737) [#2251](https://github.com/keystonejs/keystone/pull/2251) - Uses the new `mongo-join-builder` API. -- Updated dependencies [[`a34f1f72`](https://github.com/keystonejs/keystone/commit/a34f1f72613d1b7c79309ffe04fae0a79baa7737), [`7123e226`](https://github.com/keystonejs/keystone/commit/7123e226e13d3629b2ce7b6746c4292af9bf79e1)]: - - @keystonejs/mongo-join-builder@6.0.0 - -## 5.1.4 - -### Patch Changes - -- [`ef419b59`](https://github.com/keystonejs/keystone/commit/ef419b59729a050f25fc886be6ec8ce17cbb1104) [#2191](https://github.com/keystonejs/keystone/pull/2191) - Upgraded `mongoose` to `^5.8.4` and `mongodb` to `^3.4.1`. -- Updated dependencies [[`38f88b62`](https://github.com/keystonejs/keystone/commit/38f88b62d9592d91b56528d4d9c40e9399440c4a), [`f3ea15f8`](https://github.com/keystonejs/keystone/commit/f3ea15f86f7bbd08abddcf3a63c5c66e86693d29), [`3d7222cd`](https://github.com/keystonejs/keystone/commit/3d7222cd589ce8accbf3a9de141976c38e2c7e23), [`ef419b59`](https://github.com/keystonejs/keystone/commit/ef419b59729a050f25fc886be6ec8ce17cbb1104), [`05d07adf`](https://github.com/keystonejs/keystone/commit/05d07adf84059ff565cd2394f68d71d92e657485), [`78193f9c`](https://github.com/keystonejs/keystone/commit/78193f9c9d93655fb0d4b8dc494fbe4c622a4d64)]: - - @keystonejs/fields-mongoid@5.0.3 - - @keystonejs/utils@5.1.3 - - @keystonejs/keystone@5.4.1 - - @keystonejs/mongo-join-builder@5.0.2 - -## 5.1.3 - -### Patch Changes - -- [`5540771e`](https://github.com/keystonejs/keystone/commit/5540771e52b5cb1aa33c0486dede7f2f9bc0944f) [#2006](https://github.com/keystonejs/keystone/pull/2006) Thanks [@timleslie](https://github.com/timleslie)! - Consolidated implementation of all `listAdapter.find\*()` methods to use the `itemsQuery()` API for internal consistency. -- Updated dependencies [[`77056ebd`](https://github.com/keystonejs/keystone/commit/77056ebdb31e58d27372925e8e24311a8c7d9e33), [`733ac847`](https://github.com/keystonejs/keystone/commit/733ac847cab488dc92a30e7b458191d750fd5a3d), [`e68fc43b`](https://github.com/keystonejs/keystone/commit/e68fc43ba006f9c958f9c81ae20b230d05c2cab6), [`d4d89836`](https://github.com/keystonejs/keystone/commit/d4d89836700413c1da2b76e9b82b649c2cac859d), [`946a52fd`](https://github.com/keystonejs/keystone/commit/946a52fd7057bb73f4ffd465ef51498172926866), [`5540771e`](https://github.com/keystonejs/keystone/commit/5540771e52b5cb1aa33c0486dede7f2f9bc0944f), [`1f4dc33d`](https://github.com/keystonejs/keystone/commit/1f4dc33d8a5ac4e38427eb215a7a8bc3504ae153), [`ee6fbcb2`](https://github.com/keystonejs/keystone/commit/ee6fbcb264a640f58332c50a2f502a4380c0d071), [`6a348b93`](https://github.com/keystonejs/keystone/commit/6a348b93607c305c4ba61c1406a4acd508f33f64)]: - - @keystonejs/keystone@5.3.0 - - @keystonejs/fields-mongoid@5.0.1 - -## 5.1.2 - -### Patch Changes - -- [`734471e7`](https://github.com/keystonejs/keystone/commit/734471e747375ac0331255a66154d119a9bfe842) [#1926](https://github.com/keystonejs/keystone/pull/1926) Thanks [@timleslie](https://github.com/timleslie)! - Removed `mongoose-unique-validator` due to upstream bug (https://github.com/blakehaswell/mongoose-unique-validator/issues/97). - -## 5.1.1 - -### Patch Changes - -- [`ba8aef71`](https://github.com/keystonejs/keystone/commit/ba8aef71d1a04f643fb7f7590d7d6d136b1d4eba) [#1857](https://github.com/keystonejs/keystone/pull/1857) Thanks [@Vultraz](https://github.com/Vultraz)! - Deployed `mongoose-unique-validator` for a more readable error message when unique checks fail. -- Updated dependencies [[`45fd7ab8`](https://github.com/keystonejs/keystone/commit/45fd7ab899655364d0071c0d276d188378944ff5), [`b0756c65`](https://github.com/keystonejs/keystone/commit/b0756c65525625919c72364d8cefc32d864c7c0e), [`d132a3c6`](https://github.com/keystonejs/keystone/commit/d132a3c64aec707b98ed9a9ceffee44a98749b0a)]: - - @keystonejs/keystone@5.1.1 - -## 5.1.0 - -### Minor Changes - -- [`9f6bcddd`](https://github.com/keystonejs/keystone/commit/9f6bcddd84cc1d60f139ca116e9006258e417469) [#1851](https://github.com/keystonejs/keystone/pull/1851) Thanks [@jesstelford](https://github.com/jesstelford)! - Added runtime database version validation - -### Patch Changes - -- [`31b646ac`](https://github.com/keystonejs/keystone/commit/31b646ac3c06b82e809f5e55e8443ae5d21dac0f) [#1837](https://github.com/keystonejs/keystone/pull/1837) Thanks [@timleslie](https://github.com/timleslie)! - Updated mongo-related dependencies - -- Updated dependencies [[`9f6bcddd`](https://github.com/keystonejs/keystone/commit/9f6bcddd84cc1d60f139ca116e9006258e417469), [`31b646ac`](https://github.com/keystonejs/keystone/commit/31b646ac3c06b82e809f5e55e8443ae5d21dac0f), [`e4a19e3f`](https://github.com/keystonejs/keystone/commit/e4a19e3f3e261ef476aee61d24dd2639eaf61881)]: - - @keystonejs/keystone@5.1.0 - - @keystonejs/utils@5.1.0 - - @keystonejs/mongo-join-builder@5.0.1 - -## 5.0.1 - -### Patch Changes - -- [`3c19cddd`](https://github.com/keystonejs/keystone/commit/3c19cddd0b8b8d1e17385a01a813a9e84ec14bb5) [#1838](https://github.com/keystonejs/keystone/pull/1838) Thanks [@jesstelford](https://github.com/jesstelford)! - Adding a new Relationship field when using the Mongoose adapter will no longer - cause an "\$in needs an array" error to be thrown. - -## 5.0.0 - -### Major Changes - -- [`7b4ed362`](https://github.com/keystonejs/keystone/commit/7b4ed3623f5774d7783c39962bfa1ce97938e310) [#1821](https://github.com/keystonejs/keystone/pull/1821) Thanks [@jesstelford](https://github.com/jesstelford)! - Release @keystonejs/\* packages (つ^ ◡ ^)つ - - - This is the first release of `@keystonejs/*` packages (previously `@keystone-alpha/*`). - - All packages in the `@keystone-alpha` namespace are now available in the `@keystonejs` namespace, starting at version `5.0.0`. - - To upgrade your project you must update any `@keystone-alpha/*` dependencies in `package.json` to point to `"@keystonejs/*": "^5.0.0"` and update any `require`/`import` statements in your code. - -### Patch Changes - -- Updated dependencies [[`7b4ed362`](https://github.com/keystonejs/keystone/commit/7b4ed3623f5774d7783c39962bfa1ce97938e310)]: - - @keystonejs/fields-mongoid@5.0.0 - - @keystonejs/keystone@5.0.0 - - @keystonejs/logger@5.0.0 - - @keystonejs/mongo-join-builder@5.0.0 - - @keystonejs/utils@5.0.0 - -# @keystone-alpha/adapter-mongoose - -## 6.0.1 - -### Patch Changes - -- [`768420f5`](https://github.com/keystonejs/keystone/commit/768420f567c244d57a4e2a3aaafe628ea9813d9d) [#1781](https://github.com/keystonejs/keystone/pull/1781) Thanks [@simonswiss](https://github.com/simonswiss)! - changing require path to "@keystone-alpha" instead of "@keystonejs" - -- Updated dependencies [[`0a36b0f4`](https://github.com/keystonejs/keystone/commit/0a36b0f403da73a76106b5e14940a789466b4f94), [`3bc02545`](https://github.com/keystonejs/keystone/commit/3bc025452fb8e6e69790bdbee032ddfdeeb7dabb), [`a48281ba`](https://github.com/keystonejs/keystone/commit/a48281ba605bf5bebc89fcbb36d3e69c17182eec), [`effc1f63`](https://github.com/keystonejs/keystone/commit/effc1f639d5824720b7a9d82c2ee881d77acb901)]: - - @keystone-alpha/keystone@16.1.0 - - @keystone-alpha/fields-mongoid@1.1.6 - -## 6.0.0 - -### Major Changes - -- [`6d7d0df0`](https://github.com/keystonejs/keystone/commit/6d7d0df0515c3aa21c7d24db17919ddbb5701ce9) [#1729](https://github.com/keystonejs/keystone/pull/1729) Thanks [@timleslie](https://github.com/timleslie)! - This change significantly changes how and when we populate `many`-relationships during queries and mutations. - The behaviour of the GraphQL API has not changed, but queries should be more performant, particularly for items with many related items. - The `existingItem` parameter in hooks will no longer have the `many`-relationship fields populated. - `List.listQuery()` no longer populates `many` relationship fields. - For most users there should not need to be any changes to code unless they are explicitly relying on a `many`-relationship field in a hook, in which case they will need to execute an explicit query to obtain the desired values. - -### Patch Changes - -- Updated dependencies [[`6d7d0df0`](https://github.com/keystonejs/keystone/commit/6d7d0df0515c3aa21c7d24db17919ddbb5701ce9)]: - - @keystone-alpha/keystone@16.0.0 - - @keystone-alpha/mongo-join-builder@4.0.0 - - @keystone-alpha/fields-mongoid@1.1.5 - -## 5.0.0 - -### Major Changes - -- [b96a3a58](https://github.com/keystonejs/keystone/commit/b96a3a58): Remove `.queryBuilder` property of the `MongooseListAdapter`. - -### Patch Changes - -- [4e6a574d](https://github.com/keystonejs/keystone/commit/4e6a574d): Internal refactor to inline the logic which was previously computed by getRelationshipQueryCondition(). -- [a48ff0a3](https://github.com/keystonejs/keystone/commit/a48ff0a3): Internal refactor to move defintion of modifierConditions closer to where they're used. -- [82dfef03](https://github.com/keystonejs/keystone/commit/82dfef03): Move tokenizer functions out of this package and into `mongo-join-builder`. - -- Updated dependencies [da4013e4](https://github.com/keystonejs/keystone/commit/da4013e4): -- Updated dependencies [157a439d](https://github.com/keystonejs/keystone/commit/157a439d): - - @keystone-alpha/mongo-join-builder@3.0.0 - -## 4.0.8 - -### Patch Changes - -- [9b532072](https://github.com/keystonejs/keystone/commit/9b532072): Rename Keystone to KeystoneJS in docs where possible in docs -- [a7a9249b](https://github.com/keystonejs/keystone/commit/a7a9249b): Internal refactor - -## 4.0.7 - -- Updated dependencies [42a45bbd](https://github.com/keystonejs/keystone/commit/42a45bbd): - - @keystone-alpha/keystone@15.1.0 - -## 4.0.6 - -- Updated dependencies [b61289b4](https://github.com/keystonejs/keystone/commit/b61289b4): -- Updated dependencies [0bba9f07](https://github.com/keystonejs/keystone/commit/0bba9f07): -- Updated dependencies [9ade2b2d](https://github.com/keystonejs/keystone/commit/9ade2b2d): - - @keystone-alpha/keystone@15.0.0 - - @keystone-alpha/fields-mongoid@1.1.2 - -## 4.0.5 - -### Patch Changes - -- [a7ac4264](https://github.com/keystonejs/keystone/commit/a7ac4264): Enabled useUnifiedTopology to address deprecation warning - -- Updated dependencies [decf7319](https://github.com/keystonejs/keystone/commit/decf7319): -- Updated dependencies [89c0d7e9](https://github.com/keystonejs/keystone/commit/89c0d7e9): -- Updated dependencies [a8e9378d](https://github.com/keystonejs/keystone/commit/a8e9378d): - - @keystone-alpha/keystone@14.0.0 - - @keystone-alpha/fields-mongoid@1.1.1 - -## 4.0.4 - -- Updated dependencies [8d0d98c7](https://github.com/keystonejs/keystone/commit/8d0d98c7): - - @keystone-alpha/keystone@13.0.0 - -## 4.0.3 - -- Updated dependencies [33001656](https://github.com/keystonejs/keystone/commit/33001656): - - @keystone-alpha/keystone@12.0.0 - -## 4.0.2 - -- Updated dependencies [e42fdb4a](https://github.com/keystonejs/keystone/commit/e42fdb4a): - - @keystone-alpha/keystone@11.0.0 - -## 4.0.1 - -- Updated dependencies [b86f0e26](https://github.com/keystonejs/keystone/commit/b86f0e26): - - @keystone-alpha/keystone@10.5.0 - -## 4.0.0 - -### Major Changes - -- [144e6e86](https://github.com/keystonejs/keystone/commit/144e6e86): - API Changes to Adapters: - Configs are now passed directly to the adapters rather than via `adapterConnectOptions`. - Default connections strings changed for both Knex and Mongoose adapters to be more inline with system defaults. - `keystone.connect()` no longer accepts a `to` paramter - the connection options must be passed to the adapter constructor (as above). - -## 3.0.1 - -### Patch Changes - -- [ba146456](https://github.com/keystonejs/keystone/commit/ba146456): Depend on correct version of @keystone-alpha/fields-mongoid - -## 3.0.0 - -### Major Changes - -- [42c3fbc9](https://github.com/keystonejs/keystone/commit/42c3fbc9): Adding isIndexed field config and support for in most field types -- [42c3fbc9](https://github.com/keystonejs/keystone/commit/42c3fbc9): Switching lists to use standard field types for primary keys (instead of weird pseudo-field) - -### Patch Changes - -- [42c3fbc9](https://github.com/keystonejs/keystone/commit/42c3fbc9): Upgrade to mongoose 5.6.5 - -## 2.2.1 - -- Updated dependencies [4007f5dd](https://github.com/keystonejs/keystone/commit/4007f5dd): - - @keystone-alpha/keystone@8.0.0 - -## 2.2.0 - -### Minor Changes - -- [91fffa1e](https://github.com/keystonejs/keystone/commit/91fffa1e): - - Allow transforming input types for `equalityConditionsInsensitive` & `stringConditions` methods on the MongooseAdapter. - -* Updated dependencies [91fffa1e](https://github.com/keystonejs/keystone/commit/91fffa1e): - - @keystone-alpha/keystone@7.0.0 - -## 2.1.0 - -### Minor Changes - -- [3958a9c7](https://github.com/keystonejs/keystone/commit/3958a9c7): - - Removed the isRequired parameter from MongooseFieldAdapter.buildValidator() - -### Patch Changes - -- [19fe6c1b](https://github.com/keystonejs/keystone/commit/19fe6c1b): - - Move frontmatter in docs into comments - -* Updated dependencies [1b4cf4e0](https://github.com/keystonejs/keystone/commit/1b4cf4e0): - - @keystone-alpha/keystone@6.0.0 - -## 2.0.1 - -- Updated dependencies [dfcabe6a](https://github.com/keystonejs/keystone/commit/dfcabe6a): - - @keystone-alpha/keystone@5.0.0 - -## 2.0.0 - -### Major Changes - -- [9a0456ff](https://github.com/keystonejs/keystone/commit/9a0456ff): - - Removing 'dbName' config option - -## 1.0.7 - -### Patch Changes - -- [bd0ea21f](https://github.com/keystonejs/keystone/commit/bd0ea21f): - - - Add .isRequired and .isUnique properties to field adapters - -- [81dc0be5](https://github.com/keystonejs/keystone/commit/81dc0be5): - - - Update dependencies - -- [bd0ea21f](https://github.com/keystonejs/keystone/commit/bd0ea21f): - - - `mergeSchemaOptions` now uses `this.isUnique` rather than taking it as a config paramter - -* Updated dependencies [24cd26ee](https://github.com/keystonejs/keystone/commit/24cd26ee): -* Updated dependencies [2ef2658f](https://github.com/keystonejs/keystone/commit/2ef2658f): -* Updated dependencies [ae5cf6cc](https://github.com/keystonejs/keystone/commit/ae5cf6cc): -* Updated dependencies [b22d6c16](https://github.com/keystonejs/keystone/commit/b22d6c16): -* Updated dependencies [b7a2ea9c](https://github.com/keystonejs/keystone/commit/b7a2ea9c): - - @keystone-alpha/keystone@4.0.0 - - @keystone-alpha/mongo-join-builder@2.0.1 - - @keystone-alpha/utils@3.0.0 - -## 1.0.6 - -- [patch][06464afb](https://github.com/keystonejs/keystone/commit/06464afb): - - - Simplify internal APIs - -## 1.0.5 - -- [patch][b4dcf44b](https://github.com/keystonejs/keystone/commit/b4dcf44b): - - - Use named exports from @keystone-alpha/keystone package. - -- [patch][baff3c89](https://github.com/keystonejs/keystone/commit/baff3c89): - - - Use the updated logger API - -- [patch][302930a4](https://github.com/keystonejs/keystone/commit/302930a4): - - - Minor internal code cleanups - -- [patch][2f908f30](https://github.com/keystonejs/keystone/commit/2f908f30): - - - Use the updated mongo-join-builder package API. - -- [patch][8041c67e](https://github.com/keystonejs/keystone/commit/8041c67e): - - - Restructure internal code - -- Updated dependencies [baff3c89](https://github.com/keystonejs/keystone/commit/baff3c89): -- Updated dependencies [656e90c2](https://github.com/keystonejs/keystone/commit/656e90c2): -- Updated dependencies [b4dcf44b](https://github.com/keystonejs/keystone/commit/b4dcf44b): -- Updated dependencies [2f908f30](https://github.com/keystonejs/keystone/commit/2f908f30): - - @keystone-alpha/keystone@3.0.0 - - @keystone-alpha/logger@2.0.0 - - @keystone-alpha/mongo-join-builder@2.0.0 - -## 1.0.4 - -- Updated dependencies [8d385ede](https://github.com/keystonejs/keystone/commit/8d385ede): -- Updated dependencies [52f1c47b](https://github.com/keystonejs/keystone/commit/52f1c47b): - - @keystone-alpha/keystone@2.0.0 - -## 1.0.3 - -- Updated dependencies [98c02a46](https://github.com/keystonejs/keystone/commit/98c02a46): - - @keystone-alpha/keystone@1.0.4 - - @keystone-alpha/mongo-join-builder@1.0.3 - - @keystone-alpha/utils@2.0.0 - -## 1.0.2 - -- [patch][11c372fa](https://github.com/keystonejs/keystone/commit/11c372fa): - - - Update minor-level dependencies - -- [patch][619b17c2](https://github.com/keystonejs/keystone/commit/619b17c2): - - - Reformat code using latest version of Prettier (1.16.4) - -- [patch][7417ea3a](https://github.com/keystonejs/keystone/commit/7417ea3a): - - - Update patch-level dependencies - -## 1.0.1 - -- [patch][6ba2fd99](https://github.com/keystonejs/keystone/commit/6ba2fd99): - - - Mongoose option useFindAndModify is defaulted to false, resolves deprecation warnings - -- [patch][1f0bc236](https://github.com/keystonejs/keystone/commit/1f0bc236): - - - Update the package.json author field to "The Keystone Development Team" - -- [patch][9534f98f](https://github.com/keystonejs/keystone/commit/9534f98f): - - - Add README.md to package - -## 1.0.0 - -- [major] 8b6734ae: - - - This is the first release of keystone-alpha (previously voussoir). - All packages in the `@voussoir` namespace are now available in the `@keystone-alpha` namespace, starting at version `1.0.0`. - To upgrade your project you must update any `@voussoir/` dependencies in `package.json` to point to `@keystone-alpha/: "^1.0.0"` and update any `require`/`import` statements in your code. - -# @voussoir/adapter-mongoose - -## 2.0.1 - -- [patch] 6fa810f7: - - - Rename `@voussoir/core` -> `@voussoir/keystone`. This is to free up the - `@voussoir/core` package for a different purpose, and make the main import for - new Keystone projects be `@voussoir/keystone`. The exports have stayed the - same. - -- [patch] 113e16d4: - - - Remove unused dependencies - -- [patch] b155d942: - - - Update mongo/mongoose dependencies - -## 2.0.0 - -- [minor] 5f891cff: - - - Add a setupHooks method to BaseFieldAdapter - -- [major] 53e27d75: - - - Removes methods from Mongoose adapter classes: getFieldAdapterByQueryConditionKey, getSimpleQueryConditions, getRelationshipQueryConditions, getQueryConditions, getRelationshipQueryConditions, getRefListAdapter, hasQueryCondition. - -- [patch] 797dc862: - - - Move itemsQueryMeta onto the base adapter class - -- [major] 6471fc4a: - - - Remove mapsToPath method from MongooseListAdapter - -- [major] 48773907: - - - Move findFieldAdapterForQuerySegment onto the BaseListAdapter - -- [major] 860c3b80: - - - Add a postConnect method to list adapters to capture all the work which needs to be done after the database has been connected to - -- Updated dependencies [723371a0]: -- Updated dependencies [aca26f71]: -- Updated dependencies [a3d5454d]: - - @voussoir/core@2.0.0 - - @voussoir/mongo-join-builder@0.3.2 - - @voussoir/utils@1.0.0 - -## 1.0.0 - -- [patch] 21626b66: - - - preSave/postRead item hooks run consistently - -- [patch] 929b177c: - - - Enable sorting on DateTime fields - -- [major] 01718870: - - - Field configuration now tasks isRequired and isUnique, rather than required and unique - -- [patch] fc1a9055: - - - Update dependencies to latest patch versions - -- Updated dependencies [c83c9ed5]: -- Updated dependencies [c3ebd9e6]: -- Updated dependencies [ebae2d6f]: -- Updated dependencies [78fd9555]: -- Updated dependencies [d22820b1]: - - @voussoir/core@1.0.0 - -## 0.5.0 - -- [patch] ff4b98c5: - - - Consolidate mongoose schema pre/post hooks for field types - -- [minor] 9c383fe8: - - - Always use \$set and { new: true } in the mongoose adapter update() method - -- [minor] b0d19c24: - - - Use consistent query condition builders across all field types - -- Updated dependencies [45d4c379]: - - @voussoir/core@0.7.0 - -## 0.4.1 - -- Updated dependencies [d94b517]: -- Updated dependencies [a3b995c]: - - @voussoir/core@0.6.0 - -## 0.4.0 - -- [minor] 47c7dcf6" - : - - - Bump all packages with a minor version to set a new baseline - -- Updated dependencies [d94b517]: -- Updated dependencies [a3b995c]: - - @voussoir/core@0.5.0 - -## 0.3.2 - -- Updated dependencies [d94b517]: -- Updated dependencies [a3b995c]: - - @voussoir/core@0.4.0 - -## 0.3.1 - -- [patch] Updated dependencies [74af97e](74af97e) - - @voussoir/mongo-join-builder@0.2.0 - -## 0.3.0 - -- [patch] Bump all packages for Babel config fixes [d51c833](d51c833) -- [minor] Support unique field constraint for mongoose adapter [750a83e](750a83e) -- [patch] Updated dependencies [9c75136](9c75136) - - @voussoir/core@0.3.0 - - @voussoir/mongo-join-builder@0.1.3 - - @voussoir/utils@0.2.0 - -## 0.2.0 - -- [minor] Add missing dependencies for which the mono-repo was hiding that they were missing [fed0cdc](fed0cdc) - -## 0.1.2 - -- [patch] Rename readme files [a8b995e](a8b995e) - -## 0.1.1 - -- [patch] Remove tests and markdown from npm [dc3ee7d](dc3ee7d) diff --git a/packages/adapter-mongoose/README.md b/packages/adapter-mongoose/README.md deleted file mode 100644 index 42743fb9cba..00000000000 --- a/packages/adapter-mongoose/README.md +++ /dev/null @@ -1,54 +0,0 @@ - - -# Mongoose database adapter - -[![View changelog](https://img.shields.io/badge/changelogs.xyz-Explore%20Changelog-brightgreen)](https://changelogs.xyz/@keystone-next/adapter-mongoose-legacy) - -## Usage - -```javascript -const { MongooseAdapter } = require('@keystone-next/adapter-mongoose-legacy'); - -const keystone = new Keystone({ - adapter: new MongooseAdapter({...}), -}); -``` - -## Config - -### `mongoUri` (required) - -This is used as the `uri` parameter for `mongoose.connect()`. - -_**Default:**_ Environment variable (see below) or `'mongodb://localhost/'` - -If not specified, KeystoneJS will look for one of the following environment variables: - -- `CONNECT_TO` -- `DATABASE_URL` -- `MONGO_URI` -- `MONGODB_URI` -- `MONGO_URL` -- `MONGODB_URL` -- `MONGOLAB_URI` -- `MONGOLAB_URL` - -### Mongoose options (optional) - -Additional Mongoose config options are passed directly through to `mongoose.connect()`. - -_**Default:**_ - -```javascript -{ - useNewUrlParser: true, - useFindAndModify: false, - useUnifiedTopology: true, -} -``` - -See the [Mongoose docs](https://mongoosejs.com/docs/api.html#mongoose_Mongoose-connect) for a detailed list of options. diff --git a/packages/adapter-mongoose/index.js b/packages/adapter-mongoose/index.js deleted file mode 100644 index 3ba06a84479..00000000000 --- a/packages/adapter-mongoose/index.js +++ /dev/null @@ -1,6 +0,0 @@ -const { - MongooseAdapter, - MongooseListAdapter, - MongooseFieldAdapter, -} = require('./lib/adapter-mongoose'); -module.exports = { MongooseAdapter, MongooseListAdapter, MongooseFieldAdapter }; diff --git a/packages/adapter-mongoose/lib/adapter-mongoose.js b/packages/adapter-mongoose/lib/adapter-mongoose.js deleted file mode 100644 index 389ef367051..00000000000 --- a/packages/adapter-mongoose/lib/adapter-mongoose.js +++ /dev/null @@ -1,736 +0,0 @@ -const mongoose = require('mongoose'); - -const pSettle = require('p-settle'); -const { - arrayToObject, - escapeRegExp, - pick, - omit, - getType, - mapKeys, - mapKeyNames, - identity, - mergeWhereClause, - resolveAllKeys, - versionGreaterOrEqualTo, -} = require('@keystone-next/utils-legacy'); - -const { - BaseKeystoneAdapter, - BaseListAdapter, - BaseFieldAdapter, -} = require('@keystone-next/keystone-legacy'); -const { pipelineBuilder } = require('./join-builder'); -const { queryParser } = require('./query-parser'); - -const debugMongoose = () => !!process.env.DEBUG_MONGOOSE; - -class MongooseAdapter extends BaseKeystoneAdapter { - constructor() { - super(...arguments); - this.listAdapterClass = MongooseListAdapter; - this.name = 'mongoose'; - this.mongoose = new mongoose.Mongoose(); - this.minVer = '4.0.0'; - if (debugMongoose()) { - this.mongoose.set('debug', true); - } - this._manyModels = {}; - } - - async _connect() { - const { mongoUri, ...mongooseConfig } = this.config; - // Default to the localhost instance - let uri = - mongoUri || - process.env.CONNECT_TO || - process.env.DATABASE_URL || - process.env.MONGO_URI || - process.env.MONGODB_URI || - process.env.MONGO_URL || - process.env.MONGODB_URL || - process.env.MONGOLAB_URI || - process.env.MONGOLAB_URL; - - if (!uri) { - throw new Error(`No MongoDB connection URI specified.`); - } - - await this.mongoose.connect(uri, { - useNewUrlParser: true, - useFindAndModify: false, - useUnifiedTopology: true, - ...mongooseConfig, - }); - } - async postConnect({ rels }) { - // Setup all schemas - Object.values(this.listAdapters).forEach(listAdapter => { - listAdapter.fieldAdapters.forEach(fieldAdapter => { - fieldAdapter.addToMongooseSchema(listAdapter.schema, listAdapter.mongoose, rels); - }); - }); - - // Setup models for N:N tables, I guess? - for (const rel of rels.filter(({ cardinality }) => cardinality === 'N:N')) { - await this._createAdjacencyTable(rel); - } - - // Then... - return await pSettle( - Object.values(this.listAdapters).map(listAdapter => listAdapter._postConnect({ rels })) - ); - } - - async _createAdjacencyTable({ left, tableName, columnNames }) { - const schema = new this.mongoose.Schema({}, { ...DEFAULT_MODEL_SCHEMA_OPTIONS }); - - const columnKey = `${left.listKey}.${left.path}`; - const leftFkPath = columnNames[columnKey].near; - - const rightFkPath = columnNames[columnKey].far; - - schema.add({ [leftFkPath]: {} }); - schema.add({ [rightFkPath]: {} }); - - // create 2 way indexes for reference fields - schema.index({ [leftFkPath]: 1 }); - schema.index({ [rightFkPath]: 1 }); - - // 4th param is 'skipInit' which avoids calling `model.init()`. - // We call model.init() later, after we have a connection up and running to - // avoid issues with Mongoose's lazy queue and setting up the indexes. - const model = this.mongoose.model(tableName, schema, null, true); - this._manyModels[tableName] = model; - // Ensure we wait for any new indexes to be built - await model.init(); - // Then ensure the indexes are all correct - // The indexes can become out of sync if the database was modified - // manually, or if the code has been updated. In both cases, the - // _existence_ of an index (not the configuration) will cause Mongoose - // to think everything is fine. - // So, here we must manually force mongoose to check the _configuration_ - // of the existing indexes before moving on. - // NOTE: Why bother with `model.init()` first? Because Mongoose will - // always try to create new indexes on model creation in the background, - // so we have to wait for that async process to finish before trying to - // sync up indexes. - // NOTE: There's a potential race condition here when two application - // instances both try to recreate the indexes by first dropping then - // creating. See - // http://thecodebarbarian.com/whats-new-in-mongoose-5-2-syncindexes - // NOTE: If an index has changed and needs recreating, this can have a - // performance impact when dealing with large datasets! - await model.syncIndexes(); - } - - disconnect() { - return this.mongoose.disconnect(); - } - - // This will completely drop the backing database. Use wisely. - dropDatabase() { - return this.mongoose.connection.dropDatabase(); - } - - getDefaultPrimaryKeyConfig() { - // Required here due to circular refs - return {}; - } - - async checkDatabaseVersion() { - let info; - - try { - info = await new this.mongoose.mongo.Admin(this.mongoose.connection.db).buildInfo(); - } catch (error) { - console.log(`Error reading version from MongoDB: ${error}`); - } - - if (!versionGreaterOrEqualTo(info.versionArray, this.minVer)) { - throw new Error( - `MongoDB version ${info.version} is incompatible. Version ${this.minVer} or later is required.` - ); - } - } -} - -const DEFAULT_MODEL_SCHEMA_OPTIONS = { - // Later, we run `model.syncIndexes()` to ensure the indexes specified in the - // mongoose config match what's in the database. - // `model.syncIndexes()` will fail when the collection is new (ie; hasn't had - // a write yet / doesn't exist in mongo). - // By setting `autoCreate` here, mongoose will ensure the collection exists, - // thus enabling `model.syncIndexes()` to succeed. - autoCreate: true, - - // Because we're calling `model.syncIndexes()`, we don't want Mongoose to try - // calling `model.ensureIndexes()` under the hood too soon (it can cause race - // conditions with trying to access the database before it's properly setup), - // so we turn that off now. - autoIndex: false, -}; - -class MongooseListAdapter extends BaseListAdapter { - constructor(key, parentAdapter, config) { - super(...arguments); - - const { configureMongooseSchema, mongooseSchemaOptions } = config; - - this.getListAdapterByKey = parentAdapter.getListAdapterByKey.bind(parentAdapter); - this.mongoose = parentAdapter.mongoose; - this.configureMongooseSchema = configureMongooseSchema; - this.schema = new parentAdapter.mongoose.Schema( - {}, - { ...DEFAULT_MODEL_SCHEMA_OPTIONS, ...mongooseSchemaOptions } - ); - - // Need to call postConnect() once all fields have registered and the database is connected to. - this.model = null; - - this.rels = undefined; - this.realKeys = []; - } - - /** - * Note: It's not necessary to await the result of this function - it is only - * if you want access to the underlying model should you await it. Otherwise, - * the `.connect()` method of the parent adapter will handle the awaiting. - * - * @return Promise<> - */ - async _postConnect({ rels }) { - this.rels = rels; - this.fieldAdapters.forEach(fieldAdapter => { - fieldAdapter.rel = rels.find( - ({ left, right }) => - left.adapter === fieldAdapter || (right && right.adapter === fieldAdapter) - ); - if (fieldAdapter._hasRealKeys()) { - this.realKeys.push( - ...(fieldAdapter.realKeys ? fieldAdapter.realKeys : [fieldAdapter.path]) - ); - } - }); - if (this.configureMongooseSchema) { - this.configureMongooseSchema(this.schema, { mongoose: this.mongoose }); - } - - // 4th param is 'skipInit' which avoids calling `model.init()`. - // We call model.init() later, after we have a connection up and running to - // avoid issues with Mongoose's lazy queue and setting up the indexes. - this.model = this.mongoose.model(this.key, this.schema, null, true); - this.parentAdapter._manyModels[this.key] = this.model; - // Ensure we wait for any new indexes to be built - await this.model.init(); - // Then ensure the indexes are all correct - // The indexes can become out of sync if the database was modified - // manually, or if the code has been updated. In both cases, the - // _existence_ of an index (not the configuration) will cause Mongoose - // to think everything is fine. - // So, here we must manually force mongoose to check the _configuration_ - // of the existing indexes before moving on. - // NOTE: Why bother with `model.init()` first? Because Mongoose will - // always try to create new indexes on model creation in the background, - // so we have to wait for that async process to finish before trying to - // sync up indexes. - // NOTE: There's a potential race condition here when two application - // instances both try to recreate the indexes by first dropping then - // creating. See - // http://thecodebarbarian.com/whats-new-in-mongoose-5-2-syncindexes - // NOTE: If an index has changed and needs recreating, this can have a - // performance impact when dealing with large datasets! - return this.model.syncIndexes(); - } - - _getModel(tableName) { - return this.parentAdapter._manyModels[tableName]; - } - - ////////// Mutations ////////// - - async _unsetOneToOneValues(realData) { - // If there's a 1:1 FK in the real data we need to go and - // delete it from any other item; - await Promise.all( - Object.entries(realData) - .map(([key, value]) => ({ value, adapter: this.fieldAdaptersByPath[key] })) - .filter(({ adapter }) => adapter && adapter.isRelationship) - .filter( - ({ value, adapter: { rel } }) => - rel.cardinality === '1:1' && rel.tableName === this.key && value !== null - ) - .map(({ value, adapter: { rel: { tableName, columnName } } }) => - this._setNullByValue({ tableName, columnName, value }) - ) - ); - } - - async _unsetForeignOneToOneValues(data, id) { - // If there's a 1:1 FK in the data on a different list we need to go and - // delete it from any other item; - await Promise.all( - Object.keys(data) - .map(key => ({ adapter: this.fieldAdaptersByPath[key] })) - .filter(({ adapter }) => adapter && adapter.isRelationship) - .filter(({ adapter: { rel } }) => rel.cardinality === '1:1' && rel.tableName !== this.key) - .map(({ adapter: { rel: { tableName, columnName } } }) => - this._setNullByValue({ tableName, columnName, value: id }) - ) - ); - } - - async _processNonRealFields(data, processFunction) { - return resolveAllKeys( - arrayToObject( - Object.entries(omit(data, this.realKeys)).map(([path, value]) => ({ - path, - value, - adapter: this.fieldAdaptersByPath[path], - })), - 'path', - processFunction - ) - ); - } - - _getNearFar(fieldAdapter) { - const { rel, path, listAdapter } = fieldAdapter; - const { columnNames } = rel; - const columnKey = `${listAdapter.key}.${path}`; - return columnNames[columnKey]; - } - - async _createSingle(realData) { - const item = (await this.model.create(realData)).toObject(); - - const itemId = item._id; - return { item, itemId }; - } - - async _setNullByValue({ tableName, columnName, value }) { - return this._getModel(tableName).updateMany( - { [columnName]: { $eq: value } }, - { [columnName]: null } - ); - } - - async _createOrUpdateField({ value, adapter, itemId }) { - const { cardinality, columnName, tableName } = adapter.rel; - // N:N - put it in the many table - // 1:N - put it in the FK col of the other table - // 1:1 - put it in the FK col of the other table - if (cardinality === '1:1') { - if (value !== null) { - await this._getModel(tableName).updateMany({ _id: value }, { [columnName]: itemId }); - return value; - } else { - return null; - } - } else { - const values = value; // Rename this because we have a many situation - if (values.length) { - if (cardinality === 'N:N') { - const { near, far } = this._getNearFar(adapter); - return ( - await this._getModel(tableName).create( - values.map(id => ({ - [near]: mongoose.Types.ObjectId(itemId), - [far]: mongoose.Types.ObjectId(id), - })) - ) - ).map(x => x[far]); - } else { - await this._getModel(tableName).updateMany( - { _id: { $in: values } }, - { [columnName]: itemId } - ); - return values; - } - } else { - return []; - } - } - } - - async _create(data) { - const realData = pick(data, this.realKeys); - - // Unset any real 1:1 fields - await this._unsetOneToOneValues(realData); - - // Insert the real data into the table - const { item, itemId } = await this._createSingle(realData); - - // For every non-real-field, update the corresponding FK/join table. - const manyItem = await this._processNonRealFields(data, async ({ value, adapter }) => - this._createOrUpdateField({ value, adapter, itemId }) - ); - - // This currently over-populates the returned item. - // We should only be populating non-many fields, but the non-real-fields are generally many, - // which we want to ignore, with the exception of 1:1 fields with the FK on the other table, - // which we want to actually keep! - return { ...item, ...manyItem }; - } - - async _update(id, data) { - const realData = pick(data, this.realKeys); - - // Unset any real 1:1 fields - await this._unsetOneToOneValues(realData); - await this._unsetForeignOneToOneValues(data, id); - - // Update the real data - // Avoid any kind of injection attack by explicitly doing a `$set` operation - // Return the modified item, not the original - const item = await this.model.findByIdAndUpdate( - id, - { $set: realData }, - { new: true, runValidators: true, context: 'query' } - ); - - // For every many-field, update the many-table - await this._processNonRealFields(data, async ({ path, value: newValues, adapter }) => { - const { cardinality, columnName, tableName } = adapter.rel; - let value; - // Future task: Is there some way to combine the following three - // operations into a single query? - - if (cardinality !== '1:1') { - // Work out what we've currently got - let matchCol, selectCol; - if (cardinality === 'N:N') { - const { near, far } = this._getNearFar(adapter); - matchCol = near; - selectCol = far; - } else { - matchCol = columnName; - selectCol = '_id'; - } - const currentRefIds = ( - await this._getModel(tableName).aggregate([ - { $match: { [matchCol]: mongoose.Types.ObjectId(item.id) } }, - ]) - ).map(x => x[selectCol].toString()); - - // Delete what needs to be deleted - const needsDelete = currentRefIds.filter(x => !newValues.includes(x)); - if (needsDelete.length) { - if (cardinality === 'N:N') { - await this._getModel(tableName).deleteMany({ - $and: [ - { [matchCol]: { $eq: item._id } }, - { [selectCol]: { $in: needsDelete.map(id => mongoose.Types.ObjectId(id)) } }, - ], - }); - } else { - await this._getModel(tableName).updateMany( - { [selectCol]: { $in: needsDelete.map(id => mongoose.Types.ObjectId(id)) } }, - { [columnName]: null } - ); - } - } - value = newValues.filter(id => !currentRefIds.includes(id)); - } else { - // If there are values, update the other side to point to me, - // otherwise, delete the thing that was pointing to me - if (newValues === null) { - const selectCol = columnName === path ? '_id' : columnName; - await this._setNullByValue({ tableName, columnName: selectCol, value: item.id }); - } - value = newValues; - } - await this._createOrUpdateField({ value, adapter, itemId: item.id }); - }); - return (await this._itemsQuery({ where: { id: item.id }, first: 1 }))[0] || null; - } - - async _delete(id) { - id = mongoose.Types.ObjectId(id); - // Traverse all other lists and remove references to this item - // We can't just traverse our own fields, because we might have been - // a silent partner in a relationship, so we have no self-knowledge of it. - await Promise.all( - Object.values(this.parentAdapter.listAdapters).map(adapter => - Promise.all( - adapter.fieldAdapters - .filter( - a => - a.isRelationship && - a.refListKey === this.key && - this._getModel(a.rel.tableName) !== this.model - ) // If I (a list adapter) an implicated in the .rel of this field adapter - .map(fieldAdapter => { - const { cardinality, columnName, tableName } = fieldAdapter.rel; - if (cardinality === 'N:N') { - // FIXME: There is a User <-> User case which isn't captured here. - const { far } = this._getNearFar(fieldAdapter); - return this._getModel(tableName).deleteMany({ [far]: { $eq: id } }); - } else { - return this._setNullByValue({ tableName, columnName, value: id }); - } - }) - ) - ) - ); - - // Now traverse all self-referential relationships and sort them right out. - await Promise.all( - this.rels - .filter(({ tableName, left }) => tableName === this.key && left.listKey === left.refListKey) - .map(({ columnName, tableName }) => - this._setNullByValue({ tableName, columnName, value: id }) - ) - ); - - // Delete the actual item - return this.model.deleteOne({ _id: id }).then(result => result.deletedCount); - } - - ////////// Queries ////////// - - graphQlQueryPathToMongoField(path) { - const fieldAdapter = this.fieldAdaptersByPath[path]; - - if (!fieldAdapter) { - throw new Error(`Unable to find Mongo field which maps to graphQL path ${path}`); - } - - return fieldAdapter.getMongoFieldName(); - } - - async _itemsQuery(args, { meta = false, from, include } = {}) { - if (from && Object.keys(from).length) { - const { rel } = from.fromList.adapter.fieldAdaptersByPath[from.fromField]; - const { cardinality, tableName, columnName, columnNames } = rel; - let ids = []; - if (cardinality === 'N:N') { - const a = from.fromList.adapter.fieldAdaptersByPath[from.fromField]; - const columnKey = `${from.fromList.adapter.key}.${a.path}`; - ids = await this._getModel(tableName).aggregate([ - { - $match: { - [columnNames[columnKey].near]: { $eq: mongoose.Types.ObjectId(from.fromId) }, - }, - }, - ]); - ids = ids.map(x => x[columnNames[columnKey].far]); - } else { - ids = await this._getModel(tableName).aggregate([ - { $match: { [columnName]: mongoose.Types.ObjectId(from.fromId) } }, - ]); - ids = ids.map(x => x._id); - } - - args = mergeWhereClause(args, { id: { $in: ids || [] } }); - } - // Convert the args `where` clauses and modifiers into a data structure - // which can be consumed by the queryParser. Modifiers are prefixed with a - // $ symbol (e.g. skip => $skip) to be identified by the tokenizer. - // `where` keys are removed, and nested queries are handled recursively. - // { where: { a: 'A', b: { where: { c: 'C' } } }, skip: 10 } - // => { a: 'A', b: { c: 'C' }, $skip: 10 } - const graphQlQueryToMongoJoinQuery = ({ where, ...modifiers }) => ({ - ...mapKeys(where || {}, whereElement => - getType(whereElement) === 'Object' && whereElement.where - ? graphQlQueryToMongoJoinQuery(whereElement) // Recursively traverse relationship fields - : whereElement - ), - ...mapKeyNames( - pick(modifiers, ['search', 'sortBy', 'orderBy', 'skip', 'first']), - key => `$${key}` - ), - }); - let query; - try { - query = graphQlQueryToMongoJoinQuery(args); - } catch (error) { - return Promise.reject(error); - } - if (meta) { - // Order is important here, which is why we do it last (v8 will append the - // key, and keep them stable) - query.$count = 'count'; - } - - const queryTree = queryParser({ listAdapter: this }, query, [], include); - - // 1:1 relationship magic - const lookups = []; - this.fieldAdapters - .filter(a => a.isRelationship && a.rel.cardinality === '1:1' && a.rel.right === a.field) - .forEach(a => { - const { tableName, columnName } = a.rel; - const tmpName = `__${a.path}`; - lookups.push( - { - $lookup: { - from: this._getModel(tableName).collection.name, - as: tmpName, - localField: '_id', - foreignField: columnName, - }, - }, - { $unwind: { path: `$${tmpName}`, preserveNullAndEmptyArrays: true } }, - { $addFields: { [a.path]: `$${tmpName}._id` } }, - { $project: { [tmpName]: 0 } } - ); - }); - // Run the query against the given database and collection - const pipeline = pipelineBuilder(queryTree); - const ret = await this.model - .aggregate([...pipeline, ...lookups]) - .exec() - .then(foundItems => { - if (meta) { - // When there are no items, we get undefined back, so we simulate the - // normal result of 0 items. - if (!foundItems[0]) { - return { count: 0 }; - } - return foundItems[0]; - } - return foundItems; - }); - return ret; - } -} - -class MongooseFieldAdapter extends BaseFieldAdapter { - constructor() { - super(...arguments); - - // isIndexed is mutually exclusive with isUnique - this.isUnique = !!this.config.isUnique; - this.isIndexed = !!this.config.isIndexed && !this.config.isUnique; - - // We don't currently have any mongoose-specific options - // this.mongooseOptions = this.config.mongooseOptions || {}; - } - - _hasRealKeys() { - // We don't have a "real key" (i.e. a column in the table) if: - // * We're a N:N - // * We're the right hand side of a 1:1 - // * We're the 1 side of a 1:N or N:1 (e.g we are the one with config: many) - return !( - this.isRelationship && - (this.config.many || (this.rel.cardinality === '1:1' && this.rel.right.adapter === this)) - ); - } - - addToMongooseSchema() { - throw new Error(`Field type [${this.fieldName}] does not implement addToMongooseSchema()`); - } - - buildValidator(validator) { - return a => validator(a) || typeof a === 'undefined' || a === null; - } - - mergeSchemaOptions(schemaOptions, { mongooseOptions }) { - // Applying these config to all field types is probably wrong; - // ie. unique constraints on Checkboxes, Files, etc. probably don't make sense - if (this.isUnique) { - // A value of anything other than `true` causes errors with Mongoose - // constantly recreating indexes. Ie; if we just splat `unique` onto the - // options object, it would be `undefined`, which would cause Mongoose to - // drop and recreate all indexes. - schemaOptions.unique = true; - } - if (this.isIndexed || this.isRelationship) { - schemaOptions.index = true; - } - return { ...schemaOptions, ...mongooseOptions }; - } - - // The following methods provide helpers for constructing the return values of `getQueryConditions`. - // Each method takes: - // `dbPath`: The database field/column name to be used in the comparison - // `f`: (non-string methods only) A value transformation function which converts from a string type - // provided by graphQL into a native adapter type. - equalityConditions(dbPath, f = identity) { - return { - [this.path]: value => ({ [dbPath]: { $eq: f(value) } }), - [`${this.path}_not`]: value => ({ [dbPath]: { $ne: f(value) } }), - }; - } - - equalityConditionsInsensitive(dbPath, f = identity) { - return { - [`${this.path}_i`]: value => ({ [dbPath]: new RegExp(`^${escapeRegExp(f(value))}$`, 'i') }), - [`${this.path}_not_i`]: value => ({ - [dbPath]: { $not: new RegExp(`^${escapeRegExp(f(value))}$`, 'i') }, - }), - }; - } - - inConditions(dbPath, f = identity) { - return { - [`${this.path}_in`]: value => ({ [dbPath]: { $in: value.map(s => f(s)) } }), - [`${this.path}_not_in`]: value => ({ [dbPath]: { $not: { $in: value.map(s => f(s)) } } }), - }; - } - - orderingConditions(dbPath, f = identity) { - return { - [`${this.path}_lt`]: value => ({ [dbPath]: { $lt: f(value) } }), - [`${this.path}_lte`]: value => ({ [dbPath]: { $lte: f(value) } }), - [`${this.path}_gt`]: value => ({ [dbPath]: { $gt: f(value) } }), - [`${this.path}_gte`]: value => ({ [dbPath]: { $gte: f(value) } }), - }; - } - - stringConditions(dbPath, f = identity) { - return { - [`${this.path}_contains`]: value => ({ - [dbPath]: { $regex: new RegExp(escapeRegExp(f(value))) }, - }), - [`${this.path}_not_contains`]: value => ({ - [dbPath]: { $not: new RegExp(escapeRegExp(f(value))) }, - }), - [`${this.path}_starts_with`]: value => ({ - [dbPath]: { $regex: new RegExp(`^${escapeRegExp(f(value))}`) }, - }), - [`${this.path}_not_starts_with`]: value => ({ - [dbPath]: { $not: new RegExp(`^${escapeRegExp(f(value))}`) }, - }), - [`${this.path}_ends_with`]: value => ({ - [dbPath]: { $regex: new RegExp(`${escapeRegExp(f(value))}$`) }, - }), - [`${this.path}_not_ends_with`]: value => ({ - [dbPath]: { $not: new RegExp(`${escapeRegExp(f(value))}$`) }, - }), - }; - } - - stringConditionsInsensitive(dbPath) { - const f = escapeRegExp; - return { - [`${this.path}_contains_i`]: value => ({ [dbPath]: { $regex: new RegExp(f(value), 'i') } }), - [`${this.path}_not_contains_i`]: value => ({ [dbPath]: { $not: new RegExp(f(value), 'i') } }), - [`${this.path}_starts_with_i`]: value => ({ - [dbPath]: { $regex: new RegExp(`^${f(value)}`, 'i') }, - }), - [`${this.path}_not_starts_with_i`]: value => ({ - [dbPath]: { $not: new RegExp(`^${f(value)}`, 'i') }, - }), - [`${this.path}_ends_with_i`]: value => ({ - [dbPath]: { $regex: new RegExp(`${f(value)}$`, 'i') }, - }), - [`${this.path}_not_ends_with_i`]: value => ({ - [dbPath]: { $not: new RegExp(`${f(value)}$`, 'i') }, - }), - }; - } - - getMongoFieldName() { - return this.path; - } -} - -module.exports = { - MongooseAdapter, - MongooseListAdapter, - MongooseFieldAdapter, -}; diff --git a/packages/adapter-mongoose/lib/join-builder.js b/packages/adapter-mongoose/lib/join-builder.js deleted file mode 100644 index f8507326d45..00000000000 --- a/packages/adapter-mongoose/lib/join-builder.js +++ /dev/null @@ -1,137 +0,0 @@ -const { flatten, defaultObj } = require('@keystone-next/utils-legacy'); - -/** - * Format of input object: - - type Query { - relationships: { : Relationship }, - matchTerm: Object, - postJoinPipeline: [ Object ], - } - - type Relationship: { - from: String, - field: String, - many?: Boolean, (default: true) - ...Query, - } - - eg; - { - relationships: { - abc123: { - from: 'posts-collection', - field: 'posts', - many: true, - matchTerm: { title: { $eq: 'hello' } }, - postJoinPipeline: [ - { $limit: 10 }, - ], - relationships: { - ... - }, - }, - }, - matchTerm: { $and: { - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { abc123_posts_some: { $eq: true } } - }, - postJoinPipeline: [ - { $orderBy: 'name' }, - ], - } - */ - -const lookupStage = ({ from, as, targetKey, foreignKey, extraPipeline = [] }) => ({ - $lookup: { - from, - as, - let: { tmpVar: `$${targetKey}` }, - pipeline: [{ $match: { $expr: { $eq: [`$${foreignKey}`, '$$tmpVar'] } } }, ...extraPipeline], - }, -}); - -function relationshipPipeline(relationship) { - const { from, thisTable, path, rel, filterType, uniqueField } = relationship.relationshipInfo; - const { cardinality, columnNames } = rel; - const extraPipeline = pipelineBuilder(relationship); - const extraField = `${uniqueField}_all`; - if (cardinality !== 'N:N') { - // Perform a single FK join - let targetKey, foreignKey; - // FIXME: I feel like the logic here could use some revie - if (filterType !== 'only' && rel.right && rel.left.listKey === rel.right.listKey) { - targetKey = '_id'; - foreignKey = rel.columnName; - } else { - targetKey = rel.tableName === thisTable ? rel.columnName : '_id'; - foreignKey = rel.tableName === thisTable ? '_id' : rel.columnName; - } - return [ - // Join against all the items which match the relationship filter condition - lookupStage({ from, as: uniqueField, targetKey, foreignKey, extraPipeline }), - // Match against *all* the items. Required for the _every condition. - filterType === 'every' && lookupStage({ from, as: extraField, targetKey, foreignKey }), - ]; - } else { - // Perform a pair of joins through the join table - const { farCollection } = relationship.relationshipInfo; - const columnKey = `${thisTable}.${path}`; - return [ - // Join against all the items which match the relationship filter condition - lookupStage({ - from, - as: uniqueField, - targetKey: '_id', - foreignKey: columnNames[columnKey].near, - extraPipeline: [ - lookupStage({ - from: farCollection, - as: `${uniqueField}_0`, - targetKey: columnNames[columnKey].far, - foreignKey: '_id', - extraPipeline, - }), - { $match: { $expr: { $gt: [{ $size: `$${uniqueField}_0` }, 0] } } }, - ], - }), - // Match against *all* the items. Required for the _every condition. - filterType === 'every' && - lookupStage({ - from, - as: extraField, - targetKey: '_id', - foreignKey: columnNames[columnKey].near, - extraPipeline: [ - lookupStage({ - from: farCollection, - as: `${uniqueField}_0`, - targetKey: columnNames[columnKey].far, - foreignKey: '_id', - }), - ], - }), - ]; - } -} - -function pipelineBuilder({ relationships, matchTerm, excludeFields, postJoinPipeline }) { - excludeFields.push( - ...flatten( - relationships.map(({ relationshipInfo: { uniqueField, filterType } }) => [ - uniqueField, - filterType === 'every' && `${uniqueField}_all`, - ]) - ).filter(i => i) - ); - return [ - ...flatten(relationships.map(relationshipPipeline)), - matchTerm && { $match: matchTerm }, - { $addFields: { id: '$_id' } }, - excludeFields && excludeFields.length && { $project: defaultObj(excludeFields, 0) }, - ...postJoinPipeline, // $search / $orderBy / $skip / $first / $count - ].filter(i => i); -} - -module.exports = { pipelineBuilder }; diff --git a/packages/adapter-mongoose/lib/query-parser.js b/packages/adapter-mongoose/lib/query-parser.js deleted file mode 100644 index 6a6c3abd2dd..00000000000 --- a/packages/adapter-mongoose/lib/query-parser.js +++ /dev/null @@ -1,99 +0,0 @@ -const { getType, flatten } = require('@keystone-next/utils-legacy'); - -const { simpleTokenizer, relationshipTokenizer, modifierTokenizer } = require('./tokenizers'); - -// If it's 0 or 1 items, we can use it as-is. Any more needs an $and/$or -const joinTerms = (matchTerms, joinOp) => - matchTerms.length > 1 ? { [joinOp]: matchTerms } : matchTerms[0]; - -const flattenQueries = (parsedQueries, joinOp) => ({ - matchTerm: joinTerms( - parsedQueries.map(q => q.matchTerm).filter(matchTerm => matchTerm), - joinOp - ), - postJoinPipeline: flatten(parsedQueries.map(q => q.postJoinPipeline || [])).filter(pipe => pipe), - relationships: flatten(parsedQueries.map(q => q.relationships || [])), -}); - -function queryParser({ listAdapter, getUID }, query, pathSoFar = [], include) { - if (getType(query) !== 'Object') { - throw new Error( - `Expected an Object for query, got ${getType(query)} at path ${pathSoFar.join('.')}` - ); - } - const excludeFields = listAdapter.fieldAdapters - .filter(({ isRelationship, field }) => isRelationship && field.config.many) - .map(({ dbPath }) => dbPath); - const parsedQueries = Object.entries(query).map(([key, value]) => { - const path = [...pathSoFar, key]; - if (['AND', 'OR'].includes(key)) { - return flattenQueries( - value.map((_query, index) => - queryParser({ listAdapter, getUID }, _query, [...path, index]) - ), - { AND: '$and', OR: '$or' }[key] - ); - } else if (['$search', '$sortBy', '$orderBy', '$skip', '$first', '$count'].includes(key)) { - return { postJoinPipeline: [modifierTokenizer(listAdapter, query, key, path)] }; - } else if (key === 'id') { - if (getType(value) === 'Object') { - return { matchTerm: { _id: value } }; - } else { - return { matchTerm: simpleTokenizer(listAdapter, query, key, path) }; - } - } else if (getType(value) === 'Object') { - // A relationship query component - const { matchTerm, relationshipInfo } = relationshipTokenizer(listAdapter, key, path, getUID); - - // FIXME: This code introduced regressions. We need to add test coverage - // to unique exercise this code and verify its behaviour. - // // Greatly improve query using indexes - // if ( - // Object.keys(value).length === 1 && - // (value.id || value.id_not || value.id_in || value.id_not_in) - // ) { - // const { ObjectId } = listAdapter.mongoose.Types; - // const fieldParser = key.split(/(\_some|\_every|\_none)+$/gm); - // const _path = fieldParser[0]; - // const filterType = fieldParser.length > 1 ? fieldParser[1] : '_only'; - // const queryCondition = {}; - // if (value.id) { - // if (['_only', '_some', '_every'].includes(filterType)) { - // queryCondition[_path] = { $eq: ObjectId(value.id) }; - // } else if (filterType === '_none') { - // queryCondition[_path] = { $ne: ObjectId(value.id) }; - // } - // } else if (value.id_not && ['_only', '_some', '_every', '_none'].includes(filterType)) { - // queryCondition[_path] = { $ne: ObjectId(value.id_not) }; - // } else if (value.id_in && ['_only', '_some'].includes(filterType)) { - // queryCondition[_path] = { $in: value.id_in.map(el => ObjectId(el)) }; - // } else if (value.id_not_in && ['_only', '_every'].includes(filterType)) { - // queryCondition[_path] = { $not: { $in: value.id_not_in.map(el => ObjectId(el)) } }; - // } - // if (Object.keys(queryCondition).length > 0) { - // return { matchTerm: queryCondition }; - // } - // } - - return { - // matchTerm is our filtering expression. This determines if the - // parent item is included in the final list - matchTerm, - relationships: [{ relationshipInfo, ...queryParser({ listAdapter, getUID }, value, path) }], - }; - } else { - // A simple field query component - return { matchTerm: simpleTokenizer(listAdapter, query, key, path) }; - } - }); - const flatQueries = flattenQueries(parsedQueries, '$and'); - const includeFields = flatQueries.relationships.map(({ field }) => field); - if (include) includeFields.push(include); - - return { - ...flatQueries, - excludeFields: excludeFields.filter(field => !includeFields.includes(field)), - }; -} - -module.exports = { queryParser }; diff --git a/packages/adapter-mongoose/lib/tokenizers.js b/packages/adapter-mongoose/lib/tokenizers.js deleted file mode 100644 index 23003cffbb2..00000000000 --- a/packages/adapter-mongoose/lib/tokenizers.js +++ /dev/null @@ -1,161 +0,0 @@ -const cuid = require('cuid'); -const { objMerge, getType, escapeRegExp } = require('@keystone-next/utils-legacy'); - -const getRelatedListAdapterFromQueryPath = (listAdapter, queryPath) => { - if (!listAdapter) { - throw new Error('Must provide a list adapter instance'); - } - - let foundListAdapter = listAdapter; - - // NOTE: We slice the last path segment off because we're interested in the - // related list, not the field on the related list. ie, if the path is - // ['posts', 'comments', 'author_some'], - // the "virtual" field is 'author', and the related list is the one at - // ['posts', 'comments'] - queryPath = queryPath.slice(0, -1); - for (let index = 0; index < queryPath.length; index++) { - const segment = queryPath[index]; - if (segment === 'AND' || segment === 'OR') { - // skip over the next item which is an index - index += 1; - // And ignore this AND/OR - continue; - } - - // Eg; search for which field adapter handles `posts_some`, and return that one - const fieldAdapter = foundListAdapter.fieldAdapters - .filter(adapter => adapter.isRelationship) - .find(({ path }) => - [path, `${path}_every`, `${path}_some`, `${path}_none`].includes(segment) - ); - - if (!fieldAdapter) { - // prettier-ignore - throw new Error( - `'${listAdapter.key}' Mongo List Adapter failed to determine field responsible for the` - + ` query condition '${segment}'. '${segment}' was seen by following the query` - + ` '${queryPath.slice(0, index + 1).join(' > ')}'.` - ); - } - - // Then follow the breadcrumbs to find the list adapter - const currentKey = foundListAdapter.key; - foundListAdapter = fieldAdapter.getListByKey(fieldAdapter.refListKey).adapter; - - if (!foundListAdapter) { - // prettier-ignore - throw new Error( - `'${currentKey}' Mongo List Adapter doesn't have a related list.` - + ` Are you attempting to do a relationship query on a non-relationship field?` - + ` '${currentKey}' was found by following the query` - + ` '${queryPath.slice(0, index + 1).join(' > ')}'.` - ); - } - } - return foundListAdapter; -}; - -const relationshipTokenizer = (listAdapter, queryKey, path, getUID = cuid) => { - const refListAdapter = getRelatedListAdapterFromQueryPath(listAdapter, path); - const fieldAdapter = refListAdapter.fieldAdapters - .filter(adapter => adapter.isRelationship) - .find(({ path }) => [path, `${path}_every`, `${path}_some`, `${path}_none`].includes(queryKey)); - - // Nothing found, return an empty operation - // TODO: warn? - if (!fieldAdapter) return {}; - const filterType = { - [fieldAdapter.path]: 'only', - [`${fieldAdapter.path}_every`]: 'every', - [`${fieldAdapter.path}_some`]: 'some', - [`${fieldAdapter.path}_none`]: 'none', - }[queryKey]; - const refListAdapter2 = fieldAdapter.getListByKey(fieldAdapter.refListKey).adapter; - const { rel } = fieldAdapter; - const uniqueField = `${getUID(queryKey)}_${fieldAdapter.path}`; - const fieldSize = { $size: `$${uniqueField}` }; - const expr = { - only: { $eq: [fieldSize, 1] }, - every: { $eq: [fieldSize, { $size: `$${uniqueField}_all` }] }, - none: { $eq: [fieldSize, 0] }, - some: { $gt: [fieldSize, 0] }, - }[filterType]; - - return { - matchTerm: { $expr: expr }, - relationshipInfo: { - from: - rel.cardinality === 'N:N' - ? refListAdapter2._getModel(rel.tableName).collection.name - : refListAdapter2.model.collection.name, // the collection name to join with - thisTable: refListAdapter.key, - path: fieldAdapter.path, - rel, - filterType, - uniqueField, - // N:N only - farCollection: refListAdapter2.model.collection.name, - }, - }; -}; - -const simpleTokenizer = (listAdapter, query, queryKey, path) => { - const refListAdapter = getRelatedListAdapterFromQueryPath(listAdapter, path); - const simpleQueryConditions = objMerge( - refListAdapter.fieldAdapters.map(a => a.getQueryConditions(a.dbPath)) - ); - if (queryKey in simpleQueryConditions) { - return simpleQueryConditions[queryKey](query[queryKey], query); - } -}; - -const modifierTokenizer = (listAdapter, query, queryKey, path) => { - const refListAdapter = getRelatedListAdapterFromQueryPath(listAdapter, path); - const searchFieldName = listAdapter.config.searchField || 'name'; - return { - // TODO: Implement configurable search fields for lists - $search: value => { - if (!value || (getType(value) === 'String' && !value.trim())) { - return undefined; - } - return { $match: { [searchFieldName]: new RegExp(`${escapeRegExp(value)}`, 'i') } }; - }, - $orderBy: (value, _, listAdapter) => { - const [orderField, orderDirection] = value.split('_'); - - const mongoField = listAdapter.graphQlQueryPathToMongoField(orderField); - - return { $sort: { [mongoField]: orderDirection === 'DESC' ? -1 : 1 } }; - }, - $sortBy: (value, _, listAdapter) => { - const res = {}; - value.map(s => { - const [orderField, orderDirection] = s.split('_'); - const mongoField = listAdapter.graphQlQueryPathToMongoField(orderField); - - res[mongoField] = orderDirection === 'DESC' ? -1 : 1; - }); - - return { $sort: res }; - }, - $skip: value => { - if (value < Infinity && value > 0) { - return { $skip: value }; - } - }, - $first: value => { - if (value < Infinity && value > 0) { - return { $limit: value }; - } - }, - $count: value => ({ $count: value }), - }[queryKey](query[queryKey], query, refListAdapter); -}; - -module.exports = { - simpleTokenizer, - relationshipTokenizer, - modifierTokenizer, - getRelatedListAdapterFromQueryPath, -}; diff --git a/packages/adapter-mongoose/package.json b/packages/adapter-mongoose/package.json deleted file mode 100644 index af27bfa176e..00000000000 --- a/packages/adapter-mongoose/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "@keystone-next/adapter-mongoose-legacy", - "description": "KeystoneJS Mongoose Database adapter.", - "version": "11.1.3", - "author": "The KeystoneJS Development Team", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "dependencies": { - "@keystone-next/keystone-legacy": "^22.0.0", - "@keystone-next/utils-legacy": "^8.0.0", - "cuid": "^2.1.8", - "mongoose": "^5.12.2", - "p-settle": "^4.1.1" - }, - "devDependencies": { - "mongodb": "^3.6.5", - "mongodb-memory-server-core": "^6.9.6", - "pluralize": "^8.0.0" - }, - "repository": "https://github.com/keystonejs/keystone/tree/master/packages/adapter-mongoose" -} diff --git a/packages/adapter-mongoose/tests/index.test.js b/packages/adapter-mongoose/tests/index.test.js deleted file mode 100644 index c68fc5657ea..00000000000 --- a/packages/adapter-mongoose/tests/index.test.js +++ /dev/null @@ -1,93 +0,0 @@ -const { pipelineBuilder } = require('../lib/join-builder'); -const { queryParser } = require('../lib/query-parser'); -const { listAdapter } = require('./utils'); - -describe('Test main export', () => { - test('throws if listAdapter is non-Object', async () => { - expect(() => queryParser({ listAdapter: undefined }, { name: 'foobar' })).toThrow(Error); - - // Shouldn't throw - await queryParser({ listAdapter }, { name: 'foobar' }); - }); - - test('runs the query', async () => { - const query = { - AND: [ - { name: 'foobar' }, - { age: 23 }, - { posts_every: { AND: [{ title: 'hello' }, { tags_some: { name: 'foo' } }] } }, - ], - }; - const queryTree = queryParser({ listAdapter, getUID: jest.fn(key => key) }, query); - const pipeline = pipelineBuilder(queryTree); - expect(pipeline).toMatchObject([ - { - $lookup: { - from: 'posts', - as: 'posts_every_posts', - let: { tmpVar: `$_id` }, - pipeline: [ - { $match: { $expr: { $eq: [`$author`, '$$tmpVar'] } } }, - { - $lookup: { - from: 'posts_tags', - as: 'tags_some_tags', - let: { tmpVar: `$_id` }, - pipeline: [ - { $match: { $expr: { $eq: [`$Post_id`, '$$tmpVar'] } } }, - { - $lookup: { - from: 'tags', - as: 'tags_some_tags_0', - let: { tmpVar: '$Tag_id' }, - pipeline: [ - { $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }, - { $match: { name: { $eq: 'foo' } } }, - { $addFields: { id: '$_id' } }, - { $project: { posts: 0 } }, - ], - }, - }, - { $match: { $expr: { $gt: [{ $size: '$tags_some_tags_0' }, 0] } } }, - ], - }, - }, - { - $match: { - $and: [ - { title: { $eq: 'hello' } }, - { $expr: { $gt: [{ $size: '$tags_some_tags' }, 0] } }, - ], - }, - }, - { $addFields: { id: '$_id' } }, - { $project: { tags_some_tags: 0 } }, - ], - }, - }, - { - $lookup: { - from: 'posts', - as: 'posts_every_posts_all', - let: { tmpVar: '$_id' }, - pipeline: [{ $match: { $expr: { $eq: [`$author`, '$$tmpVar'] } } }], - }, - }, - { - $match: { - $and: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { - $expr: { - $eq: [{ $size: '$posts_every_posts' }, { $size: '$posts_every_posts_all' }], - }, - }, - ], - }, - }, - { $addFields: { id: '$_id' } }, - { $project: { posts_every_posts: 0, posts_every_posts_all: 0 } }, - ]); - }); -}); diff --git a/packages/adapter-mongoose/tests/join-builder.test.js b/packages/adapter-mongoose/tests/join-builder.test.js deleted file mode 100644 index 4f050144e4c..00000000000 --- a/packages/adapter-mongoose/tests/join-builder.test.js +++ /dev/null @@ -1,1001 +0,0 @@ -const { pipelineBuilder } = require('../lib/join-builder'); - -describe('join builder', () => { - test('correctly generates joins for simple queries', () => { - /* - * From this query: - - { - name: 'foobar', - age: 23, - } - - */ - const pipeline = pipelineBuilder({ - matchTerm: { $and: [{ name: { $eq: 'foobar' } }, { age: { $eq: 23 } }] }, - postJoinPipeline: [], - excludeFields: [], - relationships: [], - }); - - expect(pipeline).toMatchObject([ - { $match: { $and: [{ name: { $eq: 'foobar' } }, { age: { $eq: 23 } }] } }, - { $addFields: { id: '$_id' } }, - ]); - }); - - test('correctly generates joins for to-one relationships', () => { - /* - * From this query: - - { - title: 'foobar', - views: 23, - author: { - name: 'Alice', - }, - } - - */ - const pipeline = pipelineBuilder({ - relationships: [ - { - matchTerm: { name: { $eq: 'Alice' } }, - relationshipInfo: { - from: 'users', - uniqueField: 'abc123_author', - rel: { cardinality: '1:N', columnName: 'author' }, - filterType: 'one', - }, - excludeFields: [], - postJoinPipeline: [], - relationships: [], - }, - ], - matchTerm: { - $and: [ - { title: { $eq: 'foobar' } }, - { views: { $eq: 23 } }, - { $expr: { $eq: [{ $size: '$abc123_author' }, 1] } }, - ], - }, - excludeFields: [], - postJoinPipeline: [], - }); - - expect(pipeline).toMatchObject([ - { - $lookup: { - from: 'users', - as: 'abc123_author', - let: { tmpVar: '$author' }, - pipeline: [ - { $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }, - { $match: { name: { $eq: 'Alice' } } }, - { $addFields: { id: '$_id' } }, - ], - }, - }, - { - $match: { - $and: [ - { title: { $eq: 'foobar' } }, - { views: { $eq: 23 } }, - { $expr: { $eq: [{ $size: '$abc123_author' }, 1] } }, - ], - }, - }, - { $addFields: { id: '$_id' } }, - { $project: { abc123_author: 0 } }, - ]); - }); - - test('correctly generates joins for relationships with no filters', () => { - /* - * From this query: - - { - name: 'foobar', - age: 23, - posts_every: {}, - } - - */ - const pipeline = pipelineBuilder({ - relationships: [ - { - relationshipInfo: { - from: 'posts', - uniqueField: 'abc123_posts', - rel: { cardinality: '1:N', columnName: 'author' }, - filterType: 'every', - }, - postJoinPipeline: [], - excludeFields: [], - relationships: [], - }, - ], - matchTerm: { - $and: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { $expr: { $eq: [{ $size: '$abc123_posts' }, { $size: '$abc123_posts_all' }] } }, - ], - }, - excludeFields: [], - postJoinPipeline: [], - }); - - expect(pipeline).toMatchObject([ - { - $lookup: { - from: 'posts', - as: 'abc123_posts', - let: { tmpVar: `$author` }, - pipeline: [ - { $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }, - { $addFields: { id: '$_id' } }, - ], - }, - }, - { - $lookup: { - from: 'posts', - as: 'abc123_posts_all', - let: { tmpVar: `$author` }, - pipeline: [{ $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }], - }, - }, - { - $match: { - $and: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { $expr: { $eq: [{ $size: '$abc123_posts' }, { $size: '$abc123_posts_all' }] } }, - ], - }, - }, - { $addFields: { id: '$_id' } }, - { $project: { abc123_posts: 0, abc123_posts_all: 0 } }, - ]); - }); - - test('correctly generates joins for relationships with postJoinPipeline', () => { - /* - * From this query: - - { - name: 'foobar', - age: 23, - posts_every: {}, - } - - */ - const pipeline = pipelineBuilder({ - relationships: [ - { - relationshipInfo: { - from: 'posts', - uniqueField: 'abc123_posts', - rel: { cardinality: '1:N', columnName: 'author' }, - filterType: 'every', - }, - postJoinPipeline: [{ $sortBy: 'title' }], - relationships: [], - excludeFields: [], - }, - ], - matchTerm: { - $and: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { $expr: { $eq: [{ $size: '$abc123_posts' }, { $size: '$abc123_posts_all' }] } }, - ], - }, - excludeFields: [], - postJoinPipeline: [{ $limit: 10 }], - }); - - expect(pipeline).toMatchObject([ - { - $lookup: { - from: 'posts', - as: 'abc123_posts', - let: { tmpVar: `$author` }, - pipeline: [ - { $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }, - { $addFields: { id: '$_id' } }, - { $sortBy: 'title' }, - ], - }, - }, - { - $lookup: { - from: 'posts', - as: 'abc123_posts_all', - let: { tmpVar: `$author` }, - pipeline: [{ $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }], - }, - }, - { - $match: { - $and: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { $expr: { $eq: [{ $size: '$abc123_posts' }, { $size: '$abc123_posts_all' }] } }, - ], - }, - }, - { $addFields: { id: '$_id' } }, - { $project: { abc123_posts: 0, abc123_posts_all: 0 } }, - { $limit: 10 }, - ]); - }); - - test('correctly generates joins for nested relationships', () => { - /* - * From this query: - - { - name: 'foobar', - age: 23, - posts_every: { - title: 'hello', - tags_some: { - name: 'React', - posts_every: { - published: true, - }, - }, - }, - } - - */ - const pipeline = pipelineBuilder({ - relationships: [ - { - relationshipInfo: { - from: 'posts', - uniqueField: 'abc123_posts', - rel: { cardinality: '1:N', columnName: 'author' }, - filterType: 'every', - }, - matchTerm: { - $and: [{ title: { $eq: 'hello' } }, { $expr: { $gt: [{ $size: '$def456_tags' }, 0] } }], - }, - postJoinPipeline: [], - excludeFields: [], - relationships: [ - { - matchTerm: { - $and: [ - { name: { $eq: 'React' } }, - { - $expr: { $eq: [{ $size: '$xyz890_posts' }, { $size: '$xyz890_posts_all' }] }, - }, - ], - }, - relationshipInfo: { - from: 'posts_tags', - uniqueField: 'def456_tags', - path: 'tags', - rel: { - cardinality: 'N:N', - columnNames: { - 'Post.tags': { near: 'Post_id', far: 'Tag_id' }, - 'Tag.posts': { near: 'Tag_id', far: 'Post_id' }, - }, - }, - thisTable: 'Post', - filterType: 'some', - farCollection: 'tags', - }, - postJoinPipeline: [], - excludeFields: [], - relationships: [ - { - matchTerm: { published: { $eq: true } }, - relationshipInfo: { - from: 'posts_tags', - uniqueField: 'xyz890_posts', - path: 'posts', - rel: { - cardinality: 'N:N', - columnNames: { - 'Post.tags': { near: 'Post_id', far: 'Tag_id' }, - 'Tag.posts': { near: 'Tag_id', far: 'Post_id' }, - }, - tableName: 'Posts_Tags', - }, - thisTable: 'Tag', - filterType: 'every', - farCollection: 'posts', - }, - postJoinPipeline: [], - excludeFields: [], - relationships: [], - }, - ], - }, - ], - }, - ], - matchTerm: { - $and: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { $expr: { $eq: [{ $size: '$abc123_posts' }, { $size: '$abc123_posts_all' }] } }, - ], - }, - excludeFields: [], - postJoinPipeline: [], - }); - - expect(pipeline).toMatchObject([ - { - $lookup: { - from: 'posts', - as: 'abc123_posts', - let: { tmpVar: `$author` }, - pipeline: [ - { $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }, - { - $lookup: { - from: 'posts_tags', - as: 'def456_tags', - let: { tmpVar: `$_id` }, - pipeline: [ - { $match: { $expr: { $eq: [`$Post_id`, '$$tmpVar'] } } }, - { - $lookup: { - from: 'tags', - as: 'def456_tags_0', - let: { tmpVar: '$Tag_id' }, - pipeline: [ - { $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }, - { - $lookup: { - from: 'posts_tags', - as: 'xyz890_posts', - let: { tmpVar: `$_id` }, - pipeline: [ - { $match: { $expr: { $eq: [`$Tag_id`, '$$tmpVar'] } } }, - { - $lookup: { - from: 'posts', - as: 'xyz890_posts_0', - let: { tmpVar: `$Post_id` }, - pipeline: [ - { $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }, - { $match: { published: { $eq: true } } }, - { $addFields: { id: '$_id' } }, - ], - }, - }, - { $match: { $expr: { $gt: [{ $size: '$xyz890_posts_0' }, 0] } } }, - ], - }, - }, - { - $lookup: { - from: 'posts_tags', - as: 'xyz890_posts_all', - let: { tmpVar: `$_id` }, - pipeline: [ - { $match: { $expr: { $eq: [`$Tag_id`, '$$tmpVar'] } } }, - { - $lookup: { - from: 'posts', - as: 'xyz890_posts_0', - let: { tmpVar: `$Post_id` }, - pipeline: [{ $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }], - }, - }, - ], - }, - }, - { - $match: { - $and: [ - { name: { $eq: 'React' } }, - { - $expr: { - $eq: [{ $size: '$xyz890_posts' }, { $size: '$xyz890_posts_all' }], - }, - }, - ], - }, - }, - { $addFields: { id: '$_id' } }, - { $project: { xyz890_posts: 0, xyz890_posts_all: 0 } }, - ], - }, - }, - { $match: { $expr: { $gt: [{ $size: '$def456_tags_0' }, 0] } } }, - ], - }, - }, - { - $match: { - $and: [ - { title: { $eq: 'hello' } }, - { $expr: { $gt: [{ $size: '$def456_tags' }, 0] } }, - ], - }, - }, - { $addFields: { id: '$_id' } }, - { $project: { def456_tags: 0 } }, - ], - }, - }, - { - $lookup: { - from: 'posts', - as: 'abc123_posts_all', - let: { tmpVar: `$author` }, - pipeline: [{ $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }], - }, - }, - { - $match: { - $and: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { $expr: { $eq: [{ $size: '$abc123_posts' }, { $size: '$abc123_posts_all' }] } }, - ], - }, - }, - { $addFields: { id: '$_id' } }, - { $project: { abc123_posts: 0, abc123_posts_all: 0 } }, - ]); - }); - - test('correctly generates joins with nested AND', () => { - /* - * From this query: - - { - AND: [ - { name: 'foobar' }, - { age: 23 }, - { - posts_every: { - AND: [{ title: 'hello' }, { labels_some: { name: 'foo' } }], - }, - }, - ], - } - */ - - const pipeline = pipelineBuilder({ - relationships: [ - { - matchTerm: { - $and: [ - { title: { $eq: 'hello' } }, - { $expr: { $gt: [{ $size: '$quux987_labels' }, 0] } }, - ], - }, - relationshipInfo: { - from: 'posts', - uniqueField: 'zip567_posts', - rel: { cardinality: '1:N', columnName: 'author' }, - filterType: 'every', - }, - postJoinPipeline: [], - excludeFields: [], - relationships: [ - { - matchTerm: { name: { $eq: 'foo' } }, - relationshipInfo: { - from: 'posts_labels', - uniqueField: 'quux987_labels', - path: 'labels', - rel: { - cardinality: 'N:N', - columnNames: { - 'Post.labels': { near: 'Post_id', far: 'Label_id' }, - 'Label.posts': { near: 'Label_id', far: 'Post_id' }, - }, - }, - thisTable: 'Post', - filterType: 'some', - farCollection: 'labels', - }, - postJoinPipeline: [], - excludeFields: [], - relationships: [], - }, - ], - }, - ], - matchTerm: { - $and: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { $expr: { $eq: [{ $size: '$zip567_posts' }, { $size: '$zip567_posts_all' }] } }, - ], - }, - excludeFields: [], - postJoinPipeline: [], - }); - - expect(pipeline).toMatchObject([ - { - $lookup: { - from: 'posts', - as: 'zip567_posts', - let: { tmpVar: `$author` }, - pipeline: [ - { $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }, - { - $lookup: { - from: 'posts_labels', - as: 'quux987_labels', - let: { tmpVar: `$_id` }, - pipeline: [ - { $match: { $expr: { $eq: [`$Post_id`, '$$tmpVar'] } } }, - { - $lookup: { - from: 'labels', - as: 'quux987_labels_0', - let: { tmpVar: `$Label_id` }, - pipeline: [ - { $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }, - { $match: { name: { $eq: 'foo' } } }, - { $addFields: { id: '$_id' } }, - ], - }, - }, - { $match: { $expr: { $gt: [{ $size: '$quux987_labels_0' }, 0] } } }, - ], - }, - }, - { - $match: { - $and: [ - { title: { $eq: 'hello' } }, - { $expr: { $gt: [{ $size: '$quux987_labels' }, 0] } }, - ], - }, - }, - { $addFields: { id: '$_id' } }, - { $project: { quux987_labels: 0 } }, - ], - }, - }, - { - $lookup: { - from: 'posts', - as: 'zip567_posts_all', - let: { tmpVar: `$author` }, - pipeline: [{ $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }], - }, - }, - { - $match: { - $and: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { $expr: { $eq: [{ $size: '$zip567_posts' }, { $size: '$zip567_posts_all' }] } }, - ], - }, - }, - { $addFields: { id: '$_id' } }, - { $project: { zip567_posts: 0, zip567_posts_all: 0 } }, - ]); - }); - - test('correctly generates joins with nested OR', () => { - /* - * From this query: - - { - OR: [ - { name: 'foobar' }, - { age: 23 }, - { - posts_every: { - OR: [{ title: 'hello' }, { labels_some: { name: 'foo' } }], - }, - }, - ], - } - */ - - const pipeline = pipelineBuilder({ - relationships: [ - { - matchTerm: { - $or: [ - { title: { $eq: 'hello' } }, - { $expr: { $gt: [{ $size: '$quux987_labels' }, 0] } }, - ], - }, - relationshipInfo: { - from: 'posts', - uniqueField: 'zip567_posts', - rel: { cardinality: '1:N', columnName: 'author' }, - filterType: 'every', - }, - postJoinPipeline: [], - excludeFields: [], - relationships: [ - { - matchTerm: { name: { $eq: 'foo' } }, - relationshipInfo: { - from: 'posts_labels', - uniqueField: 'quux987_labels', - path: 'labels', - rel: { - cardinality: 'N:N', - columnNames: { - 'Post.labels': { near: 'Post_id', far: 'Label_id' }, - 'Label.posts': { near: 'Label_id', far: 'Post_id' }, - }, - }, - thisTable: 'Post', - filterType: 'some', - farCollection: 'labels', - }, - postJoinPipeline: [], - excludeFields: [], - relationships: [], - }, - ], - }, - ], - matchTerm: { - $or: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { $expr: { $eq: [{ $size: '$zip567_posts' }, { $size: '$zip567_posts_all' }] } }, - ], - }, - excludeFields: [], - postJoinPipeline: [], - }); - - expect(pipeline).toMatchObject([ - { - $lookup: { - from: 'posts', - as: 'zip567_posts', - let: { tmpVar: `$author` }, - pipeline: [ - { $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }, - { - $lookup: { - from: 'posts_labels', - as: 'quux987_labels', - let: { tmpVar: `$_id` }, - pipeline: [ - { $match: { $expr: { $eq: [`$Post_id`, '$$tmpVar'] } } }, - { - $lookup: { - from: 'labels', - as: 'quux987_labels_0', - let: { tmpVar: `$Label_id` }, - pipeline: [ - { $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }, - { $match: { name: { $eq: 'foo' } } }, - { $addFields: { id: '$_id' } }, - ], - }, - }, - { $match: { $expr: { $gt: [{ $size: '$quux987_labels_0' }, 0] } } }, - ], - }, - }, - { - $match: { - $or: [ - { title: { $eq: 'hello' } }, - { $expr: { $gt: [{ $size: '$quux987_labels' }, 0] } }, - ], - }, - }, - { $addFields: { id: '$_id' } }, - { $project: { quux987_labels: 0 } }, - ], - }, - }, - { - $lookup: { - from: 'posts', - as: 'zip567_posts_all', - let: { tmpVar: `$author` }, - pipeline: [{ $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }], - }, - }, - { - $match: { - $or: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { $expr: { $eq: [{ $size: '$zip567_posts' }, { $size: '$zip567_posts_all' }] } }, - ], - }, - }, - { $addFields: { id: '$_id' } }, - { $project: { zip567_posts: 0, zip567_posts_all: 0 } }, - ]); - }); - - test('correctly generates joins with nested AND/OR', () => { - /* - * From this query: - - { - AND: [ - { name: 'foobar' }, - { age: 23 }, - { - posts_every: { - OR: [{ title: 'hello' }, { labels_some: { name: 'foo' } }], - }, - }, - ], - } - */ - - const pipeline = pipelineBuilder({ - relationships: [ - { - matchTerm: { - $or: [ - { title: { $eq: 'hello' } }, - { $expr: { $gt: [{ $size: '$quux987_labels' }, 0] } }, - ], - }, - - relationshipInfo: { - from: 'posts', - uniqueField: 'zip567_posts', - rel: { cardinality: '1:N', columnName: 'author' }, - filterType: 'every', - }, - postJoinPipeline: [], - excludeFields: [], - relationships: [ - { - matchTerm: { name: { $eq: 'foo' } }, - relationshipInfo: { - from: 'posts_labels', - uniqueField: 'quux987_labels', - path: 'labels', - rel: { - cardinality: 'N:N', - columnNames: { - 'Post.labels': { near: 'Post_id', far: 'Label_id' }, - 'Label.posts': { near: 'Label_id', far: 'Post_id' }, - }, - }, - thisTable: 'Post', - filterType: 'some', - farCollection: 'labels', - }, - postJoinPipeline: [], - excludeFields: [], - relationships: [], - }, - ], - }, - ], - matchTerm: { - $and: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { - $expr: { - $eq: [{ $size: '$zip567_posts' }, { $size: '$zip567_posts_all' }], - }, - }, - ], - }, - excludeFields: [], - postJoinPipeline: [], - }); - - expect(pipeline).toMatchObject([ - { - $lookup: { - from: 'posts', - as: 'zip567_posts', - let: { tmpVar: `$author` }, - pipeline: [ - { $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }, - { - $lookup: { - from: 'posts_labels', - as: 'quux987_labels', - let: { tmpVar: `$_id` }, - pipeline: [ - { $match: { $expr: { $eq: [`$Post_id`, '$$tmpVar'] } } }, - { - $lookup: { - from: 'labels', - as: 'quux987_labels_0', - let: { tmpVar: `$Label_id` }, - pipeline: [ - { $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }, - { $match: { name: { $eq: 'foo' } } }, - { $addFields: { id: '$_id' } }, - ], - }, - }, - { $match: { $expr: { $gt: [{ $size: '$quux987_labels_0' }, 0] } } }, - ], - }, - }, - { - $match: { - $or: [ - { title: { $eq: 'hello' } }, - { $expr: { $gt: [{ $size: '$quux987_labels' }, 0] } }, - ], - }, - }, - { $addFields: { id: '$_id' } }, - { $project: { quux987_labels: 0 } }, - ], - }, - }, - { - $lookup: { - from: 'posts', - as: 'zip567_posts_all', - let: { tmpVar: `$author` }, - pipeline: [{ $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }], - }, - }, - { - $match: { - $and: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { $expr: { $eq: [{ $size: '$zip567_posts' }, { $size: '$zip567_posts_all' }] } }, - ], - }, - }, - { $addFields: { id: '$_id' } }, - { $project: { zip567_posts: 0, zip567_posts_all: 0 } }, - ]); - }); - - test('correctly generates joins with nested OR/AND', () => { - /* - * From this query: - - { - OR: [ - { name: 'foobar' }, - { age: 23 }, - { - posts_every: { - AND: [{ title: 'hello' }, { labels_some: { name: 'foo' } }], - }, - }, - ], - } - */ - - const pipeline = pipelineBuilder({ - relationships: [ - { - matchTerm: { - $and: [ - { title: { $eq: 'hello' } }, - { $expr: { $gt: [{ $size: '$quux987_labels' }, 0] } }, - ], - }, - relationshipInfo: { - from: 'posts', - uniqueField: 'zip567_posts', - rel: { cardinality: '1:N', columnName: 'author' }, - filterType: 'every', - }, - postJoinPipeline: [], - excludeFields: [], - relationships: [ - { - matchTerm: { name: { $eq: 'foo' } }, - relationshipInfo: { - from: 'posts_labels', - uniqueField: 'quux987_labels', - path: 'labels', - rel: { - cardinality: 'N:N', - columnNames: { - 'Post.labels': { near: 'Post_id', far: 'Label_id' }, - 'Label.posts': { near: 'Label_id', far: 'Post_id' }, - }, - }, - thisTable: 'Post', - filterType: 'some', - farCollection: 'labels', - }, - postJoinPipeline: [], - excludeFields: [], - relationships: [], - }, - ], - }, - ], - matchTerm: { - $or: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { $expr: { $eq: [{ $size: '$zip567_posts' }, { $size: '$zip567_posts_all' }] } }, - ], - }, - excludeFields: [], - postJoinPipeline: [], - }); - - expect(pipeline).toMatchObject([ - { - $lookup: { - from: 'posts', - as: 'zip567_posts', - let: { tmpVar: `$author` }, - pipeline: [ - { $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }, - { - $lookup: { - from: 'posts_labels', - as: 'quux987_labels', - let: { tmpVar: `$_id` }, - pipeline: [ - { $match: { $expr: { $eq: [`$Post_id`, '$$tmpVar'] } } }, - { - $lookup: { - from: 'labels', - as: 'quux987_labels_0', - let: { tmpVar: `$Label_id` }, - pipeline: [ - { $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }, - { $match: { name: { $eq: 'foo' } } }, - { $addFields: { id: '$_id' } }, - ], - }, - }, - { $match: { $expr: { $gt: [{ $size: '$quux987_labels_0' }, 0] } } }, - ], - }, - }, - { - $match: { - $and: [ - { title: { $eq: 'hello' } }, - { $expr: { $gt: [{ $size: '$quux987_labels' }, 0] } }, - ], - }, - }, - { $addFields: { id: '$_id' } }, - { $project: { quux987_labels: 0 } }, - ], - }, - }, - { - $lookup: { - from: 'posts', - as: 'zip567_posts_all', - let: { tmpVar: `$author` }, - pipeline: [{ $match: { $expr: { $eq: [`$_id`, '$$tmpVar'] } } }], - }, - }, - { - $match: { - $or: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { $expr: { $eq: [{ $size: '$zip567_posts' }, { $size: '$zip567_posts_all' }] } }, - ], - }, - }, - { $addFields: { id: '$_id' } }, - { $project: { zip567_posts: 0, zip567_posts_all: 0 } }, - ]); - }); -}); diff --git a/packages/adapter-mongoose/tests/list-adapter.test.js b/packages/adapter-mongoose/tests/list-adapter.test.js deleted file mode 100644 index 2808735c8d8..00000000000 --- a/packages/adapter-mongoose/tests/list-adapter.test.js +++ /dev/null @@ -1,187 +0,0 @@ -const pluralize = require('pluralize'); -function createListAdapter(MongooseListAdapter, key, { aggregateResult = [] } = {}) { - const listAdapter = new MongooseListAdapter( - key, - { - mongoose: { Schema: function schema() {} }, - getListAdapterByKey: () => {}, - }, - {} - ); - - listAdapter.model = { - aggregate: jest.fn(() => ({ exec: () => Promise.resolve(aggregateResult) })), - collection: { name: pluralize.plural(key) }, - }; - - return listAdapter; -} - -beforeEach(() => { - jest.resetModules(); -}); - -describe('MongooseListAdapter', () => { - test('Correctly applies simple conditions', async () => { - const { MongooseListAdapter } = require('../'); - - const listAdapter = createListAdapter(MongooseListAdapter, 'user'); - listAdapter.fieldAdapters = [ - { getQueryConditions: () => ({ title: value => ({ title: { $eq: value } }) }) }, - ]; - - await listAdapter.itemsQuery({ where: { title: 'foo' } }); - - expect(listAdapter.model.aggregate).toHaveBeenCalledWith([ - { $match: { title: { $eq: 'foo' } } }, - { $addFields: { id: '$_id' } }, - ]); - }); - - test('Correctly applies conditions of relationships in nested AND/OR fields', async () => { - const { MongooseListAdapter } = require('../'); - const postListAdapter = createListAdapter(MongooseListAdapter, 'post'); - postListAdapter.fieldAdapters = [ - { getQueryConditions: () => ({ name: value => ({ name: { $eq: value } }) }) }, - ]; - - const userListAdapter = createListAdapter(MongooseListAdapter, 'user'); - userListAdapter.fieldAdapters = [ - { - isRelationship: false, - getQueryConditions: () => ({ title: value => ({ title: { $eq: value } }) }), - }, - { - isRelationship: true, - getQueryConditions: () => {}, - getListByKey: () => ({ adapter: postListAdapter }), - field: { config: { many: true }, many: true }, - path: 'posts', - dbPath: 'posts', - rel: { cardinality: '1:N', tableName: 'Post', columnName: 'author' }, - }, - ]; - - await userListAdapter.itemsQuery({ - where: { AND: [{ posts_some: { name: 'foo' } }, { title: 'bar' }] }, - }); - expect(userListAdapter.model.aggregate).toHaveBeenCalledWith([ - { - $lookup: { - as: expect.any(String), - from: 'posts', - let: { tmpVar: '$_id' }, - pipeline: [ - { $match: { $expr: { $eq: ['$author', '$$tmpVar'] } } }, - { $match: { name: { $eq: 'foo' } } }, - { $addFields: { id: '$_id' } }, - { $project: { posts: 0 } }, - ], - }, - }, - { $match: { $and: [expect.any(Object), { title: { $eq: 'bar' } }] } }, - { $addFields: { id: '$_id' } }, - { $project: expect.any(Object) }, - ]); - - await userListAdapter.itemsQuery({ - where: { OR: [{ posts_some: { name: 'foo' } }, { title: 'bar' }] }, - }); - - expect(userListAdapter.model.aggregate).toHaveBeenCalledWith([ - { - $lookup: { - as: expect.any(String), - from: 'posts', - let: { tmpVar: '$_id' }, - pipeline: [ - { $match: { $expr: { $eq: ['$author', '$$tmpVar'] } } }, - { $match: { name: { $eq: 'foo' } } }, - { $addFields: { id: '$_id' } }, - { $project: { posts: 0 } }, - ], - }, - }, - { $match: { $or: [expect.any(Object), { title: { $eq: 'bar' } }] } }, - { $addFields: { id: '$_id' } }, - { $project: expect.any(Object) }, - ]); - }); - - test('Correctly applies conditions of AND/OR fields nested in relationships', async () => { - const { MongooseListAdapter } = require('../'); - - const postListAdapter = createListAdapter(MongooseListAdapter, 'post'); - postListAdapter.fieldAdapters = [ - { - isRelationship: false, - getQueryConditions: () => ({ name: value => ({ name: { $eq: value } }) }), - field: { config: { many: false }, many: false }, - }, - { - isRelationship: false, - getQueryConditions: () => ({ title: value => ({ title: { $eq: value } }) }), - field: { config: { many: false }, many: false }, - }, - ]; - - const userListAdapter = createListAdapter(MongooseListAdapter, 'user'); - userListAdapter.fieldAdapters = [ - { - isRelationship: true, - getQueryConditions: () => {}, - getListByKey: () => ({ adapter: postListAdapter }), - field: { config: { many: true }, many: true }, - path: 'posts', - dbPath: 'posts', - rel: { cardinality: '1:N', tableName: 'Post', columnName: 'author' }, - }, - ]; - - await userListAdapter.itemsQuery({ - where: { posts_some: { AND: [{ name: 'foo' }, { title: 'bar' }] } }, - }); - - expect(userListAdapter.model.aggregate).toHaveBeenCalledWith([ - { - $lookup: { - as: expect.any(String), - from: 'posts', - let: { tmpVar: '$_id' }, - pipeline: [ - { $match: { $expr: { $eq: ['$author', '$$tmpVar'] } } }, - { $match: { $and: [{ name: { $eq: 'foo' } }, { title: { $eq: 'bar' } }] } }, - { $addFields: { id: '$_id' } }, - { $project: { posts: 0 } }, - ], - }, - }, - { $match: expect.any(Object) }, - { $addFields: { id: '$_id' } }, - { $project: expect.any(Object) }, - ]); - - await userListAdapter.itemsQuery({ - where: { posts_some: { OR: [{ name: 'foo' }, { title: 'bar' }] } }, - }); - - expect(userListAdapter.model.aggregate).toHaveBeenCalledWith([ - { - $lookup: { - as: expect.any(String), - from: 'posts', - let: { tmpVar: '$_id' }, - pipeline: [ - { $match: { $expr: { $eq: ['$author', '$$tmpVar'] } } }, - { $match: { $or: [{ name: { $eq: 'foo' } }, { title: { $eq: 'bar' } }] } }, - { $addFields: { id: '$_id' } }, - { $project: { posts: 0 } }, - ], - }, - }, - { $match: expect.any(Object) }, - { $addFields: { id: '$_id' } }, - { $project: expect.any(Object) }, - ]); - }); -}); diff --git a/packages/adapter-mongoose/tests/mongo-results.test.js b/packages/adapter-mongoose/tests/mongo-results.test.js deleted file mode 100644 index d11b4095ed0..00000000000 --- a/packages/adapter-mongoose/tests/mongo-results.test.js +++ /dev/null @@ -1,385 +0,0 @@ -const { MongoClient } = require('mongodb'); -const MongoDBMemoryServer = require('mongodb-memory-server-core').default; -const { pipelineBuilder } = require('../lib/join-builder'); -const { queryParser } = require('../lib/query-parser'); -const { postsAdapter, listAdapter } = require('./utils'); - -const mongoJoinBuilder = parserOptions => { - return async (query, aggregate) => { - const queryTree = queryParser(parserOptions, query); - const pipeline = pipelineBuilder(queryTree); - // Run the query against the given database and collection - return await aggregate(pipeline); - }; -}; - -function getAggregate(database, collection) { - return pipeline => { - return new Promise((resolve, reject) => { - database.collection(collection).aggregate(pipeline, (error, cursor) => { - if (error) { - return reject(error); - } - return resolve(cursor.toArray()); - }); - }); - }; -} - -let mongoConnection; -let mongoDb; -let mongoServer; - -beforeAll(async () => { - mongoServer = new MongoDBMemoryServer(); - const mongoUri = await mongoServer.getConnectionString(); - mongoConnection = await MongoClient.connect(mongoUri, { - useNewUrlParser: true, - useUnifiedTopology: true, - }); - mongoDb = mongoConnection.db(await mongoServer.getDbName()); -}); - -afterAll(() => { - mongoConnection.close(); - mongoServer.stop(); -}); - -beforeEach(async () => { - const collections = await mongoDb.collections(); - await Promise.all(collections.map(collection => collection.deleteMany({}))); -}); - -describe('mongo memory servier is alive', () => { - it('should start mongo server', async () => { - const collection = mongoDb.collection('heartbeat'); - const result = await collection.insertMany([{ a: 1 }, { b: 1 }]); - expect(result.result).toMatchObject({ n: 2, ok: 1 }); - expect(await collection.countDocuments({})).toBe(2); - }); -}); - -describe('Testing against real data', () => { - test('performs simple queries', async () => { - const builder = mongoJoinBuilder({ listAdapter }); - - const collection = mongoDb.collection('users'); - await collection.insertMany([ - { name: 'Jess', age: 23, address: '123 nowhere' }, - { name: 'foobar', age: 23, address: '90210' }, - { name: 'Alice', age: 45, address: 'Ramsay Street' }, - { name: 'foobar', age: 23, address: 'The Joneses' }, - { name: 'foobar', age: 89, address: '456 somewhere' }, - ]); - - const query = { name: 'foobar', age: 23 }; - - const result = await builder(query, getAggregate(mongoDb, 'users')); - - expect(result).toMatchObject([ - { name: 'foobar', age: 23, address: '90210' }, - { name: 'foobar', age: 23, address: 'The Joneses' }, - ]); - }); - - test('performs AND queries', async () => { - const builder = mongoJoinBuilder({ listAdapter }); - - const collection = mongoDb.collection('users'); - await collection.insertMany([ - { name: 'Jess', age: 23, address: '123 nowhere' }, - { name: 'foobar', age: 23, address: '90210' }, - { name: 'Alice', age: 45, address: 'Ramsay Street' }, - { name: 'foobar', age: 23, address: 'The Joneses' }, - { name: 'foobar', age: 89, address: '456 somewhere' }, - ]); - - const query = { AND: [{ name: 'foobar' }, { age: 23 }] }; - - const result = await builder(query, getAggregate(mongoDb, 'users')); - - expect(result).toMatchObject([ - { name: 'foobar', age: 23, address: '90210' }, - { name: 'foobar', age: 23, address: 'The Joneses' }, - ]); - }); - - test('performs to-one relationship queries', async () => { - const builder = mongoJoinBuilder({ listAdapter: postsAdapter }); - - const usersCollection = mongoDb.collection('users'); - const postsCollection = mongoDb.collection('posts'); - - const { insertedIds } = await usersCollection.insertMany([ - { name: 'Jess', type: 'author' }, - { name: 'Sam', type: 'editor' }, - ]); - - await postsCollection.insertMany([ - { title: 'Hello world', status: 'published', author: insertedIds[0] }, - { title: 'Testing', status: 'published', author: insertedIds[1] }, - { title: 'An awesome post', status: 'draft', author: insertedIds[0] }, - { title: 'Another Thing', status: 'published', author: insertedIds[1] }, - ]); - - const query = { status: 'published', author: { name: 'Jess' } }; - - const result = await builder(query, getAggregate(mongoDb, 'posts')); - - expect(result).toMatchObject([ - { title: 'Hello world', status: 'published', author: insertedIds[0] }, - ]); - }); - - test('performs to-many relationship queries with no filter', async () => { - const builder = mongoJoinBuilder({ listAdapter }); - - const usersCollection = mongoDb.collection('users'); - const postsCollection = mongoDb.collection('posts'); - - const { insertedIds } = await usersCollection.insertMany([ - { - name: 'Jess', - type: 'author', - }, - { - name: 'Alice', - type: 'author', - }, - { - name: 'Sam', - type: 'editor', - }, - ]); - - await postsCollection.insertMany([ - { - title: 'Hello world', - status: 'published', - author: insertedIds[0], - }, - { - title: 'Testing', - status: 'published', - author: insertedIds[1], - }, - { - title: 'An awesome post', - status: 'draft', - author: insertedIds[0], - }, - { - title: 'Another Thing', - status: 'published', - author: insertedIds[1], - }, - ]); - - const query = { type: 'author' }; - - const result = await builder(query, getAggregate(mongoDb, 'users')); - - expect(result).toMatchObject([ - { - name: 'Jess', - type: 'author', - }, - { - name: 'Alice', - type: 'author', - }, - ]); - }); - - test('performs to-many relationship queries with postJoinPipeline', async () => { - const builder = mongoJoinBuilder({ listAdapter }); - - const usersCollection = mongoDb.collection('users'); - const postsCollection = mongoDb.collection('posts'); - - const { insertedIds } = await usersCollection.insertMany([ - { - name: 'Jess', - type: 'author', - }, - { - name: 'Alice', - type: 'author', - }, - { - name: 'Sam', - type: 'author', - }, - { - name: 'Alex', - type: 'editor', - }, - ]); - - await postsCollection.insertMany([ - { - title: 'Hello world', - status: 'published', - author: insertedIds[0], - }, - { - title: 'Testing', - status: 'published', - author: insertedIds[1], - }, - { - title: 'An awesome post', - status: 'draft', - author: insertedIds[0], - }, - { - title: 'Another Thing', - status: 'published', - author: insertedIds[1], - }, - ]); - - const query = { - type: 'author', - posts_every: { status: 'published', $sort: 'title_ASC' }, - $first: 1, - }; - - const result = await builder(query, getAggregate(mongoDb, 'users')); - expect(result).toMatchObject([ - { - name: 'Alice', - type: 'author', - }, - ]); - }); - - test('performs to-many relationship queries', async () => { - const builder = mongoJoinBuilder({ listAdapter }); - - const usersCollection = mongoDb.collection('users'); - const postsCollection = mongoDb.collection('posts'); - - const { insertedIds } = await usersCollection.insertMany([ - { name: 'Jess', type: 'author' }, - { name: 'Alice', type: 'author' }, - { name: 'Sam', type: 'editor' }, - ]); - - await postsCollection.insertMany([ - { - title: 'Hello world', - status: 'published', - author: insertedIds[0], - }, - { - title: 'Testing', - status: 'published', - author: insertedIds[1], - }, - { - title: 'An awesome post', - status: 'draft', - author: insertedIds[0], - }, - { - title: 'Another Thing', - status: 'published', - author: insertedIds[2], - }, - ]); - - const query = { type: 'author', posts_every: { status: 'published' } }; - const result = await builder(query, getAggregate(mongoDb, 'users')); - - expect(result).toMatchObject([{ name: 'Alice', type: 'author' }]); - }); - - test('performs to-many relationship queries with nested AND', async () => { - const builder = mongoJoinBuilder({ listAdapter }); - - const usersCollection = mongoDb.collection('users'); - const postsCollection = mongoDb.collection('posts'); - - const { insertedIds } = await usersCollection.insertMany([ - { name: 'Jess', type: 'author' }, - { name: 'Alice', type: 'author' }, - { name: 'Sam', type: 'editor' }, - ]); - - await postsCollection.insertMany([ - { - title: 'Hello world', - status: 'published', - approved: true, - author: insertedIds[0], - }, - { - title: 'Testing', - status: 'published', - approved: true, - author: insertedIds[1], - }, - { - title: 'An awesome post', - status: 'draft', - approved: true, - author: insertedIds[0], - }, - { - title: 'Another Thing', - status: 'published', - approved: true, - author: insertedIds[2], - }, - ]); - - const query = { - type: 'author', - posts_every: { AND: [{ approved: true }, { status: 'published' }] }, - }; - - const result = await builder(query, getAggregate(mongoDb, 'users')); - expect(result).toMatchObject([{ name: 'Alice', type: 'author' }]); - }); - - test('performs AND query with nested to-many relationship', async () => { - const builder = mongoJoinBuilder({ listAdapter }); - - const usersCollection = mongoDb.collection('users'); - const postsCollection = mongoDb.collection('posts'); - - const { insertedIds } = await usersCollection.insertMany([ - { name: 'Jess', type: 'author' }, - { name: 'Alice', type: 'author' }, - { name: 'Sam', type: 'editor' }, - ]); - - await postsCollection.insertMany([ - { - title: 'Hello world', - status: 'published', - author: insertedIds[0], - }, - { - title: 'Testing', - status: 'published', - author: insertedIds[1], - }, - { - title: 'An awesome post', - status: 'draft', - author: insertedIds[0], - }, - { - title: 'Another Thing', - status: 'published', - author: insertedIds[2], - }, - ]); - - const query = { AND: [{ type: 'author' }, { posts_every: { status: 'published' } }] }; - const result = await builder(query, getAggregate(mongoDb, 'users')); - expect(result).toMatchObject([{ name: 'Alice', type: 'author' }]); - }); -}); diff --git a/packages/adapter-mongoose/tests/query-parser.test.js b/packages/adapter-mongoose/tests/query-parser.test.js deleted file mode 100644 index f3ea58f6357..00000000000 --- a/packages/adapter-mongoose/tests/query-parser.test.js +++ /dev/null @@ -1,552 +0,0 @@ -const { queryParser } = require('../lib/query-parser'); -const { listAdapter } = require('./utils'); - -describe('query parser', () => { - test('requires a listAdapter option', () => { - expect(() => queryParser()).toThrow(Error); - expect(() => queryParser({}, { name: 'foobar' })).toThrow(Error); - expect(() => queryParser({ listAdapter }, { name: 'foobar' })).not.toThrow(Error); - }); - - test('requires an object for the query', () => { - expect(() => { - queryParser({ listAdapter }, 'foobar'); - }).toThrow(Error); - }); - - describe('calling tokenizing functions', () => { - test('AND query with invalid query type', () => { - expect(() => queryParser({ listAdapter }, { AND: [{ name: 'foobar' }, 23] })).toThrow(Error); - }); - - test('OR query with invalid query type', () => { - expect(() => queryParser({ listAdapter }, { OR: [{ name: 'foobar' }, 23] })).toThrow(Error); - }); - }); - - describe('simple queries', () => { - test('builds a simple query tree', () => { - const queryTree = queryParser({ listAdapter }, { name: 'foobar', age: 23 }); - - expect(queryTree).toMatchObject({ - // No relationships in this test - relationships: [], - matchTerm: { $and: [{ name: { $eq: 'foobar' } }, { age: { $eq: 23 } }] }, - }); - }); - - test('builds a query tree with ANDs', () => { - const tokenizer = { - simple: jest.fn((query, key) => ({ matchTerm: { [key]: { $eq: query[key] } } })), - }; - - const queryTree = queryParser( - { listAdapter, tokenizer }, - { AND: [{ name: 'foobar' }, { age: 23 }] } - ); - - expect(queryTree).toMatchObject({ - // No relationships in this test - relationships: {}, - matchTerm: { $and: [{ name: { $eq: 'foobar' } }, { age: { $eq: 23 } }] }, - }); - }); - - test('builds a query tree with ORs', () => { - const tokenizer = { - simple: jest.fn((query, key) => ({ matchTerm: { [key]: { $eq: query[key] } } })), - }; - - const queryTree = queryParser( - { listAdapter, tokenizer }, - { OR: [{ name: 'foobar' }, { age: 23 }] } - ); - - expect(queryTree).toMatchObject({ - // No relationships in this test - relationships: [], - matchTerm: { $or: [{ name: { $eq: 'foobar' } }, { age: { $eq: 23 } }] }, - }); - }); - }); - - describe('relationship queries', () => { - test('builds a query tree with to-many relationship and other postjoin filters', () => { - const queryTree = queryParser( - { listAdapter, getUID: jest.fn(key => key) }, - { name: 'foobar', age: 23, $first: 1, posts: { title: 'hello', $sortBy: ['title_ASC'] } } - ); - - expect(queryTree).toMatchObject({ - relationships: [ - { - matchTerm: { title: { $eq: 'hello' } }, - relationshipInfo: { - from: 'posts', - uniqueField: 'posts_posts', - thisTable: 'User', - rel: {}, - filterType: 'only', - farCollection: 'posts', - }, - postJoinPipeline: [{ $sort: { title: 1 } }], - relationships: [], - }, - ], - matchTerm: { - $and: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { $expr: { $eq: [{ $size: '$posts_posts' }, 1] } }, - ], - }, - postJoinPipeline: [{ $limit: 1 }], - }); - }); - - test('builds a query tree with to-many relationship', () => { - const queryTree = queryParser( - { listAdapter, getUID: jest.fn(key => key) }, - { name: 'foobar', age: 23, posts: { title: 'hello' } } - ); - - expect(queryTree).toMatchObject({ - relationships: [ - { - matchTerm: { title: { $eq: 'hello' } }, - relationshipInfo: { - from: 'posts', - uniqueField: 'posts_posts', - thisTable: 'User', - rel: {}, - filterType: 'only', - farCollection: 'posts', - }, - postJoinPipeline: [], - relationships: [], - }, - ], - matchTerm: { - $and: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { $expr: { $eq: [{ $size: '$posts_posts' }, 1] } }, - ], - }, - }); - }); - - test('builds a query tree for a relationship with no filters', () => { - const queryTree = queryParser( - { listAdapter, getUID: jest.fn(key => key) }, - { name: 'foobar', age: 23, posts: {} } - ); - - expect(queryTree).toMatchObject({ - relationships: [ - { - matchTerm: undefined, - relationshipInfo: { - from: 'posts', - uniqueField: 'posts_posts', - thisTable: 'User', - rel: {}, - filterType: 'only', - farCollection: 'posts', - }, - postJoinPipeline: [], - relationships: [], - }, - ], - matchTerm: { - $and: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { $expr: { $eq: [{ $size: '$posts_posts' }, 1] } }, - ], - }, - }); - }); - - test('builds a query tree with to-single relationship', () => { - const queryTree = queryParser( - { listAdapter, getUID: jest.fn(key => key) }, - { name: 'foobar', age: 23, company: { name: 'hello' } } - ); - - expect(queryTree).toMatchObject({ - relationships: [ - { - matchTerm: { name: { $eq: 'hello' } }, - relationshipInfo: { - from: 'company-collection', - uniqueField: 'company_company', - thisTable: 'User', - rel: {}, - filterType: 'only', - farCollection: 'company-collection', - }, - postJoinPipeline: [], - relationships: [], - }, - ], - matchTerm: { - $and: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { $expr: { $eq: [{ $size: '$company_company' }, 1] } }, - ], - }, - }); - }); - - test('builds a query tree with nested relationship', () => { - const queryTree = queryParser( - { listAdapter, getUID: jest.fn(key => key) }, - { - name: 'foobar', - age: 23, - posts_every: { - title: 'hello', - tags_some: { name: 'React', posts_every: { title: 'foo' } }, - }, - } - ); - - expect(queryTree).toMatchObject({ - relationships: [ - { - matchTerm: { - $and: [ - { title: { $eq: 'hello' } }, - { $expr: { $gt: [{ $size: '$tags_some_tags' }, 0] } }, - ], - }, - relationshipInfo: { - from: 'posts', - uniqueField: 'posts_every_posts', - thisTable: 'User', - rel: {}, - filterType: 'every', - farCollection: 'posts', - }, - postJoinPipeline: [], - relationships: [ - { - matchTerm: { - $and: [ - { name: { $eq: 'React' } }, - { - $expr: { - $eq: [{ $size: '$posts_every_posts' }, { $size: '$posts_every_posts_all' }], - }, - }, - ], - }, - relationshipInfo: { - from: 'posts_tags', - uniqueField: 'tags_some_tags', - thisTable: 'Post', - rel: {}, - filterType: 'some', - farCollection: 'tags', - }, - postJoinPipeline: [], - relationships: [ - { - matchTerm: { title: { $eq: 'foo' } }, - relationshipInfo: { - from: 'posts_tags', - uniqueField: 'posts_every_posts', - thisTable: 'Tag', - rel: {}, - filterType: 'every', - farCollection: 'posts', - }, - postJoinPipeline: [], - relationships: [], - }, - ], - }, - ], - }, - ], - matchTerm: { - $and: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { - $expr: { - $eq: [{ $size: '$posts_every_posts' }, { $size: '$posts_every_posts_all' }], - }, - }, - ], - }, - }); - }); - - test('builds a query tree with nested relationship with nested AND', () => { - const queryTree = queryParser( - { listAdapter, getUID: jest.fn(key => key) }, - { - AND: [ - { name: 'foobar' }, - { age: 23 }, - { posts_every: { AND: [{ title: 'hello' }, { tags_some: { name: 'foo' } }] } }, - ], - } - ); - - expect(queryTree).toMatchObject({ - relationships: [ - { - matchTerm: { - $and: [ - { title: { $eq: 'hello' } }, - { $expr: { $gt: [{ $size: '$tags_some_tags' }, 0] } }, - ], - }, - relationshipInfo: { - from: 'posts', - uniqueField: 'posts_every_posts', - thisTable: 'User', - rel: {}, - filterType: 'every', - farCollection: 'posts', - }, - postJoinPipeline: [], - relationships: [ - { - matchTerm: { name: { $eq: 'foo' } }, - relationshipInfo: { - from: 'posts_tags', - uniqueField: 'tags_some_tags', - thisTable: 'Post', - rel: {}, - filterType: 'some', - farCollection: 'tags', - }, - postJoinPipeline: [], - relationships: [], - }, - ], - }, - ], - matchTerm: { - $and: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { - $expr: { - $eq: [{ $size: '$posts_every_posts' }, { $size: '$posts_every_posts_all' }], - }, - }, - ], - }, - }); - }); - - test('builds a query tree with nested relationship with nested OR', () => { - const queryTree = queryParser( - { listAdapter, getUID: jest.fn(key => key) }, - { - OR: [ - { name: 'foobar' }, - { age: 23 }, - { posts_every: { OR: [{ title: 'hello' }, { tags_some: { name: 'foo' } }] } }, - ], - } - ); - - expect(queryTree).toMatchObject({ - relationships: [ - { - matchTerm: { - $or: [ - { title: { $eq: 'hello' } }, - { $expr: { $gt: [{ $size: '$tags_some_tags' }, 0] } }, - ], - }, - relationshipInfo: { - from: 'posts', - uniqueField: 'posts_every_posts', - thisTable: 'User', - rel: {}, - filterType: 'every', - farCollection: 'posts', - }, - postJoinPipeline: [], - relationships: [ - { - matchTerm: { name: { $eq: 'foo' } }, - relationshipInfo: { - from: 'posts_tags', - uniqueField: 'tags_some_tags', - thisTable: 'Post', - rel: {}, - filterType: 'some', - farCollection: 'tags', - }, - postJoinPipeline: [], - relationships: [], - }, - ], - }, - ], - matchTerm: { - $or: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { - $expr: { - $eq: [{ $size: '$posts_every_posts' }, { $size: '$posts_every_posts_all' }], - }, - }, - ], - }, - }); - }); - - test('builds a query tree with nested relationship with nested AND/OR', () => { - const queryTree = queryParser( - { listAdapter, getUID: jest.fn(key => key) }, - { - AND: [ - { name: 'foobar' }, - { age: 23 }, - { posts_every: { OR: [{ title: 'hello' }, { tags_some: { name: 'foo' } }] } }, - ], - } - ); - - expect(queryTree).toMatchObject({ - relationships: [ - { - matchTerm: { - $or: [ - { title: { $eq: 'hello' } }, - { $expr: { $gt: [{ $size: '$tags_some_tags' }, 0] } }, - ], - }, - relationshipInfo: { - from: 'posts', - uniqueField: 'posts_every_posts', - thisTable: 'User', - rel: {}, - filterType: 'every', - farCollection: 'posts', - }, - postJoinPipeline: [], - relationships: [ - { - matchTerm: { name: { $eq: 'foo' } }, - relationshipInfo: { - from: 'posts_tags', - uniqueField: 'tags_some_tags', - thisTable: 'Post', - rel: {}, - filterType: 'some', - farCollection: 'tags', - }, - postJoinPipeline: [], - relationships: [], - }, - ], - }, - ], - matchTerm: { - $and: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { - $expr: { - $eq: [{ $size: '$posts_every_posts' }, { $size: '$posts_every_posts_all' }], - }, - }, - ], - }, - }); - }); - - test('builds a query tree with nested relationship with nested OR/AND', () => { - const queryTree = queryParser( - { listAdapter, getUID: jest.fn(key => key) }, - { - OR: [ - { name: 'foobar' }, - { age: 23 }, - { posts_every: { AND: [{ title: 'hello' }, { tags_some: { name: 'foo' } }] } }, - ], - } - ); - - expect(queryTree).toMatchObject({ - relationships: [ - { - matchTerm: { - $and: [ - { title: { $eq: 'hello' } }, - { $expr: { $gt: [{ $size: '$tags_some_tags' }, 0] } }, - ], - }, - relationshipInfo: { - from: 'posts', - uniqueField: 'posts_every_posts', - thisTable: 'User', - rel: {}, - filterType: 'every', - farCollection: 'posts', - }, - postJoinPipeline: [], - relationships: [ - { - matchTerm: { name: { $eq: 'foo' } }, - relationshipInfo: { - from: 'posts_tags', - uniqueField: 'tags_some_tags', - thisTable: 'Post', - rel: {}, - filterType: 'some', - farCollection: 'tags', - }, - postJoinPipeline: [], - relationships: [], - }, - ], - }, - ], - matchTerm: { - $or: [ - { name: { $eq: 'foobar' } }, - { age: { $eq: 23 } }, - { - $expr: { - $eq: [{ $size: '$posts_every_posts' }, { $size: '$posts_every_posts_all' }], - }, - }, - ], - }, - }); - }); - - test('builds a query tree with nested relationship with parallel OR/AND', () => { - const queryTree = queryParser( - { listAdapter, getUID: jest.fn(key => key) }, - { - OR: [{ name: 'foobar' }, { age: 23 }], - AND: [{ age: 30 }, { email: 'foo@bar.com' }], - } - ); - - expect(queryTree).toMatchObject({ - relationships: {}, - matchTerm: { - $and: [ - { $or: [{ name: { $eq: 'foobar' } }, { age: { $eq: 23 } }] }, - { $and: [{ age: { $eq: 30 } }, { email: { $eq: 'foo@bar.com' } }] }, - ], - }, - }); - }); - }); -}); diff --git a/packages/adapter-mongoose/tests/relationship-path.test.js b/packages/adapter-mongoose/tests/relationship-path.test.js deleted file mode 100644 index 9a188b9bf67..00000000000 --- a/packages/adapter-mongoose/tests/relationship-path.test.js +++ /dev/null @@ -1,144 +0,0 @@ -const { getRelatedListAdapterFromQueryPath } = require('../lib/tokenizers'); - -describe('Relationship Path parser', () => { - describe('paths', () => { - test('Handles simple paths correctly', () => { - const fieldAdapters = [ - { - path: 'bar', - isRelationship: true, - getListByKey: jest.fn(() => ({ adapter: barListAdapter })), - }, - { - path: 'zip', - isRelationship: true, - getListByKey: jest.fn(() => ({ adapter: zipListAdapter })), - }, - ]; - - const fooListAdapter = { fieldAdapters }; - const barListAdapter = { fieldAdapters }; - const zipListAdapter = { fieldAdapters: [] }; - - expect(getRelatedListAdapterFromQueryPath(fooListAdapter, ['bar', 'zip', 'ignore'])).toEqual( - zipListAdapter - ); - }); - - test('Handles circular paths correctly', () => { - const fieldAdapter = { - path: 'foo', - isRelationship: true, - getListByKey: jest.fn(() => ({ adapter: listAdapter })), - }; - const listAdapter = { fieldAdapters: [fieldAdapter] }; - - expect( - getRelatedListAdapterFromQueryPath(listAdapter, ['foo', 'foo', 'foo', 'ignore']) - ).toEqual(listAdapter); - }); - - test('Handles arbitrary path strings correctly', () => { - const fieldAdapters = [ - { - path: 'bar_koodle', - isRelationship: true, - getListByKey: jest.fn(() => ({ adapter: barListAdapter })), - }, - { - path: 'zip-boom_zap', - isRelationship: true, - getListByKey: jest.fn(() => ({ adapter: zipListAdapter })), - }, - ]; - - const fooListAdapter = { fieldAdapters }; - const barListAdapter = { fieldAdapters }; - const zipListAdapter = { fieldAdapters: [] }; - - expect( - getRelatedListAdapterFromQueryPath(fooListAdapter, ['bar_koodle', 'zip-boom_zap', 'ignore']) - ).toEqual(zipListAdapter); - }); - - test('Handles paths with AND correctly', () => { - const fieldAdapters = [ - { - path: 'bar_koodle', - isRelationship: true, - getListByKey: jest.fn(() => ({ adapter: barListAdapter })), - }, - { - path: 'zip-boom_zap', - isRelationship: true, - getListByKey: jest.fn(() => ({ adapter: zipListAdapter })), - }, - ]; - - const fooListAdapter = { fieldAdapters }; - const barListAdapter = { fieldAdapters }; - const zipListAdapter = { fieldAdapters: [] }; - - expect( - getRelatedListAdapterFromQueryPath(fooListAdapter, [ - 'bar_koodle', - 'AND', - 1, - 'zip-boom_zap', - 'ignore', - ]) - ).toEqual(zipListAdapter); - }); - - test('Handles paths with OR correctly', () => { - const fieldAdapters = [ - { - path: 'bar_koodle', - isRelationship: true, - getListByKey: jest.fn(() => ({ adapter: barListAdapter })), - }, - { - path: 'zip-boom_zap', - isRelationship: true, - getListByKey: jest.fn(() => ({ adapter: zipListAdapter })), - }, - ]; - - const fooListAdapter = { fieldAdapters }; - const barListAdapter = { fieldAdapters }; - const zipListAdapter = { fieldAdapters: [] }; - - expect( - getRelatedListAdapterFromQueryPath(fooListAdapter, [ - 'bar_koodle', - 'OR', - 1, - 'zip-boom_zap', - 'ignore', - ]) - ).toEqual(zipListAdapter); - }); - }); - - describe('errors', () => { - test('Throws error when field not found', () => { - const fieldAdapters = [ - // NOTE: bar_koodle is missing to make the test fail - { - path: 'zip-boom_zap', - isRelationship: true, - getListByKey: jest.fn(() => ({ adapter: zipListAdapter })), - }, - ]; - - const fooListAdapter = { key: 'foo', fieldAdapters }; - const zipListAdapter = { fieldAdapters: [] }; - - expect(() => - getRelatedListAdapterFromQueryPath(fooListAdapter, ['bar_koodle', 'zip-boom_zap', 'ignore']) - ).toThrow( - /'foo' Mongo List Adapter failed to determine field responsible for the query condition 'bar_koodle'/ - ); - }); - }); -}); diff --git a/packages/adapter-mongoose/tests/relationship.test.js b/packages/adapter-mongoose/tests/relationship.test.js deleted file mode 100644 index 90e7dd4de3b..00000000000 --- a/packages/adapter-mongoose/tests/relationship.test.js +++ /dev/null @@ -1,33 +0,0 @@ -const { relationshipTokenizer } = require('../lib/tokenizers'); - -describe('Relationship tokenizer', () => { - test('Uses correct conditions', () => { - const relationshipConditions = { - isRelationship: true, - getListByKey: () => ({ adapter: { key: 'Bar', model: { collection: { name: 'name' } } } }), - field: { many: false }, - path: 'name', - rel: {}, - }; - const listAdapter = { key: 'Foo', fieldAdapters: [relationshipConditions] }; - - expect(relationshipTokenizer(listAdapter, 'name', ['name'], () => 'abc123')).toMatchObject({ - matchTerm: { $expr: { $eq: [{ $size: '$abc123_name' }, 1] } }, - relationshipInfo: { - from: 'name', - thisTable: 'Foo', - rel: {}, - filterType: 'only', - uniqueField: 'abc123_name', - farCollection: 'name', - }, - }); - }); - - test('returns empty array when no matches found', () => { - const listAdapter = { fieldAdapters: [] }; - - const result = relationshipTokenizer(listAdapter, 'name', ['name'], () => {}); - expect(result).toMatchObject({}); - }); -}); diff --git a/packages/adapter-mongoose/tests/simple.test.js b/packages/adapter-mongoose/tests/simple.test.js deleted file mode 100644 index 050d01d5ab8..00000000000 --- a/packages/adapter-mongoose/tests/simple.test.js +++ /dev/null @@ -1,49 +0,0 @@ -const { simpleTokenizer, modifierTokenizer } = require('../lib/tokenizers'); - -describe('Simple tokenizer', () => { - test('Uses correct conditions', () => { - const simpleConditions = { name: () => ({ foo: 'bar' }) }; - const getQueryConditions = jest.fn(() => simpleConditions); - const listAdapter = { fieldAdapters: [{ getQueryConditions }], config: {} }; - - expect(simpleTokenizer(listAdapter, { name: 'hi' }, 'name', ['name'])).toMatchObject({ - foo: 'bar', - }); - expect(getQueryConditions).toHaveBeenCalledTimes(1); - }); - - test('Falls back to modifier conditions when no simple condition found', () => { - const simpleConditions = { notinuse: () => ({ foo: 'bar' }) }; - const getQueryConditions = jest.fn(() => simpleConditions); - const listAdapter = { fieldAdapters: [{ getQueryConditions }], config: {} }; - - expect(modifierTokenizer(listAdapter, { $count: 'hi' }, '$count', ['$count'])).toMatchObject({ - $count: 'hi', - }); - expect(getQueryConditions).toHaveBeenCalledTimes(0); - }); - - test('returns empty array when no matches found', () => { - const simpleConditions = { notinuse: () => ({ foo: 'bar' }) }; - const getQueryConditions = jest.fn(() => simpleConditions); - const listAdapter = { fieldAdapters: [{ getQueryConditions }], config: {} }; - - const result = simpleTokenizer(listAdapter, { name: 'hi' }, 'name', ['name']); - expect(result).toBe(undefined); - expect(getQueryConditions).toHaveBeenCalledTimes(1); - }); - - test('calls condition function with correct parameters', () => { - const nameConditions = jest.fn(() => ({ foo: 'bar' })); - const simpleConditions = { name: nameConditions }; - const getQueryConditions = jest.fn(() => simpleConditions); - const listAdapter = { fieldAdapters: [{ getQueryConditions }], config: {} }; - - expect(simpleTokenizer(listAdapter, { name: 'hi' }, 'name', ['name'])).toMatchObject({ - foo: 'bar', - }); - expect(getQueryConditions).toHaveBeenCalledTimes(1); - expect(nameConditions).toHaveBeenCalledTimes(1); - expect(nameConditions).toHaveBeenCalledWith('hi', { name: 'hi' }); - }); -}); diff --git a/packages/adapter-mongoose/tests/utils.js b/packages/adapter-mongoose/tests/utils.js deleted file mode 100644 index 8cdf7bdd08a..00000000000 --- a/packages/adapter-mongoose/tests/utils.js +++ /dev/null @@ -1,141 +0,0 @@ -const tagsAdapter = { - key: 'Tag', - model: { collection: { name: 'tags' } }, - _getModel: () => ({ collection: { name: 'posts_tags' } }), - fieldAdapters: [ - { - dbPath: 'name', - getQueryConditions: dbPath => ({ [dbPath]: val => ({ [dbPath]: { $eq: val } }) }), - }, - ], - graphQlQueryPathToMongoField: orderField => orderField, - config: {}, -}; - -const postsAdapter = { - key: 'Post', - model: { collection: { name: 'posts' } }, - _getModel: () => ({ collection: { name: 'posts_tags' } }), - fieldAdapters: [ - { - dbPath: 'title', - getQueryConditions: dbPath => ({ [dbPath]: val => ({ [dbPath]: { $eq: val } }) }), - }, - { - dbPath: 'status', - getQueryConditions: dbPath => ({ [dbPath]: val => ({ [dbPath]: { $eq: val } }) }), - }, - { - path: 'tags', - dbPath: 'tags', - isRelationship: true, - field: { many: true, config: { many: true } }, - rel: { - cardinality: 'N:N', - columnNames: { - 'Tag.posts': { near: 'Tag_id', far: 'Post_id' }, - 'Post.tags': { near: 'Post_id', far: 'Tag_id' }, - }, - collectionName: 'posts_tags', - }, - getQueryConditions: () => {}, - getListByKey: () => ({ adapter: tagsAdapter }), - }, - ], - graphQlQueryPathToMongoField: orderField => orderField, - config: {}, -}; - -const listAdapter = { - key: 'User', - model: { collection: { name: 'users' } }, - fieldAdapters: [ - { - dbPath: 'name', - getQueryConditions: dbPath => ({ [dbPath]: val => ({ [dbPath]: { $eq: val } }) }), - }, - { - dbPath: 'age', - getQueryConditions: dbPath => ({ [dbPath]: val => ({ [dbPath]: { $eq: val } }) }), - }, - { - dbPath: 'address', - getQueryConditions: dbPath => ({ [dbPath]: val => ({ [dbPath]: { $eq: val } }) }), - }, - { - dbPath: 'email', - getQueryConditions: dbPath => ({ [dbPath]: val => ({ [dbPath]: { $eq: val } }) }), - }, - { - dbPath: 'type', - getQueryConditions: dbPath => ({ [dbPath]: val => ({ [dbPath]: { $eq: val } }) }), - }, - { - path: 'company', - isRelationship: true, - field: { many: false, config: { many: false } }, - rel: { columnNames: { User: {}, Company: {} } }, - getQueryConditions: () => {}, - getListByKey: () => ({ - adapter: { - model: { collection: { name: 'company-collection' } }, - fieldAdapters: [ - { - dbPath: 'name', - getQueryConditions: dbPath => ({ [dbPath]: val => ({ [dbPath]: { $eq: val } }) }), - }, - ], - }, - }), - }, - ], - config: {}, -}; - -listAdapter.fieldAdapters.push({ - getQueryConditions: () => {}, - path: 'posts', - dbPath: 'posts', - isRelationship: true, - field: { many: true, config: { many: true } }, - rel: { - cardinality: '1:N', - columnNames: { Tag: {}, Post: {} }, - columnName: 'author', - tableName: 'Post', - }, - getListByKey: () => ({ adapter: postsAdapter }), -}); - -tagsAdapter.fieldAdapters.push({ - path: 'posts', - dbPath: 'posts', - isRelationship: true, - field: { many: true, config: { many: true } }, - rel: { - cardinality: 'N:N', - columnNames: { - 'Tag.posts': { near: 'Tag_id', far: 'Post_id' }, - 'Post.tags': { near: 'Post_id', far: 'Tag_id' }, - }, - collectionName: 'posts_tags', - }, - getQueryConditions: () => {}, - getListByKey: () => ({ adapter: postsAdapter }), -}); - -postsAdapter.fieldAdapters.push({ - getQueryConditions: () => {}, - path: 'author', - isRelationship: true, - field: { many: false, config: { many: false } }, - rel: { - cardinality: '1:N', - columnNames: { Tag: {}, Post: {} }, - columnName: 'author', - tableName: 'Post', - }, - getListByKey: () => ({ adapter: listAdapter }), -}); - -module.exports = { tagsAdapter, postsAdapter, listAdapter }; diff --git a/packages/fields/README.md b/packages/fields/README.md index 23d13bdce0d..2cdd28d2a7a 100644 --- a/packages/fields/README.md +++ b/packages/fields/README.md @@ -24,10 +24,10 @@ Keystone contains a set of primitive fields types that can be imported from the In addition to these, some complex types are packaged separately: -| Field type | Description | -| :--------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [`AutoIncrement`](/packages/fields-auto-increment/README.md) | An automatically incrementing integer; the default type for `id` fields when using the Prisma DB adapter | -| [`CloudinaryImage`](/packages/fields-cloudinary-image/README.md) | Allows uploading images to the [Cloudinary](https://cloudinary.com/) image hosting service | +| Field type | Description | +| :--------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------- | +| [`AutoIncrement`](/packages/fields-auto-increment/README.md) | An automatically incrementing integer; the default type for `id` fields when using the Prisma DB adapter | +| [`CloudinaryImage`](/packages/fields-cloudinary-image/README.md) | Allows uploading images to the [Cloudinary](https://cloudinary.com/) image hosting service | > **Tip:** Need something else? Keystone lets you create [custom field types](/docs/guides/custom-field-types.md) to support almost any use case. diff --git a/packages/fields/package.json b/packages/fields/package.json index 7c998bde93b..7a07571b8d2 100644 --- a/packages/fields/package.json +++ b/packages/fields/package.json @@ -25,7 +25,6 @@ "dumb-passwords": "^0.2.1", "inflection": "^1.12.0", "lodash.groupby": "^4.6.0", - "mongoose": "^5.12.2", "p-settle": "^4.1.1" }, "devDependencies": { diff --git a/packages/fields/src/types/Select/README.md b/packages/fields/src/types/Select/README.md index fdd3c15852f..681250f2d94 100644 --- a/packages/fields/src/types/Select/README.md +++ b/packages/fields/src/types/Select/README.md @@ -57,7 +57,7 @@ keystone.createList('Rsvp', { The Select field can store its value as any of the three following types: -- `enum` (stored as a string in MongoDB) +- `enum` - `string` - `integer` diff --git a/packages/fields/tests/Implementation.test.js b/packages/fields/tests/Implementation.test.js index 15685b90c55..0a09301e2ba 100644 --- a/packages/fields/tests/Implementation.test.js +++ b/packages/fields/tests/Implementation.test.js @@ -38,14 +38,6 @@ describe('new Implementation()', () => { }); }); -test('addToMongooseSchema()', () => { - const impl = new Field('path', {}, args); - - expect(() => { - impl.adapter.addToMongooseSchema(); - }).toThrow(Error); -}); - test('getGqlAuxTypes()', () => { const impl = new Field('path', {}, args); const schemaName = 'public'; diff --git a/packages/fields/tests/test-fixtures.js b/packages/fields/tests/test-fixtures.js index d764c2d33cf..a8f711a99e9 100644 --- a/packages/fields/tests/test-fixtures.js +++ b/packages/fields/tests/test-fixtures.js @@ -111,8 +111,8 @@ export const filterTests = withKeystone => { test( 'Filter: id_in - missing id', - withKeystone(({ keystone, adapterName }) => { - const fakeID = adapterName === 'mongoose' ? '0123456789abcdef01234567' : 1000; + withKeystone(({ keystone }) => { + const fakeID = 1000; return match(keystone, { id_in: [fakeID] }, []); }) ); @@ -145,9 +145,9 @@ export const filterTests = withKeystone => { test( 'Filter: id_not_in - missing id', - withKeystone(async ({ keystone, adapterName }) => { + withKeystone(async ({ keystone }) => { const IDs = await getIDs(keystone); - const fakeID = adapterName === 'mongoose' ? '0123456789abcdef01234567' : 1000; + const fakeID = 1000; return match(keystone, { id_not_in: [fakeID] }, [ { id: IDs['person1'], name: 'person1' }, { id: IDs['person2'], name: 'person2' }, diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 5114f9ba41c..c1be0352574 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -14,7 +14,6 @@ "@keystone-next/keystone-legacy": "^22.0.0", "express": "^4.17.1", "memoize-one": "^5.1.1", - "mongodb-memory-server-core": "^6.9.6", "supertest-light": "^1.0.3" }, "repository": "https://github.com/keystonejs/keystone/tree/master/packages/test-utils" diff --git a/packages/test-utils/src/index.ts b/packages/test-utils/src/index.ts index 0116b67c123..65d9e79e07a 100644 --- a/packages/test-utils/src/index.ts +++ b/packages/test-utils/src/index.ts @@ -1,11 +1,9 @@ import path from 'path'; import crypto from 'crypto'; import { ServerResponse } from 'http'; -import url from 'url'; import express from 'express'; // @ts-ignore import supertest from 'supertest-light'; -import MongoDBMemoryServer from 'mongodb-memory-server-core'; // @ts-ignore import { Keystone } from '@keystone-next/keystone-legacy'; import { initConfig, createSystem, createExpressServer } from '@keystone-next/keystone'; @@ -19,7 +17,6 @@ const hashPrismaSchema = memoizeOne(prismaSchema => ); const argGenerator = { - mongoose: getMongoMemoryServerConfig, prisma_postgresql: () => ({ migrationMode: 'prototype', dropDatabase: true, @@ -108,20 +105,6 @@ function networkedGraphqlRequest({ })); } -// One instance per node.js thread which cleans itself up when the main process -// exits -let mongoServer: MongoDBMemoryServer | undefined | null; - -async function getMongoMemoryServerConfig() { - mongoServer = mongoServer || new MongoDBMemoryServer(); - // Passing `true` here generates a new, random DB name for us - const mongoUri = await mongoServer.getConnectionString(true); - // In theory the dbName can contain query params so lets parse it then extract the db name - const dbName = url.parse(mongoUri).pathname!.split('/').pop(); - - return { mongoUri, dbName }; -} - type Setup = { keystone: BaseKeystone; context: KeystoneContext; app: express.Application }; function _keystoneRunner(adapterName: AdapterName, tearDownFunction: () => Promise | void) { diff --git a/tests/api-tests/access-control/utils.ts b/tests/api-tests/access-control/utils.ts index 70145bd494e..3059d783ca6 100644 --- a/tests/api-tests/access-control/utils.ts +++ b/tests/api-tests/access-control/utils.ts @@ -7,12 +7,10 @@ import { objMerge } from '@keystone-next/utils-legacy'; import type { KeystoneConfig } from '@keystone-next/types'; const FAKE_ID = { - mongoose: '5b3eabd9e9f2e3e4866742ea', prisma_postgresql: 137, prisma_sqlite: 137, } as const; const FAKE_ID_2 = { - mongoose: '5b3eabd9e9f2e3e4866742eb', prisma_postgresql: 138, prisma_sqlite: 137, } as const; diff --git a/tests/api-tests/package.json b/tests/api-tests/package.json index b92f4dca615..39d323b9f46 100644 --- a/tests/api-tests/package.json +++ b/tests/api-tests/package.json @@ -12,7 +12,6 @@ "homepage": "https://github.com/keystonejs/keystone", "devDependencies": { "@hapi/iron": "^6.0.0", - "@keystone-next/adapter-mongoose-legacy": "*", "@keystone-next/auth": "*", "@keystone-next/fields": "*", "@keystone-next/keystone": "*", diff --git a/tests/benchmarks/package.json b/tests/benchmarks/package.json index 016a154163a..a961279bc1f 100644 --- a/tests/benchmarks/package.json +++ b/tests/benchmarks/package.json @@ -14,7 +14,6 @@ "repository": "https://github.com/keystonejs/keystone/tree/master/tests/benchmarks", "homepage": "https://github.com/keystonejs/keystone", "dependencies": { - "@keystone-next/adapter-mongoose-legacy": "^11.1.3", "@keystone-next/fields": "^5.4.0", "@keystone-next/fields-legacy": "^24.0.0", "@keystone-next/keystone": "^14.0.1", diff --git a/yarn.lock b/yarn.lock index eab3438031b..6f0d3fd7edf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2545,13 +2545,6 @@ "@types/connect" "*" "@types/node" "*" -"@types/bson@*": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@types/bson/-/bson-4.0.3.tgz#30889d2ffde6262abbe38659364c631454999fbf" - integrity sha512-mVRvYnTOZJz3ccpxhr3wgxVmSeiYinW+zlzQz3SXWaJmD1DuL05Jeq7nKw3SnbKmbleW5qrLG5vdyWe/A9sXhw== - dependencies: - "@types/node" "*" - "@types/classnames@^2.2.11": version "2.2.11" resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-2.2.11.tgz#2521cc86f69d15c5b90664e4829d84566052c1cf" @@ -2750,19 +2743,12 @@ resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.2.tgz#513abfd256d7ad0bf1ee1873606317b33b1b2a72" integrity sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw== -"@types/keystonejs__adapter-mongoose@^5.1.2": - version "5.1.2" - resolved "https://registry.yarnpkg.com/@types/keystonejs__adapter-mongoose/-/keystonejs__adapter-mongoose-5.1.2.tgz#524c0bedc7365cf180f502e243dfe68557db72f8" - integrity sha512-IoK2aNIrCk9WPTTCTaWnoydn5Nfm4OEPaU2lXirYhlGREPG3zED7DblbzNpqHwcr/a1FMLzw9YUUNCjYOfYC1A== - dependencies: - "@types/keystonejs__keystone" "*" - "@types/keystonejs__fields@*", "@types/keystonejs__fields@^5.1.1": version "5.1.1" resolved "https://registry.yarnpkg.com/@types/keystonejs__fields/-/keystonejs__fields-5.1.1.tgz#1c91718eeee0b2e58a2b3f57ad234967bad202df" integrity sha512-m8Ny/rTXzzoKO33UDkcspmHK0Q/qP4teo2510+HG1NMxM7pF/jPPL/viGtAJF/eIYEsSZxzwNSTFWMw/DlPIwQ== -"@types/keystonejs__keystone@*", "@types/keystonejs__keystone@^7.0.1": +"@types/keystonejs__keystone@^7.0.1": version "7.0.1" resolved "https://registry.yarnpkg.com/@types/keystonejs__keystone/-/keystonejs__keystone-7.0.1.tgz#3dbb00813aff29149f0ae877514be0b077455ec0" integrity sha512-m0LTB8aKkBQrU5+B2Qc2e5YMdi/YrmqH5doPtETqda6zMaFeV+L9DGAUQMyT8CjOK73kPDMVljNDkZ5/MvQ3RA== @@ -2831,14 +2817,6 @@ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.1.tgz#283f669ff76d7b8260df8ab7a4262cc83d988256" integrity sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg== -"@types/mongodb@^3.5.27": - version "3.6.10" - resolved "https://registry.yarnpkg.com/@types/mongodb/-/mongodb-3.6.10.tgz#80cceaabeec9f460e5b46844e938e8eba74f9266" - integrity sha512-BkwAHFiZSSWdTIqbUVGmgvIsiXXjqAketeK7Izy7oSs6G3N8Bn993tK9eq6QEovQDx6OQ2FGP2KWDDxBzdlJ6Q== - dependencies: - "@types/bson" "*" - "@types/node" "*" - "@types/node-fetch@2.5.7": version "2.5.7" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c" @@ -3028,11 +3006,6 @@ resolved "https://registry.yarnpkg.com/@types/tinycolor2/-/tinycolor2-1.4.2.tgz#721ca5c5d1a2988b4a886e35c2ffc5735b6afbdf" integrity sha512-PeHg/AtdW6aaIO2a+98Xj7rWY4KC1E6yOy7AFknJQ7VXUGNrMlyxDFxJo7HqLtjQms/ZhhQX52mLVW/EX3JGOw== -"@types/tmp@^0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.2.0.tgz#e3f52b4d7397eaa9193592ef3fdd44dc0af4298c" - integrity sha512-flgpHJjntpBAdJD43ShRosQvNC0ME97DCfGvZEDlAThQmnerRXrLbX6YgzRBQCZTthET9eAWFAMaYP0m0Y4HzQ== - "@types/tough-cookie@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.0.tgz#fef1904e4668b6e5ecee60c52cc6a078ffa6697d" @@ -4092,14 +4065,6 @@ bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" -bl@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.1.tgz#8c11a7b730655c5d56898cdc871224f40fd901d5" - integrity sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g== - dependencies: - readable-stream "^2.3.5" - safe-buffer "^5.1.1" - bl@^4.0.3: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" @@ -4114,11 +4079,6 @@ blob-util@2.0.2: resolved "https://registry.yarnpkg.com/blob-util/-/blob-util-2.0.2.tgz#3b4e3c281111bb7f11128518006cdc60b403a1eb" integrity sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ== -bluebird@3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" - integrity sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA== - bluebird@3.7.2, bluebird@^3.7.2: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" @@ -4313,11 +4273,6 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" -bson@^1.1.4: - version "1.1.6" - resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.6.tgz#fb819be9a60cd677e0853aee4ca712a785d6618a" - integrity sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg== - buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" @@ -5405,14 +5360,7 @@ debug@2, debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: dependencies: ms "2.0.0" -debug@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - -debug@4, debug@4.3.1, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0: +debug@4, debug@4.3.1, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.3.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== @@ -6678,11 +6626,6 @@ find-cache-dir@3.3.1, find-cache-dir@^3.3.1: make-dir "^3.0.2" pkg-dir "^4.1.0" -find-package-json@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/find-package-json/-/find-package-json-1.2.0.tgz#4057d1b943f82d8445fe52dc9cf456f6b8b58083" - integrity sha512-+SOGcLGYDJHtyqHd87ysBhmaeQ95oWspDKnMXBrnQ9Eq4OkLNqejgoaD8xVWu6GPa0B6roa6KinCMEMcVeqONw== - find-up@5.0.0, find-up@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" @@ -6966,11 +6909,6 @@ get-package-type@^0.1.0: resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== -get-port@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" - integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== - get-stdin@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" @@ -8823,11 +8761,6 @@ jsprim@^1.2.2: array-includes "^3.1.2" object.assign "^4.1.2" -kareem@2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.2.tgz#78c4508894985b8d38a0dc15e1a8e11078f2ca93" - integrity sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ== - keyv@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" @@ -9040,13 +8973,6 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -lockfile@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/lockfile/-/lockfile-1.0.4.tgz#07f819d25ae48f87e538e6578b6964a4981a5609" - integrity sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA== - dependencies: - signal-exit "^3.0.2" - lodash.clonedeep@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" @@ -9304,11 +9230,6 @@ match-sorter@^6.3.0: "@babel/runtime" "^7.12.5" remove-accents "0.4.2" -md5-file@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/md5-file/-/md5-file-5.0.0.tgz#e519f631feca9c39e7f9ea1780b63c4745012e20" - integrity sha512-xbEFXCYVWrSx/gEKS1VPlg84h/4L20znVIulKw6kMfmBUAZNAnF00eczz9ICMl+/hjQGo5KSXRxbL/47X3rmMw== - md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -9446,11 +9367,6 @@ memoize-one@^5.0.0, memoize-one@^5.1.1: resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0" integrity sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA== -memory-pager@^1.0.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" - integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== - meow@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/meow/-/meow-4.0.1.tgz#d48598f6f4b1472f35bf6317a95945ace347f975" @@ -9751,82 +9667,6 @@ moment@^2.27.0: resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== -mongodb-memory-server-core@^6.9.6: - version "6.9.6" - resolved "https://registry.yarnpkg.com/mongodb-memory-server-core/-/mongodb-memory-server-core-6.9.6.tgz#90ef0562bea675ef68bd687533792da02bcc81f3" - integrity sha512-ZcXHTI2TccH3L5N9JyAMGm8bbAsfLn8SUWOeYGHx/vDx7vu4qshyaNXTIxeHjpUQA29N+Z1LtTXA6vXjl1eg6w== - dependencies: - "@types/tmp" "^0.2.0" - camelcase "^6.0.0" - cross-spawn "^7.0.3" - debug "^4.2.0" - find-cache-dir "^3.3.1" - find-package-json "^1.2.0" - get-port "^5.1.1" - https-proxy-agent "^5.0.0" - lockfile "^1.0.4" - md5-file "^5.0.0" - mkdirp "^1.0.4" - semver "^7.3.2" - tar-stream "^2.1.4" - tmp "^0.2.1" - uuid "^8.3.0" - yauzl "^2.10.0" - optionalDependencies: - mongodb "^3.6.2" - -mongodb@3.6.5, mongodb@^3.6.2, mongodb@^3.6.5: - version "3.6.5" - resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.6.5.tgz#c27d786fd4d3c83dc19302483707d12a9d2aee5f" - integrity sha512-mQlYKw1iGbvJJejcPuyTaytq0xxlYbIoVDm2FODR+OHxyEiMR021vc32bTvamgBjCswsD54XIRwhg3yBaWqJjg== - dependencies: - bl "^2.2.1" - bson "^1.1.4" - denque "^1.4.1" - require_optional "^1.0.1" - safe-buffer "^5.1.2" - optionalDependencies: - saslprep "^1.0.0" - -mongoose-legacy-pluralize@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz#3ba9f91fa507b5186d399fb40854bff18fb563e4" - integrity sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ== - -mongoose@^5.12.2: - version "5.12.2" - resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-5.12.2.tgz#3274630dfb9a8e63dbda0c6e7124fd475623c6ff" - integrity sha512-kT9t6Nvu9WPsfssn7Gzke446Il8UdMilY7Sa5vALtwoOoNOGtZEVjekZBFwsBFzTWtBA/x5gBmJoYFP+1LeDlg== - dependencies: - "@types/mongodb" "^3.5.27" - bson "^1.1.4" - kareem "2.3.2" - mongodb "3.6.5" - mongoose-legacy-pluralize "1.0.2" - mpath "0.8.3" - mquery "3.2.4" - ms "2.1.2" - regexp-clone "1.0.0" - safe-buffer "5.2.1" - sift "7.0.1" - sliced "1.0.1" - -mpath@0.8.3: - version "0.8.3" - resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.8.3.tgz#828ac0d187f7f42674839d74921970979abbdd8f" - integrity sha512-eb9rRvhDltXVNL6Fxd2zM9D4vKBxjVVQNLNijlj7uoXUy19zNDsIif5zR+pWmPCWNKwAtqyo4JveQm4nfD5+eA== - -mquery@3.2.4: - version "3.2.4" - resolved "https://registry.yarnpkg.com/mquery/-/mquery-3.2.4.tgz#9c5c2e285ea6c6f20673f3528973c99ee1aaa1a0" - integrity sha512-uOLpp7iRX0BV1Uu6YpsqJ5b42LwYnmu0WeF/f8qgD/On3g0XDaQM6pfn0m6UxO6SM8DioZ9Bk6xxbWIGHm2zHg== - dependencies: - bluebird "3.5.1" - debug "3.1.0" - regexp-clone "^1.0.0" - safe-buffer "5.1.2" - sliced "1.0.1" - ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -11458,7 +11298,7 @@ read-yaml-file@^1.1.0: pify "^4.0.1" strip-bom "^3.0.0" -readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@^2.3.7: +readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@^2.3.7: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -11579,11 +11419,6 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexp-clone@1.0.0, regexp-clone@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-1.0.0.tgz#222db967623277056260b992626354a04ce9bf63" - integrity sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw== - regexp.prototype.flags@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" @@ -11856,14 +11691,6 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== -require_optional@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require_optional/-/require_optional-1.0.1.tgz#4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e" - integrity sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g== - dependencies: - resolve-from "^2.0.0" - semver "^5.1.0" - requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -11876,11 +11703,6 @@ resolve-cwd@^3.0.0: dependencies: resolve-from "^5.0.0" -resolve-from@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" - integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c= - resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" @@ -12018,7 +11840,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -12050,13 +11872,6 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" -saslprep@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" - integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag== - dependencies: - sparse-bitfield "^3.0.3" - sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -12101,7 +11916,7 @@ sembear@^0.5.0: "@types/semver" "^6.0.1" semver "^6.3.0" -"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.4.1, semver@^5.5.0: +"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -12250,11 +12065,6 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" -sift@7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/sift/-/sift-7.0.1.tgz#47d62c50b159d316f1372f8b53f9c10cd21a4b08" - integrity sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g== - signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" @@ -12353,11 +12163,6 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -sliced@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/sliced/-/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41" - integrity sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E= - smartwrap@^1.2.3: version "1.2.5" resolved "https://registry.yarnpkg.com/smartwrap/-/smartwrap-1.2.5.tgz#45ee3e09ac234e5f7f17c16e916f511834f3cd23" @@ -12463,13 +12268,6 @@ space-separated-tokens@^1.0.0: resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA== -sparse-bitfield@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" - integrity sha1-/0rm5oZWBWuks+eSqzM004JzyhE= - dependencies: - memory-pager "^1.0.2" - spawndamnit@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/spawndamnit/-/spawndamnit-2.0.0.tgz#9f762ac5c3476abb994b42ad592b5ad22bb4b0ad" @@ -13050,7 +12848,7 @@ tailwindcss@^2.0.4: reduce-css-calc "^2.1.8" resolve "^1.20.0" -tar-stream@^2.1.2, tar-stream@^2.1.4: +tar-stream@^2.1.2: version "2.2.0" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== @@ -13201,7 +12999,7 @@ tinycolor2@^1.4.2: resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803" integrity sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA== -tmp@0.2.1, tmp@^0.2.1, tmp@~0.2.1: +tmp@0.2.1, tmp@~0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==