chore(): start moving some packages to the core directory (#7215)
This commit is contained in:
1 parent
fdee748eed
commit
bbccd6481d
1436 files changed
+275
-756
No files matched your search
@@ -0,0 +1,422 @@
|
||||
# @medusajs/utils
|
||||
|
||||
## 1.11.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6922](https://github.com/medusajs/medusa/pull/6922) [`20e8df914e`](https://github.com/medusajs/medusa/commit/20e8df914ec5fdf8d562d4fa84f72c58c7056195) Thanks [@sradevski](https://github.com/sradevski)! - Return normalized DB errors from the mikro ORM repository
|
||||
|
||||
- [#6836](https://github.com/medusajs/medusa/pull/6836) [`e0b02a1012`](https://github.com/medusajs/medusa/commit/e0b02a1012981c29830d7779f59ebe805bbfd137) Thanks [@adrien2p](https://github.com/adrien2p)! - feat(utils): custom serialization that allows for non self ref
|
||||
|
||||
- [#6864](https://github.com/medusajs/medusa/pull/6864) [`e944a627f0`](https://github.com/medusajs/medusa/commit/e944a627f074fb39a56f4bc7b3d6d315736ebf7c) Thanks [@adrien2p](https://github.com/adrien2p)! - feat: region payment providers management workflows/api
|
||||
|
||||
- [`cc557c8752`](https://github.com/medusajs/medusa/commit/cc557c8752fd0554f5a1b58522d9a88dc43a8509) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - Order endpoints and Cart totals
|
||||
|
||||
- [#6842](https://github.com/medusajs/medusa/pull/6842) [`5d9aea053c`](https://github.com/medusajs/medusa/commit/5d9aea053ce6e04f242f86fb9053c13dec515d5b) Thanks [@adrien2p](https://github.com/adrien2p)! - fix(utils): Mikro orm prop filtering should check existence
|
||||
|
||||
- [#6973](https://github.com/medusajs/medusa/pull/6973) [`232322d035`](https://github.com/medusajs/medusa/commit/232322d03515f81e56867ff8c765b8409399ee68) Thanks [@adrien2p](https://github.com/adrien2p)! - Chores: Do not disable foreign keys by default
|
||||
|
||||
- [#7153](https://github.com/medusajs/medusa/pull/7153) [`4b57c5d286`](https://github.com/medusajs/medusa/commit/4b57c5d286f9dc6e2098c67e9fecb0d93175b5a1) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - Remote query supporting context
|
||||
|
||||
- [#6813](https://github.com/medusajs/medusa/pull/6813) [`a6562d2a41`](https://github.com/medusajs/medusa/commit/a6562d2a41453cbe7aa43be352c4924e3e4c79d5) Thanks [@sradevski](https://github.com/sradevski)! - Added an upsertWithReplace method to the mikro orm repository
|
||||
|
||||
- Updated dependencies [[`0c0b425de7`](https://github.com/medusajs/medusa/commit/0c0b425de7b154b80b712ab17b16215cf62d1e83), [`8d356217bd`](https://github.com/medusajs/medusa/commit/8d356217bd31c97a196e861ee243822a4d924df7), [`27f4f0d724`](https://github.com/medusajs/medusa/commit/27f4f0d7243367c2dfc6012bf1f6b7400a77ec7b), [`e944a627f0`](https://github.com/medusajs/medusa/commit/e944a627f074fb39a56f4bc7b3d6d315736ebf7c), [`1a48fe0282`](https://github.com/medusajs/medusa/commit/1a48fe0282a8bc1f8548a4736255e457d173da09), [`86f499de2f`](https://github.com/medusajs/medusa/commit/86f499de2f31356ab36ad5e93f27345443b3e5f6), [`09a2220569`](https://github.com/medusajs/medusa/commit/09a22205693da62fbf8fd450535d5024cb9c01d1), [`78f603e4f1`](https://github.com/medusajs/medusa/commit/78f603e4f18c9d16f4b58a2189c959026453d8b2), [`cc557c8752`](https://github.com/medusajs/medusa/commit/cc557c8752fd0554f5a1b58522d9a88dc43a8509), [`58c68f6715`](https://github.com/medusajs/medusa/commit/58c68f67156e993255fbc25d91db15ae23bc95c0), [`82a176e30e`](https://github.com/medusajs/medusa/commit/82a176e30e47a7d11caaf31c3023bd8db588b465), [`11517f0faf`](https://github.com/medusajs/medusa/commit/11517f0fafdf00af256240448b58d149d8b6f600), [`62b9dcc6c1`](https://github.com/medusajs/medusa/commit/62b9dcc6c1ce46aadb7944215006c12da3c9f619), [`e26cda4b6a`](https://github.com/medusajs/medusa/commit/e26cda4b6afb7fb25f0b0a7a7ce20b7f914d35db), [`bc06ad2db4`](https://github.com/medusajs/medusa/commit/bc06ad2db48c999023ab823fefc1375196976e9b), [`18f3aacee6`](https://github.com/medusajs/medusa/commit/18f3aacee6752854d377faa806f4cc67bc71456b), [`38c971f111`](https://github.com/medusajs/medusa/commit/38c971f111af69f176e7e9892eb59f5bae831fa7), [`45c49e89f2`](https://github.com/medusajs/medusa/commit/45c49e89f28123ef622fc1c07253bae94fd74875), [`528ef4ca90`](https://github.com/medusajs/medusa/commit/528ef4ca90bb2cf6173dccc9fd6a9f9932ff9b76), [`65794f4bb5`](https://github.com/medusajs/medusa/commit/65794f4bb56e4fd3f0ccb7656a948f856f05324e), [`93ef94cad3`](https://github.com/medusajs/medusa/commit/93ef94cad3ddc5b6973b4e48e422b0aa0e6ddbbe), [`4cf71af07d`](https://github.com/medusajs/medusa/commit/4cf71af07d1807c83df3889c1774f82cbd1b9a6f), [`4b57c5d286`](https://github.com/medusajs/medusa/commit/4b57c5d286f9dc6e2098c67e9fecb0d93175b5a1), [`c78915c7c5`](https://github.com/medusajs/medusa/commit/c78915c7c5e91a99c1b1bae932656c8d86b17daf), [`18f3aacee6`](https://github.com/medusajs/medusa/commit/18f3aacee6752854d377faa806f4cc67bc71456b), [`f175cac4af`](https://github.com/medusajs/medusa/commit/f175cac4af63b71066a8398ecf9beaa6f28b20cc), [`0a9b9b073d`](https://github.com/medusajs/medusa/commit/0a9b9b073dd2d3f4aa5e5cb1c16e2221a7200e0d), [`a6562d2a41`](https://github.com/medusajs/medusa/commit/a6562d2a41453cbe7aa43be352c4924e3e4c79d5), [`00e6b21bb5`](https://github.com/medusajs/medusa/commit/00e6b21bb50dbc886bc37ad052a1c40ce865294e), [`8fd1488938`](https://github.com/medusajs/medusa/commit/8fd148893850eb66c5eae00c4ca9391a80ea2eb9), [`1c6ba4468e`](https://github.com/medusajs/medusa/commit/1c6ba4468eab1440931c88929affd5b4c593f377)]:
|
||||
- @medusajs/types@1.11.16
|
||||
|
||||
## 1.11.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6796](https://github.com/medusajs/medusa/pull/6796) [`9073d7aba3`](https://github.com/medusajs/medusa/commit/9073d7aba3419e4dc0a206473291a46ebd79b8c1) Thanks [@riqwan](https://github.com/riqwan)! - feat(core-flows,medusa,types,utils): rename psma to prices
|
||||
|
||||
- [#6751](https://github.com/medusajs/medusa/pull/6751) [`4974f5e455`](https://github.com/medusajs/medusa/commit/4974f5e4557bd64a328a881ec02b91e15485bd23) Thanks [@riqwan](https://github.com/riqwan)! - feat(utils): autogenerates create and update methods when dto is provided
|
||||
|
||||
- [#6772](https://github.com/medusajs/medusa/pull/6772) [`1ef9c78cea`](https://github.com/medusajs/medusa/commit/1ef9c78cea080c3b7c136f909c6cddec9d8f0c62) Thanks [@adrien2p](https://github.com/adrien2p)! - chore: v2 - deprecate extra in favor of driver options
|
||||
|
||||
- Updated dependencies [[`deab12e27e`](https://github.com/medusajs/medusa/commit/deab12e27e8249e26d24d7bc904c18195679ff24), [`56481e683d`](https://github.com/medusajs/medusa/commit/56481e683d33ff98f0d4c4e144873bb23f993c9c), [`9073d7aba3`](https://github.com/medusajs/medusa/commit/9073d7aba3419e4dc0a206473291a46ebd79b8c1), [`05e857d256`](https://github.com/medusajs/medusa/commit/05e857d25657b5576a891c9b48c19c1759c70701), [`1ef9c78cea`](https://github.com/medusajs/medusa/commit/1ef9c78cea080c3b7c136f909c6cddec9d8f0c62)]:
|
||||
- @medusajs/types@1.11.15
|
||||
|
||||
## 1.11.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6648](https://github.com/medusajs/medusa/pull/6648) [`9288f53327`](https://github.com/medusajs/medusa/commit/9288f53327b8ce617af92ed8d14d9459cbfeb13c) Thanks [@riqwan](https://github.com/riqwan)! - feat(core-flows,medusa,utils): added price list prices upsert and delete workflows + endpoints
|
||||
|
||||
- [#6504](https://github.com/medusajs/medusa/pull/6504) [`56cbf88115`](https://github.com/medusajs/medusa/commit/56cbf88115994adea7037c3f2814f0c96af3cfc0) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(utils): Soft delete should allow self referencing circular deps
|
||||
|
||||
- [#6473](https://github.com/medusajs/medusa/pull/6473) [`36a61658f9`](https://github.com/medusajs/medusa/commit/36a61658f969a7b19c84a1e621ad1464927cafb1) Thanks [@adrien2p](https://github.com/adrien2p)! - feat(utils): Fix big number decorator and cleanup
|
||||
|
||||
- [#6436](https://github.com/medusajs/medusa/pull/6436) [`c319edb8e0`](https://github.com/medusajs/medusa/commit/c319edb8e0ecd13d086652147667916e5abab2d8) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(utils): Add default ordering to the internal service factory list/listAndCount
|
||||
|
||||
- [#6531](https://github.com/medusajs/medusa/pull/6531) [`0b9fcb6324`](https://github.com/medusajs/medusa/commit/0b9fcb6324eee9f2556c7e6317775fae93b12a47) Thanks [@riqwan](https://github.com/riqwan)! - feat(utils): consolidate promotion utils + refactor
|
||||
|
||||
- [#6525](https://github.com/medusajs/medusa/pull/6525) [`b3d826497b`](https://github.com/medusajs/medusa/commit/b3d826497b3dae5e1b26b7924706c24fd5e87ca5) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(utils): Improve big number decorator
|
||||
|
||||
- [#6386](https://github.com/medusajs/medusa/pull/6386) [`a86c87fe14`](https://github.com/medusajs/medusa/commit/a86c87fe1442afce9285e39255914e01012b4449) Thanks [@pKorsholm](https://github.com/pKorsholm)! - feat(utils): make psql index util return index instead of constraint for unique indicies becuase partial constraints don't exist :'(
|
||||
|
||||
- [#6692](https://github.com/medusajs/medusa/pull/6692) [`640eccd5dd`](https://github.com/medusajs/medusa/commit/640eccd5ddbb163e0f987ce6c772f1129c2e2632) Thanks [@riqwan](https://github.com/riqwan)! - feat(core-flows,medusa,types,utils): add rules to promotion endpoints + workflow
|
||||
|
||||
- [#6499](https://github.com/medusajs/medusa/pull/6499) [`8ea37d03c9`](https://github.com/medusajs/medusa/commit/8ea37d03c914a5004a3e42770668b2d1f7f8f564) Thanks [@riqwan](https://github.com/riqwan)! - fix(utils): bignumber util considers nullable options when setting value
|
||||
|
||||
- [#6399](https://github.com/medusajs/medusa/pull/6399) [`339a946f38`](https://github.com/medusajs/medusa/commit/339a946f389033c21e05338f9dbf07d88e140533) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - Initial Order module implementation
|
||||
|
||||
- [#6648](https://github.com/medusajs/medusa/pull/6648) [`9288f53327`](https://github.com/medusajs/medusa/commit/9288f53327b8ce617af92ed8d14d9459cbfeb13c) Thanks [@riqwan](https://github.com/riqwan)! - feat(core-flows,medusa,pricing,types,utils): added price list workflows + endpoints
|
||||
|
||||
- [#6441](https://github.com/medusajs/medusa/pull/6441) [`8dad2b51a2`](https://github.com/medusajs/medusa/commit/8dad2b51a26c4c3c14a6c95f70424c8bef2ad63e) Thanks [@riqwan](https://github.com/riqwan)! - feat(medusa-react,medusa,utils): fix login for medusa v2 admin next dashboard
|
||||
|
||||
- [#6289](https://github.com/medusajs/medusa/pull/6289) [`a6d7070dd6`](https://github.com/medusajs/medusa/commit/a6d7070dd669c21ea19d70434d42c2f8167dc309) Thanks [@riqwan](https://github.com/riqwan)! - feat(types): add util to transform get response to an update request
|
||||
|
||||
- [#6489](https://github.com/medusajs/medusa/pull/6489) [`168f02f138`](https://github.com/medusajs/medusa/commit/168f02f138ad101e1013f2c8c3f8dc19de12accf) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(util): Detect circular dependencies on soft delete
|
||||
|
||||
- [#6514](https://github.com/medusajs/medusa/pull/6514) [`f5c2256286`](https://github.com/medusajs/medusa/commit/f5c22562867f412040f8bc6c55ab5de3a3735e62) Thanks [@riqwan](https://github.com/riqwan)! - feat(core-flows,medusa,types,utils): adds update cart API with promotions
|
||||
|
||||
- [#6592](https://github.com/medusajs/medusa/pull/6592) [`000eb61e33`](https://github.com/medusajs/medusa/commit/000eb61e33e0302db95ee6ad1656ea9b430ed471) Thanks [@riqwan](https://github.com/riqwan)! - feat(pricing,medusa,utils): added list + get endpoints for price lists
|
||||
|
||||
- [#6524](https://github.com/medusajs/medusa/pull/6524) [`62a7bcc30c`](https://github.com/medusajs/medusa/commit/62a7bcc30cbc7b234b2b51d7858439951a84edeb) Thanks [@adrien2p](https://github.com/adrien2p)! - Feat(fulfillment): service provider registration + fulfillment management
|
||||
|
||||
- [#6700](https://github.com/medusajs/medusa/pull/6700) [`8f8a4f9b13`](https://github.com/medusajs/medusa/commit/8f8a4f9b1353087d98f6cc75346d43a7f49901a8) Thanks [@olivermrbl](https://github.com/olivermrbl)! - chore: Version all modules to allow for initial testing
|
||||
|
||||
- [#6396](https://github.com/medusajs/medusa/pull/6396) [`6500f18b9b`](https://github.com/medusajs/medusa/commit/6500f18b9b80c5c9c473489e7e740d55dca74303) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(): Prevent from soft deleting all entities
|
||||
|
||||
- [#6311](https://github.com/medusajs/medusa/pull/6311) [`ce39b9b66e`](https://github.com/medusajs/medusa/commit/ce39b9b66e8c277ec0691ea6d0a950003be09cc1) Thanks [@olivermrbl](https://github.com/olivermrbl)! - feat(payment-stripe): new Stripe payment provider
|
||||
|
||||
- [#6308](https://github.com/medusajs/medusa/pull/6308) [`a6a4b3f01a`](https://github.com/medusajs/medusa/commit/a6a4b3f01a6d2bd97b1580c59134279a1b033a5d) Thanks [@fPolic](https://github.com/fPolic)! - feat(types, utils): payment module - provider service
|
||||
|
||||
- [#6435](https://github.com/medusajs/medusa/pull/6435) [`56b0b45304`](https://github.com/medusajs/medusa/commit/56b0b4530401a6ec5aa155874d371e45bb388fe2) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - BigNumberField decorator
|
||||
|
||||
- [#6698](https://github.com/medusajs/medusa/pull/6698) [`cc1b66842c`](https://github.com/medusajs/medusa/commit/cc1b66842cbb37c6eab84e2d8b74844c214f38d7) Thanks [@riqwan](https://github.com/riqwan)! - feat(core-flows,medusa,types,utils): add/remove fulfillment shipping option rules
|
||||
|
||||
- [#6383](https://github.com/medusajs/medusa/pull/6383) [`e85463b2a7`](https://github.com/medusajs/medusa/commit/e85463b2a717751de2e21c39a4c745449b31affe) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(): Fix database test utils and utils
|
||||
|
||||
- Updated dependencies [[`1fd0457c15`](https://github.com/medusajs/medusa/commit/1fd0457c153b2ef7657c052878d8e5364e1b324a), [`d4b921f3db`](https://github.com/medusajs/medusa/commit/d4b921f3dbe0a38f1565a8de759996c70798d58e), [`ac86362e81`](https://github.com/medusajs/medusa/commit/ac86362e81d8523cb8e3dfad026fc94658513018), [`e4acde1aa2`](https://github.com/medusajs/medusa/commit/e4acde1aa2eb57f07e6692fe8b61f728948b9a96), [`1a661adf3e`](https://github.com/medusajs/medusa/commit/1a661adf3ef4991aa6e237dd894b6a5c47cd4aca), [`04a532e5ef`](https://github.com/medusajs/medusa/commit/04a532e5efabbf75b1e4155520b1da175b686ffc), [`640eccd5dd`](https://github.com/medusajs/medusa/commit/640eccd5ddbb163e0f987ce6c772f1129c2e2632), [`339a946f38`](https://github.com/medusajs/medusa/commit/339a946f389033c21e05338f9dbf07d88e140533), [`ac829fc67f`](https://github.com/medusajs/medusa/commit/ac829fc67f7495b08f28e55923c59f0fd6320311), [`d9d5afc3cf`](https://github.com/medusajs/medusa/commit/d9d5afc3cfc29221d0e65bff7b78474a8fb8f31f), [`c3c4f49fc2`](https://github.com/medusajs/medusa/commit/c3c4f49fc2126f950e69e291ca939ca88a15afd3), [`9288f53327`](https://github.com/medusajs/medusa/commit/9288f53327b8ce617af92ed8d14d9459cbfeb13c), [`0d46abf0ff`](https://github.com/medusajs/medusa/commit/0d46abf0ffa4c5e03bf7d2a9cdf1db828a76bea8), [`fafde4f54d`](https://github.com/medusajs/medusa/commit/fafde4f54d3ef75a7d382e6cbf94e38b3deae99b), [`0c705d7bd4`](https://github.com/medusajs/medusa/commit/0c705d7bd41a768c48017ae95b3c8414d96c6acb), [`1d91b7429b`](https://github.com/medusajs/medusa/commit/1d91b7429beebd6f09d5027f7f7e1fe74ce3a8ff), [`1ed5f918c3`](https://github.com/medusajs/medusa/commit/1ed5f918c31794a70aca4a4e4cd83cf456593baa), [`c20eb15cd9`](https://github.com/medusajs/medusa/commit/c20eb15cd9b1bd90c8d01f68eca6f0f181cd902d), [`e5945479e0`](https://github.com/medusajs/medusa/commit/e5945479e091d9560ae3e7240306a31031ef4584), [`f5c2256286`](https://github.com/medusajs/medusa/commit/f5c22562867f412040f8bc6c55ab5de3a3735e62), [`62a7bcc30c`](https://github.com/medusajs/medusa/commit/62a7bcc30cbc7b234b2b51d7858439951a84edeb), [`8f8a4f9b13`](https://github.com/medusajs/medusa/commit/8f8a4f9b1353087d98f6cc75346d43a7f49901a8), [`ce39b9b66e`](https://github.com/medusajs/medusa/commit/ce39b9b66e8c277ec0691ea6d0a950003be09cc1), [`a6a4b3f01a`](https://github.com/medusajs/medusa/commit/a6a4b3f01a6d2bd97b1580c59134279a1b033a5d), [`4d51f095b3`](https://github.com/medusajs/medusa/commit/4d51f095b3f98f468cefb760512563f7b77bb9cf), [`56b0b45304`](https://github.com/medusajs/medusa/commit/56b0b4530401a6ec5aa155874d371e45bb388fe2), [`cc1b66842c`](https://github.com/medusajs/medusa/commit/cc1b66842cbb37c6eab84e2d8b74844c214f38d7), [`24fb102a56`](https://github.com/medusajs/medusa/commit/24fb102a564b1253d1f8b039bb1e435cc5312fbb)]:
|
||||
- @medusajs/types@1.11.14
|
||||
|
||||
## 1.11.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6328](https://github.com/medusajs/medusa/pull/6328) [`3fd68d197`](https://github.com/medusajs/medusa/commit/3fd68d1979828e3cde6e028e9e6ab0d0fadcb77b) Thanks [@adrien2p](https://github.com/adrien2p)! - feat(fulfillment): Initialize models work
|
||||
|
||||
- Updated dependencies [[`3fd68d197`](https://github.com/medusajs/medusa/commit/3fd68d1979828e3cde6e028e9e6ab0d0fadcb77b)]:
|
||||
- @medusajs/types@1.11.13
|
||||
|
||||
## 1.11.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6319](https://github.com/medusajs/medusa/pull/6319) [`12054f5c0`](https://github.com/medusajs/medusa/commit/12054f5c01915899223ddc6da734151b31fbb23b) Thanks [@adrien2p](https://github.com/adrien2p)! - Feat/shipping method init
|
||||
|
||||
- [#6263](https://github.com/medusajs/medusa/pull/6263) [`45134e4d1`](https://github.com/medusajs/medusa/commit/45134e4d11cfcdc08dbd10aae687bfbe9e848ab9) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - Workflows passing MedusaContext as argument
|
||||
|
||||
- [#6218](https://github.com/medusajs/medusa/pull/6218) [`884428a1b`](https://github.com/medusajs/medusa/commit/884428a1b573e499d7659aefed639bf797147428) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - Feat: Event Aggregator
|
||||
|
||||
- [#6314](https://github.com/medusajs/medusa/pull/6314) [`882aa549b`](https://github.com/medusajs/medusa/commit/882aa549bdcc6f378934eab2a7c485df354f46aa) Thanks [@pKorsholm](https://github.com/pKorsholm)! - feat(utils): return array or single entity based on input for modules created by internal module service factory
|
||||
|
||||
- Updated dependencies [[`12054f5c0`](https://github.com/medusajs/medusa/commit/12054f5c01915899223ddc6da734151b31fbb23b), [`3db2f95e65`](https://github.com/medusajs/medusa/commit/3db2f95e65909f4fff432990b48be74509052e83), [`96ba49329`](https://github.com/medusajs/medusa/commit/96ba49329b6b05922c90f0c55f16455cb40aa5ca), [`45134e4d1`](https://github.com/medusajs/medusa/commit/45134e4d11cfcdc08dbd10aae687bfbe9e848ab9), [`82c728bec`](https://github.com/medusajs/medusa/commit/82c728bec7232a245a67dca0b01b28572ebea75d), [`e749dd653`](https://github.com/medusajs/medusa/commit/e749dd653c755bfc3632b134d32c15ceaee0a852), [`884428a1b`](https://github.com/medusajs/medusa/commit/884428a1b573e499d7659aefed639bf797147428), [`d1c18a309`](https://github.com/medusajs/medusa/commit/d1c18a3090d71c68a98343fdbb53516f416504c5)]:
|
||||
- @medusajs/types@1.11.12
|
||||
|
||||
## 1.11.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6094](https://github.com/medusajs/medusa/pull/6094) [`68ddd866a5`](https://github.com/medusajs/medusa/commit/68ddd866a5ff9414e2db5b80d75acc5e81948540) Thanks [@riqwan](https://github.com/riqwan)! - feat(utils,types): add registerUsages for promotion's computed actions
|
||||
|
||||
- [#6062](https://github.com/medusajs/medusa/pull/6062) [`72bc52231c`](https://github.com/medusajs/medusa/commit/72bc52231ca3a72fa6d197a248fe07a938ed0d85) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(utils): Update base repository to infer primary keys and support composite
|
||||
|
||||
- [#6152](https://github.com/medusajs/medusa/pull/6152) [`99045848f`](https://github.com/medusajs/medusa/commit/99045848fd3e863359c7878d9bc05271ed083a0e) Thanks [@riqwan](https://github.com/riqwan)! - feat(medusa,types,core-flows,utils): added delete endpoints for campaigns and promotions
|
||||
|
||||
- [#6021](https://github.com/medusajs/medusa/pull/6021) [`a9b4214503`](https://github.com/medusajs/medusa/commit/a9b42145032ee88aa922a11fe03e777b140c68f4) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(utils, product): Attempt to simplify module scripts export
|
||||
|
||||
- [#6127](https://github.com/medusajs/medusa/pull/6127) [`5e655dd59`](https://github.com/medusajs/medusa/commit/5e655dd59bda4ffface28db38021ba71cae6de10) Thanks [@adrien2p](https://github.com/adrien2p)! - chore: Hide repository creation if they are not custom + add upsert support by default
|
||||
|
||||
- [#6050](https://github.com/medusajs/medusa/pull/6050) [`b782d3bcb7`](https://github.com/medusajs/medusa/commit/b782d3bcb7e8088a962584b9a55200dd29c2161c) Thanks [@riqwan](https://github.com/riqwan)! - feat(utils,types): added item/shipping adjustments for order/items/shipping_methods
|
||||
|
||||
- [#6128](https://github.com/medusajs/medusa/pull/6128) [`302323916`](https://github.com/medusajs/medusa/commit/302323916b6d8eaf571cd59b5fc92a913af207de) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - Modules: Workflows Engine in-memory and Redis
|
||||
|
||||
- [#6130](https://github.com/medusajs/medusa/pull/6130) [`da5cc4cf7`](https://github.com/medusajs/medusa/commit/da5cc4cf7f7f0ef40d409704a95b025ce95477f4) Thanks [@riqwan](https://github.com/riqwan)! - feat(core-flows,medusa,utils): promotion and campaign create/update endpoint
|
||||
|
||||
- [#6161](https://github.com/medusajs/medusa/pull/6161) [`daecd82a7`](https://github.com/medusajs/medusa/commit/daecd82a7cdf7315599f464999690414c20d6748) Thanks [@riqwan](https://github.com/riqwan)! - feat(utils): update joiner config for campaigns
|
||||
|
||||
- [#6112](https://github.com/medusajs/medusa/pull/6112) [`06b33a9b4`](https://github.com/medusajs/medusa/commit/06b33a9b4525b77b1b14b35b973209700945654e) Thanks [@olivermrbl](https://github.com/olivermrbl)! - feat(cart): Line item adjustments
|
||||
|
||||
- [#6035](https://github.com/medusajs/medusa/pull/6035) [`b6ac768698`](https://github.com/medusajs/medusa/commit/b6ac768698a3b49d0162cb49e628386f3352d034) Thanks [@adrien2p](https://github.com/adrien2p)! - chore: Attempt to abstract the modules repository
|
||||
|
||||
- [#6087](https://github.com/medusajs/medusa/pull/6087) [`130c641e5c`](https://github.com/medusajs/medusa/commit/130c641e5c91cf831de64fb87aebbfdc4d23530d) Thanks [@adrien2p](https://github.com/adrien2p)! - chore: Abstract module services
|
||||
|
||||
- [#6063](https://github.com/medusajs/medusa/pull/6063) [`fade8ea7bf`](https://github.com/medusajs/medusa/commit/fade8ea7bf560343ecbde116d226ac44053cdb8e) Thanks [@riqwan](https://github.com/riqwan)! - feat(utils,types): campaigns and campaign budgets + services CRUD
|
||||
|
||||
- Updated dependencies [[`68ddd866a5`](https://github.com/medusajs/medusa/commit/68ddd866a5ff9414e2db5b80d75acc5e81948540), [`99045848f`](https://github.com/medusajs/medusa/commit/99045848fd3e863359c7878d9bc05271ed083a0e), [`af7af7374`](https://github.com/medusajs/medusa/commit/af7af737455daa0f330840a9678e6339e519dfe6), [`fc6b1772a7`](https://github.com/medusajs/medusa/commit/fc6b1772a71582bb48602c5cac7b2297e9d267a9), [`d85fee42e`](https://github.com/medusajs/medusa/commit/d85fee42ee7f661310584dfee5741d6c53b989bb), [`5e655dd59`](https://github.com/medusajs/medusa/commit/5e655dd59bda4ffface28db38021ba71cae6de10), [`b132ff7669`](https://github.com/medusajs/medusa/commit/b132ff76693148b3a06373c168e8dd5e02970757), [`e28fa7fbdf`](https://github.com/medusajs/medusa/commit/e28fa7fbdf45c5b1fa19848db731132a0bf1757d), [`a12c28b7d5`](https://github.com/medusajs/medusa/commit/a12c28b7d5faed733bebbb4963dff50b9c8a33bc), [`b782d3bcb7`](https://github.com/medusajs/medusa/commit/b782d3bcb7e8088a962584b9a55200dd29c2161c), [`7f7cb2a263`](https://github.com/medusajs/medusa/commit/7f7cb2a263c26baf540b05a40ab3732ffeb0c73c), [`302323916`](https://github.com/medusajs/medusa/commit/302323916b6d8eaf571cd59b5fc92a913af207de), [`ce81cade88`](https://github.com/medusajs/medusa/commit/ce81cade887659cefe9638e3c1c2807378191c62), [`fd78f5e24`](https://github.com/medusajs/medusa/commit/fd78f5e24263f5e158c3b7d11fbf0a4436e9c17a), [`192bc336cc`](https://github.com/medusajs/medusa/commit/192bc336cc2b6ec3820d94524c046dcd3c4ac7d9), [`06b33a9b4`](https://github.com/medusajs/medusa/commit/06b33a9b4525b77b1b14b35b973209700945654e), [`130c641e5c`](https://github.com/medusajs/medusa/commit/130c641e5c91cf831de64fb87aebbfdc4d23530d), [`fade8ea7bf`](https://github.com/medusajs/medusa/commit/fade8ea7bf560343ecbde116d226ac44053cdb8e), [`8472460f53`](https://github.com/medusajs/medusa/commit/8472460f533322cc4535199aa768ac163021bc79), [`68d8daccd`](https://github.com/medusajs/medusa/commit/68d8daccd2a8508a13e211130e49017198b51fab)]:
|
||||
- @medusajs/types@1.11.11
|
||||
|
||||
## 1.11.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5957](https://github.com/medusajs/medusa/pull/5957) [`42cc8ae3f`](https://github.com/medusajs/medusa/commit/42cc8ae3f89ed7d642e51654d1a3cca011f13155) Thanks [@riqwan](https://github.com/riqwan)! - feat(types,utils): added promotion create with rules
|
||||
|
||||
- [#5869](https://github.com/medusajs/medusa/pull/5869) [`45996d58a2`](https://github.com/medusajs/medusa/commit/45996d58a2665d72335faad11bea958f8da74195) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(medusa, interfaces, utils, webshiper): Uniformise class checks
|
||||
|
||||
- [#5728](https://github.com/medusajs/medusa/pull/5728) [`9cc787cac4`](https://github.com/medusajs/medusa/commit/9cc787cac4bf1c5d8edf1c4b548bb3205100e822) Thanks [@adrien2p](https://github.com/adrien2p)! - feat(workflows-sdk): Configurable retries upon step creation
|
||||
|
||||
- [#5858](https://github.com/medusajs/medusa/pull/5858) [`355075097`](https://github.com/medusajs/medusa/commit/3550750975a0c9359fd887929377733606ef03af) Thanks [@pKorsholm](https://github.com/pKorsholm)! - feat(pricing, types): add soft deletion for money-amounts
|
||||
feat(utils): cascade soft delete across 1:1 relationships
|
||||
|
||||
- [#6020](https://github.com/medusajs/medusa/pull/6020) [`fbee006e5`](https://github.com/medusajs/medusa/commit/fbee006e512ef2d56ffb23eeabad8b51b56be285) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(medusa, orchestration, utils, workflows-sdk): add transaction options support and cleanup
|
||||
|
||||
- [#5929](https://github.com/medusajs/medusa/pull/5929) [`c41f3002f`](https://github.com/medusajs/medusa/commit/c41f3002f3118b1f195c5c822fe0f400091d115b) Thanks [@adrien2p](https://github.com/adrien2p)! - Fix/utils object from string path
|
||||
|
||||
- [#5985](https://github.com/medusajs/medusa/pull/5985) [`d16d10619`](https://github.com/medusajs/medusa/commit/d16d10619dfbd3966a4709753de3d8cc37c6f2eb) Thanks [@pKorsholm](https://github.com/pKorsholm)! - fix(medusa-test-utils, utils, link-modules, pricing, product): upgrade mikro-orm version
|
||||
|
||||
- [#5945](https://github.com/medusajs/medusa/pull/5945) [`890e76a5c`](https://github.com/medusajs/medusa/commit/890e76a5c53039576c42ca4d46af6f6977cdebd1) Thanks [@riqwan](https://github.com/riqwan)! - feat(types,utils): add promotions create with application method
|
||||
|
||||
- [#5810](https://github.com/medusajs/medusa/pull/5810) [`fe007d01b`](https://github.com/medusajs/medusa/commit/fe007d01bd827f0e09ee545e48cef18913540c68) Thanks [@fPolic](https://github.com/fPolic)! - feat: sales channel <> order link
|
||||
|
||||
- [#5459](https://github.com/medusajs/medusa/pull/5459) [`76332ca6c`](https://github.com/medusajs/medusa/commit/76332ca6c153a786acc07d3f06ff45c3b9346fd3) Thanks [@fPolic](https://github.com/fPolic)! - feat: SalesChannel <> Cart joiner config
|
||||
|
||||
- Updated dependencies [[`6d1e3cc02`](https://github.com/medusajs/medusa/commit/6d1e3cc0285ef157fd6486060e8b32c00c01aa80), [`42cc8ae3f`](https://github.com/medusajs/medusa/commit/42cc8ae3f89ed7d642e51654d1a3cca011f13155), [`355075097`](https://github.com/medusajs/medusa/commit/3550750975a0c9359fd887929377733606ef03af), [`dc46ee118`](https://github.com/medusajs/medusa/commit/dc46ee1189c3eb719355da6a1d701c14a77e4578), [`925feea04`](https://github.com/medusajs/medusa/commit/925feea04a8222285175c33577548e50516069a7), [`3f6d79961`](https://github.com/medusajs/medusa/commit/3f6d79961dec1c5eb8950f8eacd94a5d87a4acde), [`c1c470e6b`](https://github.com/medusajs/medusa/commit/c1c470e6b8646c5f0b4bca56a8e785f6c34e1fef), [`890e76a5c`](https://github.com/medusajs/medusa/commit/890e76a5c53039576c42ca4d46af6f6977cdebd1)]:
|
||||
- @medusajs/types@1.11.10
|
||||
|
||||
## 1.11.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5752](https://github.com/medusajs/medusa/pull/5752) [`079f0da83`](https://github.com/medusajs/medusa/commit/079f0da83f482562bbb525807ee1a7e32993b4da) Thanks [@riqwan](https://github.com/riqwan)! - feat(core-flows,pricing,medusa,pricing,types,utils): Price List Prices can have their own rules
|
||||
|
||||
- [#5755](https://github.com/medusajs/medusa/pull/5755) [`8f25ed8a1`](https://github.com/medusajs/medusa/commit/8f25ed8a10fe23e9342dc3d03545546b4ad4d6da) Thanks [@adrien2p](https://github.com/adrien2p)! - feat(link-modules, pricing, product, utils): Should be able to set some custom database config even in shared mode
|
||||
|
||||
- Updated dependencies [[`079f0da83`](https://github.com/medusajs/medusa/commit/079f0da83f482562bbb525807ee1a7e32993b4da)]:
|
||||
- @medusajs/types@1.11.9
|
||||
|
||||
## 1.11.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5713](https://github.com/medusajs/medusa/pull/5713) [`18afe0b9a`](https://github.com/medusajs/medusa/commit/18afe0b9addb33ec2e3b285651b4eb1ef8065845) Thanks [@pKorsholm](https://github.com/pKorsholm)! - fix(stock-location, inventory, medusa, types, utils): allow buildQuery to take null as an argument in order to prevent default pagination
|
||||
|
||||
- [#5732](https://github.com/medusajs/medusa/pull/5732) [`de8f74867`](https://github.com/medusajs/medusa/commit/de8f748674bfd19b3dbadb9695d9080aa91940de) Thanks [@pKorsholm](https://github.com/pKorsholm)! - fix(link-modules, utils): remove limtis if primary key exists in filter for buildquery and no limit is present
|
||||
|
||||
- [#5536](https://github.com/medusajs/medusa/pull/5536) [`dc5750dd6`](https://github.com/medusajs/medusa/commit/dc5750dd665a91d35c0246ba83c7f90ec74907f4) Thanks [@pKorsholm](https://github.com/pKorsholm)! - feat(medusa,types,workflows,utils,product,pricing): PricingModule Integration of PriceLists into Core
|
||||
|
||||
- Updated dependencies [[`a39ce125c`](https://github.com/medusajs/medusa/commit/a39ce125cc96f14732d5a6301313d2376484fa23), [`18afe0b9a`](https://github.com/medusajs/medusa/commit/18afe0b9addb33ec2e3b285651b4eb1ef8065845), [`6025c702f`](https://github.com/medusajs/medusa/commit/6025c702f37d43e18af32bd716f33410d95efd19), [`fc1ef29ed`](https://github.com/medusajs/medusa/commit/fc1ef29ed935e192f0943a2bf4b8fbb05ce6890d), [`0df1c7d42`](https://github.com/medusajs/medusa/commit/0df1c7d4273545bc717555611b9294a5c222e5ae), [`dc5750dd6`](https://github.com/medusajs/medusa/commit/dc5750dd665a91d35c0246ba83c7f90ec74907f4)]:
|
||||
- @medusajs/types@1.11.8
|
||||
|
||||
## 1.11.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#5603](https://github.com/medusajs/medusa/pull/5603) [`cedab5833`](https://github.com/medusajs/medusa/commit/cedab583395275444001f0268e4b9ccab9b2b262) Thanks [@riqwan](https://github.com/riqwan)! - feat(workflows,medusa,utils): add medusa v2 feature flag
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`61aef4aaa`](https://github.com/medusajs/medusa/commit/61aef4aaa7295f178c61c9a891f03a0a48b15c81), [`1772e80ed`](https://github.com/medusajs/medusa/commit/1772e80ed1ecab27741be80204f5df92eaa3f2b4)]:
|
||||
- @medusajs/types@1.11.7
|
||||
|
||||
## 1.10.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [`c39bf69a5`](https://github.com/medusajs/medusa/commit/c39bf69a5e5cae75d7fa12aa6022b10903557a32) Thanks [@olivermrbl](https://github.com/olivermrbl)! - chore: Add missing version bumps
|
||||
|
||||
- [#5496](https://github.com/medusajs/medusa/pull/5496) [`154c9b43b`](https://github.com/medusajs/medusa/commit/154c9b43bde1fdff562aba9da8a79af2660b29b3) Thanks [@adrien2p](https://github.com/adrien2p)! - feat(medusa, modules-sdk, types, utils): Re work modules loading and remove legacy functions
|
||||
|
||||
- Updated dependencies [[`91615f9c4`](https://github.com/medusajs/medusa/commit/91615f9c459a2d8cb842561c5edb335680d30298), [`154c9b43b`](https://github.com/medusajs/medusa/commit/154c9b43bde1fdff562aba9da8a79af2660b29b3)]:
|
||||
- @medusajs/types@1.11.6
|
||||
|
||||
## 1.10.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5294](https://github.com/medusajs/medusa/pull/5294) [`378ca1b36`](https://github.com/medusajs/medusa/commit/378ca1b36e909a67e39c69ea5ca94ec58a345878) Thanks [@riqwan](https://github.com/riqwan)! - feat(pricing,types,utils): Move calculate pricing query to a repository + rule type validation
|
||||
|
||||
- [#5337](https://github.com/medusajs/medusa/pull/5337) [`e47461d95`](https://github.com/medusajs/medusa/commit/e47461d95caecf3a447ee9fa0b0950340b93f282) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(orchestration): prevent throwing on already defined workflow
|
||||
|
||||
- [#5301](https://github.com/medusajs/medusa/pull/5301) [`66413d094`](https://github.com/medusajs/medusa/commit/66413d094e916debbdb74b68800c96ca2c9302c9) Thanks [@srindom](https://github.com/srindom)! - fix: move create inventory workflow to @medusajs/workflows
|
||||
|
||||
- Updated dependencies [[`378ca1b36`](https://github.com/medusajs/medusa/commit/378ca1b36e909a67e39c69ea5ca94ec58a345878), [`69cf7215f`](https://github.com/medusajs/medusa/commit/69cf7215f1f730ffb332129e65211470be1f88f1), [`453297f52`](https://github.com/medusajs/medusa/commit/453297f525bd9f3aaa95bf0b28ff6cd31e6696b4), [`66413d094`](https://github.com/medusajs/medusa/commit/66413d094e916debbdb74b68800c96ca2c9302c9)]:
|
||||
- @medusajs/types@1.11.4
|
||||
|
||||
## 1.10.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5216](https://github.com/medusajs/medusa/pull/5216) [`eeceec791`](https://github.com/medusajs/medusa/commit/eeceec791c141996cf7fd06555afb6e738b52840) Thanks [@adrien2p](https://github.com/adrien2p)! - feat(utils): Convert remote query object to string array of fields and relations from GQL schema
|
||||
|
||||
- [#5242](https://github.com/medusajs/medusa/pull/5242) [`130cbc1f4`](https://github.com/medusajs/medusa/commit/130cbc1f437af211b6d05f80128d90138abcd38d) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - Modules exporting schema with entities and fields
|
||||
|
||||
- [#5213](https://github.com/medusajs/medusa/pull/5213) [`cb569c2df`](https://github.com/medusajs/medusa/commit/cb569c2dfe2d83e1ff72a49f2331450a83b73325) Thanks [@adrien2p](https://github.com/adrien2p)! - feat(utils): Utils to create an object select, relation from a string[]
|
||||
|
||||
- Updated dependencies [[`130cbc1f4`](https://github.com/medusajs/medusa/commit/130cbc1f437af211b6d05f80128d90138abcd38d), [`c5703a476`](https://github.com/medusajs/medusa/commit/c5703a4765a55da697885438cf3089d923669f21)]:
|
||||
- @medusajs/types@1.11.3
|
||||
|
||||
## 1.10.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5161](https://github.com/medusajs/medusa/pull/5161) [`cc4169a94`](https://github.com/medusajs/medusa/commit/cc4169a94c7c5f5bf4d04f7b6e815b409a0a8192) Thanks [@adrien2p](https://github.com/adrien2p)! - feat(utils): Provide an utils that allows to convert an array of fields to a complete remote query object
|
||||
|
||||
- [#5214](https://github.com/medusajs/medusa/pull/5214) [`1e7db5a5c`](https://github.com/medusajs/medusa/commit/1e7db5a5cb7c955e72c52e64df8a16b1607eef70) Thanks [@riqwan](https://github.com/riqwan)! - feat(types,pricing,utils): Exact match based on context + fallback on rule priority if not
|
||||
|
||||
- Updated dependencies [[`1e7db5a5c`](https://github.com/medusajs/medusa/commit/1e7db5a5cb7c955e72c52e64df8a16b1607eef70)]:
|
||||
- @medusajs/types@1.11.2
|
||||
|
||||
## 1.10.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4961](https://github.com/medusajs/medusa/pull/4961) [`6273b4b16`](https://github.com/medusajs/medusa/commit/6273b4b160493463e1199e5db4e9cfa4cff6fbe4) Thanks [@adrien2p](https://github.com/adrien2p)! - feat(utils, module-sdk, medusa, types): Extract pg connection utils to utils package
|
||||
|
||||
- Updated dependencies [[`4fa675ec2`](https://github.com/medusajs/medusa/commit/4fa675ec25b3d6fccd881c4f5a5b91f0e9e13e82), [`6273b4b16`](https://github.com/medusajs/medusa/commit/6273b4b160493463e1199e5db4e9cfa4cff6fbe4), [`30863fee5`](https://github.com/medusajs/medusa/commit/30863fee529ed035f161c749fda3cd64fa48efb1), [`3d68be2b6`](https://github.com/medusajs/medusa/commit/3d68be2b6b93ae928f5c955e102ebdf2c34fb364), [`a87d07655`](https://github.com/medusajs/medusa/commit/a87d07655bd8a1da8b90feb739daddd09295f724), [`edf90eecb`](https://github.com/medusajs/medusa/commit/edf90eecb487f6e031f2e2d0899de5ca2504cb12), [`107aaa371`](https://github.com/medusajs/medusa/commit/107aaa371c444843874d125bf8bd493ef89f5756), [`834da5c41`](https://github.com/medusajs/medusa/commit/834da5c41a7c043373f72239b6fdbf7815d9b4aa)]:
|
||||
- @medusajs/types@1.11.1
|
||||
|
||||
## 1.10.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#4695](https://github.com/medusajs/medusa/pull/4695) [`4d16acf5f`](https://github.com/medusajs/medusa/commit/4d16acf5f096b5656b645f510f9c971e7c2dc9ef) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - Medusa App Loader
|
||||
|
||||
- [#4695](https://github.com/medusajs/medusa/pull/4695) [`4d16acf5f`](https://github.com/medusajs/medusa/commit/4d16acf5f096b5656b645f510f9c971e7c2dc9ef) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - introduce @medusajs/link-modules
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4860](https://github.com/medusajs/medusa/pull/4860) [`460161a69`](https://github.com/medusajs/medusa/commit/460161a69f22cf6d561952e92e7d9b56912113e6) Thanks [@riqwan](https://github.com/riqwan)! - feat(pricing, types, utils, medusa-sdk): Pricing Module Setup + Currency service
|
||||
|
||||
- [#4909](https://github.com/medusajs/medusa/pull/4909) [`fcb6b4f51`](https://github.com/medusajs/medusa/commit/fcb6b4f510dba2757570625acb5da9476b7544fd) Thanks [@riqwan](https://github.com/riqwan)! - feat(pricing, utils, types): adds money amount to pricing module
|
||||
|
||||
- [#4915](https://github.com/medusajs/medusa/pull/4915) [`87bade096`](https://github.com/medusajs/medusa/commit/87bade096e3d536f29ddc57dbc4c04e5d7a46e4b) Thanks [@riqwan](https://github.com/riqwan)! - fix(utils, product, pricing, link-modules): add missing dependencies for utils + fix migration path issue
|
||||
|
||||
- Updated dependencies [[`460161a69`](https://github.com/medusajs/medusa/commit/460161a69f22cf6d561952e92e7d9b56912113e6), [`fcb6b4f51`](https://github.com/medusajs/medusa/commit/fcb6b4f510dba2757570625acb5da9476b7544fd), [`66bd9a835`](https://github.com/medusajs/medusa/commit/66bd9a835c61b139af7051e5faf6c9de3c7134bb), [`4d16acf5f`](https://github.com/medusajs/medusa/commit/4d16acf5f096b5656b645f510f9c971e7c2dc9ef), [`4d16acf5f`](https://github.com/medusajs/medusa/commit/4d16acf5f096b5656b645f510f9c971e7c2dc9ef), [`4d16acf5f`](https://github.com/medusajs/medusa/commit/4d16acf5f096b5656b645f510f9c971e7c2dc9ef)]:
|
||||
- @medusajs/types@1.11.0
|
||||
|
||||
## 1.9.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4825](https://github.com/medusajs/medusa/pull/4825) [`c53fa6cd3`](https://github.com/medusajs/medusa/commit/c53fa6cd3be8b1af5625fc2db7871f9f69e761ad) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - Fix mikro-orm connection loader
|
||||
|
||||
## 1.9.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4626](https://github.com/medusajs/medusa/pull/4626) [`3f3a84262`](https://github.com/medusajs/medusa/commit/3f3a84262ce9cbd911923278a54e301fbe9a4634) Thanks [@adrien2p](https://github.com/adrien2p)! - [WIP] feat(types, product, utils, medusa): Include shared connection for modules
|
||||
|
||||
- [#4733](https://github.com/medusajs/medusa/pull/4733) [`30ce35b16`](https://github.com/medusajs/medusa/commit/30ce35b163afa25f4e1d8d1bd392f401a3b413df) Thanks [@shahednasser](https://github.com/shahednasser)! - feat(create-medusa-app, utils, medusa-cli): add database options + remove util from `@medusajs/utils`
|
||||
|
||||
## 1.9.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4701](https://github.com/medusajs/medusa/pull/4701) [`5c60aad17`](https://github.com/medusajs/medusa/commit/5c60aad177a99574ffff5ebdc02ce9dc86ef9af9) Thanks [@olivermrbl](https://github.com/olivermrbl)! - feat(medusa, utils): Allow object feature flags
|
||||
|
||||
- [#4631](https://github.com/medusajs/medusa/pull/4631) [`4073b7313`](https://github.com/medusajs/medusa/commit/4073b73130c874dc7d2240726224a01b7b19b1a1) Thanks [@adrien2p](https://github.com/adrien2p)! - feat(product): Move mikro orm utils to the utils package
|
||||
|
||||
## 1.9.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4623](https://github.com/medusajs/medusa/pull/4623) [`107ae23a3`](https://github.com/medusajs/medusa/commit/107ae23a3f41ef0d676e9d03f53dafc7c1af6118) Thanks [@riqwan](https://github.com/riqwan)! - fix(utils, types, medusa-plugin-meilisearch, medusa-plugin-algolia): move SoftDeletableFilterKey, variantKeys, indexTypes from types to utils
|
||||
|
||||
## 1.9.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4535](https://github.com/medusajs/medusa/pull/4535) [`131477faf`](https://github.com/medusajs/medusa/commit/131477faf0409c49d4aacf26ea591e33b2fa22fd) Thanks [@riqwan](https://github.com/riqwan)! - feat(product,types,utils): Add tags, types, categories, collection and options CRUD to product module services
|
||||
|
||||
## 1.9.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4098](https://github.com/medusajs/medusa/pull/4098) [`499c3478c`](https://github.com/medusajs/medusa/commit/499c3478c910c8b922a15cc6f4d9fbad122a347f) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - feat: Remote Joiner
|
||||
|
||||
- [#4389](https://github.com/medusajs/medusa/pull/4389) [`9dcdc0041`](https://github.com/medusajs/medusa/commit/9dcdc0041a2b08cc0723343dd8d9127d9977b086) Thanks [@adrien2p](https://github.com/adrien2p)! - fix(medusa, utils): fix the way selects are consumed alongside the relations
|
||||
|
||||
- [#4398](https://github.com/medusajs/medusa/pull/4398) [`9760d4a96`](https://github.com/medusajs/medusa/commit/9760d4a96c27f6f89a8c3f3b6e73b17547f97f2a) Thanks [@riqwan](https://github.com/riqwan)! - feat(medusa, utils): improve devx for core entity customizations
|
||||
|
||||
## 1.9.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4273](https://github.com/medusajs/medusa/pull/4273) [`f98ba5bde`](https://github.com/medusajs/medusa/commit/f98ba5bde83ba785eead31b0c9eb9f135d664178) Thanks [@shahednasser](https://github.com/shahednasser)! - feat(create-medusa-app,medusa-cli): Allow clearing project
|
||||
|
||||
- [#4161](https://github.com/medusajs/medusa/pull/4161) [`14c0f62f8`](https://github.com/medusajs/medusa/commit/14c0f62f84704a4c87beff3daaff60a52f5c88b8) Thanks [@adrien2p](https://github.com/adrien2p)! - feat(product): Experimental product module
|
||||
|
||||
## 1.9.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#4146](https://github.com/medusajs/medusa/pull/4146) [`db4199530`](https://github.com/medusajs/medusa/commit/db419953075e0907b8c4d27ab5188e9bd3e3d72b) Thanks [@fPolic](https://github.com/fPolic)! - chore(medusa, utils, inventory, stock-location): clear deps in the utils package
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4026](https://github.com/medusajs/medusa/pull/4026) [`a91987fab`](https://github.com/medusajs/medusa/commit/a91987fab33745f9864eab21bd1c27e8e3e24571) Thanks [@olivermrbl](https://github.com/olivermrbl)! - feat(medusa): Remove sqlite support
|
||||
|
||||
- [#4148](https://github.com/medusajs/medusa/pull/4148) [`c0e527d6e`](https://github.com/medusajs/medusa/commit/c0e527d6e0a67d0c53577a0b9c3d16ee8dc5740f) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(medusa): Align build query utils
|
||||
|
||||
## 1.8.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4046](https://github.com/medusajs/medusa/pull/4046) [`cdbac2c84`](https://github.com/medusajs/medusa/commit/cdbac2c8403a3c15c0e11993f6b7dab268fa5c08) Thanks [@adrien2p](https://github.com/adrien2p)! - feat(medusa, medusa-utils): Add support for multiple where condition on the same column
|
||||
|
||||
- [#4072](https://github.com/medusajs/medusa/pull/4072) [`6511959e2`](https://github.com/medusajs/medusa/commit/6511959e23177f3b4831915db0e8e788bc9047fa) Thanks [@olivermrbl](https://github.com/olivermrbl)! - chore: Revert to official Typeorm package
|
||||
|
||||
## 1.8.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4032](https://github.com/medusajs/medusa/pull/4032) [`1ea57c3a6`](https://github.com/medusajs/medusa/commit/1ea57c3a69a5377a8dd0821df819743ded4a222b) Thanks [@pevey](https://github.com/pevey)! - update class-validator to 0.14.0 in utils package
|
||||
|
||||
## 1.8.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4002](https://github.com/medusajs/medusa/pull/4002) [`0e488e71b`](https://github.com/medusajs/medusa/commit/0e488e71b186f7d08b18c4c6ba409ef3cadb8152) Thanks [@adrien2p](https://github.com/adrien2p)! - fix(medusa, event-bus-redis, event-bus-local): Revert retrieveSubscribers as the wildcard prevent us from filtering
|
||||
|
||||
- [#3981](https://github.com/medusajs/medusa/pull/3981) [`d539c6fee`](https://github.com/medusajs/medusa/commit/d539c6feeba8ee431f9a655b6cd4e9102cba2b25) Thanks [@olivermrbl](https://github.com/olivermrbl)! - chore: Bump Typeorm to Medusa fork
|
||||
|
||||
## 1.8.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3835](https://github.com/medusajs/medusa/pull/3835) [`af710f1b4`](https://github.com/medusajs/medusa/commit/af710f1b48a4545a5064029a557013af34c4c100) Thanks [@adrien2p](https://github.com/adrien2p)! - fix(medusa): Bulk create variant and pass transaction to the inventory service context methods
|
||||
|
||||
- [#3905](https://github.com/medusajs/medusa/pull/3905) [`491566df6`](https://github.com/medusajs/medusa/commit/491566df6b7ced35f655f810961422945e10ecd0) Thanks [@olivermrbl](https://github.com/olivermrbl)! - fix(medusa,utils): Searching indexing product subscriber
|
||||
|
||||
## 1.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3778](https://github.com/medusajs/medusa/pull/3778) [`654a54622`](https://github.com/medusajs/medusa/commit/654a54622303139e7180538bd686630ad9a46cfd) Thanks [@olivermrbl](https://github.com/olivermrbl)! - chore: Bump Typeorm
|
||||
|
||||
- [#3738](https://github.com/medusajs/medusa/pull/3738) [`abdb74d99`](https://github.com/medusajs/medusa/commit/abdb74d997f49f994bff49787a396179982843b0) Thanks [@riqwan](https://github.com/riqwan)! - chore(medusa, utils): rename buildLegacyFieldsListFrom to objectToStringPath
|
||||
|
||||
## 1.8.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3685](https://github.com/medusajs/medusa/pull/3685) [`8ddb3952c`](https://github.com/medusajs/medusa/commit/8ddb3952c045e6c05c8d0f6922f0d4ba30cf3bd4) Thanks [@olivermrbl](https://github.com/olivermrbl)! - chore: Fix RC package versions
|
||||
|
||||
- [#3688](https://github.com/medusajs/medusa/pull/3688) [`a0c919a8d`](https://github.com/medusajs/medusa/commit/a0c919a8d01ca5edf62336de48e9a112e3822f38) Thanks [@olivermrbl](https://github.com/olivermrbl)! - chore(medusa-cli): Add missing utils dep
|
||||
|
||||
- [#3510](https://github.com/medusajs/medusa/pull/3510) [`74bc4b16a`](https://github.com/medusajs/medusa/commit/74bc4b16a07f78668003ca930bf2a0d928897ceb) Thanks [@olivermrbl](https://github.com/olivermrbl)! - feat(medusa-plugin-algolia): Revamp Algolia search plugin
|
||||
|
||||
- [#3531](https://github.com/medusajs/medusa/pull/3531) [`4e9d257d3`](https://github.com/medusajs/medusa/commit/4e9d257d3bf76703ef5be8ca054cc9f0f7339def) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - Remove dependency on @medusajs/medusa from Inventory and Stock-Location Modules
|
||||
|
||||
## 0.0.2-rc.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3688](https://github.com/medusajs/medusa/pull/3688) [`a0c919a8d`](https://github.com/medusajs/medusa/commit/a0c919a8d01ca5edf62336de48e9a112e3822f38) Thanks [@olivermrbl](https://github.com/olivermrbl)! - chore(medusa-cli): Add missing utils dep
|
||||
|
||||
## 0.0.2-rc.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- chore: Fix RC package versions
|
||||
|
||||
## 0.0.2-rc.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3510](https://github.com/medusajs/medusa/pull/3510) [`74bc4b16a`](https://github.com/medusajs/medusa/commit/74bc4b16a07f78668003ca930bf2a0d928897ceb) Thanks [@olivermrbl](https://github.com/olivermrbl)! - feat(medusa-plugin-algolia): Revamp Algolia search plugin
|
||||
|
||||
- [#3531](https://github.com/medusajs/medusa/pull/3531) [`4e9d257d3`](https://github.com/medusajs/medusa/commit/4e9d257d3bf76703ef5be8ca054cc9f0f7339def) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - Remove dependency on @medusajs/medusa from Inventory and Stock-Location Modules
|
||||
@@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
transform: {
|
||||
"^.+\\.[jt]s?$": [
|
||||
"ts-jest",
|
||||
{
|
||||
tsconfig: "tsconfig.spec.json",
|
||||
isolatedModules: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
testEnvironment: `node`,
|
||||
moduleFileExtensions: [`js`, `ts`],
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "@medusajs/utils",
|
||||
"version": "1.11.9",
|
||||
"description": "Medusa utilities functions shared by Medusa core and Modules",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/medusajs/medusa",
|
||||
"directory": "packages/utils"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"author": "Medusa",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.17",
|
||||
"cross-env": "^5.2.1",
|
||||
"express": "^4.18.2",
|
||||
"jest": "^29.6.3",
|
||||
"rimraf": "^5.0.1",
|
||||
"ts-jest": "^29.1.1",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"@medusajs/types": "^1.11.16",
|
||||
"@mikro-orm/core": "5.9.7",
|
||||
"@mikro-orm/migrations": "5.9.7",
|
||||
"@mikro-orm/postgresql": "5.9.7",
|
||||
"awilix": "^8.0.1",
|
||||
"bignumber.js": "^9.1.2",
|
||||
"knex": "2.4.2",
|
||||
"ulid": "^2.3.0"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublishOnly": "cross-env NODE_ENV=production tsc --build",
|
||||
"build": "rimraf dist && tsc --build",
|
||||
"watch": "tsc --build --watch",
|
||||
"test": "jest --silent --bail --maxWorkers=50% --forceExit --testPathIgnorePatterns='/integration-tests/' -- src/**/__tests__/**/*.ts",
|
||||
"test:integration": "jest --silent --bail --maxWorkers=50% --forceExit -- src/**/integration-tests/__tests__/**/*.ts"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* @enum
|
||||
*
|
||||
* The API key's type.
|
||||
*/
|
||||
export enum ApiKeyType {
|
||||
/**
|
||||
* Publishable key that is tied to eg. a sales channel
|
||||
*/
|
||||
PUBLISHABLE = "publishable",
|
||||
/**
|
||||
* Secret key that allows access to the admin API
|
||||
*/
|
||||
SECRET = "secret",
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./api-key-type"
|
||||
@@ -0,0 +1,65 @@
|
||||
import { AuthProviderScope, AuthenticationResponse } from "@medusajs/types"
|
||||
|
||||
import { MedusaError } from "../common"
|
||||
|
||||
export abstract class AbstractAuthModuleProvider {
|
||||
public static PROVIDER: string
|
||||
public static DISPLAY_NAME: string
|
||||
|
||||
protected readonly container_: any
|
||||
protected scopeConfig_: AuthProviderScope
|
||||
protected scope_: string
|
||||
|
||||
private readonly scopes_: Record<string, AuthProviderScope>
|
||||
|
||||
public get provider() {
|
||||
return (this.constructor as typeof AbstractAuthModuleProvider).PROVIDER
|
||||
}
|
||||
|
||||
public get displayName() {
|
||||
return (this.constructor as typeof AbstractAuthModuleProvider).DISPLAY_NAME
|
||||
}
|
||||
|
||||
protected constructor(
|
||||
{ scopes },
|
||||
config: { provider: string; displayName: string }
|
||||
) {
|
||||
this.container_ = arguments[0]
|
||||
this.scopes_ = scopes
|
||||
;(this.constructor as typeof AbstractAuthModuleProvider).PROVIDER ??=
|
||||
config.provider
|
||||
;(this.constructor as typeof AbstractAuthModuleProvider).DISPLAY_NAME ??=
|
||||
config.displayName
|
||||
}
|
||||
|
||||
private validateScope(scope) {
|
||||
if (!this.scopes_[scope]) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_ARGUMENT,
|
||||
`Scope "${scope}" is not valid for provider ${this.provider}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public withScope(scope: string) {
|
||||
this.validateScope(scope)
|
||||
|
||||
const cloned = new (this.constructor as any)(this.container_)
|
||||
cloned.scope_ = scope
|
||||
cloned.scopeConfig_ = this.scopes_[scope]
|
||||
|
||||
return cloned
|
||||
}
|
||||
|
||||
abstract authenticate(
|
||||
data: Record<string, unknown>
|
||||
): Promise<AuthenticationResponse>
|
||||
|
||||
public validateCallback(
|
||||
data: Record<string, unknown>
|
||||
): Promise<AuthenticationResponse> {
|
||||
throw new Error(
|
||||
`Callback authentication not implemented for provider ${this.provider}`
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./abstract-auth-provider"
|
||||
@@ -0,0 +1,17 @@
|
||||
export * as DALUtils from "./dal"
|
||||
export * as DecoratorUtils from "./decorators"
|
||||
export * as DefaultsUtils from "./defaults"
|
||||
export * as EventBusUtils from "./event-bus"
|
||||
export * as FeatureFlagUtils from "./feature-flags"
|
||||
export * as FulfillmentUtils from "./fulfillment"
|
||||
export * as ModulesSdkUtils from "./modules-sdk"
|
||||
export * as OrchestrationUtils from "./orchestration"
|
||||
export * as OrderUtils from "./order"
|
||||
export * as ProductUtils from "./product"
|
||||
export * as PromotionUtils from "./promotion"
|
||||
export * as SearchUtils from "./search"
|
||||
export * as ShippingProfileUtils from "./shipping"
|
||||
export * as UserUtils from "./user"
|
||||
export * as InventoryUtils from "./inventory"
|
||||
export * as LinkUtils from "./link"
|
||||
export * as ApiKeyUtils from "./api-key"
|
||||
@@ -0,0 +1,18 @@
|
||||
import { arrayIntersection } from "../array-intersection"
|
||||
|
||||
describe("arrayIntersection", function () {
|
||||
it("should return the intersection between two arrays", function () {
|
||||
const output = arrayIntersection(["foo", "bar"], ["bar", "baz"])
|
||||
expect(output).toEqual(["bar"])
|
||||
})
|
||||
|
||||
it("should return an empty array if there is no intersection", function () {
|
||||
const output = arrayIntersection(["bar", "baz"], ["foo", "boo"])
|
||||
expect(output).toEqual([])
|
||||
})
|
||||
|
||||
it("should return an all items when the arrays are equivalent", function () {
|
||||
const output = arrayIntersection(["bar", "baz"], ["baz", "bar"])
|
||||
expect(output).toEqual(["baz", "bar"])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,91 @@
|
||||
import { buildSelects } from "../build-query"
|
||||
|
||||
describe("buildSelects", () => {
|
||||
it("successfully build back select object shape to list", () => {
|
||||
const q = buildSelects([
|
||||
"order",
|
||||
"order.items",
|
||||
"order.swaps",
|
||||
"order.swaps.additional_items",
|
||||
"order.discounts",
|
||||
"order.discounts.rule",
|
||||
"order.claims",
|
||||
"order.claims.additional_items",
|
||||
"additional_items",
|
||||
"additional_items.variant",
|
||||
"return_order",
|
||||
"return_order.items",
|
||||
"return_order.shipping_method",
|
||||
"return_order.shipping_method.tax_lines",
|
||||
])
|
||||
|
||||
expect(q).toEqual({
|
||||
order: {
|
||||
items: true,
|
||||
swaps: {
|
||||
additional_items: true,
|
||||
},
|
||||
discounts: {
|
||||
rule: true,
|
||||
},
|
||||
claims: {
|
||||
additional_items: true,
|
||||
},
|
||||
},
|
||||
additional_items: {
|
||||
variant: true,
|
||||
},
|
||||
return_order: {
|
||||
items: true,
|
||||
shipping_method: {
|
||||
tax_lines: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("buildSelects", () => {
|
||||
it("successfully build back select object shape to list", () => {
|
||||
const q = buildSelects([
|
||||
"order",
|
||||
"order.items",
|
||||
"order.swaps",
|
||||
"order.swaps.additional_items",
|
||||
"order.discounts",
|
||||
"order.discounts.rule",
|
||||
"order.claims",
|
||||
"order.claims.additional_items",
|
||||
"additional_items",
|
||||
"additional_items.variant",
|
||||
"return_order",
|
||||
"return_order.items",
|
||||
"return_order.shipping_method",
|
||||
"return_order.shipping_method.tax_lines",
|
||||
])
|
||||
|
||||
expect(q).toEqual({
|
||||
order: {
|
||||
items: true,
|
||||
swaps: {
|
||||
additional_items: true,
|
||||
},
|
||||
discounts: {
|
||||
rule: true,
|
||||
},
|
||||
claims: {
|
||||
additional_items: true,
|
||||
},
|
||||
},
|
||||
additional_items: {
|
||||
variant: true,
|
||||
},
|
||||
return_order: {
|
||||
items: true,
|
||||
shipping_method: {
|
||||
tax_lines: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,59 @@
|
||||
import { convertItemResponseToUpdateRequest } from "../convert-item-response-to-update-request"
|
||||
|
||||
describe("convertItemResponseToUpdateRequest", function () {
|
||||
it("should return true or false for different types of data", function () {
|
||||
const expectations = [
|
||||
{
|
||||
item: {
|
||||
id: "test-id",
|
||||
test_attr: "test-name",
|
||||
relation_object_with_params: {
|
||||
id: "test-relation-object-id",
|
||||
test_attr: "test-object-name",
|
||||
},
|
||||
relation_object_without_params: {
|
||||
id: "test-relation-object-without-params-id",
|
||||
},
|
||||
relation_array: [
|
||||
{
|
||||
id: "test-relation-array-id",
|
||||
test_attr: "test-array-name",
|
||||
},
|
||||
],
|
||||
},
|
||||
selects: [
|
||||
"id",
|
||||
"test_attr",
|
||||
"relation_object_with_params.id",
|
||||
"relation_object_with_params.test_attr",
|
||||
"relation_object_without_params.id",
|
||||
"relation_array.id",
|
||||
"relation_array.test_attr",
|
||||
],
|
||||
relations: [
|
||||
"relation_object_with_params",
|
||||
"relation_object_without_params",
|
||||
"relation_array",
|
||||
],
|
||||
output: {
|
||||
id: "test-id",
|
||||
test_attr: "test-name",
|
||||
relation_object_with_params: { test_attr: "test-object-name" },
|
||||
relation_array: [{ id: "test-relation-array-id" }],
|
||||
relation_object_without_params_id:
|
||||
"test-relation-object-without-params-id",
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
expectations.forEach((expectation) => {
|
||||
const response = convertItemResponseToUpdateRequest(
|
||||
expectation.item,
|
||||
expectation.selects,
|
||||
expectation.relations
|
||||
)
|
||||
|
||||
expect(response).toEqual(expectation.output)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,92 @@
|
||||
import { createPsqlIndexStatementHelper } from "../create-psql-index-helper"
|
||||
|
||||
describe("createPsqlIndexStatementHelper", function () {
|
||||
it("should generate a simple index", function () {
|
||||
const options = {
|
||||
name: "index_name",
|
||||
tableName: "table_name",
|
||||
columns: "column_name",
|
||||
}
|
||||
|
||||
const indexStatement = createPsqlIndexStatementHelper(options)
|
||||
expect(indexStatement + "").toEqual(
|
||||
`CREATE INDEX IF NOT EXISTS "${options.name}" ON "${options.tableName}" (${options.columns})`
|
||||
)
|
||||
})
|
||||
|
||||
it("should generate a simple index and auto compose its name", function () {
|
||||
const options = {
|
||||
tableName: "table_name",
|
||||
columns: "column_name",
|
||||
}
|
||||
|
||||
const indexStatement = createPsqlIndexStatementHelper(options)
|
||||
expect(indexStatement + "").toEqual(
|
||||
`CREATE INDEX IF NOT EXISTS "IDX_table_name_column_name" ON "${options.tableName}" (${options.columns})`
|
||||
)
|
||||
})
|
||||
|
||||
it("should generate a composite index", function () {
|
||||
const options = {
|
||||
name: "index_name",
|
||||
tableName: "table_name",
|
||||
columns: ["column_name_1", "column_name_2"],
|
||||
}
|
||||
|
||||
const indexStatement = createPsqlIndexStatementHelper(options)
|
||||
expect(indexStatement.expression).toEqual(
|
||||
`CREATE INDEX IF NOT EXISTS "${options.name}" ON "${
|
||||
options.tableName
|
||||
}" (${options.columns.join(", ")})`
|
||||
)
|
||||
})
|
||||
|
||||
it("should generate an index with where clauses", function () {
|
||||
const options = {
|
||||
name: "index_name",
|
||||
tableName: "table_name",
|
||||
columns: ["column_name_1", "column_name_2"],
|
||||
where: "column_name_1 IS NOT NULL",
|
||||
}
|
||||
|
||||
const indexStatement = createPsqlIndexStatementHelper(options)
|
||||
expect(indexStatement.expression).toEqual(
|
||||
`CREATE INDEX IF NOT EXISTS "${options.name}" ON "${
|
||||
options.tableName
|
||||
}" (${options.columns.join(", ")}) WHERE ${options.where}`
|
||||
)
|
||||
})
|
||||
|
||||
it("should generate an index with where clauses and index type", function () {
|
||||
const options = {
|
||||
name: "index_name",
|
||||
tableName: "table_name",
|
||||
columns: ["column_name_1", "column_name_2"],
|
||||
type: "GIN",
|
||||
where: "column_name_1 IS NOT NULL",
|
||||
}
|
||||
|
||||
const indexStatement = createPsqlIndexStatementHelper(options)
|
||||
expect(indexStatement.toString()).toEqual(
|
||||
`CREATE INDEX IF NOT EXISTS "${options.name}" ON "${
|
||||
options.tableName
|
||||
}" USING GIN (${options.columns.join(", ")}) WHERE ${options.where}`
|
||||
)
|
||||
})
|
||||
|
||||
it("should generate unique constraint", function () {
|
||||
const options = {
|
||||
tableName: "table_name",
|
||||
columns: ["column_name_1", "column_name_2"],
|
||||
unique: true,
|
||||
where: "column_name_1 IS NOT NULL",
|
||||
}
|
||||
|
||||
const indexStatement = createPsqlIndexStatementHelper(options)
|
||||
expect(indexStatement.expression).toEqual(
|
||||
`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_table_name_column_name_1_column_name_2_unique" ON "${
|
||||
options.tableName
|
||||
}" (${options.columns.join(", ")}) WHERE ${options.where}`
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,74 @@
|
||||
import { deepCopy } from "../deep-copy"
|
||||
|
||||
class TestA {
|
||||
prop1: any
|
||||
prop2: any
|
||||
|
||||
constructor(prop1: any, prop2: any) {
|
||||
this.prop1 = prop1
|
||||
this.prop2 = prop2
|
||||
}
|
||||
}
|
||||
|
||||
class TestWrapper {
|
||||
prop1: any
|
||||
prop2: any
|
||||
|
||||
constructor(prop1: any, prop2: any) {
|
||||
this.prop1 = prop1
|
||||
this.prop2 = prop2
|
||||
}
|
||||
|
||||
factory() {
|
||||
return new TestA(deepCopy(this.prop1), deepCopy(this.prop2))
|
||||
}
|
||||
}
|
||||
|
||||
class TestWrapperWithoutDeepCopy {
|
||||
prop1: any
|
||||
prop2: any
|
||||
|
||||
constructor(prop1: any, prop2: any) {
|
||||
this.prop1 = prop1
|
||||
this.prop2 = prop2
|
||||
}
|
||||
|
||||
factory() {
|
||||
return new TestA(this.prop1, this.prop2)
|
||||
}
|
||||
}
|
||||
|
||||
describe("deepCopy", () => {
|
||||
it("should deep copy an object", () => {
|
||||
const prop1 = {
|
||||
prop1: 1,
|
||||
}
|
||||
|
||||
const prop2 = {
|
||||
prop1: 3,
|
||||
}
|
||||
|
||||
const wrapperWithoutDeepCopy = new TestWrapperWithoutDeepCopy(prop1, prop2)
|
||||
let factory1 = wrapperWithoutDeepCopy.factory()
|
||||
let factory2 = wrapperWithoutDeepCopy.factory()
|
||||
|
||||
factory1.prop1.prop1 = 2
|
||||
|
||||
expect(wrapperWithoutDeepCopy.prop1).toEqual({ prop1: 2 })
|
||||
expect(factory1.prop1).toEqual({ prop1: 2 })
|
||||
expect(factory2.prop1).toEqual({ prop1: 2 })
|
||||
|
||||
prop1.prop1 = 4
|
||||
prop2.prop1 = 4
|
||||
|
||||
const wrapper = new TestWrapper(prop1, prop2)
|
||||
factory1 = wrapper.factory()
|
||||
factory2 = wrapper.factory()
|
||||
|
||||
factory1.prop1.prop1 = 2
|
||||
|
||||
expect(wrapper.prop1).toEqual({ prop1: 4 })
|
||||
expect(factory1.prop1).toEqual({ prop1: 2 })
|
||||
expect(factory2.prop1).toEqual({ prop1: 4 })
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,33 @@
|
||||
import { deepEqualObj } from "../deep-equal-obj"
|
||||
|
||||
describe("deepEqualObj", function () {
|
||||
it("should return true if objects are equal", function () {
|
||||
const object1 = {
|
||||
foo: "bar",
|
||||
bar: "foo",
|
||||
xar: { foo: "bar", wor: { bar: "foo", ror: ["test", "test1"] } },
|
||||
}
|
||||
const object2 = {
|
||||
foo: "bar",
|
||||
bar: "foo",
|
||||
xar: { foo: "bar", wor: { bar: "foo", ror: ["test", "test1"] } },
|
||||
}
|
||||
|
||||
expect(deepEqualObj(object1, object2)).toBe(true)
|
||||
})
|
||||
|
||||
it("should return false if objects are not equal", function () {
|
||||
const object1 = {
|
||||
foo: "bar",
|
||||
bar: "foo",
|
||||
xar: { foo: "bar", wor: { bar: "foo", ror: ["test", "test1"] } },
|
||||
}
|
||||
const object2 = {
|
||||
foo: "bar",
|
||||
bar: "foo",
|
||||
xar: { foo: "bar", wor: { bar: "foo", ror: ["test", "test1_"] } },
|
||||
}
|
||||
|
||||
expect(deepEqualObj(object1, object2)).toBe(false)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,203 @@
|
||||
import { deepFlatMap } from "../deep-flat-map"
|
||||
|
||||
describe("deepFlatMap", function () {
|
||||
it("should return flat map of nested objects", function () {
|
||||
const data = [
|
||||
{
|
||||
id: "sales_channel_1",
|
||||
stock_locations: [
|
||||
{
|
||||
id: "location_1",
|
||||
fulfillment_sets: [
|
||||
{
|
||||
id: "fset_1",
|
||||
name: "Test 123",
|
||||
service_zones: [
|
||||
{
|
||||
id: "zone_123",
|
||||
shipping_options: [
|
||||
{
|
||||
id: "so_zone_123 1111",
|
||||
calculated_price: {
|
||||
calculated_amount: 3000,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "so_zone_123 22222",
|
||||
calculated_price: {
|
||||
calculated_amount: 6000,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "zone_567",
|
||||
shipping_options: [
|
||||
{
|
||||
id: "zone 567 11111",
|
||||
calculated_price: {
|
||||
calculated_amount: 1230,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "zone 567 22222",
|
||||
calculated_price: {
|
||||
calculated_amount: 1230,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "location_2",
|
||||
fulfillment_sets: [
|
||||
{
|
||||
id: "fset_2",
|
||||
name: "fset name 2",
|
||||
service_zones: [
|
||||
{
|
||||
id: "zone_ABC",
|
||||
shipping_options: [
|
||||
{
|
||||
id: "zone_abc_unique",
|
||||
calculated_price: {
|
||||
calculated_amount: 70,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
id: "sales_channel_2",
|
||||
stock_locations: [
|
||||
{
|
||||
id: "location_5",
|
||||
fulfillment_sets: [
|
||||
{
|
||||
id: "fset_aaa",
|
||||
name: "Test aaa",
|
||||
service_zones: [
|
||||
{
|
||||
id: "zone_aaa",
|
||||
shipping_options: [
|
||||
{
|
||||
id: "so_zone_aaa aaaa",
|
||||
calculated_price: {
|
||||
calculated_amount: 500,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "so_zone_aaa bbbb",
|
||||
calculated_price: {
|
||||
calculated_amount: 12,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
const result = deepFlatMap(
|
||||
data,
|
||||
"stock_locations.fulfillment_sets.service_zones.shipping_options.calculated_price",
|
||||
({
|
||||
root_,
|
||||
stock_locations,
|
||||
fulfillment_sets,
|
||||
service_zones,
|
||||
shipping_options,
|
||||
calculated_price,
|
||||
}) => {
|
||||
return {
|
||||
sales_channel_id: root_.id,
|
||||
stock_location_id: stock_locations.id,
|
||||
fulfillment_set_id: fulfillment_sets.id,
|
||||
fulfillment_set_name: fulfillment_sets.name,
|
||||
service_zone_id: service_zones.id,
|
||||
shipping_option_id: shipping_options.id,
|
||||
price: calculated_price.calculated_amount,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
sales_channel_id: "sales_channel_1",
|
||||
stock_location_id: "location_1",
|
||||
fulfillment_set_id: "fset_1",
|
||||
fulfillment_set_name: "Test 123",
|
||||
service_zone_id: "zone_123",
|
||||
shipping_option_id: "so_zone_123 1111",
|
||||
price: 3000,
|
||||
},
|
||||
{
|
||||
sales_channel_id: "sales_channel_1",
|
||||
stock_location_id: "location_1",
|
||||
fulfillment_set_id: "fset_1",
|
||||
fulfillment_set_name: "Test 123",
|
||||
service_zone_id: "zone_123",
|
||||
shipping_option_id: "so_zone_123 22222",
|
||||
price: 6000,
|
||||
},
|
||||
{
|
||||
sales_channel_id: "sales_channel_1",
|
||||
stock_location_id: "location_1",
|
||||
fulfillment_set_id: "fset_1",
|
||||
fulfillment_set_name: "Test 123",
|
||||
service_zone_id: "zone_567",
|
||||
shipping_option_id: "zone 567 11111",
|
||||
price: 1230,
|
||||
},
|
||||
{
|
||||
sales_channel_id: "sales_channel_1",
|
||||
stock_location_id: "location_1",
|
||||
fulfillment_set_id: "fset_1",
|
||||
fulfillment_set_name: "Test 123",
|
||||
service_zone_id: "zone_567",
|
||||
shipping_option_id: "zone 567 22222",
|
||||
price: 1230,
|
||||
},
|
||||
{
|
||||
sales_channel_id: "sales_channel_1",
|
||||
stock_location_id: "location_2",
|
||||
fulfillment_set_id: "fset_2",
|
||||
fulfillment_set_name: "fset name 2",
|
||||
service_zone_id: "zone_ABC",
|
||||
shipping_option_id: "zone_abc_unique",
|
||||
price: 70,
|
||||
},
|
||||
{
|
||||
sales_channel_id: "sales_channel_2",
|
||||
stock_location_id: "location_5",
|
||||
fulfillment_set_id: "fset_aaa",
|
||||
fulfillment_set_name: "Test aaa",
|
||||
service_zone_id: "zone_aaa",
|
||||
shipping_option_id: "so_zone_aaa aaaa",
|
||||
price: 500,
|
||||
},
|
||||
{
|
||||
sales_channel_id: "sales_channel_2",
|
||||
stock_location_id: "location_5",
|
||||
fulfillment_set_id: "fset_aaa",
|
||||
fulfillment_set_name: "Test aaa",
|
||||
service_zone_id: "zone_aaa",
|
||||
shipping_option_id: "so_zone_aaa bbbb",
|
||||
price: 12,
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,20 @@
|
||||
import { getDuplicates } from "../get-duplicates"
|
||||
|
||||
describe("getDuplicates", function () {
|
||||
it("should return an empty array if there are no duplicates", function () {
|
||||
const output = getDuplicates(["foo", "bar", "baz"])
|
||||
expect(output).toHaveLength(0)
|
||||
})
|
||||
|
||||
it("should return a singular duplicate", function () {
|
||||
const output = getDuplicates(["foo", "bar", "baz", "baz", "baz"])
|
||||
expect(output).toHaveLength(1)
|
||||
expect(output[0]).toEqual("baz")
|
||||
})
|
||||
|
||||
it("should return all duplicates in the array", function () {
|
||||
const output = getDuplicates(["foo", "bar", "bar", "baz", "baz", "baz"])
|
||||
expect(output).toHaveLength(2)
|
||||
expect(output).toEqual(expect.arrayContaining(["baz", "bar"]))
|
||||
})
|
||||
})
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
import { getSelectsAndRelationsFromObjectArray } from "../get-selects-and-relations-from-object-array"
|
||||
|
||||
describe("getSelectsAndRelationsFromObjectArray", function () {
|
||||
it("should return true or false for different types of data", function () {
|
||||
const expectations = [
|
||||
{
|
||||
input: [
|
||||
{
|
||||
attr_string: "string",
|
||||
attr_boolean: true,
|
||||
attr_null: null,
|
||||
attr_undefined: undefined,
|
||||
attr_object: {
|
||||
attr_string: "string",
|
||||
attr_boolean: true,
|
||||
attr_null: null,
|
||||
attr_undefined: undefined,
|
||||
},
|
||||
attr_array: [
|
||||
{
|
||||
attr_object: {
|
||||
attr_string: "string",
|
||||
attr_boolean: true,
|
||||
attr_null: null,
|
||||
attr_undefined: undefined,
|
||||
},
|
||||
},
|
||||
{
|
||||
attr_object: {
|
||||
attr_string: "string",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
output: {
|
||||
selects: [
|
||||
"attr_string",
|
||||
"attr_boolean",
|
||||
"attr_null",
|
||||
"attr_undefined",
|
||||
"attr_object.attr_string",
|
||||
"attr_object.attr_boolean",
|
||||
"attr_object.attr_null",
|
||||
"attr_object.attr_undefined",
|
||||
"attr_array.attr_object.attr_string",
|
||||
"attr_array.attr_object.attr_boolean",
|
||||
"attr_array.attr_object.attr_null",
|
||||
"attr_array.attr_object.attr_undefined",
|
||||
],
|
||||
relations: ["attr_object", "attr_array", "attr_array.attr_object"],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
expectations.forEach((expectation) => {
|
||||
expect(getSelectsAndRelationsFromObjectArray(expectation.input)).toEqual(
|
||||
expectation.output
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,50 @@
|
||||
import { groupBy } from "../group-by"
|
||||
|
||||
const array = [
|
||||
{
|
||||
id: "test-id-1",
|
||||
property: "test-id-1-property-1",
|
||||
},
|
||||
{
|
||||
id: "test-id-1",
|
||||
property: "test-id-1-property-2",
|
||||
},
|
||||
{
|
||||
id: "test-id-2",
|
||||
property: "test-id-2-property-1",
|
||||
},
|
||||
{
|
||||
id: "test-id-2",
|
||||
property: "test-id-2-property-2",
|
||||
},
|
||||
{
|
||||
id: "test-id-3",
|
||||
property: "test-id-3-property-1",
|
||||
},
|
||||
]
|
||||
|
||||
const mapToObject = (map: Map<any, any>) => Object.fromEntries(map.entries())
|
||||
|
||||
describe("groupBy", function () {
|
||||
it("should return a map grouped by an identifier", function () {
|
||||
const response = mapToObject(groupBy(array, "id"))
|
||||
|
||||
expect(response).toEqual({
|
||||
"test-id-1": [
|
||||
{ id: "test-id-1", property: "test-id-1-property-1" },
|
||||
{ id: "test-id-1", property: "test-id-1-property-2" },
|
||||
],
|
||||
"test-id-2": [
|
||||
{ id: "test-id-2", property: "test-id-2-property-1" },
|
||||
{ id: "test-id-2", property: "test-id-2-property-2" },
|
||||
],
|
||||
"test-id-3": [{ id: "test-id-3", property: "test-id-3-property-1" }],
|
||||
})
|
||||
})
|
||||
|
||||
it("should return empty map if identifier is not found in array", function () {
|
||||
const response = mapToObject(groupBy(array, "doesnotexist"))
|
||||
|
||||
expect(response).toEqual({})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,107 @@
|
||||
import {
|
||||
DatabaseErrorCode,
|
||||
handlePostgresDatabaseError,
|
||||
} from "../handle-postgres-database-error"
|
||||
import { EOL } from "os"
|
||||
|
||||
describe("handlePostgresDataError", function () {
|
||||
it("should throw a specific message on database does not exists", function () {
|
||||
const error = new Error("database does not exist")
|
||||
Object.assign(error, { code: DatabaseErrorCode.databaseDoesNotExist })
|
||||
|
||||
let outputError: any
|
||||
try {
|
||||
handlePostgresDatabaseError(error)
|
||||
} catch (e) {
|
||||
outputError = e
|
||||
}
|
||||
|
||||
expect(outputError.message).toEqual(
|
||||
`The specified PostgreSQL database does not exist. Please create it and try again.${EOL}${error.message}`
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw a specific message on database connection failure", function () {
|
||||
const error = new Error("database does not exist")
|
||||
Object.assign(error, { code: DatabaseErrorCode.connectionFailure })
|
||||
|
||||
let outputError: any
|
||||
try {
|
||||
handlePostgresDatabaseError(error)
|
||||
} catch (e) {
|
||||
outputError = e
|
||||
}
|
||||
|
||||
expect(outputError.message).toEqual(
|
||||
`Failed to establish a connection to PostgreSQL. Please ensure the following is true and try again:
|
||||
- You have a PostgreSQL database running
|
||||
- You have passed the correct credentials in medusa-config.js
|
||||
- You have formatted the database connection string correctly. See below:
|
||||
"postgres://[username]:[password]@[host]:[post]/[db_name]" - If there is no password, you can omit it from the connection string
|
||||
${EOL}
|
||||
${error.message}`
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw a specific message on database wrong credentials", function () {
|
||||
const error = new Error("database does not exist")
|
||||
Object.assign(error, { code: DatabaseErrorCode.wrongCredentials })
|
||||
|
||||
let outputError: any
|
||||
try {
|
||||
handlePostgresDatabaseError(error)
|
||||
} catch (e) {
|
||||
outputError = e
|
||||
}
|
||||
|
||||
expect(outputError.message).toEqual(
|
||||
`The specified credentials does not exists for the specified PostgreSQL database.${EOL}${error.message}`
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw a specific message on database not found", function () {
|
||||
const error = new Error("database does not exist")
|
||||
Object.assign(error, { code: DatabaseErrorCode.notFound })
|
||||
|
||||
let outputError: any
|
||||
try {
|
||||
handlePostgresDatabaseError(error)
|
||||
} catch (e) {
|
||||
outputError = e
|
||||
}
|
||||
|
||||
expect(outputError.message).toEqual(
|
||||
`The specified connection string for your PostgreSQL database might have illegal characters. Please check that it only contains allowed characters [a-zA-Z0-9]${EOL}${error.message}`
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw a specific message on database migration missing", function () {
|
||||
const error = new Error("database does not exist")
|
||||
Object.assign(error, { code: DatabaseErrorCode.migrationMissing })
|
||||
|
||||
let outputError: any
|
||||
try {
|
||||
handlePostgresDatabaseError(error)
|
||||
} catch (e) {
|
||||
outputError = e
|
||||
}
|
||||
|
||||
expect(outputError.message).toEqual(
|
||||
`Migrations missing. Please run 'medusa migrations run' and try again.`
|
||||
)
|
||||
})
|
||||
|
||||
it("should re throw unhandled error code", function () {
|
||||
const error = new Error("database does not exist")
|
||||
Object.assign(error, { code: "test" })
|
||||
|
||||
let outputError: any
|
||||
try {
|
||||
handlePostgresDatabaseError(error)
|
||||
} catch (e) {
|
||||
outputError = e
|
||||
}
|
||||
|
||||
expect(outputError.message).toEqual("database does not exist")
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,21 @@
|
||||
import { validateEmail } from "../is-email"
|
||||
|
||||
describe("validateEmail", () => {
|
||||
it("successfully validates an email", () => {
|
||||
expect(validateEmail("test@email.com")).toBe("test@email.com")
|
||||
expect(validateEmail("test.test@email.com")).toBe("test.test@email.com")
|
||||
expect(validateEmail("test.test123@email.com")).toBe(
|
||||
"test.test123@email.com"
|
||||
)
|
||||
})
|
||||
|
||||
it("throws on an invalidates email", () => {
|
||||
expect.assertions(1)
|
||||
|
||||
try {
|
||||
validateEmail("not-an-email")
|
||||
} catch (e) {
|
||||
expect(e.message).toBe("The email is not valid")
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,61 @@
|
||||
import { isPresent } from "../is-present"
|
||||
|
||||
describe("isPresent", function () {
|
||||
it("should return true or false for different types of data", function () {
|
||||
const expectations = [
|
||||
{
|
||||
input: null,
|
||||
output: false,
|
||||
},
|
||||
{
|
||||
input: undefined,
|
||||
output: false,
|
||||
},
|
||||
{
|
||||
input: "Testing",
|
||||
output: true,
|
||||
},
|
||||
{
|
||||
input: "",
|
||||
output: false,
|
||||
},
|
||||
{
|
||||
input: {},
|
||||
output: false,
|
||||
},
|
||||
{
|
||||
input: { test: 1 },
|
||||
output: true,
|
||||
},
|
||||
{
|
||||
input: [],
|
||||
output: false,
|
||||
},
|
||||
{
|
||||
input: [{ test: 1 }],
|
||||
output: true,
|
||||
},
|
||||
{
|
||||
input: new Map([["test", "test"]]),
|
||||
output: true,
|
||||
},
|
||||
{
|
||||
input: new Map([]),
|
||||
output: false,
|
||||
},
|
||||
|
||||
{
|
||||
input: new Set(["test"]),
|
||||
output: true,
|
||||
},
|
||||
{
|
||||
input: new Set([]),
|
||||
output: false,
|
||||
},
|
||||
]
|
||||
|
||||
expectations.forEach((expectation) => {
|
||||
expect(isPresent(expectation.input)).toEqual(expectation.output)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,43 @@
|
||||
import { mapObjectTo, MapToConfig } from "../map-object-to"
|
||||
|
||||
const input = {
|
||||
a: [{ id: "1" }, { id: "2" }],
|
||||
b: [{ id: "3" }, { id: "4", handle: "handle1" }],
|
||||
c: [{ id: "5", sku: "sku1" }, { id: "6" }],
|
||||
}
|
||||
|
||||
const mapToConfig: MapToConfig = {
|
||||
a: [{ mapTo: "a.id", valueFrom: "id" }],
|
||||
b: [
|
||||
{ mapTo: "b.id", valueFrom: "id" },
|
||||
{ mapTo: "b.handle", valueFrom: "handle" },
|
||||
],
|
||||
c: [
|
||||
{ mapTo: "c.id", valueFrom: "id" },
|
||||
{ mapTo: "c.sku", valueFrom: "sku" },
|
||||
],
|
||||
}
|
||||
|
||||
describe("mapObjectTo", function () {
|
||||
it("should return a new object with the keys remapped and the values picked from the original object based on the map config", function () {
|
||||
const remappedObject = mapObjectTo(input, mapToConfig)
|
||||
|
||||
expect(remappedObject).toEqual({
|
||||
"a.id": ["1", "2"],
|
||||
"b.id": ["3", "4"],
|
||||
"b.handle": ["handle1"],
|
||||
"c.id": ["5", "6"],
|
||||
"c.sku": ["sku1"],
|
||||
})
|
||||
})
|
||||
|
||||
it("should return a new object with only the picked properties", function () {
|
||||
const remappedObject = mapObjectTo(input, mapToConfig, {
|
||||
pick: ["a.id"],
|
||||
})
|
||||
|
||||
expect(remappedObject).toEqual({
|
||||
"a.id": ["1", "2"],
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,42 @@
|
||||
import { objectToStringPath } from "../object-to-string-path"
|
||||
|
||||
describe("objectToStringPath", function () {
|
||||
it("should return only the properties path of the properties that are set to true", function () {
|
||||
const res = objectToStringPath(
|
||||
{
|
||||
product: true,
|
||||
variants: {
|
||||
title: true,
|
||||
prices: {
|
||||
amount: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
includeParentPropertyFields: false,
|
||||
}
|
||||
)
|
||||
|
||||
expect(res).toEqual(["product", "variants.title", "variants.prices.amount"])
|
||||
})
|
||||
|
||||
it("should return a string path from an object including properties that are object and contains other properties set to true", function () {
|
||||
const res = objectToStringPath({
|
||||
product: true,
|
||||
variants: {
|
||||
title: true,
|
||||
prices: {
|
||||
amount: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(res).toEqual([
|
||||
"product",
|
||||
"variants",
|
||||
"variants.title",
|
||||
"variants.prices",
|
||||
"variants.prices.amount",
|
||||
])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,12 @@
|
||||
import { partitionArray } from "../../../dist"
|
||||
|
||||
describe("partitionArray", function () {
|
||||
it("should split array according to predicate", function () {
|
||||
const res = partitionArray([1, 2, 3, 4, 5], (x) => x % 2 === 0)
|
||||
|
||||
expect(res).toEqual([
|
||||
[2, 4],
|
||||
[1, 3, 5],
|
||||
])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,111 @@
|
||||
import { pickValueFromObject } from "../pick-value-from-object"
|
||||
|
||||
describe("pickValueFromObject", function () {
|
||||
it("should return true or false for different types of data", function () {
|
||||
const expectations = [
|
||||
{
|
||||
input: {
|
||||
1: "attribute.another_attribute",
|
||||
2: {
|
||||
attribute: {
|
||||
another_attribute: "test",
|
||||
},
|
||||
},
|
||||
},
|
||||
output: "test",
|
||||
},
|
||||
{
|
||||
input: {
|
||||
1: "attribute.another_attribute.array_attribute",
|
||||
2: {
|
||||
attribute: {
|
||||
another_attribute: [
|
||||
{
|
||||
array_attribute: "test 1",
|
||||
},
|
||||
{
|
||||
array_attribute: "test 2",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
output: ["test 1", "test 2"],
|
||||
},
|
||||
{
|
||||
input: {
|
||||
1: "attribute.another_attribute.array_attribute.deep_array_attribute",
|
||||
2: {
|
||||
attribute: {
|
||||
another_attribute: [
|
||||
{
|
||||
array_attribute: [
|
||||
{
|
||||
deep_array_attribute: "test 1",
|
||||
},
|
||||
{
|
||||
deep_array_attribute: "test 2",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
array_attribute: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
output: ["test 1", "test 2"],
|
||||
},
|
||||
{
|
||||
input: {
|
||||
1: "attribute.another_attribute.array_attribute",
|
||||
2: {
|
||||
attribute: {
|
||||
another_attribute: [
|
||||
{
|
||||
array_attribute: [
|
||||
{
|
||||
deep_array_attribute: "test 1",
|
||||
},
|
||||
{
|
||||
deep_array_attribute: "test 2",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
array_attribute: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
output: [
|
||||
{
|
||||
deep_array_attribute: "test 1",
|
||||
},
|
||||
{
|
||||
deep_array_attribute: "test 2",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
input: {
|
||||
1: "attribute.missing_attribute",
|
||||
2: {
|
||||
attribute: {
|
||||
another_attribute: "test",
|
||||
},
|
||||
},
|
||||
},
|
||||
output: undefined,
|
||||
},
|
||||
]
|
||||
|
||||
expectations.forEach((expectation) => {
|
||||
expect(
|
||||
pickValueFromObject(expectation.input["1"], expectation.input["2"])
|
||||
).toEqual(expectation.output)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,33 @@
|
||||
import { pluralize } from "../plurailze"
|
||||
|
||||
describe("pluralize", function () {
|
||||
it("should pluralize any words", function () {
|
||||
const words = [
|
||||
"apple",
|
||||
"box",
|
||||
"day",
|
||||
"country",
|
||||
"baby",
|
||||
"knife",
|
||||
"hero",
|
||||
"potato",
|
||||
"address",
|
||||
]
|
||||
|
||||
const expectedOutput = [
|
||||
"apples",
|
||||
"boxes",
|
||||
"days",
|
||||
"countries",
|
||||
"babies",
|
||||
"knives",
|
||||
"heroes",
|
||||
"potatoes",
|
||||
"addresses",
|
||||
]
|
||||
|
||||
words.forEach((word, index) => {
|
||||
expect(pluralize(word)).toBe(expectedOutput[index])
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,58 @@
|
||||
import { promiseAll } from "../promise-all"
|
||||
import { EOL } from "os"
|
||||
|
||||
describe("promiseAll", function () {
|
||||
it("should throw an error if any of the promises throw", async function () {
|
||||
const res = await promiseAll([
|
||||
Promise.resolve(1),
|
||||
(async () => {
|
||||
throw new Error("error")
|
||||
})(),
|
||||
Promise.resolve(3),
|
||||
]).catch((e) => e)
|
||||
|
||||
expect(res.message).toBe("error")
|
||||
})
|
||||
|
||||
it("should throw errors if any of the promises throw and aggregate them", async function () {
|
||||
const res = await promiseAll(
|
||||
[
|
||||
Promise.resolve(1),
|
||||
(async () => {
|
||||
throw new Error("error")
|
||||
})(),
|
||||
(async () => {
|
||||
throw new Error("error2")
|
||||
})(),
|
||||
Promise.resolve(3),
|
||||
],
|
||||
{
|
||||
aggregateErrors: true,
|
||||
}
|
||||
).catch((e) => e)
|
||||
|
||||
expect(res.message).toBe(["error", "error2"].join(EOL))
|
||||
})
|
||||
|
||||
it("should return all values if all promises are fulfilled", async function () {
|
||||
const res = await promiseAll([
|
||||
Promise.resolve(1),
|
||||
Promise.resolve(2),
|
||||
Promise.resolve(3),
|
||||
])
|
||||
|
||||
expect(res).toEqual([1, 2, 3])
|
||||
})
|
||||
|
||||
it("should return all values if all promises are fulfilled including waiting for nested promises", async function () {
|
||||
const res = await promiseAll([
|
||||
Promise.resolve(1),
|
||||
(async () => {
|
||||
await promiseAll([Promise.resolve(1), Promise.resolve(2)])
|
||||
})(),
|
||||
Promise.resolve(3),
|
||||
])
|
||||
|
||||
expect(res).toEqual([1, undefined, 3])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,148 @@
|
||||
import { remoteQueryObjectFromString } from "../remote-query-object-from-string"
|
||||
|
||||
const fields = [
|
||||
"id",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"url",
|
||||
"metadata",
|
||||
"tags.id",
|
||||
"tags.created_at",
|
||||
"tags.updated_at",
|
||||
"tags.deleted_at",
|
||||
"tags.value",
|
||||
"options.id",
|
||||
"options.created_at",
|
||||
"options.updated_at",
|
||||
"options.deleted_at",
|
||||
"options.title",
|
||||
"options.product_id",
|
||||
"options.metadata",
|
||||
"options.values.id",
|
||||
"options.values.created_at",
|
||||
"options.values.updated_at",
|
||||
"options.values.deleted_at",
|
||||
"options.values.value",
|
||||
"options.values.option_id",
|
||||
"options.values.variant_id",
|
||||
"options.values.metadata",
|
||||
]
|
||||
|
||||
describe("remoteQueryObjectFromString", function () {
|
||||
it("should return a remote query object", function () {
|
||||
const output = remoteQueryObjectFromString({
|
||||
entryPoint: "product",
|
||||
variables: {
|
||||
q: "name",
|
||||
options: {
|
||||
name: "option_name",
|
||||
},
|
||||
"options.values": {
|
||||
value: 123,
|
||||
},
|
||||
},
|
||||
fields,
|
||||
})
|
||||
|
||||
expect(output).toEqual({
|
||||
product: {
|
||||
__args: {
|
||||
q: "name",
|
||||
},
|
||||
fields: [
|
||||
"id",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"url",
|
||||
"metadata",
|
||||
],
|
||||
isServiceAccess: false,
|
||||
tags: {
|
||||
fields: ["id", "created_at", "updated_at", "deleted_at", "value"],
|
||||
},
|
||||
|
||||
options: {
|
||||
__args: {
|
||||
name: "option_name",
|
||||
},
|
||||
fields: [
|
||||
"id",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"title",
|
||||
"product_id",
|
||||
"metadata",
|
||||
],
|
||||
values: {
|
||||
__args: {
|
||||
value: 123,
|
||||
},
|
||||
fields: [
|
||||
"id",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"value",
|
||||
"option_id",
|
||||
"variant_id",
|
||||
"metadata",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it("should return a remote query object using service entry point", function () {
|
||||
const output = remoteQueryObjectFromString({
|
||||
service: "product",
|
||||
variables: {},
|
||||
fields,
|
||||
})
|
||||
|
||||
expect(output).toEqual({
|
||||
product: {
|
||||
__args: {},
|
||||
fields: [
|
||||
"id",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"url",
|
||||
"metadata",
|
||||
],
|
||||
isServiceAccess: true,
|
||||
tags: {
|
||||
fields: ["id", "created_at", "updated_at", "deleted_at", "value"],
|
||||
},
|
||||
|
||||
options: {
|
||||
fields: [
|
||||
"id",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"title",
|
||||
"product_id",
|
||||
"metadata",
|
||||
],
|
||||
values: {
|
||||
fields: [
|
||||
"id",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"value",
|
||||
"option_id",
|
||||
"variant_id",
|
||||
"metadata",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,219 @@
|
||||
import { remoteQueryObjectToString } from "../remote-query-object-to-string"
|
||||
|
||||
const remoteQueryObject = {
|
||||
fields: [
|
||||
"id",
|
||||
"title",
|
||||
"subtitle",
|
||||
"status",
|
||||
"external_id",
|
||||
"description",
|
||||
"handle",
|
||||
"is_giftcard",
|
||||
"discountable",
|
||||
"thumbnail",
|
||||
"collection_id",
|
||||
"type_id",
|
||||
"weight",
|
||||
"length",
|
||||
"height",
|
||||
"width",
|
||||
"hs_code",
|
||||
"origin_country",
|
||||
"mid_code",
|
||||
"material",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"metadata",
|
||||
],
|
||||
images: {
|
||||
fields: ["id", "created_at", "updated_at", "deleted_at", "url", "metadata"],
|
||||
},
|
||||
tags: {
|
||||
fields: ["id", "created_at", "updated_at", "deleted_at", "value"],
|
||||
},
|
||||
|
||||
type: {
|
||||
fields: ["id", "created_at", "updated_at", "deleted_at", "value"],
|
||||
},
|
||||
|
||||
collection: {
|
||||
fields: ["title", "handle", "id", "created_at", "updated_at", "deleted_at"],
|
||||
},
|
||||
|
||||
options: {
|
||||
fields: [
|
||||
"id",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"title",
|
||||
"product_id",
|
||||
"metadata",
|
||||
],
|
||||
values: {
|
||||
fields: [
|
||||
"id",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"value",
|
||||
"option_id",
|
||||
"variant_id",
|
||||
"metadata",
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
variants: {
|
||||
fields: [
|
||||
"id",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"title",
|
||||
"product_id",
|
||||
"sku",
|
||||
"barcode",
|
||||
"ean",
|
||||
"upc",
|
||||
"variant_rank",
|
||||
"inventory_quantity",
|
||||
"allow_backorder",
|
||||
"manage_inventory",
|
||||
"hs_code",
|
||||
"origin_country",
|
||||
"mid_code",
|
||||
"material",
|
||||
"weight",
|
||||
"length",
|
||||
"height",
|
||||
"width",
|
||||
"metadata",
|
||||
],
|
||||
|
||||
options: {
|
||||
fields: [
|
||||
"id",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"value",
|
||||
"option_id",
|
||||
"variant_id",
|
||||
"metadata",
|
||||
],
|
||||
},
|
||||
},
|
||||
profile: {
|
||||
fields: ["id", "created_at", "updated_at", "deleted_at", "name", "type"],
|
||||
},
|
||||
}
|
||||
|
||||
describe("remoteQueryObjectToString", function () {
|
||||
it("should return a string array of fields/relations", function () {
|
||||
const output = remoteQueryObjectToString(remoteQueryObject)
|
||||
|
||||
expect(output).toEqual([
|
||||
"id",
|
||||
"title",
|
||||
"subtitle",
|
||||
"status",
|
||||
"external_id",
|
||||
"description",
|
||||
"handle",
|
||||
"is_giftcard",
|
||||
"discountable",
|
||||
"thumbnail",
|
||||
"collection_id",
|
||||
"type_id",
|
||||
"weight",
|
||||
"length",
|
||||
"height",
|
||||
"width",
|
||||
"hs_code",
|
||||
"origin_country",
|
||||
"mid_code",
|
||||
"material",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"metadata",
|
||||
"images.id",
|
||||
"images.created_at",
|
||||
"images.updated_at",
|
||||
"images.deleted_at",
|
||||
"images.url",
|
||||
"images.metadata",
|
||||
"tags.id",
|
||||
"tags.created_at",
|
||||
"tags.updated_at",
|
||||
"tags.deleted_at",
|
||||
"tags.value",
|
||||
"type.id",
|
||||
"type.created_at",
|
||||
"type.updated_at",
|
||||
"type.deleted_at",
|
||||
"type.value",
|
||||
"collection.title",
|
||||
"collection.handle",
|
||||
"collection.id",
|
||||
"collection.created_at",
|
||||
"collection.updated_at",
|
||||
"collection.deleted_at",
|
||||
"options.id",
|
||||
"options.created_at",
|
||||
"options.updated_at",
|
||||
"options.deleted_at",
|
||||
"options.title",
|
||||
"options.product_id",
|
||||
"options.metadata",
|
||||
"options.values.id",
|
||||
"options.values.created_at",
|
||||
"options.values.updated_at",
|
||||
"options.values.deleted_at",
|
||||
"options.values.value",
|
||||
"options.values.option_id",
|
||||
"options.values.variant_id",
|
||||
"options.values.metadata",
|
||||
"variants.id",
|
||||
"variants.created_at",
|
||||
"variants.updated_at",
|
||||
"variants.deleted_at",
|
||||
"variants.title",
|
||||
"variants.product_id",
|
||||
"variants.sku",
|
||||
"variants.barcode",
|
||||
"variants.ean",
|
||||
"variants.upc",
|
||||
"variants.variant_rank",
|
||||
"variants.inventory_quantity",
|
||||
"variants.allow_backorder",
|
||||
"variants.manage_inventory",
|
||||
"variants.hs_code",
|
||||
"variants.origin_country",
|
||||
"variants.mid_code",
|
||||
"variants.material",
|
||||
"variants.weight",
|
||||
"variants.length",
|
||||
"variants.height",
|
||||
"variants.width",
|
||||
"variants.metadata",
|
||||
"variants.options.id",
|
||||
"variants.options.created_at",
|
||||
"variants.options.updated_at",
|
||||
"variants.options.deleted_at",
|
||||
"variants.options.value",
|
||||
"variants.options.option_id",
|
||||
"variants.options.variant_id",
|
||||
"variants.options.metadata",
|
||||
"profile.id",
|
||||
"profile.created_at",
|
||||
"profile.updated_at",
|
||||
"profile.deleted_at",
|
||||
"profile.name",
|
||||
"profile.type",
|
||||
])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,22 @@
|
||||
import { removeUndefined } from "../remove-undefined"
|
||||
|
||||
describe("removeUndefined", function () {
|
||||
it("should remove all undefined fields from an object", function () {
|
||||
const withUndefined = {
|
||||
foo: undefined,
|
||||
bar: "baz",
|
||||
foo2: null,
|
||||
}
|
||||
expect(withUndefined.hasOwnProperty("foo")).toBe(true)
|
||||
|
||||
const output = removeUndefined(withUndefined)
|
||||
expect(output.hasOwnProperty("foo")).toBe(false)
|
||||
expect(output.hasOwnProperty("bar")).toBe(true)
|
||||
expect(output.hasOwnProperty("foo2")).toBe(true)
|
||||
})
|
||||
|
||||
it("should return an empty object as-is", function () {
|
||||
const output = removeUndefined({})
|
||||
expect(output).toEqual({})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,68 @@
|
||||
import { stringToSelectRelationObject } from "../string-to-select-relation-object"
|
||||
|
||||
const fields = [
|
||||
"id",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"url",
|
||||
"metadata",
|
||||
"tags.id",
|
||||
"tags.created_at",
|
||||
"tags.updated_at",
|
||||
"tags.deleted_at",
|
||||
"tags.value",
|
||||
"options.id",
|
||||
"options.created_at",
|
||||
"options.updated_at",
|
||||
"options.deleted_at",
|
||||
"options.title",
|
||||
"options.product_id",
|
||||
"options.metadata",
|
||||
"options.values.id",
|
||||
"options.values.created_at",
|
||||
"options.values.updated_at",
|
||||
"options.values.deleted_at",
|
||||
"options.values.value",
|
||||
"options.values.option_id",
|
||||
"options.values.variant_id",
|
||||
"options.values.metadata",
|
||||
]
|
||||
|
||||
describe("stringToSelectRelationObject", function () {
|
||||
it("should return an object containing the select and relation properties", function () {
|
||||
const output = stringToSelectRelationObject(fields)
|
||||
|
||||
expect(output).toEqual({
|
||||
select: [
|
||||
"id",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"url",
|
||||
"metadata",
|
||||
"tags.id",
|
||||
"tags.created_at",
|
||||
"tags.updated_at",
|
||||
"tags.deleted_at",
|
||||
"tags.value",
|
||||
"options.id",
|
||||
"options.created_at",
|
||||
"options.updated_at",
|
||||
"options.deleted_at",
|
||||
"options.title",
|
||||
"options.product_id",
|
||||
"options.metadata",
|
||||
"options.values.id",
|
||||
"options.values.created_at",
|
||||
"options.values.updated_at",
|
||||
"options.values.deleted_at",
|
||||
"options.values.value",
|
||||
"options.values.option_id",
|
||||
"options.values.variant_id",
|
||||
"options.values.metadata",
|
||||
],
|
||||
relations: ["tags", "options", "options.values"],
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,36 @@
|
||||
import { toCamelCase } from "../to-camel-case"
|
||||
|
||||
describe("toCamelCase", function () {
|
||||
it("should convert all cases to camel case", function () {
|
||||
const expectations = [
|
||||
{
|
||||
input: "testing-camelize",
|
||||
output: "testingCamelize",
|
||||
},
|
||||
{
|
||||
input: "testing-Camelize",
|
||||
output: "testingCamelize",
|
||||
},
|
||||
{
|
||||
input: "TESTING-CAMELIZE",
|
||||
output: "testingCamelize",
|
||||
},
|
||||
{
|
||||
input: "this_is-A-test",
|
||||
output: "thisIsATest",
|
||||
},
|
||||
{
|
||||
input: "this_is-A-test ANOTHER",
|
||||
output: "thisIsATestAnother",
|
||||
},
|
||||
{
|
||||
input: "testingAlreadyCamelized",
|
||||
output: "testingAlreadyCamelized",
|
||||
},
|
||||
]
|
||||
|
||||
expectations.forEach((expectation) => {
|
||||
expect(toCamelCase(expectation.input)).toEqual(expectation.output)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,36 @@
|
||||
import { upperCaseFirst } from "../upper-case-first"
|
||||
|
||||
describe("upperCaseFirst", function () {
|
||||
it("should convert first letter of the word to capital letter", function () {
|
||||
const expectations = [
|
||||
{
|
||||
input: "testing capitalize",
|
||||
output: "Testing capitalize",
|
||||
},
|
||||
{
|
||||
input: "testing",
|
||||
output: "Testing",
|
||||
},
|
||||
{
|
||||
input: "Testing",
|
||||
output: "Testing",
|
||||
},
|
||||
{
|
||||
input: "TESTING",
|
||||
output: "TESTING",
|
||||
},
|
||||
{
|
||||
input: "t",
|
||||
output: "T",
|
||||
},
|
||||
{
|
||||
input: "",
|
||||
output: "",
|
||||
},
|
||||
]
|
||||
|
||||
expectations.forEach((expectation) => {
|
||||
expect(upperCaseFirst(expectation.input)).toEqual(expectation.output)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,32 @@
|
||||
export function generatePostgresAlterColummnIfExistStatement(
|
||||
tableName: string,
|
||||
columns: string[],
|
||||
alterExpression: string
|
||||
) {
|
||||
let script = `
|
||||
DO $$
|
||||
DECLARE
|
||||
current_column text;
|
||||
BEGIN`
|
||||
|
||||
columns.forEach((column) => {
|
||||
script += `
|
||||
current_column := '${column}';
|
||||
IF EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = '${tableName}'
|
||||
AND column_name = current_column
|
||||
) THEN
|
||||
EXECUTE format('ALTER TABLE %I ALTER COLUMN %I ${alterExpression}', '${tableName}', current_column);
|
||||
ELSE
|
||||
RAISE NOTICE 'Column % does not exist or alteration condition not met.', current_column;
|
||||
END IF;`
|
||||
})
|
||||
|
||||
script += `
|
||||
END$$;
|
||||
`
|
||||
|
||||
return script
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
type ArrayDifferenceElement = string | number
|
||||
|
||||
export function arrayDifference<TElement = ArrayDifferenceElement>(
|
||||
mainArray: TElement[],
|
||||
differingArray: TElement[]
|
||||
): TElement[] {
|
||||
const mainArraySet = new Set(mainArray)
|
||||
const differingArraySet = new Set(differingArray)
|
||||
|
||||
const difference = [...mainArraySet].filter(
|
||||
(element) => !differingArraySet.has(element)
|
||||
)
|
||||
|
||||
return difference
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
type ArrayIntersectionElement = string | number
|
||||
|
||||
export function arrayIntersection<TElement = ArrayIntersectionElement>(
|
||||
firstArray: TElement[],
|
||||
secondArray: TElement[]
|
||||
): TElement[] {
|
||||
const firstArraySet = new Set(firstArray)
|
||||
const res = new Set<TElement>()
|
||||
|
||||
secondArray.forEach((element) => {
|
||||
if (firstArraySet.has(element)) {
|
||||
res.add(element)
|
||||
}
|
||||
})
|
||||
|
||||
return Array.from(res)
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// Those utils are used in a typeorm context and we can't be sure that they can be used elsewhere
|
||||
|
||||
import { objectFromStringPath } from "./object-from-string-path"
|
||||
|
||||
|
||||
type Order = {
|
||||
[key: string]: "ASC" | "DESC" | Order
|
||||
}
|
||||
|
||||
type Selects = {
|
||||
[key: string]: boolean | Selects
|
||||
}
|
||||
|
||||
type Relations = {
|
||||
[key: string]: boolean | Relations
|
||||
}
|
||||
|
||||
export function buildSelects(selectCollection: string[]): Selects {
|
||||
return buildRelationsOrSelect(selectCollection)
|
||||
}
|
||||
|
||||
export function buildRelations(relationCollection: string[]): Relations {
|
||||
return buildRelationsOrSelect(relationCollection)
|
||||
}
|
||||
|
||||
function buildRelationsOrSelect(collection: string[]): Selects | Relations {
|
||||
return objectFromStringPath(collection)
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an order of dot string into a nested object
|
||||
* @example
|
||||
* input: { id: "ASC", "items.title": "ASC", "items.variant.title": "ASC" }
|
||||
* output: {
|
||||
* "id": "ASC",
|
||||
* "items": {
|
||||
* "id": "ASC",
|
||||
* "variant": {
|
||||
* "title": "ASC"
|
||||
* }
|
||||
* },
|
||||
* }
|
||||
* @param orderBy
|
||||
*/
|
||||
export function buildOrder<T>(orderBy: { [k: string]: "ASC" | "DESC" }): Order {
|
||||
const output: Order = {}
|
||||
|
||||
const orderKeys = Object.keys(orderBy)
|
||||
|
||||
for (const order of orderKeys) {
|
||||
if (order.indexOf(".") > -1) {
|
||||
const nestedOrder = order.split(".")
|
||||
|
||||
let parent = output
|
||||
|
||||
while (nestedOrder.length > 1) {
|
||||
const nestedRelation = nestedOrder.shift() as string
|
||||
parent = (parent[nestedRelation] as Order) ??= {}
|
||||
}
|
||||
|
||||
parent[nestedOrder[0]] = orderBy[order]
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
output[order] = orderBy[order]
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export const camelToSnakeCase = (string) =>
|
||||
string.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase()
|
||||
@@ -0,0 +1,9 @@
|
||||
export const ContainerRegistrationKeys = {
|
||||
PG_CONNECTION: "__pg_connection__",
|
||||
MANAGER: "manager",
|
||||
CONFIG_MODULE: "configModule",
|
||||
LOGGER: "logger",
|
||||
REMOTE_QUERY: "remoteQuery",
|
||||
REMOTE_LINK: "remoteLink",
|
||||
FEATURE_FLAG_ROUTER: "featureFlagRouter",
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
import { isObject } from "../common/is-object"
|
||||
|
||||
interface ItemRecord extends Record<string, any> {
|
||||
id: string
|
||||
}
|
||||
|
||||
export function convertItemResponseToUpdateRequest(
|
||||
item: ItemRecord,
|
||||
selects: string[],
|
||||
relations: string[],
|
||||
fromManyRelationships: boolean = false
|
||||
): ItemRecord {
|
||||
const newItem: ItemRecord = {
|
||||
id: item.id,
|
||||
}
|
||||
|
||||
// If item is a child of a many relationship, we just need to pass in the id of the item
|
||||
if (fromManyRelationships) {
|
||||
return newItem
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(item)) {
|
||||
if (relations.includes(key)) {
|
||||
const relation = item[key]
|
||||
|
||||
// If the relationship is an object, its either a one to one or many to one relationship
|
||||
// We typically don't update the parent from the child relationship, we can skip this for now.
|
||||
// This can be focused on solely for one to one relationships
|
||||
if (isObject(relation)) {
|
||||
// If "id" is the only one in the object, underscorize the relation. This is assuming that
|
||||
// the relationship itself was changed to another item and now we need to revert it to the old item.
|
||||
if (Object.keys(relation).length === 1 && "id" in relation) {
|
||||
newItem[`${key}_id`] = relation.id
|
||||
}
|
||||
|
||||
// If attributes of the relation have been updated, we can assume that this
|
||||
// was an update operation on the relation. We revert what was updated.
|
||||
if (Object.keys(relation).length > 1) {
|
||||
// The ID can be figured out from the relationship, we can delete the ID here
|
||||
if ("id" in relation) {
|
||||
delete relation.id
|
||||
}
|
||||
|
||||
// we just need the selects for the relation, filter it out and remove the parent scope
|
||||
const filteredSelects = selects
|
||||
.filter((s) => s.startsWith(key) && !s.includes("id"))
|
||||
.map(shiftFirstPath)
|
||||
|
||||
// Add the filtered selects to the sanitized object
|
||||
for (const filteredSelect of filteredSelects) {
|
||||
newItem[key] = newItem[key] || {}
|
||||
newItem[key][filteredSelect] = relation[filteredSelect]
|
||||
}
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// If the relation is an array, we can expect this to be a one to many or many to many
|
||||
// relationships. Recursively call the function until all relations are converted
|
||||
if (Array.isArray(relation)) {
|
||||
const newRelationsArray: ItemRecord[] = []
|
||||
|
||||
for (const rel of relation) {
|
||||
// Scope selects and relations to ones that are relevant to the current relation
|
||||
const filteredRelations = relations
|
||||
.filter((r) => r.startsWith(key))
|
||||
.map(shiftFirstPath)
|
||||
|
||||
const filteredSelects = selects
|
||||
.filter((s) => s.startsWith(key))
|
||||
.map(shiftFirstPath)
|
||||
|
||||
newRelationsArray.push(
|
||||
convertItemResponseToUpdateRequest(
|
||||
rel,
|
||||
filteredSelects,
|
||||
filteredRelations,
|
||||
true
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
newItem[key] = newRelationsArray
|
||||
}
|
||||
}
|
||||
|
||||
// if the key exists in the selects, we add them to the new sanitized array.
|
||||
// sanitisation is done because MikroORM adds relationship attributes and other default attributes
|
||||
// which we do not want to add to the update request
|
||||
if (selects.includes(key) && !fromManyRelationships) {
|
||||
newItem[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
return newItem
|
||||
}
|
||||
|
||||
function shiftFirstPath(select) {
|
||||
const selectArray = select.split(".")
|
||||
selectArray.shift()
|
||||
|
||||
return selectArray.join(".")
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { ContainerLike } from "@medusajs/types"
|
||||
|
||||
export function createContainerLike(obj): ContainerLike {
|
||||
return {
|
||||
resolve(key: string) {
|
||||
return obj[key]
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import { Index } from "@mikro-orm/core"
|
||||
|
||||
/**
|
||||
* Create a PSQL index statement
|
||||
* @param name The name of the index, if not provided it will be generated in the format IDX_tableName_columnName
|
||||
* @param tableName The name of the table
|
||||
* @param columns The columns to index
|
||||
* @param type The type of index (e.g GIN, GIST, BTREE, etc)
|
||||
* @param where The where clause
|
||||
* @param unique If the index should be a unique index
|
||||
*
|
||||
* @example
|
||||
* createPsqlIndexStatementHelper({
|
||||
* name: "idx_user_email",
|
||||
* tableName: "user",
|
||||
* columns: "email",
|
||||
* type: "btree",
|
||||
* where: "email IS NOT NULL"
|
||||
* });
|
||||
*
|
||||
* // expression: CREATE INDEX IF NOT EXISTS idx_user_email ON user USING btree (email) WHERE email IS NOT NULL;
|
||||
*
|
||||
* createPsqlIndexStatementHelper({
|
||||
* name: "idx_user_email",
|
||||
* tableName: "user",
|
||||
* columns: "email"
|
||||
* });
|
||||
*
|
||||
* // expression: CREATE INDEX IF NOT EXISTS idx_user_email ON user (email);
|
||||
*
|
||||
*/
|
||||
export function createPsqlIndexStatementHelper({
|
||||
name,
|
||||
tableName,
|
||||
columns,
|
||||
type,
|
||||
where,
|
||||
unique,
|
||||
}: {
|
||||
name?: string
|
||||
tableName: string
|
||||
columns: string | string[]
|
||||
type?: string
|
||||
where?: string
|
||||
unique?: boolean
|
||||
}) {
|
||||
const columnsName = Array.isArray(columns) ? columns.join("_") : columns
|
||||
|
||||
columns = Array.isArray(columns) ? columns.join(", ") : columns
|
||||
name = name || `IDX_${tableName}_${columnsName}${unique ? "_unique" : ""}`
|
||||
|
||||
const typeStr = type ? ` USING ${type}` : ""
|
||||
const optionsStr = where ? ` WHERE ${where}` : ""
|
||||
const uniqueStr = unique ? "UNIQUE " : ""
|
||||
|
||||
const expression = `CREATE ${uniqueStr}INDEX IF NOT EXISTS "${name}" ON "${tableName}"${typeStr} (${columns})${optionsStr}`
|
||||
return {
|
||||
toString: () => {
|
||||
return expression
|
||||
},
|
||||
valueOf: () => {
|
||||
return expression
|
||||
},
|
||||
name,
|
||||
expression,
|
||||
MikroORMIndex: (options?: Parameters<typeof Index>[0]) => {
|
||||
return Index({
|
||||
name,
|
||||
expression,
|
||||
...options,
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export function deduplicate<T = any>(collection: T[]): T[] {
|
||||
return [...new Set(collection)]
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { isObject } from "./is-object"
|
||||
|
||||
/**
|
||||
* In most casees, JSON.parse(JSON.stringify(obj)) is enough to deep copy an object.
|
||||
* But in some cases, it's not enough. For example, if the object contains a function or a proxy, it will be lost after JSON.parse(JSON.stringify(obj)).
|
||||
*
|
||||
* @param obj
|
||||
*/
|
||||
export function deepCopy<T extends Record<any, any> = Record<any, any>>(
|
||||
obj: T | T[]
|
||||
): T | T[] {
|
||||
if (obj === null || typeof obj !== "object") {
|
||||
return obj
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
const copy: any[] = []
|
||||
for (let i = 0; i < obj.length; i++) {
|
||||
copy[i] = deepCopy(obj[i])
|
||||
}
|
||||
return copy
|
||||
}
|
||||
|
||||
if (isObject(obj)) {
|
||||
const copy: Record<any, any> = {}
|
||||
for (let attr in obj) {
|
||||
if (obj.hasOwnProperty(attr)) {
|
||||
copy[attr] = deepCopy(obj[attr])
|
||||
}
|
||||
}
|
||||
return copy
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
export function deepEqualObj(obj1: object, obj2: object): boolean {
|
||||
if (typeof obj1 !== typeof obj2) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (typeof obj1 !== "object" || obj1 === null) {
|
||||
return obj1 === obj2
|
||||
}
|
||||
|
||||
const obj1Keys = Object.keys(obj1)
|
||||
const obj2Keys = Object.keys(obj2)
|
||||
|
||||
if (obj1Keys.length !== obj2Keys.length) {
|
||||
return false
|
||||
}
|
||||
|
||||
for (const key of obj1Keys) {
|
||||
if (!obj2Keys.includes(key) || !deepEqualObj(obj1[key], obj2[key])) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
import { isDefined } from "./is-defined"
|
||||
import { isObject } from "./is-object"
|
||||
|
||||
/**
|
||||
* @description
|
||||
* This function is used to flatten nested objects and arrays
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```ts
|
||||
* const data = {
|
||||
* root_level_property: "root level",
|
||||
* products: [
|
||||
* {
|
||||
* id: "1",
|
||||
* name: "product 1",
|
||||
* variants: [
|
||||
* { id: "1.1", name: "variant 1.1" },
|
||||
* { id: "1.2", name: "variant 1.2" },
|
||||
* ],
|
||||
* },
|
||||
* {
|
||||
* id: "2",
|
||||
* name: "product 2",
|
||||
* variants: [
|
||||
* { id: "2.1", name: "variant 2.1" },
|
||||
* { id: "2.2", name: "variant 2.2" },
|
||||
* ],
|
||||
* },
|
||||
* ],
|
||||
* }
|
||||
*
|
||||
* const flat = deepFlatMap(
|
||||
* data,
|
||||
* "products.variants",
|
||||
* ({ root_, products, variants }) => {
|
||||
* return {
|
||||
* root_level_property: root_.root_level_property,
|
||||
* product_id: products.id,
|
||||
* product_name: products.name,
|
||||
* variant_id: variants.id,
|
||||
* variant_name: variants.name,
|
||||
* }
|
||||
* }
|
||||
* )
|
||||
* ```
|
||||
*/
|
||||
|
||||
export function deepFlatMap(
|
||||
data: any,
|
||||
path: string,
|
||||
callback: (context: Record<string, any>) => any
|
||||
) {
|
||||
const ROOT_LEVEL = "root_"
|
||||
const keys = path.split(".")
|
||||
keys.unshift(ROOT_LEVEL)
|
||||
|
||||
const lastKey = keys[keys.length - 1]
|
||||
const stack: {
|
||||
element: any
|
||||
path: string[]
|
||||
context: Record<string, any>
|
||||
}[] = [{ element: { [ROOT_LEVEL]: data }, path: keys, context: {} }]
|
||||
|
||||
const results: any[] = []
|
||||
while (stack.length > 0) {
|
||||
const { element, path, context } = stack.shift()!
|
||||
const currentKey = path[0]
|
||||
const remainingPath = path.slice(1)
|
||||
|
||||
if (!isDefined(element[currentKey])) {
|
||||
callback({ ...context })
|
||||
continue
|
||||
}
|
||||
|
||||
if (remainingPath.length === 0) {
|
||||
if (Array.isArray(element[currentKey])) {
|
||||
element[currentKey].forEach((item) => {
|
||||
results.push(callback({ ...context, [lastKey]: item }))
|
||||
})
|
||||
} else if (isObject(element[currentKey])) {
|
||||
results.push(callback({ ...context, [lastKey]: element[currentKey] }))
|
||||
}
|
||||
} else {
|
||||
if (Array.isArray(element[currentKey])) {
|
||||
element[currentKey].forEach((item) => {
|
||||
stack.push({
|
||||
element: item,
|
||||
path: remainingPath,
|
||||
context: { ...context, [currentKey]: item },
|
||||
})
|
||||
})
|
||||
} else if (isObject(element[currentKey])) {
|
||||
stack.push({
|
||||
element: element[currentKey],
|
||||
path: remainingPath,
|
||||
context: { ...context, [currentKey]: element[currentKey] },
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* @typedef MedusaErrorType
|
||||
*
|
||||
*/
|
||||
export const MedusaErrorTypes = {
|
||||
/** Errors stemming from the database */
|
||||
DB_ERROR: "database_error",
|
||||
DUPLICATE_ERROR: "duplicate_error",
|
||||
INVALID_ARGUMENT: "invalid_argument",
|
||||
INVALID_DATA: "invalid_data",
|
||||
UNAUTHORIZED: "unauthorized",
|
||||
NOT_FOUND: "not_found",
|
||||
NOT_ALLOWED: "not_allowed",
|
||||
UNEXPECTED_STATE: "unexpected_state",
|
||||
CONFLICT: "conflict",
|
||||
PAYMENT_AUTHORIZATION_ERROR: "payment_authorization_error",
|
||||
}
|
||||
|
||||
export const MedusaErrorCodes = {
|
||||
INSUFFICIENT_INVENTORY: "insufficient_inventory",
|
||||
CART_INCOMPATIBLE_STATE: "cart_incompatible_state",
|
||||
}
|
||||
|
||||
/**
|
||||
* Standardized error to be used across Medusa project.
|
||||
* @extends Error
|
||||
*/
|
||||
export class MedusaError extends Error {
|
||||
public type: string
|
||||
public message: string
|
||||
public code?: string
|
||||
public date: Date
|
||||
public static Types = MedusaErrorTypes
|
||||
public static Codes = MedusaErrorCodes
|
||||
|
||||
/**
|
||||
* Creates a standardized error to be used across Medusa project.
|
||||
* @param {string} type - type of error
|
||||
* @param {string} message - message to go along with error
|
||||
* @param {string} code - code of error
|
||||
* @param {Array} params - params
|
||||
*/
|
||||
constructor(type: string, message: string, code?: string, ...params: any) {
|
||||
super(...params)
|
||||
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, MedusaError)
|
||||
}
|
||||
|
||||
this.type = type
|
||||
this.code = code
|
||||
this.message = message
|
||||
this.date = new Date()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { ulid } from "ulid"
|
||||
|
||||
/**
|
||||
* Generate a composed id based on the input parameters and return either the is if it exists or the generated one.
|
||||
* @param idProperty
|
||||
* @param prefix
|
||||
*/
|
||||
export function generateEntityId(idProperty?: string, prefix?: string): string {
|
||||
if (idProperty) {
|
||||
return idProperty
|
||||
}
|
||||
|
||||
const id = ulid()
|
||||
prefix = prefix ? `${prefix}_` : ""
|
||||
return `${prefix}${id}`
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { MapToConfig } from "./map-object-to"
|
||||
|
||||
export function generateLinkableKeysMap(
|
||||
linkableKeys: Record<string, string>
|
||||
): MapToConfig {
|
||||
const entityLinkableKeysMap: MapToConfig = {}
|
||||
|
||||
Object.entries(linkableKeys).forEach(([key, value]) => {
|
||||
entityLinkableKeysMap[value] ??= []
|
||||
entityLinkableKeysMap[value].push({
|
||||
mapTo: key,
|
||||
valueFrom: key.split("_").pop()!,
|
||||
})
|
||||
})
|
||||
|
||||
return entityLinkableKeysMap
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { join } from "path"
|
||||
|
||||
/**
|
||||
* Attempts to resolve the config file in a given root directory.
|
||||
* @param {string} rootDir - the directory to find the config file in.
|
||||
* @param {string} configName - the name of the config file.
|
||||
* @return {object} an object containing the config module and its path as well as an error property if the config couldn't be loaded.
|
||||
*/
|
||||
function getConfigFile<TConfig = unknown>(
|
||||
rootDir: string,
|
||||
configName: string
|
||||
): { configModule: TConfig; configFilePath: string; error?: any } {
|
||||
const configPath = join(rootDir, configName)
|
||||
let configFilePath = ``
|
||||
let configModule
|
||||
let err
|
||||
|
||||
try {
|
||||
configFilePath = require.resolve(configPath)
|
||||
configModule = require(configFilePath)
|
||||
} catch (e) {
|
||||
err = e
|
||||
}
|
||||
|
||||
if (configModule && typeof configModule.default === "object") {
|
||||
configModule = configModule.default
|
||||
}
|
||||
|
||||
return { configModule, configFilePath, error: err }
|
||||
}
|
||||
|
||||
export default getConfigFile
|
||||
@@ -0,0 +1,16 @@
|
||||
// This function is intentionally not generic, as we will likely need a comparator function in that case, which will make it more complex than necessary
|
||||
// Revisit if there is such use-case in the future
|
||||
export const getDuplicates = (collection: string[]): string[] => {
|
||||
const uniqueElements = new Set<string>()
|
||||
const duplicates = new Set<string>()
|
||||
|
||||
collection.forEach((item) => {
|
||||
if (uniqueElements.has(item)) {
|
||||
duplicates.add(item)
|
||||
} else {
|
||||
uniqueElements.add(item)
|
||||
}
|
||||
})
|
||||
|
||||
return Array.from(duplicates)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { isDate } from "./is-date"
|
||||
import { MedusaError } from "./errors"
|
||||
|
||||
export const GetIsoStringFromDate = (date: Date | string) => {
|
||||
if (!isDate(date)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Cannot format date to ISO string: ${date}`
|
||||
)
|
||||
}
|
||||
|
||||
date = new Date(date)
|
||||
|
||||
return date.toISOString()
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { join } from "path"
|
||||
|
||||
export const getMedusaVersion = (): string => {
|
||||
try {
|
||||
return require(join(
|
||||
process.cwd(),
|
||||
`node_modules`,
|
||||
`@medusajs/medusa`,
|
||||
`package.json`
|
||||
)).version
|
||||
} catch (e) {
|
||||
return ``
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import { deduplicate } from "./deduplicate"
|
||||
import { isObject } from "./is-object"
|
||||
|
||||
export function getSelectsAndRelationsFromObjectArray(
|
||||
dataArray: object[],
|
||||
options: { objectFields: string[] } = {
|
||||
objectFields: [],
|
||||
},
|
||||
prefix?: string
|
||||
): {
|
||||
selects: string[]
|
||||
relations: string[]
|
||||
} {
|
||||
const selects: string[] = []
|
||||
const relations: string[] = []
|
||||
|
||||
for (const data of dataArray) {
|
||||
for (const [key, value] of Object.entries(data)) {
|
||||
if (isObject(value) && !options.objectFields.includes(key)) {
|
||||
relations.push(setKey(key, prefix))
|
||||
const res = getSelectsAndRelationsFromObjectArray(
|
||||
[value],
|
||||
options,
|
||||
setKey(key, prefix)
|
||||
)
|
||||
selects.push(...res.selects)
|
||||
relations.push(...res.relations)
|
||||
} else if (Array.isArray(value)) {
|
||||
relations.push(setKey(key, prefix))
|
||||
const res = getSelectsAndRelationsFromObjectArray(
|
||||
value,
|
||||
options,
|
||||
setKey(key, prefix)
|
||||
)
|
||||
selects.push(...res.selects)
|
||||
relations.push(...res.relations)
|
||||
} else {
|
||||
selects.push(setKey(key, prefix))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const uniqueSelects: string[] = deduplicate(selects)
|
||||
const uniqueRelations: string[] = deduplicate(relations)
|
||||
|
||||
return {
|
||||
selects: uniqueSelects,
|
||||
relations: uniqueRelations,
|
||||
}
|
||||
}
|
||||
|
||||
function setKey(key: string, prefix?: string) {
|
||||
if (prefix) {
|
||||
return `${prefix}.${key}`
|
||||
} else {
|
||||
return key
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Get the difference between two sets. The difference is the elements that are in the original set but not in the compare set.
|
||||
* @param orignalSet
|
||||
* @param compareSet
|
||||
*/
|
||||
export function getSetDifference<T>(
|
||||
orignalSet: Set<T>,
|
||||
compareSet: Set<T>
|
||||
): Set<T> {
|
||||
const difference = new Set<T>()
|
||||
|
||||
orignalSet.forEach((element) => {
|
||||
if (!compareSet.has(element)) {
|
||||
difference.add(element)
|
||||
}
|
||||
})
|
||||
|
||||
return difference
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
export function groupBy(
|
||||
array: Record<any, any>[],
|
||||
attribute: string | number
|
||||
): Map<any, any> {
|
||||
return array.reduce<Map<any, any>>((map, obj) => {
|
||||
const key = obj[attribute]
|
||||
|
||||
if (!key) {
|
||||
return map
|
||||
}
|
||||
|
||||
if (!map.get(key)) {
|
||||
map.set(key, [])
|
||||
}
|
||||
|
||||
map.get(key).push(obj)
|
||||
|
||||
return map
|
||||
}, new Map())
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import { EOL } from "os"
|
||||
|
||||
export const DatabaseErrorCode = {
|
||||
databaseDoesNotExist: "3D000",
|
||||
connectionFailure: "ECONNREFUSED",
|
||||
wrongCredentials: "28000",
|
||||
notFound: "ENOTFOUND",
|
||||
migrationMissing: "42P01",
|
||||
}
|
||||
|
||||
export function handlePostgresDatabaseError(err: any): never {
|
||||
if (DatabaseErrorCode.databaseDoesNotExist === err.code) {
|
||||
throw new Error(
|
||||
`The specified PostgreSQL database does not exist. Please create it and try again.${EOL}${err.message}`
|
||||
)
|
||||
}
|
||||
|
||||
if (DatabaseErrorCode.connectionFailure === err.code) {
|
||||
throw new Error(
|
||||
`Failed to establish a connection to PostgreSQL. Please ensure the following is true and try again:
|
||||
- You have a PostgreSQL database running
|
||||
- You have passed the correct credentials in medusa-config.js
|
||||
- You have formatted the database connection string correctly. See below:
|
||||
"postgres://[username]:[password]@[host]:[post]/[db_name]" - If there is no password, you can omit it from the connection string
|
||||
${EOL}
|
||||
${err.message}`
|
||||
)
|
||||
}
|
||||
|
||||
if (DatabaseErrorCode.wrongCredentials === err.code) {
|
||||
throw new Error(
|
||||
`The specified credentials does not exists for the specified PostgreSQL database.${EOL}${err.message}`
|
||||
)
|
||||
}
|
||||
|
||||
if (DatabaseErrorCode.notFound === err.code) {
|
||||
throw new Error(
|
||||
`The specified connection string for your PostgreSQL database might have illegal characters. Please check that it only contains allowed characters [a-zA-Z0-9]${EOL}${err.message}`
|
||||
)
|
||||
}
|
||||
|
||||
if (DatabaseErrorCode.migrationMissing === err.code) {
|
||||
throw new Error(
|
||||
`Migrations missing. Please run 'medusa migrations run' and try again.`
|
||||
)
|
||||
}
|
||||
|
||||
throw err
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
export * from "./alter-columns-helper"
|
||||
export * from "./array-difference"
|
||||
export * from "./array-intersection"
|
||||
export * from "./build-query"
|
||||
export * from "./camel-to-snake-case"
|
||||
export * from "./container"
|
||||
export * from "./convert-item-response-to-update-request"
|
||||
export * from "./create-container-like"
|
||||
export * from "./create-psql-index-helper"
|
||||
export * from "./deduplicate"
|
||||
export * from "./deep-copy"
|
||||
export * from "./deep-equal-obj"
|
||||
export * from "./deep-flat-map"
|
||||
export * from "./errors"
|
||||
export * from "./generate-entity-id"
|
||||
export * from "./generate-linkable-keys-map"
|
||||
export * from "./get-config-file"
|
||||
export * from "./get-duplicates"
|
||||
export * from "./get-iso-string-from-date"
|
||||
export * from "./get-selects-and-relations-from-object-array"
|
||||
export * from "./get-set-difference"
|
||||
export * from "./group-by"
|
||||
export * from "./handle-postgres-database-error"
|
||||
export * from "./is-big-number"
|
||||
export * from "./is-date"
|
||||
export * from "./is-defined"
|
||||
export * from "./is-email"
|
||||
export * from "./is-object"
|
||||
export * from "./is-present"
|
||||
export * from "./is-string"
|
||||
export * from "./lower-case-first"
|
||||
export * from "./map-object-to"
|
||||
export * from "./medusa-container"
|
||||
export * from "./object-from-string-path"
|
||||
export * from "./object-to-string-path"
|
||||
export * from "./optional-numeric-serializer"
|
||||
export * from "./partition-array"
|
||||
export * from "./pick-deep"
|
||||
export * from "./pick-value-from-object"
|
||||
export * from "./plurailze"
|
||||
export * from "./prefix-array-items"
|
||||
export * from "./promise-all"
|
||||
export * from "./remote-query-object-from-string"
|
||||
export * from "./remote-query-object-to-string"
|
||||
export * from "./remove-nullisih"
|
||||
export * from "./remove-undefined"
|
||||
export * from "./rules"
|
||||
export * from "./selector-constraints-to-string"
|
||||
export * from "./set-metadata"
|
||||
export * from "./simple-hash"
|
||||
export * from "./string-or-regex-equals"
|
||||
export * from "./string-to-select-relation-object"
|
||||
export * from "./stringify-circular"
|
||||
export * from "./to-camel-case"
|
||||
export * from "./to-kebab-case"
|
||||
export * from "./to-pascal-case"
|
||||
export * from "./transaction"
|
||||
export * from "./trim-zeros"
|
||||
export * from "./upper-case-first"
|
||||
export * from "./wrap-handler"
|
||||
@@ -0,0 +1,6 @@
|
||||
import { BigNumberRawValue } from "@medusajs/types"
|
||||
import { isObject } from "./is-object"
|
||||
|
||||
export function isBigNumber(obj: any): obj is BigNumberRawValue {
|
||||
return isObject(obj) && "value" in obj
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export function isDate(value: any): value is Date {
|
||||
return value !== null && !isNaN(new Date(value).valueOf())
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export function isDefined<T = undefined | unknown>(
|
||||
val: T
|
||||
): val is T extends undefined ? never : T {
|
||||
return typeof val !== "undefined"
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { MedusaError } from "./errors"
|
||||
|
||||
const EMAIL_REGEX =
|
||||
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|.(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
||||
|
||||
/**
|
||||
* Check whether provided string is an email.
|
||||
* @param email - string to check
|
||||
*/
|
||||
function isEmail(email: string) {
|
||||
return email.toLowerCase().match(EMAIL_REGEX)
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to validate user email.
|
||||
* @param {string} email - email to validate
|
||||
* @return {string} the validated email
|
||||
*/
|
||||
export function validateEmail(email: string): string {
|
||||
const validatedEmail = isEmail(email)
|
||||
|
||||
if (!validatedEmail) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
"The email is not valid"
|
||||
)
|
||||
}
|
||||
|
||||
return email.toLowerCase()
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export function isObject(obj: any): obj is object {
|
||||
return obj != null && obj?.constructor?.name === "Object"
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { isDefined } from "./is-defined"
|
||||
import { isObject } from "./is-object"
|
||||
import { isString } from "./is-string"
|
||||
|
||||
export function isPresent(value: any): boolean {
|
||||
if (!isDefined(value) || value === null) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (isString(value) || Array.isArray(value)) {
|
||||
return value.length > 0
|
||||
}
|
||||
|
||||
if (value instanceof Map || value instanceof Set) {
|
||||
return value.size > 0
|
||||
}
|
||||
|
||||
if (isObject(value)) {
|
||||
return Object.keys(value).length > 0
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export function isString(val: any): val is string {
|
||||
return val != null && typeof val === "string"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export function lowerCaseFirst(str: string): string {
|
||||
return str.charAt(0).toLowerCase() + str.slice(1)
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
type RemapInputObject = Record<string, unknown[]>
|
||||
type RemapConfig = { mapTo: string; valueFrom: string }
|
||||
export type MapToConfig = {
|
||||
[key: string]: RemapConfig[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new object with the keys remapped and the values picked from the original object based
|
||||
* on the map config
|
||||
*
|
||||
* @param object input object
|
||||
* @param mapTo configuration to map the output object
|
||||
* @param removeIfNotRemapped if true, the keys that are not remapped will be removed from the output object
|
||||
* @param pick if provided, only the keys in the array will be picked from the output object
|
||||
*/
|
||||
export function mapObjectTo<
|
||||
TResult = any,
|
||||
T extends RemapInputObject = RemapInputObject
|
||||
>(
|
||||
object: T,
|
||||
mapTo: MapToConfig,
|
||||
{
|
||||
removeIfNotRemapped,
|
||||
pick,
|
||||
}: { removeIfNotRemapped?: boolean; pick?: string[] } = {}
|
||||
): TResult {
|
||||
removeIfNotRemapped ??= false
|
||||
|
||||
const newObject: Record<string, any> = {}
|
||||
|
||||
for (const key in object) {
|
||||
const remapConfig = mapTo[key as string]!
|
||||
|
||||
if (!remapConfig) {
|
||||
if (!removeIfNotRemapped) {
|
||||
newObject[key] = object[key]
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
remapConfig.forEach((config) => {
|
||||
if (pick?.length && !pick.includes(config.mapTo)) {
|
||||
return
|
||||
}
|
||||
|
||||
newObject[config.mapTo] = object[key]
|
||||
.map((obj: any) => obj[config.valueFrom])
|
||||
.filter(Boolean)
|
||||
})
|
||||
}
|
||||
|
||||
return newObject as TResult
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import { MedusaContainer } from "@medusajs/types"
|
||||
import {
|
||||
asFunction,
|
||||
asValue,
|
||||
AwilixContainer,
|
||||
ClassOrFunctionReturning,
|
||||
createContainer,
|
||||
Resolver,
|
||||
} from "awilix"
|
||||
|
||||
function asArray(
|
||||
resolvers: (ClassOrFunctionReturning<unknown> | Resolver<unknown>)[]
|
||||
): { resolve: (container: AwilixContainer) => unknown[] } {
|
||||
return {
|
||||
resolve: (container: AwilixContainer) =>
|
||||
resolvers.map((resolver) => container.build(resolver)),
|
||||
}
|
||||
}
|
||||
|
||||
function registerAdd(
|
||||
this: MedusaContainer,
|
||||
name: string,
|
||||
registration: typeof asFunction | typeof asValue
|
||||
) {
|
||||
const storeKey = name + "_STORE"
|
||||
|
||||
if (this.registrations[storeKey] === undefined) {
|
||||
this.register(storeKey, asValue([] as Resolver<unknown>[]))
|
||||
}
|
||||
const store = this.resolve(storeKey) as (
|
||||
| ClassOrFunctionReturning<unknown>
|
||||
| Resolver<unknown>
|
||||
)[]
|
||||
|
||||
if (this.registrations[name] === undefined) {
|
||||
this.register(name, asArray(store))
|
||||
}
|
||||
store.unshift(registration)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
export function createMedusaContainer(...args): MedusaContainer {
|
||||
const container = createContainer.apply(null, args) as MedusaContainer
|
||||
|
||||
container.registerAdd = registerAdd.bind(container)
|
||||
|
||||
const originalScope = container.createScope
|
||||
container.createScope = () => {
|
||||
const scoped = originalScope() as MedusaContainer
|
||||
scoped.registerAdd = registerAdd.bind(scoped)
|
||||
|
||||
return scoped
|
||||
}
|
||||
|
||||
return container
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Convert a collection of dot string into a nested object
|
||||
* @example
|
||||
* input: [
|
||||
* order,
|
||||
* order.items,
|
||||
* order.swaps,
|
||||
* order.swaps.additional_items,
|
||||
* order.discounts,
|
||||
* order.discounts.rule,
|
||||
* order.claims,
|
||||
* order.claims.additional_items,
|
||||
* additional_items,
|
||||
* additional_items.variant,
|
||||
* return_order,
|
||||
* return_order.items,
|
||||
* return_order.shipping_method,
|
||||
* return_order.shipping_method.tax_lines
|
||||
* ]
|
||||
* output: {
|
||||
* "order": {
|
||||
* "items": true,
|
||||
* "swaps": {
|
||||
* "additional_items": true
|
||||
* },
|
||||
* "discounts": {
|
||||
* "rule": true
|
||||
* },
|
||||
* "claims": {
|
||||
* "additional_items": true
|
||||
* }
|
||||
* },
|
||||
* "additional_items": {
|
||||
* "variant": true
|
||||
* },
|
||||
* "return_order": {
|
||||
* "items": true,
|
||||
* "shipping_method": {
|
||||
* "tax_lines": true
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* @param collection
|
||||
*/
|
||||
export function objectFromStringPath(
|
||||
collection: string[]
|
||||
): Record<string, any> {
|
||||
collection = collection.sort()
|
||||
const output: Record<string, any> = {}
|
||||
|
||||
for (const relation of collection) {
|
||||
if (!relation) {
|
||||
continue
|
||||
}
|
||||
if (relation.indexOf(".") > -1) {
|
||||
const nestedRelations = relation.split(".")
|
||||
|
||||
let parent = output
|
||||
|
||||
while (nestedRelations.length > 1) {
|
||||
const nestedRelation = nestedRelations.shift() as string
|
||||
parent = parent[nestedRelation] =
|
||||
parent[nestedRelation] !== true &&
|
||||
typeof parent[nestedRelation] === "object"
|
||||
? parent[nestedRelation]
|
||||
: {}
|
||||
}
|
||||
|
||||
parent[nestedRelations[0]] = true
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
output[relation] = output[relation] ?? true
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import { isObject } from "./is-object"
|
||||
|
||||
/**
|
||||
* Converts a structure of find options to an
|
||||
* array of string paths
|
||||
* @example
|
||||
* // With `includeTruePropertiesOnly` default value set to false
|
||||
* const result = objectToStringPath({
|
||||
* test: {
|
||||
* test1: true,
|
||||
* test2: true,
|
||||
* test3: {
|
||||
* test4: true
|
||||
* },
|
||||
* },
|
||||
* test2: true
|
||||
* })
|
||||
* console.log(result)
|
||||
* // output: ['test', 'test.test1', 'test.test2', 'test.test3', 'test.test3.test4', 'test2']
|
||||
*
|
||||
* @example
|
||||
* // With `includeTruePropertiesOnly` set to true
|
||||
* const result = objectToStringPath({
|
||||
* test: {
|
||||
* test1: true,
|
||||
* test2: true,
|
||||
* test3: {
|
||||
* test4: true
|
||||
* },
|
||||
* },
|
||||
* test2: true
|
||||
* }, {
|
||||
* includeTruePropertiesOnly: true
|
||||
* })
|
||||
* console.log(result)
|
||||
* // output: ['test.test1', 'test.test2', 'test.test3.test4', 'test2']
|
||||
*
|
||||
* @param {InputObject} input
|
||||
* @param {boolean} includeParentPropertyFields If set to true (example 1), all properties will be included as well as the parents,
|
||||
* otherwise (example 2) all properties path set to true will included, excluded the parents
|
||||
*/
|
||||
export function objectToStringPath(
|
||||
input: object = {},
|
||||
{ includeParentPropertyFields }: { includeParentPropertyFields: boolean } = {
|
||||
includeParentPropertyFields: true,
|
||||
}
|
||||
): string[] {
|
||||
if (!isObject(input) || !Object.keys(input).length) {
|
||||
return []
|
||||
}
|
||||
|
||||
const output: Set<string> = includeParentPropertyFields
|
||||
? new Set(Object.keys(input))
|
||||
: new Set()
|
||||
|
||||
for (const key of Object.keys(input)) {
|
||||
if (isObject(input[key])) {
|
||||
const deepRes = objectToStringPath(input[key], {
|
||||
includeParentPropertyFields,
|
||||
})
|
||||
|
||||
const items = deepRes.reduce((acc, val) => {
|
||||
acc.push(`${key}.${val}`)
|
||||
return acc
|
||||
}, [] as string[])
|
||||
|
||||
items.forEach((item) => output.add(item))
|
||||
continue
|
||||
}
|
||||
|
||||
if (isObject(key) || input[key] === true) {
|
||||
output.add(key)
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(output)
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import { isDefined } from "./is-defined"
|
||||
|
||||
export const optionalNumericSerializer = (value) =>
|
||||
isDefined(value) && value !== null ? Number(value) : value
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Partitions an array into two arrays based on a predicate function
|
||||
|
||||
* @example
|
||||
* const result = partitionArray([1, 2, 3, 4, 5], (x) => x % 2 === 0)
|
||||
*
|
||||
* console.log(result)
|
||||
*
|
||||
* // output: [[2, 4], [1, 3, 5]]
|
||||
*
|
||||
* @param {T} input input array of type T
|
||||
* @param {(T) => boolean} predicate function to use when split array elements
|
||||
*/
|
||||
export const partitionArray = <T>(
|
||||
input: T[],
|
||||
predicate: (T) => boolean
|
||||
): [T[], T[]] => {
|
||||
return input.reduce(
|
||||
([pos, neg], currentElement) => {
|
||||
if (predicate(currentElement)) {
|
||||
pos.push(currentElement)
|
||||
} else {
|
||||
neg.push(currentElement)
|
||||
}
|
||||
|
||||
return [pos, neg]
|
||||
},
|
||||
[[], []] as [T[], T[]]
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { isObject } from "./is-object"
|
||||
|
||||
export function pickDeep<T extends object = object>(
|
||||
input: object,
|
||||
fields: Array<number | string>,
|
||||
prefix: string = ""
|
||||
): T {
|
||||
if (!input) {
|
||||
return input
|
||||
}
|
||||
|
||||
return Object.entries(input).reduce((nextInput, [key, value]) => {
|
||||
const fieldKey = withPrefix(key, prefix)
|
||||
const fieldMatches = fields.includes(fieldKey)
|
||||
const partialKeyMatch =
|
||||
fields.filter((field) => field.toString().startsWith(`${fieldKey}.`))
|
||||
.length > 0
|
||||
|
||||
const valueIsObject = isObject(value)
|
||||
const valueIsArray = Array.isArray(value)
|
||||
|
||||
if (fieldMatches && (valueIsObject || valueIsArray)) {
|
||||
nextInput[key] = value
|
||||
|
||||
return nextInput
|
||||
}
|
||||
|
||||
if (!fieldMatches && !partialKeyMatch) {
|
||||
return nextInput
|
||||
}
|
||||
|
||||
if (valueIsArray) {
|
||||
nextInput[key] = value.map((arrItem) => {
|
||||
if (isObject(arrItem)) {
|
||||
return pickDeep(arrItem, fields, withPrefix(key, prefix))
|
||||
}
|
||||
return arrItem
|
||||
})
|
||||
|
||||
return nextInput
|
||||
} else if (valueIsObject) {
|
||||
if (Object.keys(value).length) {
|
||||
nextInput[key] = pickDeep(value, fields, withPrefix(key, prefix))
|
||||
}
|
||||
|
||||
return nextInput
|
||||
}
|
||||
|
||||
if (fieldMatches) {
|
||||
nextInput[key] = value
|
||||
}
|
||||
|
||||
return nextInput
|
||||
}, {} as T)
|
||||
}
|
||||
|
||||
function withPrefix(key: string, prefix: string): string {
|
||||
if (prefix.length) {
|
||||
return `${prefix}.${key}`
|
||||
} else {
|
||||
return key
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { isObject } from "./is-object"
|
||||
|
||||
export function pickValueFromObject(
|
||||
path: string,
|
||||
object: Record<any, any>
|
||||
): any {
|
||||
const segments = path.split(".")
|
||||
let result: any = undefined
|
||||
|
||||
for (const segment of segments) {
|
||||
const segmentsLeft = [...segments].splice(1, segments.length - 1)
|
||||
const segmentOutput = object[segment]
|
||||
|
||||
if (segmentsLeft.length === 0) {
|
||||
result = segmentOutput
|
||||
break
|
||||
}
|
||||
|
||||
if (isObject(segmentOutput)) {
|
||||
result = pickValueFromObject(segmentsLeft.join("."), segmentOutput)
|
||||
break
|
||||
}
|
||||
|
||||
if (Array.isArray(segmentOutput)) {
|
||||
result = segmentOutput
|
||||
.map((segmentOutput_) =>
|
||||
pickValueFromObject(segmentsLeft.join("."), segmentOutput_)
|
||||
)
|
||||
.flat()
|
||||
break
|
||||
}
|
||||
|
||||
result = segmentOutput
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Some library provide pluralize function with language specific rules.
|
||||
* This is a simple implementation of pluralize function.
|
||||
* @param word
|
||||
*/
|
||||
export function pluralize(word: string): string {
|
||||
// Add basic rules for forming plurals
|
||||
if (
|
||||
//word.endsWith("s") ||
|
||||
word.endsWith("sh") ||
|
||||
word.endsWith("ss") ||
|
||||
word.endsWith("ch") ||
|
||||
word.endsWith("x") ||
|
||||
word.endsWith("o") ||
|
||||
word.endsWith("z")
|
||||
) {
|
||||
return word + "es"
|
||||
} else if (word.endsWith("y") && !"aeiou".includes(word[word.length - 2])) {
|
||||
return word.slice(0, -1) + "ies"
|
||||
} else if (word.endsWith("es")) {
|
||||
return word
|
||||
} else if (word.endsWith("fe")) {
|
||||
return word.slice(0, -2) + "ves"
|
||||
} else {
|
||||
return word + "s"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Prefixes an array of strings with a specified string
|
||||
* @param array
|
||||
* @param prefix
|
||||
*/
|
||||
export function prefixArrayItems(array: string[], prefix: string): string[] {
|
||||
return array.map((arrEl) => `${prefix}${arrEl}`)
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { EOL } from "os"
|
||||
|
||||
const getMessageError = (state: PromiseRejectedResult) =>
|
||||
state.reason.message ?? state.reason
|
||||
|
||||
const isRejected = (
|
||||
state: PromiseSettledResult<unknown>
|
||||
): state is PromiseRejectedResult => {
|
||||
return state.status === "rejected"
|
||||
}
|
||||
|
||||
const getValue = (state: PromiseFulfilledResult<unknown>) => state.value
|
||||
|
||||
/**
|
||||
* Promise.allSettled with error handling, safe alternative to Promise.all
|
||||
* @param promises
|
||||
* @param aggregateErrors
|
||||
*/
|
||||
export async function promiseAll<T extends readonly unknown[] | []>(
|
||||
promises: T,
|
||||
{ aggregateErrors } = { aggregateErrors: false }
|
||||
): Promise<{ -readonly [P in keyof T]: Awaited<T[P]> }> {
|
||||
const states = await Promise.allSettled(promises)
|
||||
|
||||
const rejected = (states as PromiseSettledResult<unknown>[]).filter(
|
||||
isRejected
|
||||
)
|
||||
|
||||
if (rejected.length) {
|
||||
if (aggregateErrors) {
|
||||
throw new Error(rejected.map(getMessageError).join(EOL))
|
||||
}
|
||||
|
||||
throw rejected[0].reason // Re throw the error itself
|
||||
}
|
||||
|
||||
return (states as PromiseFulfilledResult<unknown>[]).map(
|
||||
getValue
|
||||
) as unknown as Promise<{ -readonly [P in keyof T]: Awaited<T[P]> }>
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
import { isObject } from "./is-object"
|
||||
|
||||
/**
|
||||
* Convert a string fields array to a remote query object
|
||||
* @param config - The configuration object
|
||||
*
|
||||
* @example
|
||||
* const fields = [
|
||||
* "id",
|
||||
* "created_at",
|
||||
* "updated_at",
|
||||
* "deleted_at",
|
||||
* "url",
|
||||
* "metadata",
|
||||
* "tags.id",
|
||||
* "tags.created_at",
|
||||
* "tags.updated_at",
|
||||
* "tags.deleted_at",
|
||||
* "tags.value",
|
||||
* "options.id",
|
||||
* "options.created_at",
|
||||
* "options.updated_at",
|
||||
* "options.deleted_at",
|
||||
* "options.title",
|
||||
* "options.product_id",
|
||||
* "options.metadata",
|
||||
* "options.values.id",
|
||||
* "options.values.created_at",
|
||||
* "options.values.updated_at",
|
||||
* "options.values.deleted_at",
|
||||
* "options.values.value",
|
||||
* "options.values.option_id",
|
||||
* "options.values.variant_id",
|
||||
* "options.values.metadata",
|
||||
* ]
|
||||
*
|
||||
* const remoteQueryObject = remoteQueryObjectFromString({
|
||||
* entryPoint: "product",
|
||||
* variables: {},
|
||||
* fields,
|
||||
* })
|
||||
*
|
||||
* console.log(remoteQueryObject)
|
||||
* // {
|
||||
* // product: {
|
||||
* // __args: {},
|
||||
* // fields: [
|
||||
* // "id",
|
||||
* // "created_at",
|
||||
* // "updated_at",
|
||||
* // "deleted_at",
|
||||
* // "url",
|
||||
* // "metadata",
|
||||
* // ],
|
||||
* //
|
||||
* // tags: {
|
||||
* // fields: ["id", "created_at", "updated_at", "deleted_at", "value"],
|
||||
* // },
|
||||
* //
|
||||
* // options: {
|
||||
* // fields: [
|
||||
* // "id",
|
||||
* // "created_at",
|
||||
* // "updated_at",
|
||||
* // "deleted_at",
|
||||
* // "title",
|
||||
* // "product_id",
|
||||
* // "metadata",
|
||||
* // ],
|
||||
* // values: {
|
||||
* // fields: [
|
||||
* // "id",
|
||||
* // "created_at",
|
||||
* // "updated_at",
|
||||
* // "deleted_at",
|
||||
* // "value",
|
||||
* // "option_id",
|
||||
* // "variant_id",
|
||||
* // "metadata",
|
||||
* // ],
|
||||
* // },
|
||||
* // },
|
||||
* // },
|
||||
* // }
|
||||
*/
|
||||
export function remoteQueryObjectFromString(
|
||||
config:
|
||||
| {
|
||||
entryPoint: string
|
||||
variables?: any
|
||||
fields: string[]
|
||||
}
|
||||
| {
|
||||
service: string
|
||||
variables?: any
|
||||
fields: string[]
|
||||
}
|
||||
): object {
|
||||
const { entryPoint, service, variables, fields } = {
|
||||
...config,
|
||||
entryPoint: "entryPoint" in config ? config.entryPoint : undefined,
|
||||
service: "service" in config ? config.service : undefined,
|
||||
}
|
||||
|
||||
const entryKey = (entryPoint ?? service) as string
|
||||
|
||||
const remoteJoinerConfig: object = {
|
||||
[entryKey]: {
|
||||
fields: [],
|
||||
isServiceAccess: !!service, // specifies if the entry point is a service
|
||||
},
|
||||
}
|
||||
|
||||
const usedVariables = new Set()
|
||||
|
||||
for (const field of fields) {
|
||||
if (!field.includes(".")) {
|
||||
remoteJoinerConfig[entryKey]["fields"].push(field)
|
||||
continue
|
||||
}
|
||||
|
||||
const fieldSegments = field.split(".")
|
||||
const fieldProperty = fieldSegments.pop()
|
||||
|
||||
let combinedPath = ""
|
||||
|
||||
const deepConfigRef = fieldSegments.reduce((acc, curr) => {
|
||||
combinedPath = combinedPath ? combinedPath + "." + curr : curr
|
||||
|
||||
if (isObject(variables) && combinedPath in variables) {
|
||||
acc[curr] ??= {}
|
||||
acc[curr]["__args"] = variables[combinedPath]
|
||||
usedVariables.add(combinedPath)
|
||||
} else {
|
||||
acc[curr] ??= {}
|
||||
}
|
||||
|
||||
return acc[curr]
|
||||
}, remoteJoinerConfig[entryKey])
|
||||
|
||||
deepConfigRef["fields"] ??= []
|
||||
deepConfigRef["fields"].push(fieldProperty)
|
||||
}
|
||||
|
||||
const topLevelArgs = {}
|
||||
for (const key of Object.keys(variables ?? {})) {
|
||||
if (!usedVariables.has(key)) {
|
||||
topLevelArgs[key] = variables[key]
|
||||
}
|
||||
}
|
||||
|
||||
remoteJoinerConfig[entryKey]["__args"] = topLevelArgs ?? {}
|
||||
|
||||
return remoteJoinerConfig
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Transform a remote query object to a string array containing the chain of fields and relations
|
||||
*
|
||||
* @param fields
|
||||
* @param parent
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* const remoteQueryObject = {
|
||||
* fields: [
|
||||
* "id",
|
||||
* "title",
|
||||
* ],
|
||||
* images: {
|
||||
* fields: ["id", "created_at", "updated_at", "deleted_at", "url", "metadata"],
|
||||
* },
|
||||
* }
|
||||
*
|
||||
* const fields = remoteQueryObjectToString(remoteQueryObject)
|
||||
*
|
||||
* console.log(fields)
|
||||
* // ["id", "title", "images.id", "images.created_at", "images.updated_at", "images.deleted_at", "images.url", "images.metadata"]
|
||||
*/
|
||||
export function remoteQueryObjectToString(
|
||||
fields: object,
|
||||
parent?: string
|
||||
): string[] {
|
||||
return Object.keys(fields).reduce((acc, key) => {
|
||||
if (key === "fields") {
|
||||
if (parent) {
|
||||
fields[key].map((fieldKey) => acc.push(`${parent}.${fieldKey}`))
|
||||
} else {
|
||||
fields[key].map((fieldKey) => acc.push(fieldKey))
|
||||
}
|
||||
|
||||
return acc
|
||||
}
|
||||
|
||||
if (typeof fields[key] === "object") {
|
||||
acc = acc.concat(
|
||||
remoteQueryObjectToString(
|
||||
fields[key],
|
||||
parent ? `${parent}.${key}` : key
|
||||
)
|
||||
)
|
||||
return acc
|
||||
}
|
||||
|
||||
return acc
|
||||
}, [] as string[])
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { isDefined } from "./is-defined"
|
||||
|
||||
export function removeNullish<T = unknown>(
|
||||
obj: Record<string, T>
|
||||
): Record<string, T> {
|
||||
return Object.entries(obj).reduce(
|
||||
(resultObject, [currentKey, currentValue]) => {
|
||||
if (!isDefined(currentValue) || currentValue === null) {
|
||||
return resultObject
|
||||
}
|
||||
|
||||
resultObject[currentKey] = currentValue
|
||||
|
||||
return resultObject
|
||||
},
|
||||
{}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// useful in cases where presence of undefined is not desired (eg. in microORM operations)
|
||||
export const removeUndefined = <T extends Record<string, any>>(obj: T): T => {
|
||||
return JSON.parse(JSON.stringify(obj)) as T
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export enum RuleOperator {
|
||||
IN = "in",
|
||||
EQ = "eq",
|
||||
NE = "ne",
|
||||
GT = "gt",
|
||||
GTE = "gte",
|
||||
LT = "lt",
|
||||
LTE = "lte",
|
||||
NIN = "nin",
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
export function selectorConstraintsToString(
|
||||
selector: object | object[]
|
||||
): string {
|
||||
const selectors = Array.isArray(selector) ? selector : [selector]
|
||||
|
||||
return selectors
|
||||
.map((selector_) => {
|
||||
return Object.entries(selector_)
|
||||
.map(
|
||||
([key, value]: [string, any]) =>
|
||||
`${key}: ${value._type ? `${value._type}(${value._value})` : value}`
|
||||
)
|
||||
.join(", ")
|
||||
})
|
||||
.join(" or ")
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { MedusaError } from "./errors"
|
||||
|
||||
/**
|
||||
* Dedicated method to set metadata.
|
||||
* @param obj - the entity to apply metadata to.
|
||||
* @param metadata - the metadata to set
|
||||
* @return resolves to the updated result.
|
||||
*/
|
||||
export function setMetadata(
|
||||
obj: { metadata: Record<string, unknown> | null },
|
||||
metadata: Record<string, unknown>
|
||||
): Record<string, unknown> {
|
||||
const existing = obj.metadata || {}
|
||||
const newData = {}
|
||||
|
||||
for (const [key, value] of Object.entries(metadata)) {
|
||||
if (typeof key !== "string") {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_ARGUMENT,
|
||||
"Key type is invalid. Metadata keys must be strings"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* We reserve the empty string as a way to delete a key.
|
||||
* If the value is an empty string, we don't
|
||||
* set it, and if it exists in the existing metadata, we
|
||||
* unset the field.
|
||||
*/
|
||||
if (value === "") {
|
||||
if (key in existing) {
|
||||
delete existing[key]
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
newData[key] = value
|
||||
}
|
||||
|
||||
return {
|
||||
...existing,
|
||||
...newData,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// DJB2 hash function
|
||||
export function simpleHash(text: string): string {
|
||||
let hash = 5381
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
hash = (hash << 5) + hash + text.charCodeAt(i)
|
||||
}
|
||||
return hash.toString(16)
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export const stringEqualsOrRegexMatch = (
|
||||
stringOrRegex: string | RegExp,
|
||||
testString: string
|
||||
) => {
|
||||
if (stringOrRegex instanceof RegExp) {
|
||||
return stringOrRegex.test(testString)
|
||||
}
|
||||
return stringOrRegex === testString
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Convert a string fields array to a specific object such as { select, relation }
|
||||
* @param fields
|
||||
*
|
||||
* @example
|
||||
* const fields = [
|
||||
* "id",
|
||||
* "created_at",
|
||||
* "updated_at",
|
||||
* "deleted_at",
|
||||
* "url",
|
||||
* "metadata",
|
||||
* "tags.id",
|
||||
* "tags.created_at",
|
||||
* "tags.updated_at",
|
||||
* "tags.deleted_at",
|
||||
* "tags.value",
|
||||
* "options.id",
|
||||
* "options.created_at",
|
||||
* "options.updated_at",
|
||||
* "options.deleted_at",
|
||||
* "options.title",
|
||||
* "options.product_id",
|
||||
* "options.metadata",
|
||||
* "options.values.id",
|
||||
* "options.values.created_at",
|
||||
* "options.values.updated_at",
|
||||
* "options.values.deleted_at",
|
||||
* "options.values.value",
|
||||
* "options.values.option_id",
|
||||
* "options.values.variant_id",
|
||||
* "options.values.metadata",
|
||||
* ]
|
||||
*
|
||||
* const remoteQueryObject = stringToSelectRelationObject(fields)
|
||||
*
|
||||
* console.log(remoteQueryObject)
|
||||
* // {
|
||||
* // select: [
|
||||
* // "id",
|
||||
* // "created_at",
|
||||
* // "updated_at",
|
||||
* // "deleted_at",
|
||||
* // "url",
|
||||
* // "metadata",
|
||||
* // "tags.id",
|
||||
* // "tags.created_at",
|
||||
* // "tags.updated_at",
|
||||
* // "tags.deleted_at",
|
||||
* // "tags.value",
|
||||
* // "options.id",
|
||||
* // "options.created_at",
|
||||
* // "options.updated_at",
|
||||
* // "options.deleted_at",
|
||||
* // "options.title",
|
||||
* // "options.product_id",
|
||||
* // "options.metadata",
|
||||
* // "options.values.id",
|
||||
* // "options.values.created_at",
|
||||
* // "options.values.updated_at",
|
||||
* // "options.values.deleted_at",
|
||||
* // "options.values.value",
|
||||
* // "options.values.option_id",
|
||||
* // "options.values.variant_id",
|
||||
* // "options.values.metadata",
|
||||
* // ],
|
||||
* // relations: ["tags", "options", "options.values"],
|
||||
* // }
|
||||
*/
|
||||
export function stringToSelectRelationObject(fields: string[]): {
|
||||
select: string[]
|
||||
relations: string[]
|
||||
} {
|
||||
const tempResult = {
|
||||
select: new Set<string>(),
|
||||
relations: new Set<string>(),
|
||||
}
|
||||
|
||||
for (const field of fields) {
|
||||
tempResult.select.add(field)
|
||||
|
||||
if (!field.includes(".")) {
|
||||
continue
|
||||
}
|
||||
|
||||
const segments = field.split(".")
|
||||
segments.pop()
|
||||
const relationPath = segments.join(".")
|
||||
|
||||
tempResult.relations.add(relationPath)
|
||||
}
|
||||
|
||||
return {
|
||||
select: Array.from(tempResult.select),
|
||||
relations: Array.from(tempResult.relations),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
const isObject = (value: any): value is object =>
|
||||
typeof value === "object" &&
|
||||
value != null &&
|
||||
!(value instanceof Boolean) &&
|
||||
!(value instanceof Date) &&
|
||||
!(value instanceof Number) &&
|
||||
!(value instanceof RegExp) &&
|
||||
!(value instanceof String)
|
||||
|
||||
const isPrimitive = (val) => {
|
||||
return val !== Object(val)
|
||||
}
|
||||
|
||||
function decycle(object: any, replacer?: Function | null) {
|
||||
const objects = new WeakMap()
|
||||
|
||||
function deepCopy(value, path) {
|
||||
let oldPath
|
||||
let newObj
|
||||
|
||||
if (replacer != null) {
|
||||
value = replacer(value)
|
||||
}
|
||||
|
||||
if (isObject(value)) {
|
||||
oldPath = objects.get(value)
|
||||
if (oldPath !== undefined) {
|
||||
return { $ref: oldPath }
|
||||
}
|
||||
|
||||
objects.set(value, path)
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
newObj = []
|
||||
value.forEach((el, idx) => {
|
||||
newObj[idx] = deepCopy(el, path + "[" + idx + "]")
|
||||
})
|
||||
} else {
|
||||
newObj = {}
|
||||
Object.keys(value).forEach((name) => {
|
||||
newObj[name] = deepCopy(
|
||||
value[name],
|
||||
path + "[" + JSON.stringify(name) + "]"
|
||||
)
|
||||
})
|
||||
}
|
||||
return newObj
|
||||
}
|
||||
|
||||
return !isPrimitive(value) ? value + "" : value
|
||||
}
|
||||
|
||||
return deepCopy(object, "$")
|
||||
}
|
||||
|
||||
export function stringifyCircular(
|
||||
object: any,
|
||||
replacer?: Function | null,
|
||||
space?: number
|
||||
): string {
|
||||
return JSON.stringify(decycle(object, replacer), null, space)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export function toCamelCase(str: string): string {
|
||||
return /^([a-z]+)(([A-Z]([a-z]+))+)$/.test(str)
|
||||
? str
|
||||
: str
|
||||
.toLowerCase()
|
||||
.replace(/[^a-zA-Z0-9]+(.)/g, (m, chr) => chr.toUpperCase())
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export const kebabCase = (string) =>
|
||||
string
|
||||
.replace(/([a-z])([A-Z])/g, "$1-$2")
|
||||
.replace(/[\s_]+/g, "-")
|
||||
.toLowerCase()
|
||||
@@ -0,0 +1,5 @@
|
||||
export function toPascalCase(s: string): string {
|
||||
return s.replace(/(^\w|_\w)/g, (match) =>
|
||||
match.replace(/_/g, "").toUpperCase()
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export function doNotForceTransaction(): boolean {
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./do-not-force-transaction"
|
||||
export * from "./should-force-transaction"
|
||||
@@ -0,0 +1,5 @@
|
||||
import { MODULE_RESOURCE_TYPE } from "@medusajs/types"
|
||||
|
||||
export function shouldForceTransaction(target: any): boolean {
|
||||
return target.moduleDeclaration?.resources === MODULE_RESOURCE_TYPE.ISOLATED
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
export function trimZeros(value: string) {
|
||||
const [whole, fraction] = value.split(".")
|
||||
|
||||
if (fraction) {
|
||||
const exp = fraction.split("e")
|
||||
|
||||
const decimal = exp[0].replace(/0+$/, "")
|
||||
const expStr = exp.length > 1 ? `e${exp[1]}` : ""
|
||||
|
||||
if (!decimal) {
|
||||
return whole + expStr
|
||||
}
|
||||
|
||||
return `${whole}.${decimal}` + expStr
|
||||
}
|
||||
|
||||
return whole
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export function upperCaseFirst(str: string): string {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1)
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { NextFunction, Request, RequestHandler, Response } from "express"
|
||||
|
||||
type handler = (req: Request, res: Response) => Promise<void>
|
||||
|
||||
export const wrapHandler = (fn: handler): RequestHandler => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
const req_ = req as Request & { errors?: Error[] }
|
||||
if (req_?.errors?.length) {
|
||||
return res.status(400).json({
|
||||
errors: req_.errors,
|
||||
message:
|
||||
"Provided request body contains errors. Please check the data and retry the request",
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
return await fn(req, res)
|
||||
} catch (err) {
|
||||
next(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @schema MultipleErrors
|
||||
* title: "Multiple Errors"
|
||||
* type: object
|
||||
* properties:
|
||||
* errors:
|
||||
* type: array
|
||||
* description: Array of errors
|
||||
* items:
|
||||
* $ref: "#/components/schemas/Error"
|
||||
* message:
|
||||
* type: string
|
||||
* default: "Provided request body contains errors. Please check the data and retry the request"
|
||||
*/
|
||||
@@ -0,0 +1,10 @@
|
||||
export * from "./mikro-orm/big-number-field"
|
||||
export * from "./mikro-orm/mikro-orm-create-connection"
|
||||
export * from "./mikro-orm/mikro-orm-free-text-search-filter"
|
||||
export * from "./mikro-orm/mikro-orm-repository"
|
||||
export * from "./mikro-orm/mikro-orm-soft-deletable-filter"
|
||||
export * from "./mikro-orm/mikro-orm-serializer"
|
||||
export * from "./mikro-orm/utils"
|
||||
export * from "./mikro-orm/decorators/searchable"
|
||||
export * from "./repositories"
|
||||
export * from "./utils"
|
||||
@@ -0,0 +1,351 @@
|
||||
import {
|
||||
Collection,
|
||||
Entity,
|
||||
ManyToOne,
|
||||
OneToMany,
|
||||
PrimaryKey,
|
||||
Property,
|
||||
} from "@mikro-orm/core"
|
||||
import { Searchable } from "../decorators/searchable"
|
||||
|
||||
// Circular dependency one level
|
||||
@Entity()
|
||||
class RecursiveEntity1 {
|
||||
constructor(props: { id: string; deleted_at: Date | null }) {
|
||||
this.id = props.id
|
||||
this.deleted_at = props.deleted_at
|
||||
}
|
||||
|
||||
@PrimaryKey()
|
||||
id: string
|
||||
|
||||
@Property()
|
||||
deleted_at: Date | null
|
||||
|
||||
@OneToMany(() => RecursiveEntity2, (entity2) => entity2.entity1, {
|
||||
cascade: ["soft-remove"] as any,
|
||||
})
|
||||
entity2 = new Collection<RecursiveEntity2>(this)
|
||||
}
|
||||
|
||||
@Entity()
|
||||
class RecursiveEntity2 {
|
||||
constructor(props: {
|
||||
id: string
|
||||
deleted_at: Date | null
|
||||
entity1: RecursiveEntity1
|
||||
}) {
|
||||
this.id = props.id
|
||||
this.deleted_at = props.deleted_at
|
||||
this.entity1 = props.entity1
|
||||
}
|
||||
|
||||
@PrimaryKey()
|
||||
id: string
|
||||
|
||||
@Property()
|
||||
deleted_at: Date | null
|
||||
|
||||
@ManyToOne(() => RecursiveEntity1, {
|
||||
cascade: ["soft-remove"] as any,
|
||||
})
|
||||
entity1: RecursiveEntity1
|
||||
}
|
||||
|
||||
// No circular dependency
|
||||
@Entity()
|
||||
class Entity1 {
|
||||
constructor(props: { id: string; deleted_at: Date | null }) {
|
||||
this.id = props.id
|
||||
this.deleted_at = props.deleted_at
|
||||
}
|
||||
|
||||
@PrimaryKey()
|
||||
id: string
|
||||
|
||||
@Property()
|
||||
deleted_at: Date | null
|
||||
|
||||
@OneToMany(() => Entity2, (entity2) => entity2.entity1, {
|
||||
cascade: ["soft-remove"] as any,
|
||||
})
|
||||
entity2 = new Collection<Entity2>(this)
|
||||
}
|
||||
|
||||
@Entity()
|
||||
class Entity2 {
|
||||
constructor(props: {
|
||||
id: string
|
||||
deleted_at: Date | null
|
||||
entity1: Entity1
|
||||
}) {
|
||||
this.id = props.id
|
||||
this.deleted_at = props.deleted_at
|
||||
this.entity1 = props.entity1
|
||||
this.entity1_id = props.entity1.id
|
||||
}
|
||||
|
||||
@PrimaryKey()
|
||||
id: string
|
||||
|
||||
@Property()
|
||||
deleted_at: Date | null
|
||||
|
||||
@ManyToOne(() => Entity1, { mapToPk: true })
|
||||
entity1_id: string
|
||||
|
||||
@ManyToOne(() => Entity1, { persist: false })
|
||||
entity1: Entity1
|
||||
}
|
||||
|
||||
// Circular dependency deep level
|
||||
|
||||
@Entity()
|
||||
class DeepRecursiveEntity1 {
|
||||
constructor(props: { id: string; deleted_at: Date | null }) {
|
||||
this.id = props.id
|
||||
this.deleted_at = props.deleted_at
|
||||
}
|
||||
|
||||
@PrimaryKey()
|
||||
id: string
|
||||
|
||||
@Property()
|
||||
deleted_at: Date | null
|
||||
|
||||
@OneToMany(() => DeepRecursiveEntity2, (entity2) => entity2.entity1, {
|
||||
cascade: ["soft-remove"] as any,
|
||||
})
|
||||
entity2 = new Collection<DeepRecursiveEntity2>(this)
|
||||
}
|
||||
|
||||
@Entity()
|
||||
class DeepRecursiveEntity2 {
|
||||
constructor(props: {
|
||||
id: string
|
||||
deleted_at: Date | null
|
||||
entity1: DeepRecursiveEntity1
|
||||
entity3: DeepRecursiveEntity3
|
||||
}) {
|
||||
this.id = props.id
|
||||
this.deleted_at = props.deleted_at
|
||||
this.entity3 = props.entity3
|
||||
}
|
||||
|
||||
@PrimaryKey()
|
||||
id: string
|
||||
|
||||
@Property()
|
||||
deleted_at: Date | null
|
||||
|
||||
@ManyToOne(() => DeepRecursiveEntity1)
|
||||
entity1: DeepRecursiveEntity1
|
||||
|
||||
@ManyToOne(() => DeepRecursiveEntity3, {
|
||||
cascade: ["soft-remove"] as any,
|
||||
})
|
||||
entity3: DeepRecursiveEntity3
|
||||
}
|
||||
|
||||
@Entity()
|
||||
class DeepRecursiveEntity3 {
|
||||
constructor(props: {
|
||||
id: string
|
||||
deleted_at: Date | null
|
||||
entity1: DeepRecursiveEntity1
|
||||
}) {
|
||||
this.id = props.id
|
||||
this.deleted_at = props.deleted_at
|
||||
this.entity1 = props.entity1
|
||||
}
|
||||
|
||||
@PrimaryKey()
|
||||
id: string
|
||||
|
||||
@Property()
|
||||
deleted_at: Date | null
|
||||
|
||||
@ManyToOne(() => DeepRecursiveEntity1, {
|
||||
cascade: ["soft-remove"] as any,
|
||||
})
|
||||
entity1: DeepRecursiveEntity1
|
||||
}
|
||||
|
||||
@Entity()
|
||||
class DeepRecursiveEntity4 {
|
||||
constructor(props: {
|
||||
id: string
|
||||
deleted_at: Date | null
|
||||
entity1: DeepRecursiveEntity1
|
||||
}) {
|
||||
this.id = props.id
|
||||
this.deleted_at = props.deleted_at
|
||||
this.entity1 = props.entity1
|
||||
}
|
||||
|
||||
@PrimaryKey()
|
||||
id: string
|
||||
|
||||
@Property()
|
||||
deleted_at: Date | null
|
||||
|
||||
@ManyToOne(() => DeepRecursiveEntity1)
|
||||
entity1: DeepRecursiveEntity1
|
||||
}
|
||||
|
||||
// Internal circular dependency
|
||||
|
||||
@Entity()
|
||||
class InternalCircularDependencyEntity1 {
|
||||
constructor(props: {
|
||||
id: string
|
||||
deleted_at: Date | null
|
||||
parent?: InternalCircularDependencyEntity1
|
||||
}) {
|
||||
this.id = props.id
|
||||
this.deleted_at = props.deleted_at
|
||||
|
||||
if (props.parent) {
|
||||
this.parent = props.parent
|
||||
}
|
||||
}
|
||||
|
||||
@PrimaryKey()
|
||||
id: string
|
||||
|
||||
@Property()
|
||||
deleted_at: Date | null
|
||||
|
||||
@OneToMany(
|
||||
() => InternalCircularDependencyEntity1,
|
||||
(entity) => entity.parent,
|
||||
{
|
||||
cascade: ["soft-remove"] as any,
|
||||
}
|
||||
)
|
||||
children = new Collection<InternalCircularDependencyEntity1>(this)
|
||||
|
||||
@ManyToOne(() => InternalCircularDependencyEntity1)
|
||||
parent: InternalCircularDependencyEntity1
|
||||
}
|
||||
|
||||
// With un decorated prop
|
||||
|
||||
@Entity()
|
||||
class Entity1WithUnDecoratedProp {
|
||||
constructor(props: { id: string; deleted_at: Date | null }) {
|
||||
this.id = props.id
|
||||
this.deleted_at = props.deleted_at
|
||||
}
|
||||
|
||||
unknownProp: string
|
||||
|
||||
@PrimaryKey()
|
||||
id: string
|
||||
|
||||
@Property()
|
||||
deleted_at: Date | null
|
||||
|
||||
@OneToMany(() => Entity2WithUnDecoratedProp, (entity2) => entity2.entity1, {
|
||||
cascade: ["soft-remove"] as any,
|
||||
})
|
||||
entity2 = new Collection<Entity2WithUnDecoratedProp>(this)
|
||||
}
|
||||
|
||||
@Entity()
|
||||
class Entity2WithUnDecoratedProp {
|
||||
constructor(props: {
|
||||
id: string
|
||||
deleted_at: Date | null
|
||||
entity1: Entity1WithUnDecoratedProp
|
||||
}) {
|
||||
this.id = props.id
|
||||
this.deleted_at = props.deleted_at
|
||||
this.entity1 = props.entity1
|
||||
this.entity1_id = props.entity1.id
|
||||
}
|
||||
|
||||
unknownProp: string
|
||||
|
||||
@PrimaryKey()
|
||||
id: string
|
||||
|
||||
@Property()
|
||||
deleted_at: Date | null
|
||||
|
||||
@ManyToOne(() => Entity1WithUnDecoratedProp, { mapToPk: true })
|
||||
entity1_id: string
|
||||
|
||||
@ManyToOne(() => Entity1WithUnDecoratedProp, { persist: false })
|
||||
entity1: Entity1WithUnDecoratedProp
|
||||
}
|
||||
|
||||
// Searchable fields
|
||||
|
||||
@Entity()
|
||||
class SearchableEntity1 {
|
||||
constructor(props: { id: string; deleted_at: Date | null }) {
|
||||
this.id = props.id
|
||||
this.deleted_at = props.deleted_at
|
||||
}
|
||||
|
||||
@PrimaryKey()
|
||||
id: string
|
||||
|
||||
@Property()
|
||||
deleted_at: Date | null
|
||||
|
||||
@Searchable()
|
||||
@Property()
|
||||
searchableField: string
|
||||
|
||||
@Searchable()
|
||||
@OneToMany(() => SearchableEntity2, (entity2) => entity2.entity1)
|
||||
entity2 = new Collection<SearchableEntity2>(this)
|
||||
}
|
||||
|
||||
@Entity()
|
||||
class SearchableEntity2 {
|
||||
constructor(props: {
|
||||
id: string
|
||||
deleted_at: Date | null
|
||||
entity1: SearchableEntity1
|
||||
}) {
|
||||
this.id = props.id
|
||||
this.deleted_at = props.deleted_at
|
||||
this.entity1 = props.entity1
|
||||
this.entity1_id = props.entity1.id
|
||||
}
|
||||
|
||||
@PrimaryKey()
|
||||
id: string
|
||||
|
||||
@Property()
|
||||
deleted_at: Date | null
|
||||
|
||||
@Searchable()
|
||||
@Property()
|
||||
searchableField: string
|
||||
|
||||
@ManyToOne(() => SearchableEntity1, { mapToPk: true })
|
||||
entity1_id: string
|
||||
|
||||
@ManyToOne(() => SearchableEntity1, { persist: false })
|
||||
entity1: SearchableEntity1
|
||||
}
|
||||
|
||||
export {
|
||||
RecursiveEntity1,
|
||||
RecursiveEntity2,
|
||||
Entity1,
|
||||
Entity2,
|
||||
DeepRecursiveEntity1,
|
||||
DeepRecursiveEntity2,
|
||||
DeepRecursiveEntity3,
|
||||
DeepRecursiveEntity4,
|
||||
InternalCircularDependencyEntity1,
|
||||
Entity1WithUnDecoratedProp,
|
||||
Entity2WithUnDecoratedProp,
|
||||
SearchableEntity1,
|
||||
SearchableEntity2,
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import { BigNumberRawValue } from "@medusajs/types"
|
||||
import { Entity, MikroORM, PrimaryKey } from "@mikro-orm/core"
|
||||
import { BigNumber } from "../../../totals/big-number"
|
||||
import { MikroOrmBigNumberProperty } from "../big-number-field"
|
||||
|
||||
@Entity()
|
||||
class TestAmount {
|
||||
@PrimaryKey()
|
||||
id: string
|
||||
|
||||
@MikroOrmBigNumberProperty()
|
||||
amount: BigNumber | number
|
||||
|
||||
raw_amount: BigNumberRawValue
|
||||
|
||||
@MikroOrmBigNumberProperty({ nullable: true })
|
||||
nullable_amount: BigNumber | number | null = null
|
||||
|
||||
raw_nullable_amount: BigNumberRawValue | null = null
|
||||
}
|
||||
|
||||
describe("@MikroOrmBigNumberProperty", () => {
|
||||
let orm!: MikroORM
|
||||
|
||||
beforeEach(async () => {
|
||||
orm = await MikroORM.init({
|
||||
entities: [TestAmount],
|
||||
dbName: "test",
|
||||
type: "postgresql",
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await orm.close()
|
||||
})
|
||||
|
||||
it("should correctly assign and update BigNumber values", () => {
|
||||
const testAmount = new TestAmount()
|
||||
|
||||
expect(testAmount.amount).toBeUndefined()
|
||||
expect(testAmount.raw_amount).toBeUndefined()
|
||||
|
||||
testAmount.amount = 100
|
||||
|
||||
expect(testAmount.amount).toEqual(100)
|
||||
expect(testAmount.raw_amount).toEqual({
|
||||
value: "100",
|
||||
precision: 20,
|
||||
})
|
||||
|
||||
try {
|
||||
;(testAmount as any).amount = null
|
||||
} catch (e) {
|
||||
expect(e.message).toEqual(
|
||||
"Invalid BigNumber value: null. Should be one of: string, number, BigNumber (bignumber.js), BigNumberRawValue"
|
||||
)
|
||||
}
|
||||
|
||||
testAmount.nullable_amount = null
|
||||
expect(testAmount.nullable_amount).toEqual(null)
|
||||
// Update the amount
|
||||
|
||||
testAmount.amount = 200
|
||||
|
||||
expect(testAmount.amount).toEqual(200)
|
||||
expect(testAmount.raw_amount).toEqual({
|
||||
value: "200",
|
||||
precision: 20,
|
||||
})
|
||||
|
||||
// Update with big number
|
||||
|
||||
testAmount.amount = new BigNumber(300, { precision: 5 })
|
||||
|
||||
expect(testAmount.amount).toEqual(300)
|
||||
expect(testAmount.raw_amount).toEqual({ value: "300", precision: 5 })
|
||||
})
|
||||
})
|
||||
Loaded 100 of 1436 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user