{"_id":"@reflet/mongoose","_rev":"35-660232a84f2c6e17e374a4a6a3d937ec","name":"@reflet/mongoose","dist-tags":{"latest":"2.0.0","next":"2.0.0-next.14"},"versions":{"1.0.0":{"name":"@reflet/mongoose","version":"1.0.0","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet/tree/master/mongoose"},"description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/mongoose":"^5","@types/node":">=8","mongoose":"^5","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^1.1.5","@types/mongoose":"^5.7.8","mongoose":"^5.9.7"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"a0338b37abb10f9c02d33e05f3739483b62cf92e","_id":"@reflet/mongoose@1.0.0","_nodeVersion":"12.15.0","_npmVersion":"lerna/3.20.2/node@v12.15.0+x64 (win32)","_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"dist":{"integrity":"sha512-kwEso1HIdppbv1pr2nH6ziK0HM9eim1BqKSG5B3lZMgNukB6LTYD4wVzzK7FgLKZ0bxPX5uoaPhuOlBE0AED6A==","shasum":"a55101ff2b4a62afa1b14f96366fbebcc3762815","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-1.0.0.tgz","fileCount":15,"unpackedSize":83678,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJejE6aCRA9TVsSAnZWagAAxfUP/jH3nz03EL6DNsmtm/37\ndGULJhkyc7rGvhxWPCgpjO9vAc67AxHEvmlivA4CtiQNBcE5VCIhHO/RQDjN\n+P1NDl6hASazVJs+quG1ecimNO455xkGMXPHj/bWuiWcp68go6TQd+z3DjSJ\nyqGZSrknI9q8TI8a+CcbHL9l8be0lVboCTzY0jxo/6dHJsD71S7CFz07IxxL\nOLWASF7++Da5Ju9o8AVismQeGN9LEwU9ppXM2pGvKtk10ewEFQwu64tYXT2S\nYZwFnY1sn+KL1TOmz/FgbJevawT01q7p9FPo53KDxAKdOzIFZ3jW+xSxzDKj\nDNx9n1Noc2Wrgrb0Jq+U/0V57163YzHhBkvS9cGNzjD2YorM87ZNbgwZmKL5\nOMGF2NXbEUfjmX6uuKiHUAs/B9HB6DD4N2z3i9v/tZD62OE/qSb8YzhHlEGY\nodsHFTg1S9bXR3n/BFf5tZ4Ucejwk+ldDyP9N2BL7EwHkklA5pSMPfT7TlFI\nLH2fUEozbbysvFzkRP19Ps2/Ke0fe10xDj9+HTui30+Xgwtvtt2v6XqOla93\nNCkbQVzsK2VM8ZOcNs7PgYYBKWTsgPlz1ibNwv++s5nhQHCAyAxWNu9fAANB\nmI3gpsoO+ez9bpLv7jhdGeojKGxmoAD+eiKgq0pbogDi64BoGwxPpWvv4/Zy\nkK53\r\n=nR/K\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIC00p2ngb36h50RFu4NjFYE/yHRyRrUn9ZUZjb1Z4gfHAiEA3OGXRx+QHugU4ac/CLB9ri9VaLxa32ynrwkiHM4r704="}]},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_1.0.0_1586253465594_0.6030405214686823"},"_hasShrinkwrap":false},"1.0.1":{"name":"@reflet/mongoose","version":"1.0.1","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet/tree/master/mongoose"},"description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/mongoose":"^5.7.6","@types/node":">=8","mongoose":"^5","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^1.1.5","@types/mongoose":"^5.7.11","mongoose":"^5.9.9"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"2e438d664485d78b334ef609c1db93e228a86190","_id":"@reflet/mongoose@1.0.1","_nodeVersion":"12.15.0","_npmVersion":"lerna/3.20.2/node@v12.15.0+x64 (win32)","_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"dist":{"integrity":"sha512-0uMTZNUuHXBw3sY84pz2U9hYqcaMiuhiGMLSzo/aDxjo9fpL3oFx1XaeuvECVSfopdf8+c8s9oz40IfrEJe9rA==","shasum":"2902fcad03fdb7e6fbbeeecdc049a7289cc6bc63","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-1.0.1.tgz","fileCount":16,"unpackedSize":99832,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJemKhfCRA9TVsSAnZWagAAxNgP/1ETulHKolTNymGC/Me5\n1c8/X404DcqIXx1v8Pz8B0UB4Hhq4TwEQRnTTDqDtm64k4F56GVO9+Eotc6d\nAezzkq/rHCNyxtC+LdadVIvSP3xJwW6kQl4mUEfEnrIHINRB2PTRsOYHcCxp\nLWpepxEwNT/p+nzfKoBChZu0ZT/oVCFh9syNeKEdfEG5w2q+VtI2dXErIUnM\no6/WatpJAKaGzZteQPK5DFltRdV6wGx7gjvLyWflg34pReDxHTZ0z+puQ0iI\nloDuPVn55XKaOOuNMuuyWU25ZHaAY4XFZe7PaZRJZo0BXTBeLWwdKAo9x5lw\nKvmasRTO+ULONhdMIsCo37XhnRFniiI1CLPhoJE9A5v5f9C10LQOYBswXK2i\nXMmMTDfaqfru9ttbcRiGS/rzMXFSMOhuGUorBiLBhu3AqocpYfmqaHnFNG+s\nex779cdQ8q+8b1R4Cyp9IgIVRkLpPs6fvpkAFczPqWR374EMIuWimJmR218D\nE7coMRVNlOjKqz26wvmc6D8Avp+U9uvJsBzR2CK55Linazt0ZOMTQzvSNKZ5\npq9tvEwX5aJjkw5bA9MUQSrD3je1kGnBkZrn1G14A233In+0CqOpwy/22BAy\nKLBp026vVNe6hHLtNzfjvy1fVal1Z6q4MjgvDoNa2p/qpT9E8wTm/u3FotFT\nSdtl\r\n=aj7n\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDh7/eO03PmUxUqWGn2YN7YDVeVtlSnJnMQbHnbUs/WeAiALmq8nfoGDjHPyPEeD6oC4xtdIdjLfvcccgApJfCHhyQ=="}]},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_1.0.1_1587062879261_0.8554372210823551"},"_hasShrinkwrap":false},"1.0.2":{"name":"@reflet/mongoose","version":"1.0.2","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet/tree/master/mongoose"},"description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/mongoose":"^5.7.6","@types/node":">=8","mongoose":"^5","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^1.1.5","@types/mongoose":"^5.7.11","mongoose":"^5.9.9"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json"},"licenseText":"MIT License\n\nCopyright (c) 2020 Jeremy Bensimon\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@reflet/mongoose@1.0.2","dist":{"shasum":"147d196f3160dcc710242e3618098df8701c8e37","integrity":"sha512-6vUVgEf3A8zwJcg+g+FixFxixP0yCA2fi2vuy2eAujK7PHMVF15upfW9A7R/Ys47FmZF12OEwsdMOYFeHX2wrw==","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-1.0.2.tgz","fileCount":17,"unpackedSize":99889,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJembH+CRA9TVsSAnZWagAAuSAP/jkoHer7VCuqU9MP4ldw\nc7YuTjsTMMcGoHq4yYbcIAaAjJWqpCVN0r2FftnPDZLL7W/COfM0pqk3Q3R0\n5CrAYN00ZeZdszSxIoLWApTyYQ47U9AxgWkAb7paUGtzQRicbC08AYYNVq8f\nKjkqDqF/3BGvKwlUhjCNQ0Te6V8DQ1HuLcV7696b4N7gKtbGMUqRo6YQK3hZ\nRQcFUvCG8DPfuP8q/XYJtDYDCpcmETsD7v7Cza2NSWGTYddjoAbpT0qw104n\nMA/o+5U1YSHsvek+AELVr5h+QpVRAu/KiRw29Od8AAr3xiSajE6mNrqaLWSn\n9MFnHhvizXA+5q0jdMY9xZLfMKz8xo2CorjPrh9tPlWJCG+YCZI5vur8xQLP\nTNzzMM75xWuD74jeCfgsWpOwJUryohrrRZtO9y5M7NEsUQQj3TZiUOU2Ugof\n8qgajUdFyLNHyxUhQEBymlxBbOc7srgwfgUyaEpcoM5tuwLYMQ/Kmi8V1a9b\nub0SNVhI0uMBrFeanl7HCBEj6Uqyw4afzHp4lRxJwQbSmKW/8VTWU+9M1sCX\nvEMkOma7dJw+CFfYMdcYd3/S0i9fe9miUlWR+4jXHHVJsdV1vx+mq3yyp3nX\nr/f2s4JhANQjzyNZEeCRuE/rLQHpq1wOrRQwXvfxOj4ZbhTIRu057CoRazt6\n77+6\r\n=9Ugy\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEb930xExx6WH/+9pLX7FlTBfxyOdzO8GVq5QlKzYsHeAiBzAW+FiP1TqjWD6AVH1N2LeiU1BgFP7DYu5N1kaT+9fA=="}]},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_1.0.2_1587130878111_0.7457164799310603"},"_hasShrinkwrap":false},"1.0.3":{"name":"@reflet/mongoose","version":"1.0.3","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet/tree/master/mongoose"},"description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/mongoose":"^5.7.12","@types/node":">=8","mongoose":"^5","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^1.1.5","@types/mongoose":"^5.7.12","mongoose":"^5.9.9"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"12d128ca7a7cb1df8b1327fe6cd307be6a449dd2","_id":"@reflet/mongoose@1.0.3","_nodeVersion":"12.15.0","_npmVersion":"lerna/3.20.2/node@v12.15.0+x64 (win32)","_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"dist":{"integrity":"sha512-H46rk+hxCtlblFYnCNnKVpjU1KRblSal3DyHhux6bJxM13NiV0ROPOKoacAYvCeieEKvD4v+vQgbOONqfzutHw==","shasum":"e82dacb21ccff970959c0a5f6659a8c8b359f9b4","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-1.0.3.tgz","fileCount":15,"unpackedSize":100945,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJenHTCCRA9TVsSAnZWagAAlyYP/izkIINNEh5HJ4kmjvEf\niFAyUItUYaDOKTBrnRMBov7SKKZfbIpt7EaYLygqJUMvLSJEPXJxn4DcPTB/\nS5oGsYDmk2wgn3W1wzV3Ry8wqeK6OGqjioKpeMBzsF7GupVx6O8Aogl7UFYm\n1ciWnECwTltZfusKf/ytUqb5DFQGkNonwCPUMlfZk2NWSUlzsxz+4sjtVk5l\nqbzMDGrD5/eSwOrrLyDh8eaeoVwiJXfoWdZ9nnwx3t0JkJiRVXrz0zbQy8pw\nfyQsQyu8QFZn0J7mu+A+tcmjLx7gbg2OY+kOUYelCuMEWrfKKJBbI9Y3EQb/\nOm0meprQG6+FDxCgBkUIGJ4uHepBh5NnocxSsj/Eb4lxlF0oFG0MS9WOMA1E\nkCVhvf7jPWlIptFHqZmOSwOSFyHZbJJX0Y7GVVD5xgYxG1sq/Y845h/zg00K\nnJ5PwQQ4bu8TJ0g6Z21SBlDWxkR6GqZDipJs7rJVWiFOfIBxbXFxEcRcSO0a\nfx8IJO5e03omiI5ZBMeEFrBUFLoWZwMJSRNcIf4ghNKnnxNTsKQJpLwx15qq\nMhTmuvtVKhJZfYs4eW0BB7KXh3dCi3P5ydabplN4voF4rowQM9iCXo9x0V8O\n5PUXYv8JM71M4W2wXlMqjqeBFD4ydnGqmsOMPPfiOatRbSgJIGaR3XD0TE1l\nKTG8\r\n=GYrG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDh1t4upkNjIdsw/sgI+5Xs71Bs5ujweJwSYWLP3U9DVgIgOPYh03QQnly33BqcdF1POm1o8NS2eYwrfo0VrLzZk6U="}]},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_1.0.3_1587311810354_0.8022334611466708"},"_hasShrinkwrap":false},"1.0.4":{"name":"@reflet/mongoose","version":"1.0.4","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet/tree/master/mongoose"},"description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/mongoose":"^5.7.12","@types/node":">=8","mongoose":"^5","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^1.1.5","@types/mongoose":"^5.7.12","mongoose":"^5.9.9"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"011017a1f374a6d8132e904d024ea7a3723be9e7","_id":"@reflet/mongoose@1.0.4","_nodeVersion":"12.15.0","_npmVersion":"lerna/3.20.2/node@v12.15.0+x64 (win32)","_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"dist":{"integrity":"sha512-kC46rrGWgg2lLIuTOYapZMEnyN0vuDJ9nOtSUN3nFr1/XaQGShGPJ/8AQa0Bnblc3lqBMX7AIILeLSlTQGtIqw==","shasum":"4c7818cfca6dbab7cea2c597968bcee3b7b6a93d","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-1.0.4.tgz","fileCount":15,"unpackedSize":103702,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJenbgOCRA9TVsSAnZWagAAC2cP/3x72iO5lsl9zqXvNiT0\nc4hNVHzuyH3/Wv+7X5uMeF+x7m93UvuAY6W6PRTDnx7d4p+r7iCJEcJeljuM\nS+dwTBTzXoyqjoXZ/GgIK3v6cZuOBZPgt22A70jqh0CpNQ8/LO6GiX2+Yo04\nHGFB65rqiR0soeM6pjkE5E2KdLR1/+iWiqXcJym7LuA5ED7nRqMNmYFvEvRM\n2JjepjFaCMyBMULeu/yVcYBUJTXGsdkWWUNK6yiPB2sDHAoXtmxxAQ5wXHO8\nzrnbJAIBY40KvCU0v9p8dVBMvug2SQcGHfh2R1bXpVGbPlCXpO1X0w3q0dyo\nvnEyQJOLHerbTCckli9jD1jbF79pawQgV4Vzvd2jq69WopnJxGqJjsQBBG0d\nAFFdL/kN5ws/NoR7y7CTdxe93mdbvlcjBPlhTG794T4fDvHN4SXyiTT4AEQr\nqFm4ETPlEToyIyAJJfzguQRXX7kQ/PMxjlYgoDG8pE4LtA/NvEefSYrUSiaG\n1AWxAs/CmtwJVZYqM00+wFCVJSFnZGm+e6+KyanKtXPvQbSCm3K7yu0ZI44e\n5Am1hk9pKjeZsafnLZC8ztSLKB5lBN0MwBOFmbX9oDrAHDh9XztGXsez6aA5\nyDtE9l4wpoezR8sJ+uNWPtz0uB28X+9LnAquyb+RukKvz3O7C79Q8fbM6P1J\nugot\r\n=Aidv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHFKgezrnR3wN5LYT8WZHZjIZTw0NTouFxXfd5brSSETAiEAxQ84nQ9Qq3qaGrwsRLYdCXl9DXCKveaFf7jqg0yi0sk="}]},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_1.0.4_1587394573446_0.6992918704949764"},"_hasShrinkwrap":false},"1.0.5":{"name":"@reflet/mongoose","version":"1.0.5","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet/tree/master/mongoose"},"description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/mongoose":"^5.7.12","@types/node":">=8","mongoose":"^5","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^1.1.5","@types/mongoose":"^5.7.12","mongoose":"^5.9.9"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"9bc9a45f24927426ae084cbd4f7b741f879cac6c","_id":"@reflet/mongoose@1.0.5","_nodeVersion":"12.15.0","_npmVersion":"lerna/3.20.2/node@v12.15.0+x64 (win32)","_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"dist":{"integrity":"sha512-Va0EDDAknhU8XxdpZLFuE8RrIKTnQ5boyagxjxZnVYFszZyorBn+fD4m1iO2KSST3blGkTM7NodayEPvSd4z/g==","shasum":"de81b2444273ddb9185e002a2c21f21104f7f8c7","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-1.0.5.tgz","fileCount":15,"unpackedSize":107275,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeqotQCRA9TVsSAnZWagAA40gP/ig88y2/ZkC72EfvCCGX\npDrOVE6ONHbYz5W36cPCM2DtW0XseGMQGdksliAbfj7ayjAEVWWQRV5/XlqI\nBnp7ZR5tIRVrv394MLPbZ8wYAywywEhh9xFVmtLmmf7cUfCVb4sXg0ZHJavP\nkOaoAwWYP6lf41gu3cUTjs3of+uahr1KNYaqy99gRq6nsDVAf7h3hE42XJPv\no4+2WcdiRjurHqW31PX7kGIfdBSB6ua4TtjxRH27bVGAvTcwltagwkBZ3gpc\npW1HtCzema9Wajs1UoBwpk7bFnYezYN02X7qApaETptLn+tylpH2iGbh9zgz\nAncSzzWhJPOiqFQJOzNc1rG+7YbfZoPACre9pVzJUEBx0oAexwDrg5l7NnNh\nWw1xoLKKmNed7u7BQ7+EumguxAdto0J9YAeGs2uiBD5Ap+ZuCDhIUkQTNULU\nnvlITwVUTXJvdXVHN201uRVsf2KsMWT3pm1GOZt4ChHEcVlgvRDVHnq/CIHo\nfjd814kbcBFd2cna9gayYukoLywwhpOrMXX7ikIEJZo030ToQaNA+GP21mTR\nJjdc36Wrcspd4roqUICEvWHp2J84bjltYWfSD71qUsSBr6+8m/D64eSoOteV\nZQFyHl/hfOU/HD+OFGn7T/yuzBpvDMxHPfA4k9sW16h4oRskIIHOgWQkrv8B\nnjc7\r\n=XRGZ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDNIRX9HGT764TtrjUIyAZbJv12v//ufrZUMoHS72nvRAIgVITQQCVl9mVEO2EDUN6kNPGLALhLl1iwfnoxTYSZ9AQ="}]},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_1.0.5_1588235088080_0.3115035025533921"},"_hasShrinkwrap":false},"1.0.6":{"name":"@reflet/mongoose","version":"1.0.6","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet/tree/master/mongoose"},"description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/mongoose":"^5.7.12","@types/node":">=8","mongoose":"^5","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^1.1.5","@types/mongoose":"^5.7.12","mongoose":"^5.9.9"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"a4f6b98cebf9cf1937d7543f12efa4c21f6b1d5b","_id":"@reflet/mongoose@1.0.6","_nodeVersion":"12.15.0","_npmVersion":"lerna/3.20.2/node@v12.15.0+x64 (win32)","_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"dist":{"integrity":"sha512-GsShG6r+Dp0+UEZrAssroPjkD9HPreMeApRBVvrPsFTkRC10Q20zgRzMq/4q2FAG3wqJAPwXs7vAdQ9X+vEl3A==","shasum":"d9d7698586ad95a04a10234750cb9e4bdf5b458e","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-1.0.6.tgz","fileCount":15,"unpackedSize":107246,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeqvWwCRA9TVsSAnZWagAAvEEP/0TRcA5kcHswBJKIxpKk\noqEKiiDq37u7x6I++4sMhTM3Y4Z/hE2Qe4D5L7cubuEjYuws4vOks2gtFEIm\nliXcuTswlWS3x/zN1rZQ8JYqM3z6APaGE6AK51OlWJhjgiDkBFAYr/lopK8Q\nPAZ4cSTW67To9Xe2lig7ZJ1W8N4Uay0jhgUO9rS3mGQStHLz6VQGJGJQL5p9\nhPGgeT9OQSSsmJ/Y4QI92HfdDhB02UGjMpQPNV2ctuiXnXg+JPWXCdnmyxLf\nYUIR4p5ukWeEwgqnHByESnYSDin4FTZyfO7C5hX3NGVrWsAkTCmCD9xW8h9T\nwN39hWGWAW1W+Ng7VYiDq3W4qfe5iBEmDth9KntAAjMYeI+Ab6G9jsRNhNgs\nTIGcCLGxQWO4qFrkjJQ/BHDDCxqBoK99mevsusOC9R/sfqsjVGHWpqkEfkvr\nrUn1jituaRWBMwmdZpWu8WoVvrp69xEuF+m5PQU77VJr1wrm8CqzbCtVH4ef\nD/2g/E3VH7UnOCJQ8qV7yKEA+9DMapxfWZMjYhYZA4byC3kwL+t2sfDx2gHS\npGqIrAbhSS3KAQ139uaispx1T2ZpECMWWG/MUOH9WZOACBeW8J2H1Fo2TMkt\nORosuo4IPpe8rRYO7NNIAPsRUj6P5BnIXLbLL4eXiLXRE6tlrVqvdXj8TvbF\nfwdn\r\n=a74X\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIH+MU9oVs3FCKT8zr/DMFulVCS4faoY53z/VHPe9wx+NAiEA1OGGBp8aOEJODqA9A0dcoxD/OU3uHchU21p07Ya540s="}]},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_1.0.6_1588262320087_0.13286195198153616"},"_hasShrinkwrap":false},"1.0.7":{"name":"@reflet/mongoose","version":"1.0.7","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet/tree/master/mongoose"},"description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/mongoose":"^5.7.12","@types/node":">=8","mongoose":"^5","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^1.1.5","@types/mongoose":"^5.7.12","mongoose":"^5.9.9"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"0fdc30e7b2f0bec14f8be25fd71ac405e4982120","_id":"@reflet/mongoose@1.0.7","_nodeVersion":"12.15.0","_npmVersion":"lerna/3.20.2/node@v12.15.0+x64 (win32)","_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"dist":{"integrity":"sha512-tWXZN8lnHWWGMiXZBe6qg8JJOGDnBpbtz/zQ0cFru6DRtNtzVaYYsGB3Jyhqw7ki0keLVIugYHE0EnEufnjpOA==","shasum":"be6b6b9ccbf4e47904511ea09f0d6b38e16b4949","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-1.0.7.tgz","fileCount":15,"unpackedSize":107591,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeqxDKCRA9TVsSAnZWagAANL8P/AuBKSYf9V+osoOyi9hl\nOSKWxDnwYkjpd85uVAqHPatVzdwZ8p5V0mKdzj1Jer57UHZzDmOXv945kGAh\nhEk1BAibkKHUl0mlNnMp8GLxY5SuGC7dbAY01sbcUqnFIus+ou3XQhmyGNq6\nVh/9IjfCTfDAPDuOSbRc1wmgYn8H6reTAPkaUlCI6Bzl+59e19ql8jUh0iDr\nYWUAO0zVvoJLLAV41nJXhgGb5zLDrrrMIXghg1gxJrFhwoiCHIsyWAMZ8eei\nEgeW2o+M8jCkMbvSXRZ92PgnsnTwYoXpDMw0+WhjGKHNVIgvrRI54OhhtmI6\n6Uqmqb5QlX7T9SiTxSIZKu8NLdRddsYzl7aSTO6TCnMU7rFM3PcLQgvIoerC\nM8zott/DDdLKoR1wQWBUVIbmQmOK1Znm8p71X0ZNFA3r0QTBbheoHXsldtxJ\nOjapBXg7tBThkiamqjd7hPzm5rpIPVEfyOzBuey+FbiT+gzvbRm7UACKTpht\ntT+Ig8KGbztYmq7vIEhqdbvIV3PvWbV7PM/RGdTMGuX1CB67aiqcyc25gcuW\nJQRBcvNyNcxyDoQWP9g4+k+uZFGqJFFwFSBBhH7SVvt5OXWOzlb++myHYHAf\nF5q+GdxPMHQD8nBlhHjjG8mMnQBmUMD3TKo/8TiCB1j1h3GheM/QnwEesfN0\nm4UO\r\n=kfkQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAvlX612BoQqTXg3Slrk7ilqoOOFJ5cciWjAIOG4n8XsAiEA1z5zs7W3BQY4MQ8zGrjKBPXpjJYtc6VfKxqwLTkJlhE="}]},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_1.0.7_1588269257640_0.6478430946344726"},"_hasShrinkwrap":false},"1.0.8":{"name":"@reflet/mongoose","version":"1.0.8","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet/tree/master/mongoose"},"description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/mongoose":"^5.7.20","@types/node":">=8","mongoose":"^5","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^1.1.5","@types/mongoose":"^5.7.20","mongoose":"^5.9.14"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"82ce413defd045186fa383999e2ed4eefdd3a672","_id":"@reflet/mongoose@1.0.8","_nodeVersion":"12.16.3","_npmVersion":"lerna/3.21.0/node@v12.16.3+x64 (win32)","_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"dist":{"integrity":"sha512-lbN6YHQ7F7qNo4Mp44TNHj9NAnPd8Dtx3iYCBwbov9/wGol48gB9PaE5HwlkqFq022NDPwtLObKfJcpm6P34eA==","shasum":"b57e4d1e2759c133b89bbc56648ed8c6ba3aad4e","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-1.0.8.tgz","fileCount":15,"unpackedSize":109312,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeyvt3CRA9TVsSAnZWagAA1fAP/jR1V+rsVOkS+r5jVHRc\nHTia1yqr76NuGt2QeLTCvi13RSr557GY+5xYjC9Sp8x+MEORNGkHmKb7IPH5\naa/kelfwpEkYJpi9oVm3qC5DEwmBKqYuXgN87v6zgwNUpK4Lvx0IK6pjwPnD\nKvN6PIfrqftIgduHfpJONu+9h/L7sdJZ4k+EUmLDJhrYE3yV3hk1NIj77Ukt\nhWIZD6w88+Vl34Xah4blX/1/cQK4K3VxnAYsLmLsuVD0srIrCz9DB977/67/\nmve5fx/zGYZkHgjW3WBEmDQKkMhIW8MiyigYL4l+ED7Btv/Z0NtRtAg063cw\nI/P4TqOyoRH+nD7KZ3A4s9xLdrcxV1MIpdo4K8KSaTbpDMeZDm5lNRNgAxwy\n9ch9WilvC3I856PHJux/lw3zPts/W5f1QAj4PDvkpW7FyKWLqKW+WzY5gwdS\n+LKtruoBz7NHat4s50dq/2GmsS4aVHeasxaTL6bBh1wnf4O/VckAZC5DqhaZ\nttf71SJ1/ycT00fOiD87M7hDedTUCtb/LCMw9EB9v447sCcW/I6Jbtt48nUt\n7tbju7QQTY98QelT5pZj0gxTY8cYi5//BJRkyGz72V+5ONVzQGbackne8s1F\ndLoH0YVVUDZ69MZz3S0GxqU/mxuPreB3j0h2+NAkdKuf1x6V6SuztU7egswJ\n/IIH\r\n=s8Fp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEb+m7wwXCdBXohAzCxwU0ci1Ux0rKx362rt7g+tXgdDAiA4LLx/HpX/j7ojfaM5D3d4ytVTqB5SKCvAET7YvxTing=="}]},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_1.0.8_1590360950943_0.8835162017638443"},"_hasShrinkwrap":false},"1.0.9":{"name":"@reflet/mongoose","version":"1.0.9","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet/tree/master/mongoose"},"description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/mongoose":"^5.7.20","@types/node":">=8","mongoose":"^5","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^1.1.5","@types/mongoose":"^5.7.24","mongoose":"^5.9.18"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"4fe61378f57ab94a5cd38d5db4b1fb100fdf0929","_id":"@reflet/mongoose@1.0.9","_nodeVersion":"12.16.3","_npmVersion":"lerna/3.22.1/node@v12.16.3+x64 (win32)","_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"dist":{"integrity":"sha512-b7utTM7F6uGh4a5qvjx7UnhEAmjPXoYeLdx5a4WLfFLrIOBwY/xfLcC+6WQUWPfj6cYPq6uuUUyEB4sNeG3X7g==","shasum":"1203ec8c11aa96b8846984e0b5bc8371ca696f36","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-1.0.9.tgz","fileCount":15,"unpackedSize":112915,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe5SolCRA9TVsSAnZWagAACcwP/24HR+KumJeTBpXI8y2r\ncvSu8GOqyxpk6pgf+eWTOMB3mksqc7BNlSdd6d1yqZYFsr5rtL7bYPrwINi5\nRLQiv4MCiqUUM+Ig333+TwRmBrm+l/O1bCsalaRgE2EIcvnKidaV9YfDp3sH\n9v5Ry1dlz6De7Apr8c1CXRpgMRqv5hGnY9b0OI+9Qhku89lZm6+pKyVJX/1k\nm91tmb7dWFC4nVqKYYK5fvKbSz3xglcg0hhuG4VZKCqlRF7nrBZanw57s6MX\njg9xUgq+t/z7iun6H47nUwed+rIrPMgvCMNjZwxSHOWNktX6W5ZQBm0MMvak\nhAbEIUCEcDR4tiun4B2MmnBzs+YxezWvaNVlT3iiAgrlnTwWzhJgELu+TSED\nk70p7Dy172UevgVF3DP7fmy9J5fh/nYCmJKjuGTQSqkOpfR4ldG4Q/MwLTcY\n9UZ2c1Cb6ln1hurYlZi9qD3smBQv2UtvnEm5sFdVqPnYJfSu7T/yaP/1Gmlw\n6b30n91IiBnhKqApxOg4ZeBsAxRuKWwkM3gCkmfU1kw7BK8O6gK0IksfHCQG\nX6Io9JyeR2FBSoD9ilAyEnZjXKh25NHoYEaoawS2Y/ByQZ/8k2w2S2BhNuW2\nuBbBjYDeuKDAtDBD34eBnkVfZMvsvIPtEChWmEFe9GOddsaKitkrpksGdP5y\njlBb\r\n=64fP\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEkJ7emVd+obgFsnYMBwI5FXWFEm/7o8PM8zyAqQ0Az5AiEA21D4xQGCRZhwf410Vf8WvmujznYudXzNsgNosKI5io4="}]},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_1.0.9_1592076836751_0.33175674606606687"},"_hasShrinkwrap":false},"1.1.0":{"name":"@reflet/mongoose","version":"1.1.0","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet/tree/master/mongoose"},"description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/mongoose":"^5.7.20","@types/node":">=8","mongoose":"^5","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^1.1.5","@types/mongoose":"^5.7.24","mongoose":"^5.9.18"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"1a871588ebf78d00a381125e982e528eebc4ddc0","_id":"@reflet/mongoose@1.1.0","_nodeVersion":"12.16.3","_npmVersion":"lerna/3.22.1/node@v12.16.3+x64 (win32)","_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"dist":{"integrity":"sha512-TdKzaLBoYUuAyoInqY1ESYGrytOIW54382dE78siBA/zyRT9F3bDhN1XQ+Vk2FBUBHZP4UpNzs9TDNurdrKwoQ==","shasum":"4748b65c40f5bb2a0200bffe2c88365419d46a7b","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-1.1.0.tgz","fileCount":16,"unpackedSize":118969,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe55j8CRA9TVsSAnZWagAACOAQAIchINv6qqu+AU2WbFqV\nqqgGKNWEF2tPzs9oIoVAwfxjLAKi6DHmVAuqRtiwJp0oUuNtgFL7Bf66jVZh\nLPumVeYJ2OXmbB8yfJkdL0zmjcxqMj3VImzKckCRqQsWsqNcMEFuk0TqDHdA\nuqqLTgkkjA3yf5kaPCCkADgSHOeJqSBYqg5a9yOYcJWfwsnIhtQLOpcVU2Of\n3FkzWEClF0WMVqhXdR1M4/oUOTe7zdQE5MwZnxJAiJLL1TkGFVSZzY8Bkwpu\nWcJ8qAM4Cbma1lDV5N45MyBH2UrRVSJXFFUIZu/qBJ/Xkp4oLy6WaXnbIowW\npAKGaO6MHiq9Pg3hGIaL4DUSgrYeX71IyhGDFphlr2xPiBLfHrlMuUy3RICz\nfpXEQWf6S7iZcWdjFVKzP4RqGgUfuUJfi+9ZAWQ3z+ImXuMz6L1MJ3/uUhCz\nlYhtWDmW4UlGfhr6q5Hi95plDK3KhB/vAe4SOrYI/IgVLT9tJg/DYZ4hFnuD\n9/scH98n7DA/R27p9XyB/8ew4TNnccpeMROcgMcOcNTa7M+0zoeQpO3ZaRi0\nR2w7fK8Az1D6itLfCtoYIIdqo34FvjVTvXVEePolIPpSijwIvxE6je3bw77A\n71qQTJLrsVhpjA1+nW0y1Xz+0Xx693IXVNv5g3wu9dRvXSGlXj+l5l51MyUP\n5lCB\r\n=gdYE\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGcqS2aEgyePlyxxuNa8wKLhciChF31lJhvZLJSiyc4/AiAKWNfxQsoxmgsokfSZ27Z8+mS0YTEc3qBMJP8RilhHQw=="}]},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_1.1.0_1592236284351_0.1607300507491154"},"_hasShrinkwrap":false},"1.2.0":{"name":"@reflet/mongoose","version":"1.2.0","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet/tree/master/mongoose"},"description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/mongoose":"^5.7.20","@types/node":">=8","mongoose":"^5","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^1.1.5","@types/mongoose":"^5.7.36","mongoose":"^5.10.1"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"a581232122cd70c80c6e1c2a11679bb9962386a3","_id":"@reflet/mongoose@1.2.0","_nodeVersion":"12.16.3","_npmVersion":"lerna/3.22.1/node@v12.16.3+x64 (win32)","_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"dist":{"integrity":"sha512-ELTz0axhQJZEoxma7G2haAa/CmdEyw8AFw9WJf/vWtNgFZC5egoOV1OsJcJHwBMiV3xLE1daYVt1a4PH127gIQ==","shasum":"83a1b9f76bffe8d0ec3cfa3dc74ce0d36f22a858","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-1.2.0.tgz","fileCount":16,"unpackedSize":119722,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSX2lCRA9TVsSAnZWagAArpkQAJLwUVPbxbws1O/YhudU\nu0P0bbRiEgkfqqjMZyp+sokEbLq8IzfWluatkPUjD+USIcd1HPYcS8Rt/lMv\n01sxw3xpSGu1OZ0K56aDPyXtu+qnphF5n1oY2S4VBqxepLVng205WNqNFOcV\nL/Nr4tF6eUprJTS6ChA3UwxMCo8sSRtHjbt+ND8OrS9kj8Nrd/btWgbSrptl\n6IV5DffrosDIKtPKzr+CoDYbSA1Ww5nl9NVLCNUbPVINUVhJHQ+oTeDpao/c\nmYt9VEcYVCVLAX5+/ifqKPJ3MGb+cZl51tuEcPBKVrnWackEjmETU8VLnQIx\n+EfRYcfS96v9SbEfLpNU9K6T5W5huBQghKbu04hihMEL5AcJZUhFrKTVWN/v\n7GSq8Q40OeLjQEWEqEFBk1MVn5ErVv5J4JwXVxa/Dv7+nbmzCh+sVQT28Dro\n3MYNqcq256ytsNUEnxWl5x/SmdC8vi/M0OYcOCS3ewfUteahdhzlN7qf7FsJ\nF6fOxVOoYlpJLOjxYNEKCTCX9V6cHtX4xejjqngylBroyIwff0itbzuP426W\nD2YE5MEu0YGvSLaeHpe/d+G63vbAO8gho+TDeLfLSZIlk+UaoCByJK2nzqt/\nfIkzU3CgjWMhlDi0P3I+24DCX2rNyWEba2nshrI4cFrorgnVt2xfTFtPWxFm\nbF4V\r\n=KFzw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHPLgdk1e5A9othveM+XiMRQG+Z57OleYbCk18kUKFh2AiEA6BuD+ThIhPoplTV0gVewKTWD8cV/sxxoFgL3YNDULgw="}]},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_1.2.0_1598651812874_0.8611253231802889"},"_hasShrinkwrap":false},"1.2.1":{"name":"@reflet/mongoose","version":"1.2.1","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet/tree/master/mongoose"},"description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/mongoose":"^5.7.20","@types/node":">=8","mongoose":"^5","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^1.2.3","@types/mongoose":"^5.7.36","mongoose":"^5.10.9"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"d3fc420141fc2960938635bd8c6198dc435c6871","_id":"@reflet/mongoose@1.2.1","_nodeVersion":"12.16.3","_npmVersion":"lerna/3.22.1/node@v12.16.3+x64 (win32)","_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"dist":{"integrity":"sha512-BfcnUP0fBMDA/3LYiMvc97WQOBz49x6RttoNIeb0oai6GPZ/DVcGeVWYm2G32eZZsyUjAAVRTzUPRDs3wdJSiA==","shasum":"d94ad7ff8522b197b47e5120381ccb90aae559f6","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-1.2.1.tgz","fileCount":16,"unpackedSize":122473,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfgwj9CRA9TVsSAnZWagAA5qMP/007+QQoqi87fyNT1dEM\nQcTFEHo4eHKg6IeEvQo65d+BVfKzuREAqxwl22pPrAH9OIxjMqYW3D2gWmKP\nhyZ51diR1JcoPrAa8nHIGt/XK/8o87tHS59kNbhx5XCi07wBXaHh5LJBHHE2\nqf+DfXN9b6x18aouwEAQu6XPddGqD4aYzhCkS70+CkNgCic84Fnzi+twFrBX\nvl9YVA0ZhVu0PxXfxp8jYk8QM1MauR5Gz2J144AmTF2WYC/opfUF2q75tioG\nrdW9c+sXWbjNz6SDXpXrp9w8i8lCsjWEnYzkFhIzYAyCfOE4JduSqw3qGM8L\nXq0hU1a6sU45IkML/oLTUlB8qnK2LOlFVwMwNDrQ6Zc0tPSRqYNg/3dKJ6gD\nglAG7a9YMA6TTN097P66DEvLXsg89Kq/Dm/ePTFf9j6zIPq4ktRv1B+FVZXq\nPy0EBpv+jNmwRavwvqvJQKXevgku0F3oUbow4Ar7d6bsRffMa/OF9jBOCdl/\nN+xw7Wjfgk7bT+bx8hUSmnULTgtl7BEukGMExmU2AQWjKWQbH9BtXWeaPsN7\n7cE6/gBxOS9gXklk7Mmaq1EFz2k1ctGgt7Jlb6DxjRALsehbGJ6DNLxeiH7P\nHVo93RQ9+liMCxilN0utlJTTMuXvJpu9xmDhqTs4mw9aYNfayS+5OruetbTA\n9OEP\r\n=zdzR\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCOtYVZH2Ayw+QyGlWzlg8fm00gu31Ypk2bN9iiP7OL6gIgPhiKFOegWzuHsM3BSBmotfj1IrAbPgF+pfVfMQoQYZY="}]},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_1.2.1_1602423037058_0.7771388281431137"},"_hasShrinkwrap":false},"1.3.0":{"name":"@reflet/mongoose","version":"1.3.0","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet/tree/master/mongoose"},"description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/mongoose":"^5.7.20","@types/node":">=8","mongoose":">=5.0 <5.11","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^1.2.3","@types/mongoose":"^5.10.3","mongoose":"5.10.19"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"7589e8c4fbfe88d13dedfd94215e26b15c214e9f","_id":"@reflet/mongoose@1.3.0","_nodeVersion":"12.19.1","_npmVersion":"lerna/3.22.1/node@v12.19.1+x64 (win32)","_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"dist":{"integrity":"sha512-83+ycZMmOTpUcF8dYiq3friTD7Gu8TOlakUiLOOhMTxZlLnpl3qkXtM2kPbCZ2wC2/yA/4JB4WYwH++XNE3EJw==","shasum":"0d5e106b0bd306dd86e67a8ca229598108bd3bd6","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-1.3.0.tgz","fileCount":17,"unpackedSize":127720,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf37u5CRA9TVsSAnZWagAADUwP/3Pu1bOp37YlMCevM8jp\nSQROzV82c9qRlkJ4RwUVTISsTSFBnDNvP7CJUrcFhShkolciuRopbZwvaU1/\n7PruUSZRHohOZM1uRa35QfroHMSdaZAmqJ5KsW3z0ix6emEyXdUpipTDOlOu\nZeP9O2RcpRf4y1r1OFgTyal4envGmCcS+fAQYrpYpfWRbCbePD0sigyiCJwU\nFyK7yXrd6JngaTHIWjwcs8XBYKgviXpcRoQb1frMYLeeoNfAkIvchYTjM9yE\nREQseZu9tcV4lmgG53KPfdX+MFeGxrcXLS5DIrEHWfkeaeEtKLT13/gN+5v+\n5d/tV84LM7i8xdvg03yHxUsBjauzLAxuNuQVAB/cb40f65z+Ih2mi0jnGNH4\nyQARdHeXMKxdkPQV+4atdcQgLnB40xWvslRYCqr2hWWU97gV8BIsggVC4d4N\nSumBQGxqkY4QujqqJ21a7sPSrhNulF/vnXnY6pKVuwRjbOSQi5yg8xOihJkW\nK4pBYHu3RgrUp+CJYtMAmvIS1pilGwOT4QWz3sKV9vc7RXTuW0kahKBffnLY\nRR3uX5blvR8wPLvcUwz2YSzx5I/UEtSsvAyvPfEv0Ux8m3eLh81OBl0HbHFE\n0au8CEnnalY5H+HGFCs30MiEuTEJQ4tQCofeZNSsZgqLc01YDwai8OBaPoq2\nLTPW\r\n=CoIL\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICOaic4Ou3jmNiKHo/CZqgTEzdOq0AfFrcyUoR/ARdYmAiEAofzd4oljD2NLEMOWdrKMFwxsoW8TPo4q+NbbvmGceQ8="}]},"directories":{},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_1.3.0_1608498104933_0.5559726730313836"},"_hasShrinkwrap":false},"1.4.0":{"name":"@reflet/mongoose","version":"1.4.0","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet/tree/master/mongoose"},"description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/mongoose":"^5.7.20","@types/node":">=8","mongoose":">=5.0 <5.11","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^1.2.3","@types/mongoose":"^5.10.3","mongoose":"5.10.19"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"ebdc41d747efdb829aa0e95e8e6f9bc4513b3918","_id":"@reflet/mongoose@1.4.0","_nodeVersion":"12.19.1","_npmVersion":"lerna/3.22.1/node@v12.19.1+x64 (win32)","_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"dist":{"integrity":"sha512-roGe5kXdnyNYngoyvwWdUhLV52k4075+uaDVBvXY/o/AdjRF/2EN1Wt0kzLt28GpI3JXsp3cJdzSS67+nBKPOQ==","shasum":"e50faf0652d59d9d3c2d441a6b989a0ba3036451","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-1.4.0.tgz","fileCount":17,"unpackedSize":129477,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf4TrvCRA9TVsSAnZWagAANeUQAJZzCBNYnZlXuU9ei29v\nG7Dxkz1HDHfi9q8Kx219FLDdfolwheVnPSawWOg6PuENWAhxzqGER3eq2+K7\nKlMCVbNCfgrUpMC4zA1Nk4lDCZHwM9yiPstfps0IUDXUsK5ECBr8MVuMLgxB\nRm6y6uzn+jRsHlnd0wNDyIikzqDx69+eIiowItbF0/TKBRrWZfBzg+4TOmOl\nTYU1ieLAHPn2iRss73z15Biw2iVmMMLscdQJrt7HTTVhwA+cWYnHcw+bsWf0\ns9Im33TiuQV65/6axEeNUd4YtPhCayhuzj/fi59KgrU/dceXsVnO1PgqLIT+\nv9Lx6uydyW2bYAGGSuvYuWpTr61vZ4rhBJ1cB4/umsWSWQ1e9v5q1dlqBrni\n2uTHff48GVyphgq8/uKxE8OsqhFuffJ+Xe9FSl0lVE2erWtxcwG9cfblUJHG\nOdCZsSak8AYKGzPiFNGJsj5ivmKD3oXR4HbU+bc/CxXlTCDL2V3esyGfhoDc\n+Ev9pKM/cpN3uB7s29los728009mOpKgzPG75fagmeRzjJFQG+CWD8WLmBe+\nl5rSsYW9mect03ERy04vrU11bnzqUhFYZsNc+2s52G50gJnnoN5barEUQ0A7\nLPwBgU7PRLNz7j2prwPVhciXsIzAuy8Wawog8KuCYKdhQzp5mXmDGB0tSYMe\npoG2\r\n=0SVA\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCC3Kaxfi/Vw8IlBAeIHiV7iHJxdOGvo3lbpYq7gqpwfAIhALHqyeMoZul1p9KnFlBZKi1zOWi4f4BC2aHNFjXpX/8l"}]},"directories":{},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_1.4.0_1608596206817_0.8961440277247883"},"_hasShrinkwrap":false},"1.4.1":{"name":"@reflet/mongoose","version":"1.4.1","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet/tree/master/mongoose"},"description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/mongoose":"^5.7.20","@types/node":">=8","mongoose":">=5.0 <5.11","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^1.2.3","@types/mongoose":"^5.10.3","mongoose":"5.10.19"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"86da25d1e64b7cee3e80982c239177c736db5959","_id":"@reflet/mongoose@1.4.1","_nodeVersion":"12.19.1","_npmVersion":"lerna/3.22.1/node@v12.19.1+x64 (win32)","_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"dist":{"integrity":"sha512-jCQAv61RAcywW21U3T58brRUtfcdWU2OLLlfzdgSodNdqfluYbSwZNRK/RKChYwsRkdnBQMOvFCcI5akKsod3A==","shasum":"3669b9b314eb60556c3e160d521491826d80d234","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-1.4.1.tgz","fileCount":17,"unpackedSize":130508,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf9t7hCRA9TVsSAnZWagAAkxIP/jJ69Pb9be+VyEn+vbDV\neTeRvNOzRfs0sOSlVE9kofsMkYaTk4PNnfOZdrGL5dG/3nJdlhoNAkgbGdfH\nWicoJSdyuXLVHJm9nbcH6Twi7uI037XuV6IOP3A43avdMzIpwkSkqh4yXAsR\ncrXDm0xvfhKP5QagN4l3W9nPQRMMkqVKAEDzENbvJ6OSydRNvBRbQj1e7Cvz\nHyjoxbQ9Lixt+Q/43yPC5vBubOdx9SAyZLqSHLACiJs/8YYezJbsiqaDaKAi\nHF1s+kti6BLIGsQecd6rnbiBFk8yh/FDoghxkBJMQc6e5BjDGTVX9OLeRjH3\nUNttQGpk9l3kV4vzh6jiGYmWIvxgJVgY/0Xheu+F7OcuTJowLIFO9HX48AS9\nL+7mdYVlz9v44YGisyTGr9vYNmKxdSxlYl8SMI4ezp/YtGYp8qTTYyilopID\nMI+OwO9OHSOs5kC9XayVmdxvIGf5XYRvCk8pbygFNTpqpAEWmcq4mz0biPP4\nDrpNpx2JVrSXENr7eDxCmoyy8lEMrAy9+3qXzyKna+Eo9TKUYO0rSughPD9t\nDwghG5rDei3qNKE06/Rj1ArEJtX5vexAW7cjA1CKauXrePcKmXSRvKlJSjcr\nEwdF3m59qnFzbKNhxAp0odMwGIeRs4ECkT6FAjcdr1SRDaIhcNDA55HRr90Y\nEO7Q\r\n=GV7b\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDxk2gh9uivdmt5g4FPzYN4SHFpRpdrynbT4KGzs7PEWgIhAOlOf+Zv1oq1AZR0xirdsVr320Y+gkQG7fg39Ia9dcjb"}]},"directories":{},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_1.4.1_1610014433042_0.012042449430619051"},"_hasShrinkwrap":false},"1.4.2":{"name":"@reflet/mongoose","version":"1.4.2","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet/tree/master/mongoose"},"description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/mongoose":"^5.7.20","@types/node":">=8","mongoose":">=5.0 <5.11","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^1.2.3","@types/mongoose":"^5.10.3","mongoose":"5.10.19"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"e3b2d4199476f07896d1e5f145613414017863ba","_id":"@reflet/mongoose@1.4.2","_nodeVersion":"12.19.1","_npmVersion":"lerna/3.22.1/node@v12.19.1+x64 (win32)","_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"dist":{"integrity":"sha512-InYEiNOeVQDUfetBdf30WAY00SBxSlvu8d05RhQFDO+9R8mf2/HCsN6b2W8DKTEhBDpxfPukoaPDJLZtr0v3/g==","shasum":"323aa84868ff7b2d03810d66fcc17a6d46543954","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-1.4.2.tgz","fileCount":17,"unpackedSize":133469,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgQPt3CRA9TVsSAnZWagAAhV4P/jHwB3gUeHnAWPJ9D0P3\nRmJ7OTCacrLDXFJDxBDErAuk5etVmOe7scNwYLDUuSsTxhTrRxfyUj7CdOxw\nO8WL0zhhi7Fbf1uKGl+HzcR3tpxaWbb4tYeCjaN8KKCPZPr0IsTN7wAzMkBs\ngHC+I3Z6/38MyduWq+lRHn6M/vFIIN+mp+fK+X2fivaE6QnXjhwmNspbyntl\nME0diC0JPuAW6WR3O1cg584hDn3ZStQI3YeJUyPdGD/clY4G74rU2XgSMgwa\nnnhoa+0dV1feQMmNWD19aa00VQRcLEudkh2wpDmNMe3bV8RG4jowUrpfPQgw\n0i/kO+c7wBcWWXlqxd0FG1GCSQurY7nmkuwlIQBkjdqezuz3dkBbL58EgjgN\nb81lvL4syzkjX+VM/WNumzuW4YNyYH4fdhOSc8MaWneJq5kiQP0BdlnxmbLa\nxUMECmEgJpjlpCGEBSHUQe3qXeuVhRlbtrK+JA1lGdRWJXl4YcZvRQMcc4VW\nbafR0NiJNMHt82Gl8tJtFKKWdPhbJYaf1rIOVW2RHBgh/8pZ0gSA7fhBAzd2\nh0dcnJKO3vCh0J1U0+03aIeXqhPEmURdDb6G3vMEjBPql5vuA3/oP0XSW1yr\nyZ2MCRWi1+2efX+ovpoW7tH0plKECSFThBZ0CeGCGPGSXwxyhMDkDaJYBZUg\n8Aj3\r\n=C/KW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGNyQC9tG9bsrYdwW6JSjsMbWUpquKtprtijfl7fMqOBAiEA4vzJlgma/sPaT69o2Lw/EZwBglnEagAh2jq/dBGRur8="}]},"directories":{},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_1.4.2_1614871414523_0.7869280976463726"},"_hasShrinkwrap":false},"1.4.3":{"name":"@reflet/mongoose","version":"1.4.3","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/jeremyben/reflet.git","directory":"mongoose"},"homepage":"https://github.com/jeremyben/reflet/tree/master/mongoose#readme","description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/mongoose":"^5.7.20","@types/node":">=8","mongoose":">=5.0 <5.11","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^1.2.3","@types/mongoose":"^5.10.3","mongoose":"5.10.19"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"3beb133f4e3f954651d58e7308f16f5d8173ad30","bugs":{"url":"https://github.com/jeremyben/reflet/issues"},"_id":"@reflet/mongoose@1.4.3","_nodeVersion":"12.19.1","_npmVersion":"lerna/4.0.0/node@v12.19.1+x64 (win32)","dist":{"integrity":"sha512-08bLO98ULjZP2MuSuLOAVw/i4/KGVrs4TJ12INKO/apUounXOZ8jMf/lCjqspE8oNbO3IQ/TRJ3AF8L9/V0EOg==","shasum":"51c6564f4494c69666fc43a53d1989f6b6f48f6f","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-1.4.3.tgz","fileCount":17,"unpackedSize":132915,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgSqIdCRA9TVsSAnZWagAAkPAQAKNLcMF91dcTVlydrwR8\nvEwFeAjVRpj+lFFajSvaeChhcYCRMPEQhVJVxAivgMsLprZRWkifJkMk7BNS\nmtjfLzjDTXPos0SaWNwe8H7nOibeizUwnfBuR4spFfBt2knvH2nboiNdM4mx\nTNrQ7yjXB0fty+tqnRwj7qy6tvan/xcYpuFUaXN8FykQ8Q7OSVmTizXHomep\nCdPMyd9bLWzal5WDcCMk2iS6YOMYR0oKOe+1ATAEKmB7zcrgp/ilmCr6mz7+\n3+q/bCXMTVOysRRmNR593GKVePLRw4TfwJ54TRtGcGtQkbAqIzH8iWhx4ly0\nOsEO2VP3/vEjy3VmIDBef5Ryos6UvweiapRLWB207dOvwTfzveASW5OdUv+l\nmcfkDgOJP1xDoUiw2mg8OdYdqS5QiWL92J1K/G4BgJA6K5Gpl5+LlcjyR0Wa\nl7ZtnVsY9QHlCMYZiz7e19qN2PvwHRDjEAyquOGvNMh5EwAUrTekWKFPnwua\npwx7Q4vkIrB9hv9uCBZwUsq5xpUuzgdcHDPSyGMQJ3bmGdLhqZuOJt9Re/vi\nw27GQv3n7pxuDrUrbMVUDpRGsgh4x0zHs06b+Bfhco2iW00D2slx2mqqYIWL\naqxRj3TIXZBtQh957+fKGQWdLajO+yrfKGn40vpAzpCiYx9JnHnaoiXhY0Sk\njPTt\r\n=8SL7\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDPtGgXVBt8ISO7OpJReKkdcMqCBsjrz2B8189i/csfiwIhAKLXeuOEwfRYmLexkM3gi2iAsLhDzDXB8iHAbou+tTBp"}]},"_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"directories":{},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_1.4.3_1615503900935_0.7088875049056897"},"_hasShrinkwrap":false},"2.0.0-next.0":{"name":"@reflet/mongoose","version":"2.0.0-next.0","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/jeremyben/reflet.git","directory":"mongoose"},"homepage":"https://github.com/jeremyben/reflet/tree/master/mongoose#readme","description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/node":">=8","mongoose":">=5.11","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^1.2.3","mongoose":"^5.12.13"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"349dcaf14cd2fb40474aa07e04a13a0de5986f54","readme":"# `@reflet/mongoose` 🌠\n\n[![lines coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=lines&query=total.lines.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![statements coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=statements&query=total.statements.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![functions coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=functions&query=total.functions.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![branches coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=branches&query=total.branches.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n\nThe **best** decorators for [Mongoose](https://mongoosejs.com/). Have a look at [Reflet's philosophy](../README.MD#Philosophy-).\n\n* [Getting started](#getting-started)\n* [Schema definition](#schema-definition)\n* [Model](#model)\n* [Schema options](#schema-options)\n* [Schema retrieval](#schema-retrieval)\n* [Hooks](#hooks)\n* [Model discriminators](#model-discriminators)\n* [Embedded discriminators](#embedded-discriminators)\n* [Populate virtuals](#populate-virtuals)\n* [Plain helper](#plain-helper)\n* [Augmentations](#augmentations)\n\n## Getting started\n\n1. <details>\n    <summary>Make sure you have decorators enabled. (click for details)</summary>\n    <p>\n\n    * Enable them in your TypeScript compiler options.\n\n        ```json\n        \"experimentalDecorators\": true,\n        \"emitDecoratorMetadata\": true,\n        ```\n\n    * Install `reflect-metadata` shim.\n\n        ```sh\n        yarn add reflect-metadata\n        ```\n\n    * Import the shim in your program before everything else.\n\n        ```ts\n        import 'reflect-metadata'\n        ```\n\n    </p>\n    </details>\n\n2. Install the package along with peer dependencies.\n\n    ```sh\n    yarn add @reflet/mongoose mongoose && yarn add -D @types/mongoose @types/node\n    ```\n\n3. Create your decorated models.\n\n    ```ts\n    // user.model.ts\n    import { Model, Field } from '@reflet/mongoose'\n\n    @Model()\n    export class User extends Model.Interface {\n      static findByEmail(email) {\n        return this.findOne({ email });\n      }\n\n      @Fied({ type: String, required: true })\n      email: string\n\n      getProfileUrl() {\n        return `https://mysite.com/${this.email}`;\n      }\n    }\n    ```\n\n4. Connect to MongoDB and save your documents.\n\n    ```ts\n    // server.ts\n    import 'reflect-metadata'\n    import * as mongoose from 'mongoose'\n    import { User } from './user.model.ts'\n\n    mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true })\n\n    User.create({ email: 'jeremy@example.com' }).then((user) => {\n      console.log(`User ${user._id} has been saved.`)\n    })\n    ```\n\n### The Mongoose way\n\nConnect Mongoose in the way you already know. Models defined with Reflet will simply be attached to the default Mongoose connection.\nThis means you can **progressively** decorate your Mongoose models. 😉\n\n## Schema definition\n\n> 🔦 `@Field(schemaType)`<br>\n> 💫 Related Mongoose object: [SchemaTypes](https://mongoosejs.com/docs/schematypes)\n\nMongoose [already](https://mongoosejs.com/docs/api#schema_Schema-loadClass) allows you to load an ES6 class to attach getters, setters, instance and static methods to a schema.\nBut what about properties ? Enters the `@Field` decorator :\n\n```ts\nclass User {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field(Number)\n  age?: number\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThe `@Field` API is a direct wrapper of Mongoose [SchemaType](https://mongoosejs.com/docs/schematypes), you can put in there everything that you used to.\n\n### Nested properties\n\n> 🔦 `@Field.Nested(schemaTypes)`\n\n```ts\nclass User {\n  @Field.Nested({\n    street: { type: String, required: true },\n    city: { type: String, required: true },\n    country: { type: String, required: true },\n  })\n  address: {\n    street: string\n    city: string\n    country: string\n  }\n}\n```\n\n_`@Field.Nested` works the same as `@Field` at runtime. Its type is simply looser to allow nested objects._\n\n## Model\n\n> 🔦 `@Model(collection?, connection?)`<br>\n> 💫 Related Mongoose method: [`model`](https://mongoosejs.com/docs/models#compiling)\n\nTypeScript [class decorators](https://www.typescriptlang.org/docs/handbook/decorators#class-decorators) can modify and even replace class constructors. Reflet takes advantage of this feature and transforms a class directly into a Mongoose Model.\n\nThis means you don't have to deal with the procedural and separate creation of both schema and model anymore !\nAnd now your properties and methods are statically typed.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\nclass User extends Model.Interface {\n  @Field({ type: String, required: true })\n  email: string\n}\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  email: string\n}\n\nconst userSchema = new mongoose.Schema({\n  email: { type: String, required: true }\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nYour class needs to inherit a special empty class, **`Model.Interface`** or **`Model.I`**, to have Mongoose document properties and methods.\n\n⚠️ `@Model` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n#### Custom collection name\n\nBy default, Mongoose automatically creates a collection named as the plural, lowercased version of your model name. You can customize the collection name, with the first argument:\n\n```ts\n@Model('people')\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n#### Custom Mongoose connection\n\nYou can use a different database by creating a Mongoose connection and passing it as the second argument:\n\n```ts\nconst otherDb = mongoose.createConnection('mongodb://localhost/other', { useNewUrlParser: true })\n\n@Model(undefined, otherDb)\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n## Schema options\n\n> 🔦 `@SchemaOptions(options)`<br>\n> 💫 Related Mongoose object: [Schema options](https://mongoosejs.com/docs/guide#options)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({\n  autoIndex: false,\n  strict: 'throw'\n})\nclass User extends Model.I {           \n  @Field(String)\n  name: string\n}\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    autoIndex: false,\n    strict: 'throw'\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@SchemaOptions` API is a direct wrapper of Mongoose [schema options](https://mongoosejs.com/docs/guide#options), you can put in there everything that you used to.\n\n### Timestamps\n\n> 🔦 `@CreatedAt`, `@UpdatedAt`<br>\n> 💫 Related Mongoose option property: [`timestamps`](https://mongoosejs.com/docs/guide#timestamps)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({ minimize: false })\nclass User extends Model.I {             \n  @Field(String)\n  name: string\n\n  @CreatedAt\n  creationDate: Date\n\n  @UpdatedAt\n  updateDate: Date\n}\n\n\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n  creationDate: Date\n  updateDate: Date\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    minimize: false,\n    timestamps: {\n      createdAt: 'creationDate',\n      updatedAt: 'updateDate'\n    },\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n### Advanced schema manipulation\n\n> 🔦 `@SchemaCallback(callback)`<br>\n> 💫 Related Mongoose object: [`Schema`](https://mongoosejs.com/docs/api/schema)\n\nIf you need more advanced schema manipulation before `@Model` compiles it, you can use `@SchemaCallback`:\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaCallback((schema) => {\n  schema.index({ name: 1, type: -1 })\n})\nclass Animal extends Model.I {          \n  @Field(String)\n  name: string\n\n  @Field(String)\n  type: string\n}\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface AnimalDocument extends mongoose.Document {\n  name: string\n  type: string\n}\n\nconst userSchema = new mongoose.Schema({\n  name: String,\n  type: String\n})\n\nuserSchema.index({ name: 1, type: -1 })\n\nconst Animal = mongoose.model<AnimalDocument>('Animal', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n_Beware of defining hooks in the callback if your schema has embedded discriminators. Mongoose documentation recommends declaring hooks **before** embedded discriminators, the callback is applied **after** them. You should use the dedicated hooks decorators `@PreHook` and `@PostHook`._\n\n## Schema retrieval\n\n> 🔦 `schemaFrom(class)`\n\nYou can retrieve a schema from any decorated class, for advanced manipulation or embedded use in another schema.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Location {\n  @Field(Number)\n  lat: number\n\n  @Field(Number)\n  lng: number\n}\n\n@Model()\nclass City extends Model.I {            \n  @Field(String)\n  name: string\n\n  @Field(schemaFrom(Location))\n  location: Location\n}\n\nconst citySchema = schemaFrom(City)\n```\n\n  </td>\n  <td>\n\n```ts\ninterface CityDocument extends mongoose.Document {\n  name: string\n  location: {\n    lat: number,\n    lng: number\n  }\n}\n\nconst locationSchema = new mongoose.Schema(\n  { lat: Number, lng: Number },\n  { _id: false }\n)\n\nconst citySchema = new mongoose.Schema({\n  name: String,\n  location: locationSchema\n})\n\nconst City = mongoose.model<CityDocument>('City', citySchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n🗣️ As a good practice, you should make your schema-only classes `abstract`, so you don't instantiate them by mistake.\n\n\n### Sub schemas\n\n> 🔦 `Field.Schema(class)`\n\nAs an alternative for the above use of `schemaFrom` inside the `Field` decorator, you can do:\n\n```ts\n@Model()\nclass City extends Model.I {            \n  @Field.Schema(Location)\n  location: Location\n}\n```\n\n## Hooks\n\n### Pre hook\n\n> 🔦 `@PreHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.pre`](https://mongoosejs.com/docs/middleware#pre)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PreHook<User>('save', function(next) {\n  next()\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.pre<UserDocument>('save', function (doc, next) {\n  next()\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PreHook` API is a direct wrapper of Mongoose [Schema.pre method](https://mongoosejs.com/docs/api/schema#schema_Schema-pre), you can put in there everything that you used to.\n\n### Post hook\n\n> 🔦 `@PostHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.post`](https://mongoosejs.com/docs/middleware#post)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PostHook<User>('find', function(result) {\n  console.log(result)\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.post<UserDocument>('find', function (result) {\n  console.log(result)\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PostHook` API is a direct wrapper of Mongoose [Schema.post method](https://mongoosejs.com/docs/api/schema#schema_Schema-post), you can put in there everything that you used to.\n\n#### Post error handling middleware\n\nTo help the compiler accurately infer the [error handling middleware](https://mongoosejs.com/docs/middleware#error-handling-middleware) signature, pass a second type argument to `@PostHook`:\n\n```ts\n@Model()\n@PostHook<User, Error>('save', function(error, doc, next) {\n  if (error.name === 'MongoError' && error.code === 11000) {\n    next(new Error('There was a duplicate key error'))\n  } else {\n    next()\n  }\n})\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n```\n\n## Model discriminators\n\n> 🔦 `@Model.Discriminator(rootModel)`<br>\n> 💫 Related Mongoose method: [`model.discriminator`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Worker extends User {\n  @Field(String)\n  job: string\n\n  // No need to decorate the default discriminatorKey.\n  __t: 'Worker'\n\n  // You can strictly type the constructor of a discriminator model by using the Plain Helper (see below).\n  constructor(worker: Plain.Omit<Worker, '_id' | '__t'>) {\n    super() // required by the compiler.\n  }\n}\n\nconst worker = await Worker.create({ name: 'Jeremy', job: 'developer' })\n// { _id: '5d023ae14043262bcfd9b384', __t: 'Worker', name: 'Jeremy', job: 'developer' }\n```\n\nAs you know, `_t` is the default `discriminatorKey`, and its value will be the class name. If you want to customize both the key and the value, check out the following `@Kind` decorator.\n\n⚠️ `@Model.Discriminator` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model.Discriminator` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n### Kind / DiscriminatorKey\n\n> 🔦 `@Kind(value?)` alias `@DiscriminatorKey`<br>\n> 💫 Related Mongoose option property: [`discriminatorKey`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\nMongoose `discriminatorKey` is usually defined in the parent model options, and appears in the children model documents.\n`@Kind` (or its alias `@DiscriminatorKey`) exists to define `discriminatorKey` **directly** on the children class instead of the parent model.\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Developer extends User {\n  @Kind\n  kind: 'Developer' // Value will be the class name by default.\n}\n\n@Model.Discriminator(User)\nclass Doctor extends User {\n  @Kind('doctor') // Customize the discriminator value by passing a string.\n  kind: 'doctor'\n}\n\n// This is equivalent to setting `{ discriminatorKey: 'kind' }` on User schema options.\n```\n\nA mecanism will check and prevent you from defining a different `@Kind` key on sibling discriminators.\n\n## Embedded discriminators\n\n### Single nested discriminators\n\n> 🔦 `@Field.Union(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`SingleNestedPath.discriminator`](https://mongoosejs.com/docs/discriminators#single-nested-discriminators)\n\n`@Field.Union` allows you to embed discriminators on an single property.\n\n```ts\nabstract class Circle {\n  @Field(Number)\n  radius: number\n\n  __t: 'Circle'\n  // __t is the default discriminatorKey (no need to decorate).\n  // Value will be the class name.\n}\n\nabstract class Square {\n  @Field(Number)\n  side: number\n\n  __t: 'Square'\n}\n\n@Model()\nclass Shape extends Model.I {\n  @Field.Union([Circle, Square], { \n    required: true, // Make the field itself `shape` required.\n    strict: true // Make the discriminator key `__t` required and narrowed to its possible values.\n  })\n  shape: Circle | Square\n}\n\nconst circle = new Shape({ shape: { __t: 'Circle', radius: 5 } })\nconst square = new Shape({ shape: { __t: 'Square', side: 4 } })\n```\n\n### Embedded discriminators in arrays\n\n> 🔦 `@Field.ArrayOfUnion(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`DocumentArrayPath.discriminator`](https://mongoosejs.com/docs/discriminators#embedded-discriminators-in-arrays)\n\n`@Field.ArrayOfUnion` allows you to embed discriminators in an array.\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Clicked {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  element: string\n\n  @Kind\n  kind: 'Clicked'\n}\n\n@SchemaOptions({ _id: false })\nabstract class Purchased {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  product: string\n\n  @Kind\n  kind: 'Purchased'\n}\n\n@Model()\nclass Batch extends Model.I {\n  @Field.ArrayOfUnion([Clicked, Purchased], { \n    strict: true  // Make the discriminator key `kind` required and narrowed to its possible values.\n  })\n  events: (Clicked | Purchased)[]\n}\n\nconst batch = new Batch({\n  events: [\n    { kind: 'Clicked', element: '#hero', message: 'hello' },\n    { kind: 'Purchased', product: 'action-figure', message: 'world' },\n  ]\n})\n```\n\n## Populate virtuals\n\n> 🔦 `@PopulateVirtual(options)`<br>\n> 💫 Related Mongoose method: [`schema.virtual`](https://mongoosejs.com/docs/populate#populate-virtuals)\n\n```ts\n@Model()\nclass Person extends Model.I {\n  @Field(String)\n  name: string\n\n  @Field(String)\n  band: string\n}\n\n@Model()\n@SchemaOptions({\n  toObject: { virtuals: true },\n  toJson: { virtuals: true }\n})\nclass Band extends Model.I {\n  @Field(String)\n  name: string\n\n  @PopulateVirtual<Person, Band>({\n    ref: 'Person',\n    foreignField: 'band',\n    localField: 'name'\n  })\n  readonly members: string[]\n}\n\nconst bands = await Band.find({}).populate('members')\n```\n\n## Plain helper\n\n> 🔦 `Plain<class, options?>`\n\nReflet provides a generic type to discard Mongoose properties and methods from a Document.\n\n* `Plain<T>` removes inherited Mongoose properties (except `_id`) and all methods from `T`.\n* `Plain.Partial<T>` does the same as `Plain` and makes remaining properties of `T` optional.\n* `Plain.PartialDeep<T>` does the same as `Plain.Partial` recursively.\n\n`Plain` also has a second type argument to omit other properties and/or make them optional:\n\n* `Plain<T, { Omit: keyof T; Optional: keyof T } >`\n\n_These options exist as standalone generics as well: `Plain.Omit<T, keyof T>` and `Plain.Optional<T, keyof T>`._\n\n### One document, multiple shapes\n\nIn each of your models, some fields might be present when you read the document from the database, but optional or even absent when you create it. 😕\n\nGiven the following model:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field({ type: Boolean, default: () => false })\n  activated: boolean\n\n  @CreatedAt\n  createdAt: Date\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThis is how you can type `constructor` and `create` parameters:\n\n```ts\ntype NewUser = Plain<User, { Omit: 'fullname' | 'createdAt'; Optional: '_id' | 'activated' }>\n\n@Model()\nclass User extends Model.I  {\n  // ...\n\n  // @ts-ignore implementation\n  constructor(user: NewUser)\n  \n  static create(doc: NewUser): Promise<User>\n\t// @ts-ignore implementation\n  static create(docs: NewUser[]): Promise<User[]>\n}\n\nconst user = new User({ firstname: 'John', lastname: 'Doe' })\nawait user.save()\nawait User.create({ firstname: 'Jeremy', lastname: 'Doe', activated: true })\n```\n\n_You can safely use ts-ignore to avoid a useless wrapper of `create` or even the `constructor`, the compiler will still check `NewUser` as we need._\n\nYou can also narrow the return type of `toObject()` and `toJson()`:\n\n```ts\nconst userPlain = user.toObject({ getters: false }) as Plain.Omit<User, 'fullname'>\n```\n\n## Augmentations\n\nReflet comes with a dedicated global namespace `RefletMongoose`, so you can augment or narrow specific types.\n\n### SchemaType options augmentation\n\nIf you use plugins like [mongoose-autopopulate](https://github.com/mongodb-js/mongoose-autopopulate),\nyou can augment the global interface `SchemaTypeOptions` to have new options in the `@Field` API.\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface SchemaTypeOptions {\n      autopopulate?: boolean\n    }\n  }\n}\n```\n\nNow you have access to `autopopulate` option in your schemas:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: Company,\n    autopopulate: true\n  })\n  company: Company\n}\n```\n\n### Model and Document augmentation\n\nYou can augment `Model` and `Document` interfaces with the dedicated global interfaces.\nHere is an example with the [@casl/mongoose](https://github.com/stalniy/casl/tree/master/packages/casl-mongoose) plugin:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface Model {\n      accessibleBy<T extends mongoose.Document>(ability: AnyMongoAbility, action?: string): mongoose.DocumentQuery<T[], T>\n    }\n    interface Document {}\n  }\n}\n```\n\n### References narrowing\n\n[SchemaType `ref` option](https://mongoosejs.com/docs/api#schematypeoptions_SchemaTypeOptions-ref) can be either a Model or a model name. With Reflet, by default, any class can be passed as a Model and any string can be passed as a model name.\n\nBy augmenting the global interface `Ref`, you can:\n\n* Narrow the class to an union of your models.\n* Narrow the string to an union of your models' names.\n\n```ts\n// company.model.ts\n@Model()\nclass Company extends Model.I {\n  @Field(String)\n  name: string\n}\n\n// You should augment the global interface in each of your models' files, to keep it close to the model.\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      Company: Company\n    }\n  }\n}\n```\n\n```ts\n// user.model.ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: 'Company',\n  })\n  company: Company\n}\n\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      User: User\n    }\n  }\n}\n```\n","readmeFilename":"README.MD","bugs":{"url":"https://github.com/jeremyben/reflet/issues"},"_id":"@reflet/mongoose@2.0.0-next.0","_nodeVersion":"14.16.0","_npmVersion":"lerna/4.0.0/node@v14.16.0+x64 (win32)","dist":{"integrity":"sha512-GE81bu9s9fG9RxRm+MJEtk8UktV/iqdS5zH9hAVNTsH70e9LD63nv3f/8r7E6ItDnngZpvj8Wed7xKf5wLrKHg==","shasum":"c3cce121db3adae43f91a3d4e61b07e295be41b3","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-2.0.0-next.0.tgz","fileCount":17,"unpackedSize":130869,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgvQXiCRA9TVsSAnZWagAA5lYP/A+LM1EBt/cs12tcYsdF\nrDNhUwecxzbJV5jd5KS1TkUcVssCEbkW64fcvI4zHxGDymTxFYbsAAxDo9pH\nKDlFFOzB3+88HsUFn8hFCeOMRo6pByjc/zygc6ubUQ/HO7dvNJ6zcU7DJX9u\nah/l3u8VWutlXVzEMGjJjIl58M0nS35NDQs/mF7L58/RUNbAIP6TcYBkjI85\n0tytsHcAnA4kul3faVFD5dfd1ivHEFuoV943Z5uqlbutj9V+OO20Gq/kLE3b\nE8HNCWt0EEYV1AE6Q+aIas5msEfAedEyOPugBkCyV0YSYJHTxCVoqsmMoXv7\nEs4vk8oxXsORjnOnsJvHMjZbhbkv5NkebLAhLKIRkQU5UsKRhtZgrMipefpl\nRXT/BfqP2XvBCJZohFFOeExYV9KSij4dJ+8ysUj7QpIo3qFqrAWJ1t8I+Chw\nA1zL64Q5Aqv6WRNkyg4Wb9iCVAeG1jddIxGby2YaSOpWVdfl4KhsH/W+S4NI\nZ9erQPm0CfovoqBQ39u3de4gedL/40LO4j0HnBqR4bXb6hFQ6Cjf5UraPDGA\nvj8zhhAq+kvz4NtFkCvRyY4xesuKWIFUmkVuAO0HvSTrpmz4/nMsBHNzTjBU\nqIUvkbPe0zdPnw+4kp8eXcudTpqBl/CnK9iNgQe9oclPuOkqkawy4UoVZuog\nsBuR\r\n=9YWm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD3CeIxpePLAijfIIraQh4XYy4gzSiD8KttHQDfFTh9TQIgRw7zCOBg8RobuvSLcwa/YvDPxtE6dlNQCnrrNObNqeE="}]},"_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"directories":{},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_2.0.0-next.0_1623000546236_0.2891601418177232"},"_hasShrinkwrap":false},"2.0.0-next.1":{"name":"@reflet/mongoose","version":"2.0.0-next.1","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/jeremyben/reflet.git","directory":"mongoose"},"homepage":"https://github.com/jeremyben/reflet/tree/master/mongoose#readme","description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/node":">=8","mongoose":">=5.11","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^1.2.3","mongoose":"^5.12.13"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"ea591a654fbb8dd7f14c41eedc441170ae946e04","readme":"# `@reflet/mongoose` 🌠\n\n[![lines coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=lines&query=total.lines.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![statements coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=statements&query=total.statements.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![functions coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=functions&query=total.functions.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![branches coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=branches&query=total.branches.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n\nThe **best** decorators for [Mongoose](https://mongoosejs.com/). Have a look at [Reflet's philosophy](../README.MD#Philosophy-).\n\n* [Getting started](#getting-started)\n* [Schema definition](#schema-definition)\n* [Model](#model)\n* [Schema options](#schema-options)\n* [Schema retrieval](#schema-retrieval)\n* [Hooks](#hooks)\n* [Model discriminators](#model-discriminators)\n* [Embedded discriminators](#embedded-discriminators)\n* [Populate virtuals](#populate-virtuals)\n* [Plain helper](#plain-helper)\n* [Augmentations](#augmentations)\n\n## Getting started\n\n1. <details>\n    <summary>Make sure you have decorators enabled. (click for details)</summary>\n    <p>\n\n    * Enable them in your TypeScript compiler options.\n\n        ```json\n        \"experimentalDecorators\": true,\n        \"emitDecoratorMetadata\": true,\n        ```\n\n    * Install `reflect-metadata` shim.\n\n        ```sh\n        yarn add reflect-metadata\n        ```\n\n    * Import the shim in your program before everything else.\n\n        ```ts\n        import 'reflect-metadata'\n        ```\n\n    </p>\n    </details>\n\n2. Install the package along with peer dependencies.\n\n    ```sh\n    yarn add @reflet/mongoose mongoose && yarn add -D @types/mongoose @types/node\n    ```\n\n3. Create your decorated models.\n\n    ```ts\n    // user.model.ts\n    import { Model, Field } from '@reflet/mongoose'\n\n    @Model()\n    export class User extends Model.Interface {\n      static findByEmail(email) {\n        return this.findOne({ email });\n      }\n\n      @Fied({ type: String, required: true })\n      email: string\n\n      getProfileUrl() {\n        return `https://mysite.com/${this.email}`;\n      }\n    }\n    ```\n\n4. Connect to MongoDB and save your documents.\n\n    ```ts\n    // server.ts\n    import 'reflect-metadata'\n    import * as mongoose from 'mongoose'\n    import { User } from './user.model.ts'\n\n    mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true })\n\n    User.create({ email: 'jeremy@example.com' }).then((user) => {\n      console.log(`User ${user._id} has been saved.`)\n    })\n    ```\n\n### The Mongoose way\n\nConnect Mongoose in the way you already know. Models defined with Reflet will simply be attached to the default Mongoose connection.\nThis means you can **progressively** decorate your Mongoose models. 😉\n\n## Schema definition\n\n> 🔦 `@Field(schemaType)`<br>\n> 💫 Related Mongoose object: [SchemaTypes](https://mongoosejs.com/docs/schematypes)\n\nMongoose [already](https://mongoosejs.com/docs/api#schema_Schema-loadClass) allows you to load an ES6 class to attach getters, setters, instance and static methods to a schema.\nBut what about properties ? Enters the `@Field` decorator :\n\n```ts\nclass User {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field(Number)\n  age?: number\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThe `@Field` API is a direct wrapper of Mongoose [SchemaType](https://mongoosejs.com/docs/schematypes), you can put in there everything that you used to.\n\n### Nested properties\n\n> 🔦 `@Field.Nested(schemaTypes)`\n\n```ts\nclass User {\n  @Field.Nested({\n    street: { type: String, required: true },\n    city: { type: String, required: true },\n    country: { type: String, required: true },\n  })\n  address: {\n    street: string\n    city: string\n    country: string\n  }\n}\n```\n\n_`@Field.Nested` works the same as `@Field` at runtime. Its type is simply looser to allow nested objects._\n\n## Model\n\n> 🔦 `@Model(collection?, connection?)`<br>\n> 💫 Related Mongoose method: [`model`](https://mongoosejs.com/docs/models#compiling)\n\nTypeScript [class decorators](https://www.typescriptlang.org/docs/handbook/decorators#class-decorators) can modify and even replace class constructors. Reflet takes advantage of this feature and transforms a class directly into a Mongoose Model.\n\nThis means you don't have to deal with the procedural and separate creation of both schema and model anymore !\nAnd now your properties and methods are statically typed.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\nclass User extends Model.Interface {\n  @Field({ type: String, required: true })\n  email: string\n}\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  email: string\n}\n\nconst userSchema = new mongoose.Schema({\n  email: { type: String, required: true }\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nYour class needs to inherit a special empty class, **`Model.Interface`** or **`Model.I`**, to have Mongoose document properties and methods.\n\n⚠️ `@Model` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n#### Custom collection name\n\nBy default, Mongoose automatically creates a collection named as the plural, lowercased version of your model name. You can customize the collection name, with the first argument:\n\n```ts\n@Model('people')\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n#### Custom Mongoose connection\n\nYou can use a different database by creating a Mongoose connection and passing it as the second argument:\n\n```ts\nconst otherDb = mongoose.createConnection('mongodb://localhost/other', { useNewUrlParser: true })\n\n@Model(undefined, otherDb)\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n## Schema options\n\n> 🔦 `@SchemaOptions(options)`<br>\n> 💫 Related Mongoose object: [Schema options](https://mongoosejs.com/docs/guide#options)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({\n  autoIndex: false,\n  strict: 'throw'\n})\nclass User extends Model.I {           \n  @Field(String)\n  name: string\n}\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    autoIndex: false,\n    strict: 'throw'\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@SchemaOptions` API is a direct wrapper of Mongoose [schema options](https://mongoosejs.com/docs/guide#options), you can put in there everything that you used to.\n\n### Timestamps\n\n> 🔦 `@CreatedAt`, `@UpdatedAt`<br>\n> 💫 Related Mongoose option property: [`timestamps`](https://mongoosejs.com/docs/guide#timestamps)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({ minimize: false })\nclass User extends Model.I {             \n  @Field(String)\n  name: string\n\n  @CreatedAt\n  creationDate: Date\n\n  @UpdatedAt\n  updateDate: Date\n}\n\n\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n  creationDate: Date\n  updateDate: Date\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    minimize: false,\n    timestamps: {\n      createdAt: 'creationDate',\n      updatedAt: 'updateDate'\n    },\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n### Advanced schema manipulation\n\n> 🔦 `@SchemaCallback(callback)`<br>\n> 💫 Related Mongoose object: [`Schema`](https://mongoosejs.com/docs/api/schema)\n\nIf you need more advanced schema manipulation before `@Model` compiles it, you can use `@SchemaCallback`:\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaCallback((schema) => {\n  schema.index({ name: 1, type: -1 })\n})\nclass Animal extends Model.I {          \n  @Field(String)\n  name: string\n\n  @Field(String)\n  type: string\n}\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface AnimalDocument extends mongoose.Document {\n  name: string\n  type: string\n}\n\nconst userSchema = new mongoose.Schema({\n  name: String,\n  type: String\n})\n\nuserSchema.index({ name: 1, type: -1 })\n\nconst Animal = mongoose.model<AnimalDocument>('Animal', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n_Beware of defining hooks in the callback if your schema has embedded discriminators. Mongoose documentation recommends declaring hooks **before** embedded discriminators, the callback is applied **after** them. You should use the dedicated hooks decorators `@PreHook` and `@PostHook`._\n\n## Schema retrieval\n\n> 🔦 `schemaFrom(class)`\n\nYou can retrieve a schema from any decorated class, for advanced manipulation or embedded use in another schema.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Location {\n  @Field(Number)\n  lat: number\n\n  @Field(Number)\n  lng: number\n}\n\n@Model()\nclass City extends Model.I {            \n  @Field(String)\n  name: string\n\n  @Field(schemaFrom(Location))\n  location: Location\n}\n\nconst citySchema = schemaFrom(City)\n```\n\n  </td>\n  <td>\n\n```ts\ninterface CityDocument extends mongoose.Document {\n  name: string\n  location: {\n    lat: number,\n    lng: number\n  }\n}\n\nconst locationSchema = new mongoose.Schema(\n  { lat: Number, lng: Number },\n  { _id: false }\n)\n\nconst citySchema = new mongoose.Schema({\n  name: String,\n  location: locationSchema\n})\n\nconst City = mongoose.model<CityDocument>('City', citySchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n🗣️ As a good practice, you should make your schema-only classes `abstract`, so you don't instantiate them by mistake.\n\n\n### Sub schemas\n\n> 🔦 `Field.Schema(class)`\n\nAs an alternative for the above use of `schemaFrom` inside the `Field` decorator, you can do:\n\n```ts\n@Model()\nclass City extends Model.I {            \n  @Field.Schema(Location)\n  location: Location\n}\n```\n\n## Hooks\n\n### Pre hook\n\n> 🔦 `@PreHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.pre`](https://mongoosejs.com/docs/middleware#pre)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PreHook<User>('save', function(next) {\n  next()\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.pre<UserDocument>('save', function (doc, next) {\n  next()\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PreHook` API is a direct wrapper of Mongoose [Schema.pre method](https://mongoosejs.com/docs/api/schema#schema_Schema-pre), you can put in there everything that you used to.\n\n### Post hook\n\n> 🔦 `@PostHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.post`](https://mongoosejs.com/docs/middleware#post)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PostHook<User>('find', function(result) {\n  console.log(result)\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.post<UserDocument>('find', function (result) {\n  console.log(result)\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PostHook` API is a direct wrapper of Mongoose [Schema.post method](https://mongoosejs.com/docs/api/schema#schema_Schema-post), you can put in there everything that you used to.\n\n#### Post error handling middleware\n\nTo help the compiler accurately infer the [error handling middleware](https://mongoosejs.com/docs/middleware#error-handling-middleware) signature, pass a second type argument to `@PostHook`:\n\n```ts\n@Model()\n@PostHook<User, Error>('save', function(error, doc, next) {\n  if (error.name === 'MongoError' && error.code === 11000) {\n    next(new Error('There was a duplicate key error'))\n  } else {\n    next()\n  }\n})\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n```\n\n## Model discriminators\n\n> 🔦 `@Model.Discriminator(rootModel)`<br>\n> 💫 Related Mongoose method: [`model.discriminator`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Worker extends User {\n  @Field(String)\n  job: string\n\n  // No need to decorate the default discriminatorKey.\n  __t: 'Worker'\n\n  // You can strictly type the constructor of a discriminator model by using the Plain Helper (see below).\n  constructor(worker: Plain.Omit<Worker, '_id' | '__t'>) {\n    super() // required by the compiler.\n  }\n}\n\nconst worker = await Worker.create({ name: 'Jeremy', job: 'developer' })\n// { _id: '5d023ae14043262bcfd9b384', __t: 'Worker', name: 'Jeremy', job: 'developer' }\n```\n\nAs you know, `_t` is the default `discriminatorKey`, and its value will be the class name. If you want to customize both the key and the value, check out the following `@Kind` decorator.\n\n⚠️ `@Model.Discriminator` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model.Discriminator` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n### Kind / DiscriminatorKey\n\n> 🔦 `@Kind(value?)` alias `@DiscriminatorKey`<br>\n> 💫 Related Mongoose option property: [`discriminatorKey`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\nMongoose `discriminatorKey` is usually defined in the parent model options, and appears in the children model documents.\n`@Kind` (or its alias `@DiscriminatorKey`) exists to define `discriminatorKey` **directly** on the children class instead of the parent model.\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Developer extends User {\n  @Kind\n  kind: 'Developer' // Value will be the class name by default.\n}\n\n@Model.Discriminator(User)\nclass Doctor extends User {\n  @Kind('doctor') // Customize the discriminator value by passing a string.\n  kind: 'doctor'\n}\n\n// This is equivalent to setting `{ discriminatorKey: 'kind' }` on User schema options.\n```\n\nA mecanism will check and prevent you from defining a different `@Kind` key on sibling discriminators.\n\n## Embedded discriminators\n\n### Single nested discriminators\n\n> 🔦 `@Field.Union(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`SingleNestedPath.discriminator`](https://mongoosejs.com/docs/discriminators#single-nested-discriminators)\n\n`@Field.Union` allows you to embed discriminators on an single property.\n\n```ts\nabstract class Circle {\n  @Field(Number)\n  radius: number\n\n  __t: 'Circle'\n  // __t is the default discriminatorKey (no need to decorate).\n  // Value will be the class name.\n}\n\nabstract class Square {\n  @Field(Number)\n  side: number\n\n  __t: 'Square'\n}\n\n@Model()\nclass Shape extends Model.I {\n  @Field.Union([Circle, Square], { \n    required: true, // Make the field itself `shape` required.\n    strict: true // Make the discriminator key `__t` required and narrowed to its possible values.\n  })\n  shape: Circle | Square\n}\n\nconst circle = new Shape({ shape: { __t: 'Circle', radius: 5 } })\nconst square = new Shape({ shape: { __t: 'Square', side: 4 } })\n```\n\n### Embedded discriminators in arrays\n\n> 🔦 `@Field.ArrayOfUnion(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`DocumentArrayPath.discriminator`](https://mongoosejs.com/docs/discriminators#embedded-discriminators-in-arrays)\n\n`@Field.ArrayOfUnion` allows you to embed discriminators in an array.\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Clicked {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  element: string\n\n  @Kind\n  kind: 'Clicked'\n}\n\n@SchemaOptions({ _id: false })\nabstract class Purchased {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  product: string\n\n  @Kind\n  kind: 'Purchased'\n}\n\n@Model()\nclass Batch extends Model.I {\n  @Field.ArrayOfUnion([Clicked, Purchased], { \n    strict: true  // Make the discriminator key `kind` required and narrowed to its possible values.\n  })\n  events: (Clicked | Purchased)[]\n}\n\nconst batch = new Batch({\n  events: [\n    { kind: 'Clicked', element: '#hero', message: 'hello' },\n    { kind: 'Purchased', product: 'action-figure', message: 'world' },\n  ]\n})\n```\n\n## Populate virtuals\n\n> 🔦 `@PopulateVirtual(options)`<br>\n> 💫 Related Mongoose method: [`schema.virtual`](https://mongoosejs.com/docs/populate#populate-virtuals)\n\n```ts\n@Model()\nclass Person extends Model.I {\n  @Field(String)\n  name: string\n\n  @Field(String)\n  band: string\n}\n\n@Model()\n@SchemaOptions({\n  toObject: { virtuals: true },\n  toJson: { virtuals: true }\n})\nclass Band extends Model.I {\n  @Field(String)\n  name: string\n\n  @PopulateVirtual<Person, Band>({\n    ref: 'Person',\n    foreignField: 'band',\n    localField: 'name'\n  })\n  readonly members: string[]\n}\n\nconst bands = await Band.find({}).populate('members')\n```\n\n## Plain helper\n\n> 🔦 `Plain<class, options?>`\n\nReflet provides a generic type to discard Mongoose properties and methods from a Document.\n\n* `Plain<T>` removes inherited Mongoose properties (except `_id`) and all methods from `T`.\n* `Plain.Partial<T>` does the same as `Plain` and makes remaining properties of `T` optional.\n* `Plain.PartialDeep<T>` does the same as `Plain.Partial` recursively.\n\n`Plain` also has a second type argument to omit other properties and/or make them optional:\n\n* `Plain<T, { Omit: keyof T; Optional: keyof T } >`\n\n_These options exist as standalone generics as well: `Plain.Omit<T, keyof T>` and `Plain.Optional<T, keyof T>`._\n\n### One document, multiple shapes\n\nIn each of your models, some fields might be present when you read the document from the database, but optional or even absent when you create it. 😕\n\nGiven the following model:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field({ type: Boolean, default: () => false })\n  activated: boolean\n\n  @CreatedAt\n  createdAt: Date\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThis is how you can type `constructor` and `create` parameters:\n\n```ts\ntype NewUser = Plain<User, { Omit: 'fullname' | 'createdAt'; Optional: '_id' | 'activated' }>\n\n@Model()\nclass User extends Model.I<typeof User>  {\n  // @ts-ignore implementation\n  constructor(doc?: NewUser, strict?: boolean | 'throw')\n}\n\nconst user = new User({ firstname: 'John', lastname: 'Doe' })\nawait user.save()\nawait User.create({ firstname: 'Jeremy', lastname: 'Doe', activated: true })\n```\n\nBy passing `typeof User` to `Model.I`, Reflet is now able to use the constructor signature to type the following static methods: `create`, `insertMany` and `replaceOne`.\n\n_The compiler checks `NewUser` as we need, so you can safely use ts-ignore on the `constructor` to avoid implementing an empty one (remember that `@Model` will replace it with mongoose Model constructor)._\n\nYou can also narrow the return type of `toObject()` and `toJson()`:\n\n```ts\nconst userPlain = user.toObject({ getters: false }) as Plain.Omit<User, 'fullname'>\n```\n\n## Augmentations\n\nReflet comes with a dedicated global namespace `RefletMongoose`, so you can augment or narrow specific types.\n\n### SchemaType options augmentation\n\nIf you use plugins like [mongoose-autopopulate](https://github.com/mongodb-js/mongoose-autopopulate),\nyou can augment the global interface `SchemaTypeOptions` to have new options in the `@Field` API.\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface SchemaTypeOptions {\n      autopopulate?: boolean\n    }\n  }\n}\n```\n\nNow you have access to `autopopulate` option in your schemas:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: Company,\n    autopopulate: true\n  })\n  company: Company\n}\n```\n\n### Model and Document augmentation\n\nYou can augment `Model` and `Document` interfaces with the dedicated global interfaces.\nHere is an example with the [@casl/mongoose](https://github.com/stalniy/casl/tree/master/packages/casl-mongoose) plugin:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface Model {\n      accessibleBy<T extends mongoose.Document>(ability: AnyMongoAbility, action?: string): mongoose.DocumentQuery<T[], T>\n    }\n    interface Document {}\n  }\n}\n```\n\n### References narrowing\n\n[SchemaType `ref` option](https://mongoosejs.com/docs/api#schematypeoptions_SchemaTypeOptions-ref) can be either a Model or a model name. With Reflet, by default, any class can be passed as a Model and any string can be passed as a model name.\n\nBy augmenting the global interface `Ref`, you can:\n\n* Narrow the class to an union of your models.\n* Narrow the string to an union of your models' names.\n\n```ts\n// company.model.ts\n@Model()\nclass Company extends Model.I {\n  @Field(String)\n  name: string\n}\n\n// You should augment the global interface in each of your models' files, to keep it close to the model.\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      Company: Company\n    }\n  }\n}\n```\n\n```ts\n// user.model.ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: 'Company',\n  })\n  company: Company\n}\n\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      User: User\n    }\n  }\n}\n```\n","readmeFilename":"README.MD","bugs":{"url":"https://github.com/jeremyben/reflet/issues"},"_id":"@reflet/mongoose@2.0.0-next.1","_nodeVersion":"14.16.0","_npmVersion":"lerna/4.0.0/node@v14.16.0+x64 (win32)","dist":{"integrity":"sha512-CmwM8prbDoT7QlWjD5foNbBWoJcFgtqYWTtkS2931fDuqJhFzvirT6SHXSPUHgbI7Ldd6r69Gr5YpL+bN8kL3Q==","shasum":"579e673770e88922556ee13fe3e90c7d54d2d6ef","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-2.0.0-next.1.tgz","fileCount":17,"unpackedSize":131621,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgvoJaCRA9TVsSAnZWagAAkpYQAJmXr3birvb6POuZFGtf\nNlUNN2YTJ+CjnZUFDEUD+2Sf6Fbc74w5ChxDH5Nu2Djm8Zy0uv8xkHbulzxa\nHGsNsSb7z3jGaTkIW5oJYxY9RUQfUzXwIcnKEusq7abryknxZTY4Plm0j3ZM\nS1OXafIt5EKE/WS8w9QZZIzzk6awPbtBiTJjXgzN0UdP9h+1KhTh2ekPgyil\nDBGyE+VJKdHgOqUo9LHQEfl2hqrD+UtvKXV1ctbqRRn4LeqVGTN4W/SB89L+\nnA5b32Rw1rBWNWN35SOoGyl102pOB1uj+kToS7oDEGa7ApnaSc9kkwnLtRot\nAZDWskw+DVR8Enud+t9W5BXMtlBgjKKAvGSvrMfqm/lzcs69Rnkx+7vSIaoz\ncXg8LN5N/Jj9l+vLiTHkxtIxhiQPoYonF88C6zDDVbIL/DR5uj5jbhYd2HSM\nN1Tq85HjD29M2mf6PFsZ5bvJZB0vzlwELc0x8/OFaUFPw99+Yg/tkh3aikqa\nsUkue7VEJXBHdfsIWxuvawejwN7SuJyzZlyNwH5iaMi90yHO6lJKZzNpiARJ\nGTIFquD4DrVvgYOFFlu9aWknEdkSETeWUtHIR0OtkX9c++Z20dEW2HYQEYAQ\nojvoDAdqI7bQAL2GlhYawp8xgjOckJE6XgabHIavh0g0q+LPEmL5Im6NjiqM\nanUK\r\n=Z4lE\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDt6Niy6L/jawuFy2ji2smJKjY4U0loTq5ZwQObYNNoegIhAL9X4NGq/yFnP3G0e28ICMlzQOWp7Pk8NZTs9gmAWGYu"}]},"_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"directories":{},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_2.0.0-next.1_1623097946492_0.9560778261825187"},"_hasShrinkwrap":false},"2.0.0-next.2":{"name":"@reflet/mongoose","version":"2.0.0-next.2","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/jeremyben/reflet.git","directory":"mongoose"},"homepage":"https://github.com/jeremyben/reflet/tree/master/mongoose#readme","description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/node":">=8","mongoose":">=6","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^2.1.0","mongoose":"^6.0.7"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"425f5ff6a9a7411bc52fcc35037db56740247754","readme":"# `@reflet/mongoose` 🌠\n\n[![lines coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=lines&query=total.lines.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![statements coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=statements&query=total.statements.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![functions coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=functions&query=total.functions.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![branches coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=branches&query=total.branches.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n\nThe **best** decorators for [Mongoose](https://mongoosejs.com/). Have a look at [Reflet's philosophy](../README.MD#Philosophy-).\n\n* [Getting started](#getting-started)\n* [Schema definition](#schema-definition)\n* [Model](#model)\n* [Schema options](#schema-options)\n* [Schema retrieval](#schema-retrieval)\n* [Hooks](#hooks)\n* [Model discriminators](#model-discriminators)\n* [Embedded discriminators](#embedded-discriminators)\n* [Populated virtuals](#populated-virtuals)\n* [Plain helper](#plain-helper)\n* [Augmentations](#augmentations)\n\n## Getting started\n\n1. <details>\n    <summary>Make sure you have decorators enabled. (click for details)</summary>\n    <p>\n\n    * Enable them in your TypeScript compiler options.\n\n        ```json\n        \"experimentalDecorators\": true,\n        \"emitDecoratorMetadata\": true,\n        ```\n\n    * Install `reflect-metadata` shim.\n\n        ```sh\n        yarn add reflect-metadata\n        ```\n\n    * Import the shim in your program before everything else.\n\n        ```ts\n        import 'reflect-metadata'\n        ```\n\n    </p>\n    </details>\n\n2. Install the package along with peer dependencies.\n\n    ```sh\n    yarn add @reflet/mongoose mongoose && yarn add -D @types/mongoose @types/node\n    ```\n\n3. Create your decorated models.\n\n    ```ts\n    // user.model.ts\n    import { Model, Field } from '@reflet/mongoose'\n\n    @Model()\n    export class User extends Model.Interface {\n      static findByEmail(email) {\n        return this.findOne({ email });\n      }\n\n      @Fied({ type: String, required: true })\n      email: string\n\n      getProfileUrl() {\n        return `https://mysite.com/${this.email}`;\n      }\n    }\n    ```\n\n4. Connect to MongoDB and save your documents.\n\n    ```ts\n    // server.ts\n    import 'reflect-metadata'\n    import * as mongoose from 'mongoose'\n    import { User } from './user.model.ts'\n\n    mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true })\n\n    User.create({ email: 'jeremy@example.com' }).then((user) => {\n      console.log(`User ${user._id} has been saved.`)\n    })\n    ```\n\n### The Mongoose way\n\nConnect Mongoose in the way you already know. Models defined with Reflet will simply be attached to the default Mongoose connection.\nThis means you can **progressively** decorate your Mongoose models. 😉\n\n## Schema definition\n\n> 🔦 `@Field(schemaType)`<br>\n> 💫 Related Mongoose object: [SchemaTypes](https://mongoosejs.com/docs/schematypes)\n\nMongoose [already](https://mongoosejs.com/docs/api#schema_Schema-loadClass) allows you to load an ES6 class to attach getters, setters, instance and static methods to a schema.\nBut what about properties ? Enters the `@Field` decorator :\n\n```ts\nclass User {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field(Number)\n  age?: number\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThe `@Field` API is a direct wrapper of Mongoose [SchemaType](https://mongoosejs.com/docs/schematypes), you can put in there everything that you used to.\n\n### Nested properties\n\n> 🔦 `@Field.Nested(schemaTypes)`\n\n```ts\nclass User {\n  @Field.Nested({\n    street: { type: String, required: true },\n    city: { type: String, required: true },\n    country: { type: String, required: true },\n  })\n  address: {\n    street: string\n    city: string\n    country: string\n  }\n}\n```\n\n_`@Field.Nested` works the same as `@Field` at runtime. Its type is simply looser to allow nested objects._\n\n## Model\n\n> 🔦 `@Model(collection?, connection?)`<br>\n> 💫 Related Mongoose method: [`model`](https://mongoosejs.com/docs/models#compiling)\n\nTypeScript [class decorators](https://www.typescriptlang.org/docs/handbook/decorators#class-decorators) can modify and even replace class constructors. Reflet takes advantage of this feature and transforms a class directly into a Mongoose Model.\n\nThis means you don't have to deal with the procedural and separate creation of both schema and model anymore !\nAnd now your properties and methods are statically typed.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\nclass User extends Model.Interface {\n  @Field({ type: String, required: true })\n  email: string\n}\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  email: string\n}\n\nconst userSchema = new mongoose.Schema({\n  email: { type: String, required: true }\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nYour class needs to inherit a special empty class, **`Model.Interface`** or **`Model.I`**, to have Mongoose document properties and methods.\n\n⚠️ `@Model` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n#### Custom collection name\n\nBy default, Mongoose automatically creates a collection named as the plural, lowercased version of your model name. You can customize the collection name, with the first argument:\n\n```ts\n@Model('people')\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n#### Custom Mongoose connection\n\nYou can use a different database by creating a Mongoose connection and passing it as the second argument:\n\n```ts\nconst otherDb = mongoose.createConnection('mongodb://localhost/other', { useNewUrlParser: true })\n\n@Model(undefined, otherDb)\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n## Schema options\n\n> 🔦 `@SchemaOptions(options)`<br>\n> 💫 Related Mongoose object: [Schema options](https://mongoosejs.com/docs/guide#options)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({\n  autoIndex: false,\n  strict: 'throw'\n})\nclass User extends Model.I {           \n  @Field(String)\n  name: string\n}\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    autoIndex: false,\n    strict: 'throw'\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@SchemaOptions` API is a direct wrapper of Mongoose [schema options](https://mongoosejs.com/docs/guide#options), you can put in there everything that you used to.\n\n### Timestamps\n\n> 🔦 `@CreatedAt`, `@UpdatedAt`<br>\n> 💫 Related Mongoose option property: [`timestamps`](https://mongoosejs.com/docs/guide#timestamps)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({ minimize: false })\nclass User extends Model.I {             \n  @Field(String)\n  name: string\n\n  @CreatedAt\n  creationDate: Date\n\n  @UpdatedAt\n  updateDate: Date\n}\n\n\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n  creationDate: Date\n  updateDate: Date\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    minimize: false,\n    timestamps: {\n      createdAt: 'creationDate',\n      updatedAt: 'updateDate'\n    },\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n### Advanced schema manipulation\n\n> 🔦 `@SchemaCallback(callback)`<br>\n> 💫 Related Mongoose object: [`Schema`](https://mongoosejs.com/docs/api/schema)\n\nIf you need more advanced schema manipulation before `@Model` compiles it, you can use `@SchemaCallback`:\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaCallback((schema) => {\n  schema.index({ name: 1, type: -1 })\n})\nclass Animal extends Model.I {          \n  @Field(String)\n  name: string\n\n  @Field(String)\n  type: string\n}\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface AnimalDocument extends mongoose.Document {\n  name: string\n  type: string\n}\n\nconst userSchema = new mongoose.Schema({\n  name: String,\n  type: String\n})\n\nuserSchema.index({ name: 1, type: -1 })\n\nconst Animal = mongoose.model<AnimalDocument>('Animal', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n_Beware of defining hooks in the callback if your schema has embedded discriminators. Mongoose documentation recommends declaring hooks **before** embedded discriminators, the callback is applied **after** them. You should use the dedicated hooks decorators `@PreHook` and `@PostHook`._\n\n## Schema retrieval\n\n> 🔦 `schemaFrom(class)`\n\nYou can retrieve a schema from any decorated class, for advanced manipulation or embedded use in another schema.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Location {\n  @Field(Number)\n  lat: number\n\n  @Field(Number)\n  lng: number\n}\n\n@Model()\nclass City extends Model.I {            \n  @Field(String)\n  name: string\n\n  @Field(schemaFrom(Location))\n  location: Location\n}\n\nconst citySchema = schemaFrom(City)\n```\n\n  </td>\n  <td>\n\n```ts\ninterface CityDocument extends mongoose.Document {\n  name: string\n  location: {\n    lat: number,\n    lng: number\n  }\n}\n\nconst locationSchema = new mongoose.Schema(\n  { lat: Number, lng: Number },\n  { _id: false }\n)\n\nconst citySchema = new mongoose.Schema({\n  name: String,\n  location: locationSchema\n})\n\nconst City = mongoose.model<CityDocument>('City', citySchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n🗣️ As a good practice, you should make your schema-only classes `abstract`, so you don't instantiate them by mistake.\n\n\n### Sub schemas\n\n> 🔦 `Field.Schema(class)`\n\nAs an alternative for the above use of `schemaFrom` inside the `Field` decorator, you can do:\n\n```ts\n@Model()\nclass City extends Model.I {            \n  @Field.Schema(Location)\n  location: Location\n}\n```\n\n## Hooks\n\n### Pre hook\n\n> 🔦 `@PreHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.pre`](https://mongoosejs.com/docs/middleware#pre)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PreHook<User>('save', function(next) {\n  next()\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.pre<UserDocument>('save', function (doc, next) {\n  next()\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PreHook` API is a direct wrapper of Mongoose [Schema.pre method](https://mongoosejs.com/docs/api/schema#schema_Schema-pre), you can put in there everything that you used to.\n\n### Post hook\n\n> 🔦 `@PostHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.post`](https://mongoosejs.com/docs/middleware#post)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PostHook<User>('find', function(result) {\n  console.log(result)\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.post<UserDocument>('find', function (result) {\n  console.log(result)\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PostHook` API is a direct wrapper of Mongoose [Schema.post method](https://mongoosejs.com/docs/api/schema#schema_Schema-post), you can put in there everything that you used to.\n\n#### Post error handling middleware\n\nTo help the compiler accurately infer the [error handling middleware](https://mongoosejs.com/docs/middleware#error-handling-middleware) signature, pass a second type argument to `@PostHook`:\n\n```ts\n@Model()\n@PostHook<User, Error>('save', function(error, doc, next) {\n  if (error.name === 'MongoError' && error.code === 11000) {\n    next(new Error('There was a duplicate key error'))\n  } else {\n    next()\n  }\n})\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n```\n\n## Model discriminators\n\n> 🔦 `@Model.Discriminator(rootModel)`<br>\n> 💫 Related Mongoose method: [`model.discriminator`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Worker extends User {\n  @Field(String)\n  job: string\n\n  // No need to decorate the default discriminatorKey.\n  __t: 'Worker'\n\n  // You can strictly type the constructor of a discriminator model by using the Plain Helper (see below).\n  constructor(worker: Plain.Omit<Worker, '_id' | '__t'>) {\n    super() // required by the compiler.\n  }\n}\n\nconst worker = await Worker.create({ name: 'Jeremy', job: 'developer' })\n// { _id: '5d023ae14043262bcfd9b384', __t: 'Worker', name: 'Jeremy', job: 'developer' }\n```\n\nAs you know, `_t` is the default `discriminatorKey`, and its value will be the class name. If you want to customize both the key and the value, check out the following `@Kind` decorator.\n\n⚠️ `@Model.Discriminator` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model.Discriminator` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n### Kind / DiscriminatorKey\n\n> 🔦 `@Kind(value?)` alias `@DiscriminatorKey`<br>\n> 💫 Related Mongoose option property: [`discriminatorKey`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\nMongoose `discriminatorKey` is usually defined in the parent model options, and appears in the children model documents.\n`@Kind` (or its alias `@DiscriminatorKey`) exists to define `discriminatorKey` **directly** on the children class instead of the parent model.\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Developer extends User {\n  @Kind\n  kind: 'Developer' // Value will be the class name by default.\n}\n\n@Model.Discriminator(User)\nclass Doctor extends User {\n  @Kind('doctor') // Customize the discriminator value by passing a string.\n  kind: 'doctor'\n}\n\n// This is equivalent to setting `{ discriminatorKey: 'kind' }` on User schema options.\n```\n\nA mecanism will check and prevent you from defining a different `@Kind` key on sibling discriminators.\n\n## Embedded discriminators\n\n### Single nested discriminators\n\n> 🔦 `@Field.Union(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`SingleNestedPath.discriminator`](https://mongoosejs.com/docs/discriminators#single-nested-discriminators)\n\n`@Field.Union` allows you to embed discriminators on an single property.\n\n```ts\nabstract class Circle {\n  @Field(Number)\n  radius: number\n\n  __t: 'Circle'\n  // __t is the default discriminatorKey (no need to decorate).\n  // Value will be the class name.\n}\n\nabstract class Square {\n  @Field(Number)\n  side: number\n\n  __t: 'Square'\n}\n\n@Model()\nclass Shape extends Model.I {\n  @Field.Union([Circle, Square], { \n    required: true, // Make the field itself `shape` required.\n    strict: true // Make the discriminator key `__t` required and narrowed to its possible values.\n  })\n  shape: Circle | Square\n}\n\nconst circle = new Shape({ shape: { __t: 'Circle', radius: 5 } })\nconst square = new Shape({ shape: { __t: 'Square', side: 4 } })\n```\n\n### Embedded discriminators in arrays\n\n> 🔦 `@Field.ArrayOfUnion(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`DocumentArrayPath.discriminator`](https://mongoosejs.com/docs/discriminators#embedded-discriminators-in-arrays)\n\n`@Field.ArrayOfUnion` allows you to embed discriminators in an array.\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Clicked {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  element: string\n\n  @Kind\n  kind: 'Clicked'\n}\n\n@SchemaOptions({ _id: false })\nabstract class Purchased {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  product: string\n\n  @Kind\n  kind: 'Purchased'\n}\n\n@Model()\nclass Batch extends Model.I {\n  @Field.ArrayOfUnion([Clicked, Purchased], { \n    strict: true  // Make the discriminator key `kind` required and narrowed to its possible values.\n  })\n  events: (Clicked | Purchased)[]\n}\n\nconst batch = new Batch({\n  events: [\n    { kind: 'Clicked', element: '#hero', message: 'hello' },\n    { kind: 'Purchased', product: 'action-figure', message: 'world' },\n  ]\n})\n```\n\n## Populated virtuals\n\n> 🔦 `@Virtual(options)`<br>\n> 💫 Related Mongoose method: [`schema.virtual`](https://mongoosejs.com/docs/populate#populate-virtuals)\n\n```ts\n@Model()\nclass Person extends Model.I {\n  @Field(String)\n  name: string\n\n  @Field(String)\n  band: string\n}\n\n@Model()\n@SchemaOptions({\n  toObject: { virtuals: true },\n  toJson: { virtuals: true }\n})\nclass Band extends Model.I {\n  @Field(String)\n  name: string\n\n  @Virtual<Person, Band>({\n    ref: 'Person',\n    foreignField: 'band',\n    localField: 'name'\n  })\n  readonly members: string[]\n}\n\nconst bands = await Band.find({}).populate('members')\n```\n\n## Plain helper\n\n> 🔦 `Plain<class, options?>`\n\nReflet provides a generic type to discard Mongoose properties and methods from a Document.\n\n* `Plain<T>` removes inherited Mongoose properties (except `_id`) and all methods from `T`.\n* `Plain.Partial<T>` does the same as `Plain` and makes remaining properties of `T` optional.\n* `Plain.PartialDeep<T>` does the same as `Plain.Partial` recursively.\n\n`Plain` also has a second type argument to omit other properties and/or make them optional:\n\n* `Plain<T, { Omit: keyof T; Optional: keyof T } >`\n\n_These options exist as standalone generics as well: `Plain.Omit<T, keyof T>` and `Plain.Optional<T, keyof T>`._\n\nWith this you can narrow the return type of `toObject()` and `toJson()`:\n\n```ts\nconst userPlain = user.toObject({ getters: false }) as Plain.Omit<User, 'fullname'>\n```\n\n#### Allow `string` for `ObjectId`\n\n> 🔦 `Plain.AllowString<class, options?>`\n\nWhen creating or querying documents, you can pass `ObjectId` as `string`. To allow this, Reflet provides a generic type with the same API as `Plain`:\n\n* `Plain.AllowString<T, { Omit: keyof T; Optional: keyof T } >`\n* `Plain.AllowString.Partial<T>`\n* `Plain.AllowString.PartialDeep<T>`\n\n### One document, multiple shapes\n\nIn each of your models, some fields might be present when you read the document from the database, but optional or even absent when you create it. 😕\n\nGiven the following model:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field({ type: Boolean, default: () => false })\n  activated: boolean\n\n  @CreatedAt\n  createdAt: Date\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThis is how you can type `constructor` and `create` parameters:\n\n```ts\ntype NewUser = Plain.AllowString<User, { Omit: 'fullname' | 'createdAt'; Optional: '_id' | 'activated' }>\n\n@Model()\nclass User extends Model.I<typeof User>  {\n  // @ts-ignore implementation\n  constructor(doc?: NewUser, strict?: boolean | 'throw')\n}\n\nconst user = new User({ firstname: 'John', lastname: 'Doe' })\nawait user.save()\nawait User.create({ firstname: 'Jeremy', lastname: 'Doe', activated: true })\n```\n\nBy passing `typeof User` to `Model.I`, Reflet is now able to use the constructor signature to type the following static methods: `create`, `insertMany` and `replaceOne`.\n\n_The compiler checks `NewUser` as we need, so you can safely use ts-ignore on the `constructor` to avoid implementing an empty one (remember that `@Model` will replace it with mongoose Model constructor)._\n\n## Augmentations\n\nReflet comes with a dedicated global namespace `RefletMongoose`, so you can augment or narrow specific types.\n\n### SchemaType options augmentation\n\nIf you use plugins like [mongoose-autopopulate](https://github.com/mongodb-js/mongoose-autopopulate),\nyou can augment the global interface `SchemaTypeOptions` to have new options in the `@Field` API.\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface SchemaTypeOptions {\n      autopopulate?: boolean\n    }\n  }\n}\n```\n\nNow you have access to `autopopulate` option in your schemas:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: Company,\n    autopopulate: true\n  })\n  company: Company\n}\n```\n\n#### Virtual options\n\nThe same can be done with the `@Virtual` decorator:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface VirtualOptions {}\n  }\n}\n```\n\n### Model and Document augmentation\n\nYou can augment `Model` and `Document` interfaces with the dedicated global interfaces.\nHere is an example with the [@casl/mongoose](https://github.com/stalniy/casl/tree/master/packages/casl-mongoose) plugin:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface Model {\n      accessibleBy<T extends mongoose.Document>(ability: AnyMongoAbility, action?: string): mongoose.DocumentQuery<T[], T>\n    }\n    interface Document {}\n  }\n}\n```\n\n### References narrowing\n\n[SchemaType `ref` option](https://mongoosejs.com/docs/api#schematypeoptions_SchemaTypeOptions-ref) can be either a Model or a model name. With Reflet, by default, any class can be passed as a Model and any string can be passed as a model name.\n\nBy augmenting the global interface `Ref`, you can:\n\n* Narrow the class to an union of your models.\n* Narrow the string to an union of your models' names.\n\n```ts\n// company.model.ts\n@Model()\nclass Company extends Model.I {\n  @Field(String)\n  name: string\n}\n\n// You should augment the global interface in each of your models' files, to keep it close to the model.\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      Company: Company\n    }\n  }\n}\n```\n\n```ts\n// user.model.ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: 'Company',\n  })\n  company: Company\n}\n\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      User: User\n    }\n  }\n}\n```\n","readmeFilename":"README.MD","bugs":{"url":"https://github.com/jeremyben/reflet/issues"},"_id":"@reflet/mongoose@2.0.0-next.2","_nodeVersion":"14.17.4","_npmVersion":"lerna/4.0.0/node@v14.17.4+x64 (win32)","dist":{"integrity":"sha512-2dcdklSlbN7ITtJ0ZbOFha2JnfQOZT40jOCOzGmxKKC+I5nS6S4AkImeGRbazRaRauOFGO/XIFmzuekIFCE8cw==","shasum":"b4f7e6a4b77a865f34a3c53955309b84a046a605","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-2.0.0-next.2.tgz","fileCount":17,"unpackedSize":132563,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCiYLTM+74/LPs5hkGxy2oZ0HSe1fscFkAycezlQ6hwJwIhAOzdxZCRA2ahywMPVYL6gri5Itb30yG6aMvCLOYRbGlh"}]},"_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"directories":{},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_2.0.0-next.2_1632431936209_0.20888876560114555"},"_hasShrinkwrap":false},"2.0.0-next.3":{"name":"@reflet/mongoose","version":"2.0.0-next.3","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/jeremyben/reflet.git","directory":"mongoose"},"homepage":"https://github.com/jeremyben/reflet/tree/master/mongoose#readme","description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/node":">=8","mongoose":">=6","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^2.1.0","mongoose":"^6.0.7"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"555c3d38e85b5cf9546bae0f7b2868f75b7211e4","readme":"# `@reflet/mongoose` 🌠\n\n[![lines coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=lines&query=total.lines.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![statements coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=statements&query=total.statements.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![functions coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=functions&query=total.functions.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![branches coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=branches&query=total.branches.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n\nThe **best** decorators for [Mongoose](https://mongoosejs.com/). Have a look at [Reflet's philosophy](../README.MD#Philosophy-).\n\n* [Getting started](#getting-started)\n* [Schema definition](#schema-definition)\n* [Model](#model)\n* [Schema options](#schema-options)\n* [Schema retrieval](#schema-retrieval)\n* [Hooks](#hooks)\n* [Model discriminators](#model-discriminators)\n* [Embedded discriminators](#embedded-discriminators)\n* [Populated virtuals](#populated-virtuals)\n* [Plain helper](#plain-helper)\n* [Augmentations](#augmentations)\n\n## Getting started\n\n1. <details>\n    <summary>Make sure you have decorators enabled. (click for details)</summary>\n    <p>\n\n    * Enable them in your TypeScript compiler options.\n\n        ```json\n        \"experimentalDecorators\": true,\n        \"emitDecoratorMetadata\": true,\n        ```\n\n    * Install `reflect-metadata` shim.\n\n        ```sh\n        yarn add reflect-metadata\n        ```\n\n    * Import the shim in your program before everything else.\n\n        ```ts\n        import 'reflect-metadata'\n        ```\n\n    </p>\n    </details>\n\n2. Install the package along with peer dependencies.\n\n    ```sh\n    yarn add @reflet/mongoose mongoose && yarn add -D @types/mongoose @types/node\n    ```\n\n3. Create your decorated models.\n\n    ```ts\n    // user.model.ts\n    import { Model, Field } from '@reflet/mongoose'\n\n    @Model()\n    export class User extends Model.Interface {\n      static findByEmail(email) {\n        return this.findOne({ email });\n      }\n\n      @Fied({ type: String, required: true })\n      email: string\n\n      getProfileUrl() {\n        return `https://mysite.com/${this.email}`;\n      }\n    }\n    ```\n\n4. Connect to MongoDB and save your documents.\n\n    ```ts\n    // server.ts\n    import 'reflect-metadata'\n    import * as mongoose from 'mongoose'\n    import { User } from './user.model.ts'\n\n    mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true })\n\n    User.create({ email: 'jeremy@example.com' }).then((user) => {\n      console.log(`User ${user._id} has been saved.`)\n    })\n    ```\n\n### The Mongoose way\n\nConnect Mongoose in the way you already know. Models defined with Reflet will simply be attached to the default Mongoose connection.\nThis means you can **progressively** decorate your Mongoose models. 😉\n\n## Schema definition\n\n> 🔦 `@Field(schemaType)`<br>\n> 💫 Related Mongoose object: [SchemaTypes](https://mongoosejs.com/docs/schematypes)\n\nMongoose [already](https://mongoosejs.com/docs/api#schema_Schema-loadClass) allows you to load an ES6 class to attach getters, setters, instance and static methods to a schema.\nBut what about properties ? Enters the `@Field` decorator :\n\n```ts\nclass User {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field(Number)\n  age?: number\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThe `@Field` API is a direct wrapper of Mongoose [SchemaType](https://mongoosejs.com/docs/schematypes), you can put in there everything that you used to.\n\n### Nested properties\n\n> 🔦 `@Field.Nested(schemaTypes)`\n\n```ts\nclass User {\n  @Field.Nested({\n    street: { type: String, required: true },\n    city: { type: String, required: true },\n    country: { type: String, required: true },\n  })\n  address: {\n    street: string\n    city: string\n    country: string\n  }\n}\n```\n\n_`@Field.Nested` works the same as `@Field` at runtime. Its type is simply looser to allow nested objects._\n\n## Model\n\n> 🔦 `@Model(collection?, connection?)`<br>\n> 💫 Related Mongoose method: [`model`](https://mongoosejs.com/docs/models#compiling)\n\nTypeScript [class decorators](https://www.typescriptlang.org/docs/handbook/decorators#class-decorators) can modify and even replace class constructors. Reflet takes advantage of this feature and transforms a class directly into a Mongoose Model.\n\nThis means you don't have to deal with the procedural and separate creation of both schema and model anymore !\nAnd now your properties and methods are statically typed.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\nclass User extends Model.Interface {\n  @Field({ type: String, required: true })\n  email: string\n}\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  email: string\n}\n\nconst userSchema = new mongoose.Schema({\n  email: { type: String, required: true }\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nYour class needs to inherit a special empty class, **`Model.Interface`** or **`Model.I`**, to have Mongoose document properties and methods.\n\n⚠️ `@Model` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n#### Custom collection name\n\nBy default, Mongoose automatically creates a collection named as the plural, lowercased version of your model name. You can customize the collection name, with the first argument:\n\n```ts\n@Model('people')\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n#### Custom Mongoose connection\n\nYou can use a different database by creating a Mongoose connection and passing it as the second argument:\n\n```ts\nconst otherDb = mongoose.createConnection('mongodb://localhost/other', { useNewUrlParser: true })\n\n@Model(undefined, otherDb)\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n## Schema options\n\n> 🔦 `@SchemaOptions(options)`<br>\n> 💫 Related Mongoose object: [Schema options](https://mongoosejs.com/docs/guide#options)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({\n  autoIndex: false,\n  strict: 'throw'\n})\nclass User extends Model.I {           \n  @Field(String)\n  name: string\n}\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    autoIndex: false,\n    strict: 'throw'\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@SchemaOptions` API is a direct wrapper of Mongoose [schema options](https://mongoosejs.com/docs/guide#options), you can put in there everything that you used to.\n\n### Timestamps\n\n> 🔦 `@CreatedAt`, `@UpdatedAt`<br>\n> 💫 Related Mongoose option property: [`timestamps`](https://mongoosejs.com/docs/guide#timestamps)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({ minimize: false })\nclass User extends Model.I {             \n  @Field(String)\n  name: string\n\n  @CreatedAt\n  creationDate: Date\n\n  @UpdatedAt\n  updateDate: Date\n}\n\n\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n  creationDate: Date\n  updateDate: Date\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    minimize: false,\n    timestamps: {\n      createdAt: 'creationDate',\n      updatedAt: 'updateDate'\n    },\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n### Advanced schema manipulation\n\n> 🔦 `@SchemaCallback(callback)`<br>\n> 💫 Related Mongoose object: [`Schema`](https://mongoosejs.com/docs/api/schema)\n\nIf you need more advanced schema manipulation before `@Model` compiles it, you can use `@SchemaCallback`:\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaCallback((schema) => {\n  schema.index({ name: 1, type: -1 })\n})\nclass Animal extends Model.I {          \n  @Field(String)\n  name: string\n\n  @Field(String)\n  type: string\n}\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface AnimalDocument extends mongoose.Document {\n  name: string\n  type: string\n}\n\nconst userSchema = new mongoose.Schema({\n  name: String,\n  type: String\n})\n\nuserSchema.index({ name: 1, type: -1 })\n\nconst Animal = mongoose.model<AnimalDocument>('Animal', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n_Beware of defining hooks in the callback if your schema has embedded discriminators. Mongoose documentation recommends declaring hooks **before** embedded discriminators, the callback is applied **after** them. You should use the dedicated hooks decorators `@PreHook` and `@PostHook`._\n\n## Schema retrieval\n\n> 🔦 `schemaFrom(class)`\n\nYou can retrieve a schema from any decorated class, for advanced manipulation or embedded use in another schema.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Location {\n  @Field(Number)\n  lat: number\n\n  @Field(Number)\n  lng: number\n}\n\n@Model()\nclass City extends Model.I {            \n  @Field(String)\n  name: string\n\n  @Field(schemaFrom(Location))\n  location: Location\n}\n\nconst citySchema = schemaFrom(City)\n```\n\n  </td>\n  <td>\n\n```ts\ninterface CityDocument extends mongoose.Document {\n  name: string\n  location: {\n    lat: number,\n    lng: number\n  }\n}\n\nconst locationSchema = new mongoose.Schema(\n  { lat: Number, lng: Number },\n  { _id: false }\n)\n\nconst citySchema = new mongoose.Schema({\n  name: String,\n  location: locationSchema\n})\n\nconst City = mongoose.model<CityDocument>('City', citySchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n🗣️ As a good practice, you should make your schema-only classes `abstract`, so you don't instantiate them by mistake.\n\n\n### Sub schemas\n\n> 🔦 `Field.Schema(class)`\n\nAs an alternative for the above use of `schemaFrom` inside the `Field` decorator, you can do:\n\n```ts\n@Model()\nclass City extends Model.I {            \n  @Field.Schema(Location)\n  location: Location\n}\n```\n\n## Hooks\n\n### Pre hook\n\n> 🔦 `@PreHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.pre`](https://mongoosejs.com/docs/middleware#pre)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PreHook<User>('save', function(next) {\n  next()\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.pre<UserDocument>('save', function (doc, next) {\n  next()\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PreHook` API is a direct wrapper of Mongoose [Schema.pre method](https://mongoosejs.com/docs/api/schema#schema_Schema-pre), you can put in there everything that you used to.\n\n### Post hook\n\n> 🔦 `@PostHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.post`](https://mongoosejs.com/docs/middleware#post)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PostHook<User>('find', function(result) {\n  console.log(result)\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.post<UserDocument>('find', function (result) {\n  console.log(result)\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PostHook` API is a direct wrapper of Mongoose [Schema.post method](https://mongoosejs.com/docs/api/schema#schema_Schema-post), you can put in there everything that you used to.\n\n#### Post error handling middleware\n\nTo help the compiler accurately infer the [error handling middleware](https://mongoosejs.com/docs/middleware#error-handling-middleware) signature, pass a second type argument to `@PostHook`:\n\n```ts\n@Model()\n@PostHook<User, Error>('save', function(error, doc, next) {\n  if (error.name === 'MongoError' && error.code === 11000) {\n    next(new Error('There was a duplicate key error'))\n  } else {\n    next()\n  }\n})\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n```\n\n## Model discriminators\n\n> 🔦 `@Model.Discriminator(rootModel)`<br>\n> 💫 Related Mongoose method: [`model.discriminator`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Worker extends User {\n  @Field(String)\n  job: string\n\n  // No need to decorate the default discriminatorKey.\n  __t: 'Worker'\n\n  // You can strictly type the constructor of a discriminator model by using the Plain Helper (see below).\n  constructor(worker: Plain.Omit<Worker, '_id' | '__t'>) {\n    super() // required by the compiler.\n  }\n}\n\nconst worker = await Worker.create({ name: 'Jeremy', job: 'developer' })\n// { _id: '5d023ae14043262bcfd9b384', __t: 'Worker', name: 'Jeremy', job: 'developer' }\n```\n\nAs you know, `_t` is the default `discriminatorKey`, and its value will be the class name. If you want to customize both the key and the value, check out the following `@Kind` decorator.\n\n⚠️ `@Model.Discriminator` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model.Discriminator` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n### Kind / DiscriminatorKey\n\n> 🔦 `@Kind(value?)` alias `@DiscriminatorKey`<br>\n> 💫 Related Mongoose option property: [`discriminatorKey`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\nMongoose `discriminatorKey` is usually defined in the parent model options, and appears in the children model documents.\n`@Kind` (or its alias `@DiscriminatorKey`) exists to define `discriminatorKey` **directly** on the children class instead of the parent model.\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Developer extends User {\n  @Kind\n  kind: 'Developer' // Value will be the class name by default.\n}\n\n@Model.Discriminator(User)\nclass Doctor extends User {\n  @Kind('doctor') // Customize the discriminator value by passing a string.\n  kind: 'doctor'\n}\n\n// This is equivalent to setting `{ discriminatorKey: 'kind' }` on User schema options.\n```\n\nA mecanism will check and prevent you from defining a different `@Kind` key on sibling discriminators.\n\n## Embedded discriminators\n\n### Single nested discriminators\n\n> 🔦 `@Field.Union(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`SingleNestedPath.discriminator`](https://mongoosejs.com/docs/discriminators#single-nested-discriminators)\n\n`@Field.Union` allows you to embed discriminators on an single property.\n\n```ts\nabstract class Circle {\n  @Field(Number)\n  radius: number\n\n  __t: 'Circle'\n  // __t is the default discriminatorKey (no need to decorate).\n  // Value will be the class name.\n}\n\nabstract class Square {\n  @Field(Number)\n  side: number\n\n  __t: 'Square'\n}\n\n@Model()\nclass Shape extends Model.I {\n  @Field.Union([Circle, Square], { \n    required: true, // Make the field itself `shape` required.\n    strict: true // Make the discriminator key `__t` required and narrowed to its possible values.\n  })\n  shape: Circle | Square\n}\n\nconst circle = new Shape({ shape: { __t: 'Circle', radius: 5 } })\nconst square = new Shape({ shape: { __t: 'Square', side: 4 } })\n```\n\n### Embedded discriminators in arrays\n\n> 🔦 `@Field.ArrayOfUnion(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`DocumentArrayPath.discriminator`](https://mongoosejs.com/docs/discriminators#embedded-discriminators-in-arrays)\n\n`@Field.ArrayOfUnion` allows you to embed discriminators in an array.\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Clicked {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  element: string\n\n  @Kind\n  kind: 'Clicked'\n}\n\n@SchemaOptions({ _id: false })\nabstract class Purchased {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  product: string\n\n  @Kind\n  kind: 'Purchased'\n}\n\n@Model()\nclass Batch extends Model.I {\n  @Field.ArrayOfUnion([Clicked, Purchased], { \n    strict: true  // Make the discriminator key `kind` required and narrowed to its possible values.\n  })\n  events: (Clicked | Purchased)[]\n}\n\nconst batch = new Batch({\n  events: [\n    { kind: 'Clicked', element: '#hero', message: 'hello' },\n    { kind: 'Purchased', product: 'action-figure', message: 'world' },\n  ]\n})\n```\n\n## Populated virtuals\n\n> 🔦 `@Virtual(options)`<br>\n> 💫 Related Mongoose method: [`schema.virtual`](https://mongoosejs.com/docs/populate#populate-virtuals)\n\n```ts\n@Model()\nclass Person extends Model.I {\n  @Field(String)\n  name: string\n\n  @Field(String)\n  band: string\n}\n\n@Model()\n@SchemaOptions({\n  toObject: { virtuals: true },\n  toJson: { virtuals: true }\n})\nclass Band extends Model.I {\n  @Field(String)\n  name: string\n\n  @Virtual<Person, Band>({\n    ref: 'Person',\n    foreignField: 'band',\n    localField: 'name'\n  })\n  readonly members: string[]\n}\n\nconst bands = await Band.find({}).populate('members')\n```\n\n## Plain helper\n\n> 🔦 `Plain<class, options?>`\n\nReflet provides a generic type to discard Mongoose properties and methods from a Document.\n\n* `Plain<T>` removes inherited Mongoose properties (except `_id`) and all methods from `T`.\n* `Plain.Partial<T>` does the same as `Plain` and makes remaining properties of `T` optional.\n* `Plain.PartialDeep<T>` does the same as `Plain.Partial` recursively.\n\n`Plain` also has a second type argument to omit other properties and/or make them optional:\n\n* `Plain<T, { Omit: keyof T; Optional: keyof T } >`\n\n_These options exist as standalone generics as well: `Plain.Omit<T, keyof T>` and `Plain.Optional<T, keyof T>`._\n\nWith this you can narrow the return type of `toObject()` and `toJson()`:\n\n```ts\nconst userPlain = user.toObject({ getters: false }) as Plain.Omit<User, 'fullname'>\n```\n\n#### Allow `string` for `ObjectId`\n\n> 🔦 `Plain.AllowString<class, options?>`\n\nWhen creating or querying documents, you can pass `ObjectId` as `string`. To allow this, Reflet provides a generic type with the same API as `Plain`:\n\n* `Plain.AllowString<T, { Omit: keyof T; Optional: keyof T } >`\n* `Plain.AllowString.Partial<T>`\n* `Plain.AllowString.PartialDeep<T>`\n\n### One document, multiple shapes\n\nIn each of your models, some fields might be present when you read the document from the database, but optional or even absent when you create it. 😕\n\nGiven the following model:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field({ type: Boolean, default: () => false })\n  activated: boolean\n\n  @CreatedAt\n  createdAt: Date\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThis is how you can type `constructor` and `create` parameters:\n\n```ts\ntype NewUser = Plain.AllowString<User, { Omit: 'fullname' | 'createdAt'; Optional: '_id' | 'activated' }>\n\n@Model()\nclass User extends Model.I<typeof User>  {\n  // @ts-ignore implementation\n  constructor(doc?: NewUser, strict?: boolean | 'throw')\n}\n\nconst user = new User({ firstname: 'John', lastname: 'Doe' })\nawait user.save()\nawait User.create({ firstname: 'Jeremy', lastname: 'Doe', activated: true })\n```\n\nBy passing `typeof User` to `Model.I`, Reflet is now able to use the constructor signature to type the following static methods: `create`, `insertMany` and `replaceOne`.\n\n_The compiler checks `NewUser` as we need, so you can safely use ts-ignore on the `constructor` to avoid implementing an empty one (remember that `@Model` will replace it with mongoose Model constructor)._\n\n## Augmentations\n\nReflet comes with a dedicated global namespace `RefletMongoose`, so you can augment or narrow specific types.\n\n### SchemaType options augmentation\n\nIf you use plugins like [mongoose-autopopulate](https://github.com/mongodb-js/mongoose-autopopulate),\nyou can augment the global interface `SchemaTypeOptions` to have new options in the `@Field` API.\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface SchemaTypeOptions {\n      autopopulate?: boolean\n    }\n  }\n}\n```\n\nNow you have access to `autopopulate` option in your schemas:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: Company,\n    autopopulate: true\n  })\n  company: Company\n}\n```\n\n#### Virtual options\n\nThe same can be done with the `@Virtual` decorator:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface VirtualOptions {}\n  }\n}\n```\n\n### Model and Document augmentation\n\nYou can augment `Model` and `Document` interfaces with the dedicated global interfaces.\nHere is an example with the [@casl/mongoose](https://github.com/stalniy/casl/tree/master/packages/casl-mongoose) plugin:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface Model {\n      accessibleBy<T extends mongoose.Document>(ability: AnyMongoAbility, action?: string): mongoose.DocumentQuery<T[], T>\n    }\n    interface Document {}\n  }\n}\n```\n\n### References narrowing\n\n[SchemaType `ref` option](https://mongoosejs.com/docs/api#schematypeoptions_SchemaTypeOptions-ref) can be either a Model or a model name. With Reflet, by default, any class can be passed as a Model and any string can be passed as a model name.\n\nBy augmenting the global interface `Ref`, you can:\n\n* Narrow the class to an union of your models.\n* Narrow the string to an union of your models' names.\n\n```ts\n// company.model.ts\n@Model()\nclass Company extends Model.I {\n  @Field(String)\n  name: string\n}\n\n// You should augment the global interface in each of your models' files, to keep it close to the model.\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      Company: Company\n    }\n  }\n}\n```\n\n```ts\n// user.model.ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: 'Company',\n  })\n  company: Company\n}\n\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      User: User\n    }\n  }\n}\n```\n","readmeFilename":"README.MD","bugs":{"url":"https://github.com/jeremyben/reflet/issues"},"_id":"@reflet/mongoose@2.0.0-next.3","_nodeVersion":"14.17.4","_npmVersion":"lerna/4.0.0/node@v14.17.4+x64 (win32)","dist":{"integrity":"sha512-6Kjf95/BSUI99Rksgl4CLKdO5NRZKJUvaurFHMQKsE1xt79VBi92rGwZQ1/dsb1cOpHSNMny9X+FnlpdAqnPig==","shasum":"481e5a93dbb711e68c1c7db24f0083e79b4acb6b","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-2.0.0-next.3.tgz","fileCount":17,"unpackedSize":132352,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDOH13lKADN3hZk/we47tGu3fzJA2k0XjFE1PC6dXeS7QIgLM50USh1XEhCnIbxCk9yr2fXbBsOrQ5MrAfNFOd4dJI="}]},"_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"directories":{},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_2.0.0-next.3_1633386939798_0.5591152003805833"},"_hasShrinkwrap":false},"2.0.0-next.4":{"name":"@reflet/mongoose","version":"2.0.0-next.4","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/jeremyben/reflet.git","directory":"mongoose"},"homepage":"https://github.com/jeremyben/reflet/tree/master/mongoose#readme","description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=8.10"},"engineStrict":true,"peerDependencies":{"@types/node":">=8","mongoose":">=6","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^2.1.0","mongoose":"^6.0.12","mongoose-autopopulate":"^0.16.0"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"e419b54ee676ede7c05cff293ce40421660461a7","readme":"# `@reflet/mongoose` 🌠\n\n[![lines coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=lines&query=total.lines.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![statements coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=statements&query=total.statements.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![functions coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=functions&query=total.functions.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![branches coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=branches&query=total.branches.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n\nThe **best** decorators for [Mongoose](https://mongoosejs.com/). Have a look at [Reflet's philosophy](../README.MD#Philosophy-).\n\n* [Getting started](#getting-started)\n* [Schema definition](#schema-definition)\n* [Model](#model)\n* [Schema options](#schema-options)\n* [Schema retrieval](#schema-retrieval)\n* [Hooks](#hooks)\n* [Model discriminators](#model-discriminators)\n* [Embedded discriminators](#embedded-discriminators)\n* [Populated virtuals](#populated-virtuals)\n* [Plain helper](#plain-helper)\n* [Augmentations](#augmentations)\n\n## Getting started\n\n1. <details>\n    <summary>Make sure you have decorators enabled. (click for details)</summary>\n    <p>\n\n    * Enable them in your TypeScript compiler options.\n\n        ```json\n        \"experimentalDecorators\": true,\n        \"emitDecoratorMetadata\": true,\n        ```\n\n    * Install `reflect-metadata` shim.\n\n        ```sh\n        yarn add reflect-metadata\n        ```\n\n    * Import the shim in your program before everything else.\n\n        ```ts\n        import 'reflect-metadata'\n        ```\n\n    </p>\n    </details>\n\n2. Install the package along with peer dependencies.\n\n    ```sh\n    yarn add @reflet/mongoose mongoose && yarn add -D @types/mongoose @types/node\n    ```\n\n3. Create your decorated models.\n\n    ```ts\n    // user.model.ts\n    import { Model, Field } from '@reflet/mongoose'\n\n    @Model()\n    export class User extends Model.Interface {\n      static findByEmail(email) {\n        return this.findOne({ email });\n      }\n\n      @Fied({ type: String, required: true })\n      email: string\n\n      getProfileUrl() {\n        return `https://mysite.com/${this.email}`;\n      }\n    }\n    ```\n\n4. Connect to MongoDB and save your documents.\n\n    ```ts\n    // server.ts\n    import 'reflect-metadata'\n    import * as mongoose from 'mongoose'\n    import { User } from './user.model.ts'\n\n    mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true })\n\n    User.create({ email: 'jeremy@example.com' }).then((user) => {\n      console.log(`User ${user._id} has been saved.`)\n    })\n    ```\n\n### The Mongoose way\n\nConnect Mongoose in the way you already know. Models defined with Reflet will simply be attached to the default Mongoose connection.\nThis means you can **progressively** decorate your Mongoose models. 😉\n\n## Schema definition\n\n> 🔦 `@Field(schemaType)`<br>\n> 💫 Related Mongoose object: [SchemaTypes](https://mongoosejs.com/docs/schematypes)\n\nMongoose [already](https://mongoosejs.com/docs/api#schema_Schema-loadClass) allows you to load an ES6 class to attach getters, setters, instance and static methods to a schema.\nBut what about properties ? Enters the `@Field` decorator :\n\n```ts\nclass User {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field(Number)\n  age?: number\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThe `@Field` API is a direct wrapper of Mongoose [SchemaType](https://mongoosejs.com/docs/schematypes), you can put in there everything that you used to.\n\n### Nested properties\n\n> 🔦 `@Field.Nested(schemaTypes)`\n\n```ts\nclass User {\n  @Field.Nested({\n    street: { type: String, required: true },\n    city: { type: String, required: true },\n    country: { type: String, required: true },\n  })\n  address: {\n    street: string\n    city: string\n    country: string\n  }\n}\n```\n\n_`@Field.Nested` works the same as `@Field` at runtime. Its type is simply looser to allow nested objects._\n\n## Model\n\n> 🔦 `@Model(collection?, connection?)`<br>\n> 💫 Related Mongoose method: [`model`](https://mongoosejs.com/docs/models#compiling)\n\nTypeScript [class decorators](https://www.typescriptlang.org/docs/handbook/decorators#class-decorators) can modify and even replace class constructors. Reflet takes advantage of this feature and transforms a class directly into a Mongoose Model.\n\nThis means you don't have to deal with the procedural and separate creation of both schema and model anymore !\nAnd now your properties and methods are statically typed.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\nclass User extends Model.Interface {\n  @Field({ type: String, required: true })\n  email: string\n}\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  email: string\n}\n\nconst userSchema = new mongoose.Schema({\n  email: { type: String, required: true }\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nYour class needs to inherit a special empty class, **`Model.Interface`** or **`Model.I`**, to have Mongoose document properties and methods.\n\n⚠️ `@Model` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n#### Custom collection name\n\nBy default, Mongoose automatically creates a collection named as the plural, lowercased version of your model name. You can customize the collection name, with the first argument:\n\n```ts\n@Model('people')\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n#### Custom Mongoose connection\n\nYou can use a different database by creating a Mongoose connection and passing it as the second argument:\n\n```ts\nconst otherDb = mongoose.createConnection('mongodb://localhost/other', { useNewUrlParser: true })\n\n@Model(undefined, otherDb)\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n## Schema options\n\n> 🔦 `@SchemaOptions(options)`<br>\n> 💫 Related Mongoose object: [Schema options](https://mongoosejs.com/docs/guide#options)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({\n  autoIndex: false,\n  strict: 'throw'\n})\nclass User extends Model.I {           \n  @Field(String)\n  name: string\n}\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    autoIndex: false,\n    strict: 'throw'\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@SchemaOptions` API is a direct wrapper of Mongoose [schema options](https://mongoosejs.com/docs/guide#options), you can put in there everything that you used to.\n\n### Timestamps\n\n> 🔦 `@CreatedAt`, `@UpdatedAt`<br>\n> 💫 Related Mongoose option property: [`timestamps`](https://mongoosejs.com/docs/guide#timestamps)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({ minimize: false })\nclass User extends Model.I {             \n  @Field(String)\n  name: string\n\n  @CreatedAt\n  creationDate: Date\n\n  @UpdatedAt\n  updateDate: Date\n}\n\n\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n  creationDate: Date\n  updateDate: Date\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    minimize: false,\n    timestamps: {\n      createdAt: 'creationDate',\n      updatedAt: 'updateDate'\n    },\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n### Advanced schema manipulation\n\n> 🔦 `@SchemaCallback(callback)`<br>\n> 💫 Related Mongoose object: [`Schema`](https://mongoosejs.com/docs/api/schema)\n\nIf you need more advanced schema manipulation before `@Model` compiles it, you can use `@SchemaCallback`:\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaCallback((schema) => {\n  schema.index({ name: 1, type: -1 })\n})\nclass Animal extends Model.I {          \n  @Field(String)\n  name: string\n\n  @Field(String)\n  type: string\n}\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface AnimalDocument extends mongoose.Document {\n  name: string\n  type: string\n}\n\nconst userSchema = new mongoose.Schema({\n  name: String,\n  type: String\n})\n\nuserSchema.index({ name: 1, type: -1 })\n\nconst Animal = mongoose.model<AnimalDocument>('Animal', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n_Beware of defining hooks in the callback if your schema has embedded discriminators. Mongoose documentation recommends declaring hooks **before** embedded discriminators, the callback is applied **after** them. You should use the dedicated hooks decorators `@PreHook` and `@PostHook`._\n\n## Schema retrieval\n\n> 🔦 `schemaFrom(class)`\n\nYou can retrieve a schema from any decorated class, for advanced manipulation or embedded use in another schema.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Location {\n  @Field(Number)\n  lat: number\n\n  @Field(Number)\n  lng: number\n}\n\n@Model()\nclass City extends Model.I {            \n  @Field(String)\n  name: string\n\n  @Field(schemaFrom(Location))\n  location: Location\n}\n\nconst citySchema = schemaFrom(City)\n```\n\n  </td>\n  <td>\n\n```ts\ninterface CityDocument extends mongoose.Document {\n  name: string\n  location: {\n    lat: number,\n    lng: number\n  }\n}\n\nconst locationSchema = new mongoose.Schema(\n  { lat: Number, lng: Number },\n  { _id: false }\n)\n\nconst citySchema = new mongoose.Schema({\n  name: String,\n  location: locationSchema\n})\n\nconst City = mongoose.model<CityDocument>('City', citySchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n🗣️ As a good practice, you should make your schema-only classes `abstract`, so you don't instantiate them by mistake.\n\n\n### Sub schemas\n\n> 🔦 `Field.Schema(class)`\n\nAs an alternative for the above use of `schemaFrom` inside the `Field` decorator, you can do:\n\n```ts\n@Model()\nclass City extends Model.I {            \n  @Field.Schema(Location)\n  location: Location\n}\n```\n\n## Hooks\n\n### Pre hook\n\n> 🔦 `@PreHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.pre`](https://mongoosejs.com/docs/middleware#pre)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PreHook<User>('save', function(next) {\n  next()\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.pre<UserDocument>('save', function (doc, next) {\n  next()\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PreHook` API is a direct wrapper of Mongoose [Schema.pre method](https://mongoosejs.com/docs/api/schema#schema_Schema-pre), you can put in there everything that you used to.\n\nSuccessive `@PreHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n### Post hook\n\n> 🔦 `@PostHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.post`](https://mongoosejs.com/docs/middleware#post)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PostHook<User>('find', function(result) {\n  console.log(result)\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.post<UserDocument>('find', function (result) {\n  console.log(result)\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PostHook` API is a direct wrapper of Mongoose [Schema.post method](https://mongoosejs.com/docs/api/schema#schema_Schema-post), you can put in there everything that you used to.\n\nSuccessive `@PostHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n#### Post error handling middleware\n\nTo help the compiler accurately infer the [error handling middleware](https://mongoosejs.com/docs/middleware#error-handling-middleware) signature, pass a second type argument to `@PostHook`:\n\n```ts\n@Model()\n@PostHook<User, Error>('save', function(error, doc, next) {\n  if (error.name === 'MongoError' && error.code === 11000) {\n    next(new Error('There was a duplicate key error'))\n  } else {\n    next()\n  }\n})\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n```\n\n## Model discriminators\n\n> 🔦 `@Model.Discriminator(rootModel)`<br>\n> 💫 Related Mongoose method: [`model.discriminator`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Worker extends User {\n  @Field(String)\n  job: string\n\n  // No need to decorate the default discriminatorKey.\n  __t: 'Worker'\n\n  // You can strictly type the constructor of a discriminator model by using the Plain Helper (see below).\n  constructor(worker: Plain.Omit<Worker, '_id' | '__t'>) {\n    super() // required by the compiler.\n  }\n}\n\nconst worker = await Worker.create({ name: 'Jeremy', job: 'developer' })\n// { _id: '5d023ae14043262bcfd9b384', __t: 'Worker', name: 'Jeremy', job: 'developer' }\n```\n\nAs you know, `_t` is the default `discriminatorKey`, and its value will be the class name. If you want to customize both the key and the value, check out the following `@Kind` decorator.\n\n⚠️ `@Model.Discriminator` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model.Discriminator` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n### Kind / DiscriminatorKey\n\n> 🔦 `@Kind(value?)` alias `@DiscriminatorKey`<br>\n> 💫 Related Mongoose option property: [`discriminatorKey`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\nMongoose `discriminatorKey` is usually defined in the parent model options, and appears in the children model documents.\n`@Kind` (or its alias `@DiscriminatorKey`) exists to define `discriminatorKey` **directly** on the children class instead of the parent model.\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Developer extends User {\n  @Kind\n  kind: 'Developer' // Value will be the class name by default.\n}\n\n@Model.Discriminator(User)\nclass Doctor extends User {\n  @Kind('doctor') // Customize the discriminator value by passing a string.\n  kind: 'doctor'\n}\n\n// This is equivalent to setting `{ discriminatorKey: 'kind' }` on User schema options.\n```\n\nA mecanism will check and prevent you from defining a different `@Kind` key on sibling discriminators.\n\n## Embedded discriminators\n\n### Single nested discriminators\n\n> 🔦 `@Field.Union(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`SingleNestedPath.discriminator`](https://mongoosejs.com/docs/discriminators#single-nested-discriminators)\n\n`@Field.Union` allows you to embed discriminators on an single property.\n\n```ts\nabstract class Circle {\n  @Field(Number)\n  radius: number\n\n  __t: 'Circle'\n  // __t is the default discriminatorKey (no need to decorate).\n  // Value will be the class name.\n}\n\nabstract class Square {\n  @Field(Number)\n  side: number\n\n  __t: 'Square'\n}\n\n@Model()\nclass Shape extends Model.I {\n  @Field.Union([Circle, Square], { \n    required: true, // Make the field itself `shape` required.\n    strict: true // Make the discriminator key `__t` required and narrowed to its possible values.\n  })\n  shape: Circle | Square\n}\n\nconst circle = new Shape({ shape: { __t: 'Circle', radius: 5 } })\nconst square = new Shape({ shape: { __t: 'Square', side: 4 } })\n```\n\n### Embedded discriminators in arrays\n\n> 🔦 `@Field.ArrayOfUnion(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`DocumentArrayPath.discriminator`](https://mongoosejs.com/docs/discriminators#embedded-discriminators-in-arrays)\n\n`@Field.ArrayOfUnion` allows you to embed discriminators in an array.\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Clicked {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  element: string\n\n  @Kind\n  kind: 'Clicked'\n}\n\n@SchemaOptions({ _id: false })\nabstract class Purchased {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  product: string\n\n  @Kind\n  kind: 'Purchased'\n}\n\n@Model()\nclass Batch extends Model.I {\n  @Field.ArrayOfUnion([Clicked, Purchased], { \n    strict: true  // Make the discriminator key `kind` required and narrowed to its possible values.\n  })\n  events: (Clicked | Purchased)[]\n}\n\nconst batch = new Batch({\n  events: [\n    { kind: 'Clicked', element: '#hero', message: 'hello' },\n    { kind: 'Purchased', product: 'action-figure', message: 'world' },\n  ]\n})\n```\n\n## Populated virtuals\n\n> 🔦 `@Virtual(options)`<br>\n> 💫 Related Mongoose method: [`schema.virtual`](https://mongoosejs.com/docs/populate#populate-virtuals)\n\n```ts\n@Model()\nclass Person extends Model.I {\n  @Field(String)\n  name: string\n\n  @Field(String)\n  band: string\n}\n\n@Model()\n@SchemaOptions({\n  toObject: { virtuals: true },\n  toJson: { virtuals: true }\n})\nclass Band extends Model.I {\n  @Field(String)\n  name: string\n\n  @Virtual<Band, Person>({\n    ref: 'Person',\n    foreignField: 'band',\n    localField: 'name'\n  })\n  readonly members: string[]\n}\n\nconst bands = await Band.find({}).populate('members')\n```\n\n## Plain helper\n\n> 🔦 `Plain<class, options?>`\n\nReflet provides a generic type to discard Mongoose properties and methods from a Document.\n\n* `Plain<T>` removes inherited Mongoose properties (except `_id`) and all methods from `T`.\n* `Plain.Partial<T>` does the same as `Plain` and makes remaining properties of `T` optional.\n* `Plain.PartialDeep<T>` does the same as `Plain.Partial` recursively.\n\n`Plain` also has a second type argument to omit other properties and/or make them optional:\n\n* `Plain<T, { Omit: keyof T; Optional: keyof T } >`\n\n_These options exist as standalone generics as well: `Plain.Omit<T, keyof T>` and `Plain.Optional<T, keyof T>`._\n\nWith this you can narrow the return type of `toObject()` and `toJson()`:\n\n```ts\nconst userPlain = user.toObject({ getters: false }) as Plain.Omit<User, 'fullname'>\n```\n\n#### Allow `string` for `ObjectId`\n\n> 🔦 `Plain.AllowString<class, options?>`\n\nWhen creating or querying documents, you can pass `ObjectId` as `string`. To allow this, Reflet provides a generic type with the same API as `Plain`:\n\n* `Plain.AllowString<T, { Omit: keyof T; Optional: keyof T } >`\n* `Plain.AllowString.Partial<T>`\n* `Plain.AllowString.PartialDeep<T>`\n\n### One document, multiple shapes\n\nIn each of your models, some fields might be present when you read the document from the database, but optional or even absent when you create it. 😕\n\nGiven the following model:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field({ type: Boolean, default: () => false })\n  activated: boolean\n\n  @CreatedAt\n  createdAt: Date\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThis is how you can type `constructor` and `create` parameters:\n\n```ts\ntype NewUser = Plain.AllowString<User, { Omit: 'fullname' | 'createdAt'; Optional: '_id' | 'activated' }>\n\n@Model()\nclass User extends Model.I<typeof User>  {\n  // @ts-ignore implementation\n  constructor(doc?: NewUser, strict?: boolean | 'throw')\n}\n\nconst user = new User({ firstname: 'John', lastname: 'Doe' })\nawait user.save()\nawait User.create({ firstname: 'Jeremy', lastname: 'Doe', activated: true })\n```\n\nBy passing `typeof User` to `Model.I`, Reflet is now able to use the constructor signature to type the following static methods: `create`, `insertMany` and `replaceOne`.\n\n_The compiler checks `NewUser` as we need, so you can safely use ts-ignore on the `constructor` to avoid implementing an empty one (remember that `@Model` will replace it with mongoose Model constructor)._\n\n## Augmentations\n\nReflet comes with a dedicated global namespace `RefletMongoose`, so you can augment or narrow specific types.\n\n### SchemaType options augmentation\n\nIf you use plugins like [mongoose-autopopulate](https://github.com/mongodb-js/mongoose-autopopulate),\nyou can augment the global interface `SchemaTypeOptions` to have new options in the `@Field` API.\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface SchemaTypeOptions {\n      autopopulate?: boolean\n    }\n  }\n}\n```\n\nNow you have access to `autopopulate` option in your schemas:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: Company,\n    autopopulate: true\n  })\n  company: Company\n}\n```\n\n#### Virtual options\n\nThe same can be done with the `@Virtual` decorator:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface VirtualOptions {}\n  }\n}\n```\n\n### Model and Document augmentation\n\nYou can augment `Model` and `Document` interfaces with the dedicated global interfaces.\nHere is an example with the [@casl/mongoose](https://github.com/stalniy/casl/tree/master/packages/casl-mongoose) plugin:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface Model {\n      accessibleBy<T extends mongoose.Document>(ability: AnyMongoAbility, action?: string): mongoose.DocumentQuery<T[], T>\n    }\n    interface Document {}\n  }\n}\n```\n\n### References narrowing\n\n[SchemaType `ref` option](https://mongoosejs.com/docs/api#schematypeoptions_SchemaTypeOptions-ref) can be either a Model or a model name. With Reflet, by default, any class can be passed as a Model and any string can be passed as a model name.\n\nBy augmenting the global interface `Ref`, you can:\n\n* Narrow the class to an union of your models.\n* Narrow the string to an union of your models' names.\n\n```ts\n// company.model.ts\n@Model()\nclass Company extends Model.I {\n  @Field(String)\n  name: string\n}\n\n// You should augment the global interface in each of your models' files, to keep it close to the model.\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      Company: Company\n    }\n  }\n}\n```\n\n```ts\n// user.model.ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: 'Company',\n  })\n  company: Company\n}\n\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      User: User\n    }\n  }\n}\n```\n","readmeFilename":"README.MD","bugs":{"url":"https://github.com/jeremyben/reflet/issues"},"_id":"@reflet/mongoose@2.0.0-next.4","_nodeVersion":"14.17.4","_npmVersion":"lerna/4.0.0/node@v14.17.4+x64 (win32)","dist":{"integrity":"sha512-BLK0MRnY6JhCn5gcQL9Dx3+p19f7w7oTrmk+7ayZsD++nDeMmZ6onnEujQbm8oCtg9P4PvrkZq35ZlHJtMkomw==","shasum":"ea51c28ff1e5cbe9958368c2eb6fa3e8b41124fb","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-2.0.0-next.4.tgz","fileCount":20,"unpackedSize":158097,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIC1biJmmna8EdaCINl4gH/3ysy59C/LiuusLgqkA5YrjAiAEVSxJGv8Wr82ZSC/svooSeB6knSfcyXaOPasjj86Tcg=="}]},"_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"directories":{},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_2.0.0-next.4_1636650773917_0.12755303897725123"},"_hasShrinkwrap":false},"2.0.0-next.5":{"name":"@reflet/mongoose","version":"2.0.0-next.5","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/jeremyben/reflet.git","directory":"mongoose"},"homepage":"https://github.com/jeremyben/reflet/tree/master/mongoose#readme","description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=10"},"engineStrict":true,"peerDependencies":{"@types/node":">=10","mongoose":">=6","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^2.1.0","mongoose":"^6.0.12","mongoose-autopopulate":"^0.16.0"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"0789b79957a68cfa5f778d09c6a4a61946945470","readme":"# `@reflet/mongoose` 🌠\n\n[![lines coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=lines&query=total.lines.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![statements coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=statements&query=total.statements.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![functions coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=functions&query=total.functions.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![branches coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=branches&query=total.branches.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n\nThe **best** decorators for [Mongoose](https://mongoosejs.com/). Have a look at [Reflet's philosophy](../README.MD#Philosophy-).\n\n* [Getting started](#getting-started)\n* [Schema definition](#schema-definition)\n* [Model](#model)\n* [Schema options](#schema-options)\n* [Schema retrieval](#schema-retrieval)\n* [Hooks](#hooks)\n* [Model discriminators](#model-discriminators)\n* [Embedded discriminators](#embedded-discriminators)\n* [Populated virtuals](#populated-virtuals)\n* [Plain helper](#plain-helper)\n* [Augmentations](#augmentations)\n\n## Getting started\n\n1. <details>\n    <summary>Make sure you have decorators enabled. (click for details)</summary>\n    <p>\n\n    * Enable them in your TypeScript compiler options.\n\n        ```json\n        \"experimentalDecorators\": true,\n        \"emitDecoratorMetadata\": true,\n        ```\n\n    * Install `reflect-metadata` shim.\n\n        ```sh\n        yarn add reflect-metadata\n        ```\n\n    * Import the shim in your program before everything else.\n\n        ```ts\n        import 'reflect-metadata'\n        ```\n\n    </p>\n    </details>\n\n2. Install the package along with peer dependencies.\n\n    ```sh\n    yarn add @reflet/mongoose mongoose && yarn add -D @types/mongoose @types/node\n    ```\n\n3. Create your decorated models.\n\n    ```ts\n    // user.model.ts\n    import { Model, Field } from '@reflet/mongoose'\n\n    @Model()\n    export class User extends Model.Interface {\n      static findByEmail(email) {\n        return this.findOne({ email });\n      }\n\n      @Fied({ type: String, required: true })\n      email: string\n\n      getProfileUrl() {\n        return `https://mysite.com/${this.email}`;\n      }\n    }\n    ```\n\n4. Connect to MongoDB and save your documents.\n\n    ```ts\n    // server.ts\n    import 'reflect-metadata'\n    import * as mongoose from 'mongoose'\n    import { User } from './user.model.ts'\n\n    mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true })\n\n    User.create({ email: 'jeremy@example.com' }).then((user) => {\n      console.log(`User ${user._id} has been saved.`)\n    })\n    ```\n\n### The Mongoose way\n\nConnect Mongoose in the way you already know. Models defined with Reflet will simply be attached to the default Mongoose connection.\nThis means you can **progressively** decorate your Mongoose models. 😉\n\n## Schema definition\n\n> 🔦 `@Field(schemaType)`<br>\n> 💫 Related Mongoose object: [SchemaTypes](https://mongoosejs.com/docs/schematypes)\n\nMongoose [already](https://mongoosejs.com/docs/api#schema_Schema-loadClass) allows you to load an ES6 class to attach getters, setters, instance and static methods to a schema.\nBut what about properties ? Enters the `@Field` decorator :\n\n```ts\nclass User {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field(Number)\n  age?: number\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThe `@Field` API is a direct wrapper of Mongoose [SchemaType](https://mongoosejs.com/docs/schematypes), you can put in there everything that you used to.\n\n### Nested properties\n\n> 🔦 `@Field.Nested(schemaTypes)`\n\n```ts\nclass User {\n  @Field.Nested({\n    street: { type: String, required: true },\n    city: { type: String, required: true },\n    country: { type: String, required: true },\n  })\n  address: {\n    street: string\n    city: string\n    country: string\n  }\n}\n```\n\n_`@Field.Nested` works the same as `@Field` at runtime. Its type is simply looser to allow nested objects._\n\n## Model\n\n> 🔦 `@Model(collection?, connection?)`<br>\n> 💫 Related Mongoose method: [`model`](https://mongoosejs.com/docs/models#compiling)\n\nTypeScript [class decorators](https://www.typescriptlang.org/docs/handbook/decorators#class-decorators) can modify and even replace class constructors. Reflet takes advantage of this feature and transforms a class directly into a Mongoose Model.\n\nThis means you don't have to deal with the procedural and separate creation of both schema and model anymore !\nAnd now your properties and methods are statically typed.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\nclass User extends Model.Interface {\n  @Field({ type: String, required: true })\n  email: string\n}\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  email: string\n}\n\nconst userSchema = new mongoose.Schema({\n  email: { type: String, required: true }\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nYour class needs to inherit a special empty class, **`Model.Interface`** or **`Model.I`**, to have Mongoose document properties and methods.\n\n⚠️ `@Model` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n#### Custom collection name\n\nBy default, Mongoose automatically creates a collection named as the plural, lowercased version of your model name. You can customize the collection name, with the first argument:\n\n```ts\n@Model('people')\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n#### Custom Mongoose connection\n\nYou can use a different database by creating a Mongoose connection and passing it as the second argument:\n\n```ts\nconst otherDb = mongoose.createConnection('mongodb://localhost/other', { useNewUrlParser: true })\n\n@Model(undefined, otherDb)\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n## Schema options\n\n> 🔦 `@SchemaOptions(options)`<br>\n> 💫 Related Mongoose object: [Schema options](https://mongoosejs.com/docs/guide#options)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({\n  autoIndex: false,\n  strict: 'throw'\n})\nclass User extends Model.I {           \n  @Field(String)\n  name: string\n}\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    autoIndex: false,\n    strict: 'throw'\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@SchemaOptions` API is a direct wrapper of Mongoose [schema options](https://mongoosejs.com/docs/guide#options), you can put in there everything that you used to.\n\n### Timestamps\n\n> 🔦 `@CreatedAt`, `@UpdatedAt`<br>\n> 💫 Related Mongoose option property: [`timestamps`](https://mongoosejs.com/docs/guide#timestamps)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({ minimize: false })\nclass User extends Model.I {             \n  @Field(String)\n  name: string\n\n  @CreatedAt\n  creationDate: Date\n\n  @UpdatedAt\n  updateDate: Date\n}\n\n\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n  creationDate: Date\n  updateDate: Date\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    minimize: false,\n    timestamps: {\n      createdAt: 'creationDate',\n      updatedAt: 'updateDate'\n    },\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n### Advanced schema manipulation\n\n> 🔦 `@SchemaCallback(callback)`<br>\n> 💫 Related Mongoose object: [`Schema`](https://mongoosejs.com/docs/api/schema)\n\nIf you need more advanced schema manipulation before `@Model` compiles it, you can use `@SchemaCallback`:\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaCallback((schema) => {\n  schema.index({ name: 1, type: -1 })\n})\nclass Animal extends Model.I {          \n  @Field(String)\n  name: string\n\n  @Field(String)\n  type: string\n}\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface AnimalDocument extends mongoose.Document {\n  name: string\n  type: string\n}\n\nconst userSchema = new mongoose.Schema({\n  name: String,\n  type: String\n})\n\nuserSchema.index({ name: 1, type: -1 })\n\nconst Animal = mongoose.model<AnimalDocument>('Animal', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n_Beware of defining hooks in the callback if your schema has embedded discriminators. Mongoose documentation recommends declaring hooks **before** embedded discriminators, the callback is applied **after** them. You should use the dedicated hooks decorators `@PreHook` and `@PostHook`._\n\n## Schema retrieval\n\n> 🔦 `schemaFrom(class)`\n\nYou can retrieve a schema from any decorated class, for advanced manipulation or embedded use in another schema.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Location {\n  @Field(Number)\n  lat: number\n\n  @Field(Number)\n  lng: number\n}\n\n@Model()\nclass City extends Model.I {            \n  @Field(String)\n  name: string\n\n  @Field(schemaFrom(Location))\n  location: Location\n}\n\nconst citySchema = schemaFrom(City)\n```\n\n  </td>\n  <td>\n\n```ts\ninterface CityDocument extends mongoose.Document {\n  name: string\n  location: {\n    lat: number,\n    lng: number\n  }\n}\n\nconst locationSchema = new mongoose.Schema(\n  { lat: Number, lng: Number },\n  { _id: false }\n)\n\nconst citySchema = new mongoose.Schema({\n  name: String,\n  location: locationSchema\n})\n\nconst City = mongoose.model<CityDocument>('City', citySchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n🗣️ As a good practice, you should make your schema-only classes `abstract`, so you don't instantiate them by mistake.\n\n\n### Sub schemas\n\n> 🔦 `Field.Schema(class)`\n\nAs an alternative for the above use of `schemaFrom` inside the `Field` decorator, you can do:\n\n```ts\n@Model()\nclass City extends Model.I {            \n  @Field.Schema(Location)\n  location: Location\n}\n```\n\n## Hooks\n\n### Pre hook\n\n> 🔦 `@PreHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.pre`](https://mongoosejs.com/docs/middleware#pre)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PreHook<User>('save', function(next) {\n  next()\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.pre<UserDocument>('save', function (doc, next) {\n  next()\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PreHook` API is a direct wrapper of Mongoose [Schema.pre method](https://mongoosejs.com/docs/api/schema#schema_Schema-pre), you can put in there everything that you used to.\n\nSuccessive `@PreHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n### Post hook\n\n> 🔦 `@PostHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.post`](https://mongoosejs.com/docs/middleware#post)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PostHook<User>('find', function(result) {\n  console.log(result)\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.post<UserDocument>('find', function (result) {\n  console.log(result)\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PostHook` API is a direct wrapper of Mongoose [Schema.post method](https://mongoosejs.com/docs/api/schema#schema_Schema-post), you can put in there everything that you used to.\n\nSuccessive `@PostHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n#### Post error handling middleware\n\nTo help the compiler accurately infer the [error handling middleware](https://mongoosejs.com/docs/middleware#error-handling-middleware) signature, pass a second type argument to `@PostHook`:\n\n```ts\n@Model()\n@PostHook<User, Error>('save', function(error, doc, next) {\n  if (error.name === 'MongoError' && error.code === 11000) {\n    next(new Error('There was a duplicate key error'))\n  } else {\n    next()\n  }\n})\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n```\n\n## Model discriminators\n\n> 🔦 `@Model.Discriminator(rootModel)`<br>\n> 💫 Related Mongoose method: [`model.discriminator`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Worker extends User {\n  @Field(String)\n  job: string\n\n  // No need to decorate the default discriminatorKey.\n  __t: 'Worker'\n\n  // You can strictly type the constructor of a discriminator model by using the Plain Helper (see below).\n  constructor(worker: Plain.Omit<Worker, '_id' | '__t'>) {\n    super() // required by the compiler.\n  }\n}\n\nconst worker = await Worker.create({ name: 'Jeremy', job: 'developer' })\n// { _id: '5d023ae14043262bcfd9b384', __t: 'Worker', name: 'Jeremy', job: 'developer' }\n```\n\nAs you know, `_t` is the default `discriminatorKey`, and its value will be the class name. If you want to customize both the key and the value, check out the following `@Kind` decorator.\n\n⚠️ `@Model.Discriminator` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model.Discriminator` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n### Kind / DiscriminatorKey\n\n> 🔦 `@Kind(value?)` alias `@DiscriminatorKey`<br>\n> 💫 Related Mongoose option property: [`discriminatorKey`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\nMongoose `discriminatorKey` is usually defined in the parent model options, and appears in the children model documents.\n`@Kind` (or its alias `@DiscriminatorKey`) exists to define `discriminatorKey` **directly** on the children class instead of the parent model.\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Developer extends User {\n  @Kind\n  kind: 'Developer' // Value will be the class name by default.\n}\n\n@Model.Discriminator(User)\nclass Doctor extends User {\n  @Kind('doctor') // Customize the discriminator value by passing a string.\n  kind: 'doctor'\n}\n\n// This is equivalent to setting `{ discriminatorKey: 'kind' }` on User schema options.\n```\n\nA mecanism will check and prevent you from defining a different `@Kind` key on sibling discriminators.\n\n## Embedded discriminators\n\n### Single nested discriminators\n\n> 🔦 `@Field.Union(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`SingleNestedPath.discriminator`](https://mongoosejs.com/docs/discriminators#single-nested-discriminators)\n\n`@Field.Union` allows you to embed discriminators on an single property.\n\n```ts\nabstract class Circle {\n  @Field(Number)\n  radius: number\n\n  __t: 'Circle'\n  // __t is the default discriminatorKey (no need to decorate).\n  // Value will be the class name.\n}\n\nabstract class Square {\n  @Field(Number)\n  side: number\n\n  __t: 'Square'\n}\n\n@Model()\nclass Shape extends Model.I {\n  @Field.Union([Circle, Square], { \n    required: true, // Make the field itself `shape` required.\n    strict: true // Make the discriminator key `__t` required and narrowed to its possible values.\n  })\n  shape: Circle | Square\n}\n\nconst circle = new Shape({ shape: { __t: 'Circle', radius: 5 } })\nconst square = new Shape({ shape: { __t: 'Square', side: 4 } })\n```\n\n### Embedded discriminators in arrays\n\n> 🔦 `@Field.ArrayOfUnion(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`DocumentArrayPath.discriminator`](https://mongoosejs.com/docs/discriminators#embedded-discriminators-in-arrays)\n\n`@Field.ArrayOfUnion` allows you to embed discriminators in an array.\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Clicked {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  element: string\n\n  @Kind\n  kind: 'Clicked'\n}\n\n@SchemaOptions({ _id: false })\nabstract class Purchased {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  product: string\n\n  @Kind\n  kind: 'Purchased'\n}\n\n@Model()\nclass Batch extends Model.I {\n  @Field.ArrayOfUnion([Clicked, Purchased], { \n    strict: true  // Make the discriminator key `kind` required and narrowed to its possible values.\n  })\n  events: (Clicked | Purchased)[]\n}\n\nconst batch = new Batch({\n  events: [\n    { kind: 'Clicked', element: '#hero', message: 'hello' },\n    { kind: 'Purchased', product: 'action-figure', message: 'world' },\n  ]\n})\n```\n\n## Populated virtuals\n\n> 🔦 `@Virtual(options)`<br>\n> 💫 Related Mongoose method: [`schema.virtual`](https://mongoosejs.com/docs/populate#populate-virtuals)\n\n```ts\n@Model()\nclass Person extends Model.I {\n  @Field(String)\n  name: string\n\n  @Field(String)\n  band: string\n}\n\n@Model()\n@SchemaOptions({\n  toObject: { virtuals: true },\n  toJson: { virtuals: true }\n})\nclass Band extends Model.I {\n  @Field(String)\n  name: string\n\n  @Virtual<Band, Person>({\n    ref: 'Person',\n    foreignField: 'band',\n    localField: 'name'\n  })\n  readonly members: string[]\n}\n\nconst bands = await Band.find({}).populate('members')\n```\n\n## Plain helper\n\n> 🔦 `Plain<class, options?>`\n\nReflet provides a generic type to discard Mongoose properties and methods from a Document.\n\n* `Plain<T>` removes inherited Mongoose properties (except `_id`) and all methods from `T`.\n* `Plain.Partial<T>` does the same as `Plain` and makes remaining properties of `T` optional.\n* `Plain.PartialDeep<T>` does the same as `Plain.Partial` recursively.\n\n`Plain` also has a second type argument to omit other properties and/or make them optional:\n\n* `Plain<T, { Omit: keyof T; Optional: keyof T } >`\n\n_These options exist as standalone generics as well: `Plain.Omit<T, keyof T>` and `Plain.Optional<T, keyof T>`._\n\nWith this you can narrow the return type of `toObject()` and `toJson()`:\n\n```ts\nconst userPlain = user.toObject({ getters: false }) as Plain.Omit<User, 'fullname'>\n```\n\n#### Allow `string` for `ObjectId`\n\n> 🔦 `Plain.AllowString<class, options?>`\n\nWhen creating or querying documents, you can pass `ObjectId` as `string`. To allow this, Reflet provides a generic type with the same API as `Plain`:\n\n* `Plain.AllowString<T, { Omit: keyof T; Optional: keyof T } >`\n* `Plain.AllowString.Partial<T>`\n* `Plain.AllowString.PartialDeep<T>`\n\n### One document, multiple shapes\n\nIn each of your models, some fields might be present when you read the document from the database, but optional or even absent when you create it. 😕\n\nGiven the following model:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field({ type: Boolean, default: () => false })\n  activated: boolean\n\n  @CreatedAt\n  createdAt: Date\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThis is how you can type `constructor` and `create` parameters:\n\n```ts\ntype NewUser = Plain.AllowString<User, { Omit: 'fullname' | 'createdAt'; Optional: '_id' | 'activated' }>\n\n@Model()\nclass User extends Model.I<typeof User>  {\n  // @ts-ignore implementation\n  constructor(doc?: NewUser, strict?: boolean | 'throw')\n}\n\nconst user = new User({ firstname: 'John', lastname: 'Doe' })\nawait user.save()\nawait User.create({ firstname: 'Jeremy', lastname: 'Doe', activated: true })\n```\n\nBy passing `typeof User` to `Model.I`, Reflet is now able to use the constructor signature to type the following static methods: `create`, `insertMany` and `replaceOne`.\n\n_The compiler checks `NewUser` as we need, so you can safely use ts-ignore on the `constructor` to avoid implementing an empty one (remember that `@Model` will replace it with mongoose Model constructor)._\n\n## Augmentations\n\nReflet comes with a dedicated global namespace `RefletMongoose`, so you can augment or narrow specific types.\n\n### SchemaType options augmentation\n\nIf you use plugins like [mongoose-autopopulate](https://github.com/mongodb-js/mongoose-autopopulate),\nyou can augment the global interface `SchemaTypeOptions` to have new options in the `@Field` API.\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface SchemaTypeOptions {\n      autopopulate?: boolean\n    }\n  }\n}\n```\n\nNow you have access to `autopopulate` option in your schemas:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: Company,\n    autopopulate: true\n  })\n  company: Company\n}\n```\n\n#### Virtual options\n\nThe same can be done with the `@Virtual` decorator:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface VirtualOptions {}\n  }\n}\n```\n\n### Model and Document augmentation\n\nYou can augment `Model` and `Document` interfaces with the dedicated global interfaces.\nHere is an example with the [@casl/mongoose](https://github.com/stalniy/casl/tree/master/packages/casl-mongoose) plugin:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface Model {\n      accessibleBy<T extends mongoose.Document>(ability: AnyMongoAbility, action?: string): mongoose.DocumentQuery<T[], T>\n    }\n    interface Document {}\n  }\n}\n```\n\n### References narrowing\n\n[SchemaType `ref` option](https://mongoosejs.com/docs/api#schematypeoptions_SchemaTypeOptions-ref) can be either a Model or a model name. With Reflet, by default, any class can be passed as a Model and any string can be passed as a model name.\n\nBy augmenting the global interface `Ref`, you can:\n\n* Narrow the class to an union of your models.\n* Narrow the string to an union of your models' names.\n\n```ts\n// company.model.ts\n@Model()\nclass Company extends Model.I {\n  @Field(String)\n  name: string\n}\n\n// You should augment the global interface in each of your models' files, to keep it close to the model.\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      Company: Company\n    }\n  }\n}\n```\n\n```ts\n// user.model.ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: 'Company',\n  })\n  company: Company\n}\n\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      User: User\n    }\n  }\n}\n```\n","readmeFilename":"README.MD","bugs":{"url":"https://github.com/jeremyben/reflet/issues"},"_id":"@reflet/mongoose@2.0.0-next.5","_nodeVersion":"14.17.4","_npmVersion":"lerna/4.0.0/node@v14.17.4+x64 (win32)","dist":{"integrity":"sha512-Q3Mod5AxZezcVXGW+cdClcgXJjUNVWM+dbeJpCh5FCRQVDGcs2UxT3dqAKaU4AgcH0GTTQDn0dxsM3pGkSNv8Q==","shasum":"777cb5afaae3b59d8697a2f53d71f140082025de","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-2.0.0-next.5.tgz","fileCount":20,"unpackedSize":157373,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCRIfyKWqFRV0eElCfHS0Hz3lfemnPYy4kX8Tz2K7Pb3wIhAI+cKBmLm/TOePP2lJopcWm/a+/u3ASexCH761wgh+Zi"}]},"_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"directories":{},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_2.0.0-next.5_1636742138246_0.36395224129409387"},"_hasShrinkwrap":false},"2.0.0-next.6":{"name":"@reflet/mongoose","version":"2.0.0-next.6","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/jeremyben/reflet.git","directory":"mongoose"},"homepage":"https://github.com/jeremyben/reflet/tree/master/mongoose#readme","description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=10"},"engineStrict":true,"peerDependencies":{"@types/node":">=10","mongoose":">=6","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^2.1.0","mongoose":"^6.0.12","mongoose-autopopulate":"^0.16.0"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build"},"gitHead":"4901916b85ebcf823fe1973fc80f96c0b25f369f","readme":"# `@reflet/mongoose` 🌠\n\n[![lines coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=lines&query=total.lines.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![statements coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=statements&query=total.statements.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![functions coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=functions&query=total.functions.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![branches coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=branches&query=total.branches.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n\nThe **best** decorators for [Mongoose](https://mongoosejs.com/). Have a look at [Reflet's philosophy](../README.MD#Philosophy-).\n\n* [Getting started](#getting-started)\n* [Schema definition](#schema-definition)\n* [Model](#model)\n* [Schema options](#schema-options)\n* [Schema retrieval](#schema-retrieval)\n* [Hooks](#hooks)\n* [Model discriminators](#model-discriminators)\n* [Embedded discriminators](#embedded-discriminators)\n* [Populated virtuals](#populated-virtuals)\n* [Plain helper](#plain-helper)\n* [Augmentations](#augmentations)\n\n## Getting started\n\n1. <details>\n    <summary>Make sure you have decorators enabled. (click for details)</summary>\n    <p>\n\n    * Enable them in your TypeScript compiler options.\n\n        ```json\n        \"experimentalDecorators\": true,\n        \"emitDecoratorMetadata\": true,\n        ```\n\n    * Install `reflect-metadata` shim.\n\n        ```sh\n        yarn add reflect-metadata\n        ```\n\n    * Import the shim in your program before everything else.\n\n        ```ts\n        import 'reflect-metadata'\n        ```\n\n    </p>\n    </details>\n\n2. Install the package along with peer dependencies.\n\n    ```sh\n    yarn add @reflet/mongoose mongoose && yarn add -D @types/mongoose @types/node\n    ```\n\n3. Create your decorated models.\n\n    ```ts\n    // user.model.ts\n    import { Model, Field } from '@reflet/mongoose'\n\n    @Model()\n    export class User extends Model.Interface {\n      static findByEmail(email) {\n        return this.findOne({ email });\n      }\n\n      @Fied({ type: String, required: true })\n      email: string\n\n      getProfileUrl() {\n        return `https://mysite.com/${this.email}`;\n      }\n    }\n    ```\n\n4. Connect to MongoDB and save your documents.\n\n    ```ts\n    // server.ts\n    import 'reflect-metadata'\n    import * as mongoose from 'mongoose'\n    import { User } from './user.model.ts'\n\n    mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true })\n\n    User.create({ email: 'jeremy@example.com' }).then((user) => {\n      console.log(`User ${user._id} has been saved.`)\n    })\n    ```\n\n### The Mongoose way\n\nConnect Mongoose in the way you already know. Models defined with Reflet will simply be attached to the default Mongoose connection.\nThis means you can **progressively** decorate your Mongoose models. 😉\n\n## Schema definition\n\n> 🔦 `@Field(schemaType)`<br>\n> 💫 Related Mongoose object: [SchemaTypes](https://mongoosejs.com/docs/schematypes)\n\nMongoose [already](https://mongoosejs.com/docs/api#schema_Schema-loadClass) allows you to load an ES6 class to attach getters, setters, instance and static methods to a schema.\nBut what about properties ? Enters the `@Field` decorator :\n\n```ts\nclass User {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field(Number)\n  age?: number\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThe `@Field` API is a direct wrapper of Mongoose [SchemaType](https://mongoosejs.com/docs/schematypes), you can put in there everything that you used to.\n\n### Nested properties\n\n> 🔦 `@Field.Nested(schemaTypes)`\n\n```ts\nclass User {\n  @Field.Nested({\n    street: { type: String, required: true },\n    city: { type: String, required: true },\n    country: { type: String, required: true },\n  })\n  address: {\n    street: string\n    city: string\n    country: string\n  }\n}\n```\n\n_`@Field.Nested` works the same as `@Field` at runtime. Its type is simply looser to allow nested objects._\n\n## Model\n\n> 🔦 `@Model(collection?, connection?)`<br>\n> 💫 Related Mongoose method: [`model`](https://mongoosejs.com/docs/models#compiling)\n\nTypeScript [class decorators](https://www.typescriptlang.org/docs/handbook/decorators#class-decorators) can modify and even replace class constructors. Reflet takes advantage of this feature and transforms a class directly into a Mongoose Model.\n\nThis means you don't have to deal with the procedural and separate creation of both schema and model anymore !\nAnd now your properties and methods are statically typed.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\nclass User extends Model.Interface {\n  @Field({ type: String, required: true })\n  email: string\n}\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  email: string\n}\n\nconst userSchema = new mongoose.Schema({\n  email: { type: String, required: true }\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nYour class needs to inherit a special empty class, **`Model.Interface`** or **`Model.I`**, to have Mongoose document properties and methods.\n\n⚠️ `@Model` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n#### Custom collection name\n\nBy default, Mongoose automatically creates a collection named as the plural, lowercased version of your model name. You can customize the collection name, with the first argument:\n\n```ts\n@Model('people')\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n#### Custom Mongoose connection\n\nYou can use a different database by creating a Mongoose connection and passing it as the second argument:\n\n```ts\nconst otherDb = mongoose.createConnection('mongodb://localhost/other', { useNewUrlParser: true })\n\n@Model(undefined, otherDb)\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n## Schema options\n\n> 🔦 `@SchemaOptions(options)`<br>\n> 💫 Related Mongoose object: [Schema options](https://mongoosejs.com/docs/guide#options)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({\n  autoIndex: false,\n  strict: 'throw'\n})\nclass User extends Model.I {           \n  @Field(String)\n  name: string\n}\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    autoIndex: false,\n    strict: 'throw'\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@SchemaOptions` API is a direct wrapper of Mongoose [schema options](https://mongoosejs.com/docs/guide#options), you can put in there everything that you used to.\n\n### Timestamps\n\n> 🔦 `@CreatedAt`, `@UpdatedAt`<br>\n> 💫 Related Mongoose option property: [`timestamps`](https://mongoosejs.com/docs/guide#timestamps)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({ minimize: false })\nclass User extends Model.I {             \n  @Field(String)\n  name: string\n\n  @CreatedAt\n  creationDate: Date\n\n  @UpdatedAt\n  updateDate: Date\n}\n\n\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n  creationDate: Date\n  updateDate: Date\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    minimize: false,\n    timestamps: {\n      createdAt: 'creationDate',\n      updatedAt: 'updateDate'\n    },\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n### Advanced schema manipulation\n\n> 🔦 `@SchemaCallback(callback)`<br>\n> 💫 Related Mongoose object: [`Schema`](https://mongoosejs.com/docs/api/schema)\n\nIf you need more advanced schema manipulation before `@Model` compiles it, you can use `@SchemaCallback`:\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaCallback((schema) => {\n  schema.index({ name: 1, type: -1 })\n})\nclass Animal extends Model.I {          \n  @Field(String)\n  name: string\n\n  @Field(String)\n  type: string\n}\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface AnimalDocument extends mongoose.Document {\n  name: string\n  type: string\n}\n\nconst userSchema = new mongoose.Schema({\n  name: String,\n  type: String\n})\n\nuserSchema.index({ name: 1, type: -1 })\n\nconst Animal = mongoose.model<AnimalDocument>('Animal', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n_Beware of defining hooks in the callback if your schema has embedded discriminators. Mongoose documentation recommends declaring hooks **before** embedded discriminators, the callback is applied **after** them. You should use the dedicated hooks decorators `@PreHook` and `@PostHook`._\n\n## Schema retrieval\n\n> 🔦 `schemaFrom(class)`\n\nYou can retrieve a schema from any decorated class, for advanced manipulation or embedded use in another schema.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Location {\n  @Field(Number)\n  lat: number\n\n  @Field(Number)\n  lng: number\n}\n\n@Model()\nclass City extends Model.I {            \n  @Field(String)\n  name: string\n\n  @Field(schemaFrom(Location))\n  location: Location\n}\n\nconst citySchema = schemaFrom(City)\n```\n\n  </td>\n  <td>\n\n```ts\ninterface CityDocument extends mongoose.Document {\n  name: string\n  location: {\n    lat: number,\n    lng: number\n  }\n}\n\nconst locationSchema = new mongoose.Schema(\n  { lat: Number, lng: Number },\n  { _id: false }\n)\n\nconst citySchema = new mongoose.Schema({\n  name: String,\n  location: locationSchema\n})\n\nconst City = mongoose.model<CityDocument>('City', citySchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n🗣️ As a good practice, you should make your schema-only classes `abstract`, so you don't instantiate them by mistake.\n\n\n### Sub schemas\n\n> 🔦 `Field.Schema(class)`\n\nAs an alternative for the above use of `schemaFrom` inside the `Field` decorator, you can do:\n\n```ts\n@Model()\nclass City extends Model.I {            \n  @Field.Schema(Location)\n  location: Location\n}\n```\n\n## Hooks\n\n### Pre hook\n\n> 🔦 `@PreHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.pre`](https://mongoosejs.com/docs/middleware#pre)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PreHook<User>('save', function(next) {\n  next()\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.pre<UserDocument>('save', function (doc, next) {\n  next()\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PreHook` API is a direct wrapper of Mongoose [Schema.pre method](https://mongoosejs.com/docs/api/schema#schema_Schema-pre), you can put in there everything that you used to.\n\nSuccessive `@PreHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n### Post hook\n\n> 🔦 `@PostHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.post`](https://mongoosejs.com/docs/middleware#post)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PostHook<User>('find', function(result) {\n  console.log(result)\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.post<UserDocument>('find', function (result) {\n  console.log(result)\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PostHook` API is a direct wrapper of Mongoose [Schema.post method](https://mongoosejs.com/docs/api/schema#schema_Schema-post), you can put in there everything that you used to.\n\nSuccessive `@PostHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n#### Post error handling middleware\n\nTo help the compiler accurately infer the [error handling middleware](https://mongoosejs.com/docs/middleware#error-handling-middleware) signature, pass a second type argument to `@PostHook`:\n\n```ts\n@Model()\n@PostHook<User, Error>('save', function(error, doc, next) {\n  if (error.name === 'MongoError' && error.code === 11000) {\n    next(new Error('There was a duplicate key error'))\n  } else {\n    next()\n  }\n})\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n```\n\n## Model discriminators\n\n> 🔦 `@Model.Discriminator(rootModel)`<br>\n> 💫 Related Mongoose method: [`model.discriminator`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Worker extends User {\n  @Field(String)\n  job: string\n\n  // No need to decorate the default discriminatorKey.\n  __t: 'Worker'\n\n  // You can strictly type the constructor of a discriminator model by using the Plain Helper (see below).\n  constructor(worker: Plain.Omit<Worker, '_id' | '__t'>) {\n    super() // required by the compiler.\n  }\n}\n\nconst worker = await Worker.create({ name: 'Jeremy', job: 'developer' })\n// { _id: '5d023ae14043262bcfd9b384', __t: 'Worker', name: 'Jeremy', job: 'developer' }\n```\n\nAs you know, `_t` is the default `discriminatorKey`, and its value will be the class name. If you want to customize both the key and the value, check out the following `@Kind` decorator.\n\n⚠️ `@Model.Discriminator` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model.Discriminator` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n### Kind / DiscriminatorKey\n\n> 🔦 `@Kind(value?)` alias `@DiscriminatorKey`<br>\n> 💫 Related Mongoose option property: [`discriminatorKey`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\nMongoose `discriminatorKey` is usually defined in the parent model options, and appears in the children model documents.\n`@Kind` (or its alias `@DiscriminatorKey`) exists to define `discriminatorKey` **directly** on the children class instead of the parent model.\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Developer extends User {\n  @Kind\n  kind: 'Developer' // Value will be the class name by default.\n}\n\n@Model.Discriminator(User)\nclass Doctor extends User {\n  @Kind('doctor') // Customize the discriminator value by passing a string.\n  kind: 'doctor'\n}\n\n// This is equivalent to setting `{ discriminatorKey: 'kind' }` on User schema options.\n```\n\nA mecanism will check and prevent you from defining a different `@Kind` key on sibling discriminators.\n\n## Embedded discriminators\n\n### Single nested discriminators\n\n> 🔦 `@Field.Union(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`SingleNestedPath.discriminator`](https://mongoosejs.com/docs/discriminators#single-nested-discriminators)\n\n`@Field.Union` allows you to embed discriminators on an single property.\n\n```ts\nabstract class Circle {\n  @Field(Number)\n  radius: number\n\n  __t: 'Circle'\n  // __t is the default discriminatorKey (no need to decorate).\n  // Value will be the class name.\n}\n\nabstract class Square {\n  @Field(Number)\n  side: number\n\n  __t: 'Square'\n}\n\n@Model()\nclass Shape extends Model.I {\n  @Field.Union([Circle, Square], { \n    required: true, // Make the field itself `shape` required.\n    strict: true // Make the discriminator key `__t` required and narrowed to its possible values.\n  })\n  shape: Circle | Square\n}\n\nconst circle = new Shape({ shape: { __t: 'Circle', radius: 5 } })\nconst square = new Shape({ shape: { __t: 'Square', side: 4 } })\n```\n\n### Embedded discriminators in arrays\n\n> 🔦 `@Field.ArrayOfUnion(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`DocumentArrayPath.discriminator`](https://mongoosejs.com/docs/discriminators#embedded-discriminators-in-arrays)\n\n`@Field.ArrayOfUnion` allows you to embed discriminators in an array.\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Clicked {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  element: string\n\n  @Kind\n  kind: 'Clicked'\n}\n\n@SchemaOptions({ _id: false })\nabstract class Purchased {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  product: string\n\n  @Kind\n  kind: 'Purchased'\n}\n\n@Model()\nclass Batch extends Model.I {\n  @Field.ArrayOfUnion([Clicked, Purchased], { \n    strict: true  // Make the discriminator key `kind` required and narrowed to its possible values.\n  })\n  events: (Clicked | Purchased)[]\n}\n\nconst batch = new Batch({\n  events: [\n    { kind: 'Clicked', element: '#hero', message: 'hello' },\n    { kind: 'Purchased', product: 'action-figure', message: 'world' },\n  ]\n})\n```\n\n## Populated virtuals\n\n> 🔦 `@Virtual(options)`<br>\n> 💫 Related Mongoose method: [`schema.virtual`](https://mongoosejs.com/docs/populate#populate-virtuals)\n\n```ts\n@Model()\nclass Person extends Model.I {\n  @Field(String)\n  name: string\n\n  @Field(String)\n  band: string\n}\n\n@Model()\n@SchemaOptions({\n  toObject: { virtuals: true },\n  toJson: { virtuals: true }\n})\nclass Band extends Model.I {\n  @Field(String)\n  name: string\n\n  @Virtual<Band, Person>({\n    ref: 'Person',\n    foreignField: 'band',\n    localField: 'name'\n  })\n  readonly members: string[]\n}\n\nconst bands = await Band.find({}).populate('members')\n```\n\n## Plain helper\n\n> 🔦 `Plain<class, options?>`\n\nReflet provides a generic type to discard Mongoose properties and methods from a Document.\n\n* `Plain<T>` removes inherited Mongoose properties (except `_id`) and all methods from `T`.\n* `Plain.Partial<T>` does the same as `Plain` and makes remaining properties of `T` optional.\n* `Plain.PartialDeep<T>` does the same as `Plain.Partial` recursively.\n\n`Plain` also has a second type argument to omit other properties and/or make them optional:\n\n* `Plain<T, { Omit: keyof T; Optional: keyof T } >`\n\n_These options exist as standalone generics as well: `Plain.Omit<T, keyof T>` and `Plain.Optional<T, keyof T>`._\n\nWith this you can narrow the return type of `toObject()` and `toJson()`:\n\n```ts\nconst userPlain = user.toObject({ getters: false }) as Plain.Omit<User, 'fullname'>\n```\n\n#### Allow `string` for `ObjectId`\n\n> 🔦 `Plain.AllowString<class, options?>`\n\nWhen creating or querying documents, you can pass `ObjectId` as `string`. To allow this, Reflet provides a generic type with the same API as `Plain`:\n\n* `Plain.AllowString<T, { Omit: keyof T; Optional: keyof T } >`\n* `Plain.AllowString.Partial<T>`\n* `Plain.AllowString.PartialDeep<T>`\n\n### One document, multiple shapes\n\nIn each of your models, some fields might be present when you read the document from the database, but optional or even absent when you create it. 😕\n\nGiven the following model:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field({ type: Boolean, default: () => false })\n  activated: boolean\n\n  @CreatedAt\n  createdAt: Date\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThis is how you can type `constructor` and `create` parameters:\n\n```ts\ntype NewUser = Plain.AllowString<User, { Omit: 'fullname' | 'createdAt'; Optional: '_id' | 'activated' }>\n\n@Model()\nclass User extends Model.I<typeof User>  {\n  // @ts-ignore implementation\n  constructor(doc?: NewUser, strict?: boolean | 'throw')\n}\n\nconst user = new User({ firstname: 'John', lastname: 'Doe' })\nawait user.save()\nawait User.create({ firstname: 'Jeremy', lastname: 'Doe', activated: true })\n```\n\nBy passing `typeof User` to `Model.I`, Reflet is now able to use the constructor signature to type the following static methods: `create`, `insertMany` and `replaceOne`.\n\n_The compiler checks `NewUser` as we need, so you can safely use ts-ignore on the `constructor` to avoid implementing an empty one (remember that `@Model` will replace it with mongoose Model constructor)._\n\n## Augmentations\n\nReflet comes with a dedicated global namespace `RefletMongoose`, so you can augment or narrow specific types.\n\n### SchemaType options augmentation\n\nIf you use plugins like [mongoose-autopopulate](https://github.com/mongodb-js/mongoose-autopopulate),\nyou can augment the global interface `SchemaTypeOptions` to have new options in the `@Field` API.\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface SchemaTypeOptions {\n      autopopulate?: boolean\n    }\n  }\n}\n```\n\nNow you have access to `autopopulate` option in your schemas:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: Company,\n    autopopulate: true\n  })\n  company: Company\n}\n```\n\n#### Virtual options\n\nThe same can be done with the `@Virtual` decorator:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface VirtualOptions {}\n  }\n}\n```\n\n### Model and Document augmentation\n\nYou can augment `Model` and `Document` interfaces with the dedicated global interfaces.\nHere is an example with the [@casl/mongoose](https://github.com/stalniy/casl/tree/master/packages/casl-mongoose) plugin:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface Model {\n      accessibleBy<T extends mongoose.Document>(ability: AnyMongoAbility, action?: string): mongoose.DocumentQuery<T[], T>\n    }\n    interface Document {}\n  }\n}\n```\n\n### References narrowing\n\n[SchemaType `ref` option](https://mongoosejs.com/docs/api#schematypeoptions_SchemaTypeOptions-ref) can be either a Model or a model name. With Reflet, by default, any class can be passed as a Model and any string can be passed as a model name.\n\nBy augmenting the global interface `Ref`, you can:\n\n* Narrow the class to an union of your models.\n* Narrow the string to an union of your models' names.\n\n```ts\n// company.model.ts\n@Model()\nclass Company extends Model.I {\n  @Field(String)\n  name: string\n}\n\n// You should augment the global interface in each of your models' files, to keep it close to the model.\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      Company: Company\n    }\n  }\n}\n```\n\n```ts\n// user.model.ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: 'Company',\n  })\n  company: Company\n}\n\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      User: User\n    }\n  }\n}\n```\n","readmeFilename":"README.MD","bugs":{"url":"https://github.com/jeremyben/reflet/issues"},"_id":"@reflet/mongoose@2.0.0-next.6","_nodeVersion":"14.17.4","_npmVersion":"lerna/4.0.0/node@v14.17.4+x64 (win32)","dist":{"integrity":"sha512-tvIDmoS39F22zkwv/1Sv7PscAnZq82JqmSdImDPJn2w4CMPTZ+1zyUkw8Fdfn728JInojhxwmBZAw/o2NHyC3w==","shasum":"b8088fdd57bdc9262627f22a8881698b0e8429f4","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-2.0.0-next.6.tgz","fileCount":21,"unpackedSize":159362,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCl8boLo2VLBKDIqOyQIj9rEndiqUyLjcyWuQtyY/ZfFAIgeTeqPIW96kniMYhzA/NHMRg8lsHCtwGHeeRXfmUWFJk="}]},"_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"directories":{},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_2.0.0-next.6_1636925383843_0.9166925498715857"},"_hasShrinkwrap":false},"2.0.0-next.7":{"name":"@reflet/mongoose","version":"2.0.0-next.7","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet.git","directory":"mongoose"},"homepage":"https://github.com/jeremyben/reflet/tree/master/mongoose#readme","description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=10"},"engineStrict":true,"peerDependencies":{"@types/node":">=10","mongoose":">=6","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^2.1.0","mongoose":"^6.0.12","mongoose-autopopulate":"^0.16.0"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build","publish:next":"yarn publish --tag next"},"readmeFilename":"README.MD","readme":"# `@reflet/mongoose` 🌠\n\n[![lines coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=lines&query=total.lines.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![statements coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=statements&query=total.statements.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![functions coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=functions&query=total.functions.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![branches coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=branches&query=total.branches.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n\nThe **best** decorators for [Mongoose](https://mongoosejs.com/). Have a look at [Reflet's philosophy](../README.MD#Philosophy-).\n\n* [Getting started](#getting-started)\n* [Schema definition](#schema-definition)\n* [Model](#model)\n* [Schema options](#schema-options)\n* [Schema retrieval](#schema-retrieval)\n* [Hooks](#hooks)\n* [Model discriminators](#model-discriminators)\n* [Embedded discriminators](#embedded-discriminators)\n* [Populated virtuals](#populated-virtuals)\n* [Plain helper](#plain-helper)\n* [Augmentations](#augmentations)\n\n## Getting started\n\n1. <details>\n    <summary>Make sure you have decorators enabled. (click for details)</summary>\n    <p>\n\n    * Enable them in your TypeScript compiler options.\n\n        ```json\n        \"experimentalDecorators\": true,\n        \"emitDecoratorMetadata\": true,\n        ```\n\n    * Install `reflect-metadata` shim.\n\n        ```sh\n        yarn add reflect-metadata\n        ```\n\n    * Import the shim in your program before everything else.\n\n        ```ts\n        import 'reflect-metadata'\n        ```\n\n    </p>\n    </details>\n\n2. Install the package along with peer dependencies.\n\n    ```sh\n    yarn add @reflet/mongoose mongoose && yarn add -D @types/mongoose @types/node\n    ```\n\n3. Create your decorated models.\n\n    ```ts\n    // user.model.ts\n    import { Model, Field } from '@reflet/mongoose'\n\n    @Model()\n    export class User extends Model.Interface {\n      static findByEmail(email) {\n        return this.findOne({ email });\n      }\n\n      @Fied({ type: String, required: true })\n      email: string\n\n      getProfileUrl() {\n        return `https://mysite.com/${this.email}`;\n      }\n    }\n    ```\n\n4. Connect to MongoDB and save your documents.\n\n    ```ts\n    // server.ts\n    import 'reflect-metadata'\n    import * as mongoose from 'mongoose'\n    import { User } from './user.model.ts'\n\n    mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true })\n\n    User.create({ email: 'jeremy@example.com' }).then((user) => {\n      console.log(`User ${user._id} has been saved.`)\n    })\n    ```\n\n### The Mongoose way\n\nConnect Mongoose in the way you already know. Models defined with Reflet will simply be attached to the default Mongoose connection.\nThis means you can **progressively** decorate your Mongoose models. 😉\n\n## Schema definition\n\n> 🔦 `@Field(schemaType)`<br>\n> 💫 Related Mongoose object: [SchemaTypes](https://mongoosejs.com/docs/schematypes)\n\nMongoose [already](https://mongoosejs.com/docs/api#schema_Schema-loadClass) allows you to load an ES6 class to attach getters, setters, instance and static methods to a schema.\nBut what about properties ? Enters the `@Field` decorator :\n\n```ts\nclass User {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field(Number)\n  age?: number\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThe `@Field` API is a direct wrapper of Mongoose [SchemaType](https://mongoosejs.com/docs/schematypes), you can put in there everything that you used to.\n\n### Nested properties\n\n> 🔦 `@Field.Nested(schemaTypes)`\n\n```ts\nclass User {\n  @Field.Nested({\n    street: { type: String, required: true },\n    city: { type: String, required: true },\n    country: { type: String, required: true },\n  })\n  address: {\n    street: string\n    city: string\n    country: string\n  }\n}\n```\n\n_`@Field.Nested` works the same as `@Field` at runtime. Its type is simply looser to allow nested objects._\n\n## Model\n\n> 🔦 `@Model(collection?, connection?)`<br>\n> 💫 Related Mongoose method: [`model`](https://mongoosejs.com/docs/models#compiling)\n\nTypeScript [class decorators](https://www.typescriptlang.org/docs/handbook/decorators#class-decorators) can modify and even replace class constructors. Reflet takes advantage of this feature and transforms a class directly into a Mongoose Model.\n\nThis means you don't have to deal with the procedural and separate creation of both schema and model anymore !\nAnd now your properties and methods are statically typed.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\nclass User extends Model.Interface {\n  @Field({ type: String, required: true })\n  email: string\n}\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  email: string\n}\n\nconst userSchema = new mongoose.Schema({\n  email: { type: String, required: true }\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nYour class needs to inherit a special empty class, **`Model.Interface`** or **`Model.I`**, to have Mongoose document properties and methods.\n\n⚠️ `@Model` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n#### Custom collection name\n\nBy default, Mongoose automatically creates a collection named as the plural, lowercased version of your model name. You can customize the collection name, with the first argument:\n\n```ts\n@Model('people')\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n#### Custom Mongoose connection\n\nYou can use a different database by creating a Mongoose connection and passing it as the second argument:\n\n```ts\nconst otherDb = mongoose.createConnection('mongodb://localhost/other', { useNewUrlParser: true })\n\n@Model(undefined, otherDb)\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n## Schema options\n\n> 🔦 `@SchemaOptions(options)`<br>\n> 💫 Related Mongoose object: [Schema options](https://mongoosejs.com/docs/guide#options)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({\n  autoIndex: false,\n  strict: 'throw'\n})\nclass User extends Model.I {           \n  @Field(String)\n  name: string\n}\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    autoIndex: false,\n    strict: 'throw'\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@SchemaOptions` API is a direct wrapper of Mongoose [schema options](https://mongoosejs.com/docs/guide#options), you can put in there everything that you used to.\n\n### Timestamps\n\n> 🔦 `@CreatedAt`, `@UpdatedAt`<br>\n> 💫 Related Mongoose option property: [`timestamps`](https://mongoosejs.com/docs/guide#timestamps)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({ minimize: false })\nclass User extends Model.I {             \n  @Field(String)\n  name: string\n\n  @CreatedAt\n  creationDate: Date\n\n  @UpdatedAt\n  updateDate: Date\n}\n\n\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n  creationDate: Date\n  updateDate: Date\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    minimize: false,\n    timestamps: {\n      createdAt: 'creationDate',\n      updatedAt: 'updateDate'\n    },\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n### Advanced schema manipulation\n\n> 🔦 `@SchemaCallback(callback)`<br>\n> 💫 Related Mongoose object: [`Schema`](https://mongoosejs.com/docs/api/schema)\n\nIf you need more advanced schema manipulation before `@Model` compiles it, you can use `@SchemaCallback`:\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaCallback((schema) => {\n  schema.index({ name: 1, type: -1 })\n})\nclass Animal extends Model.I {          \n  @Field(String)\n  name: string\n\n  @Field(String)\n  type: string\n}\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface AnimalDocument extends mongoose.Document {\n  name: string\n  type: string\n}\n\nconst userSchema = new mongoose.Schema({\n  name: String,\n  type: String\n})\n\nuserSchema.index({ name: 1, type: -1 })\n\nconst Animal = mongoose.model<AnimalDocument>('Animal', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n_Beware of defining hooks in the callback if your schema has embedded discriminators. Mongoose documentation recommends declaring hooks **before** embedded discriminators, the callback is applied **after** them. You should use the dedicated hooks decorators `@PreHook` and `@PostHook`._\n\n## Schema retrieval\n\n> 🔦 `schemaFrom(class)`\n\nYou can retrieve a schema from any decorated class, for advanced manipulation or embedded use in another schema.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Location {\n  @Field(Number)\n  lat: number\n\n  @Field(Number)\n  lng: number\n}\n\n@Model()\nclass City extends Model.I {            \n  @Field(String)\n  name: string\n\n  @Field(schemaFrom(Location))\n  location: Location\n}\n\nconst citySchema = schemaFrom(City)\n```\n\n  </td>\n  <td>\n\n```ts\ninterface CityDocument extends mongoose.Document {\n  name: string\n  location: {\n    lat: number,\n    lng: number\n  }\n}\n\nconst locationSchema = new mongoose.Schema(\n  { lat: Number, lng: Number },\n  { _id: false }\n)\n\nconst citySchema = new mongoose.Schema({\n  name: String,\n  location: locationSchema\n})\n\nconst City = mongoose.model<CityDocument>('City', citySchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n🗣️ As a good practice, you should make your schema-only classes `abstract`, so you don't instantiate them by mistake.\n\n\n### Sub schemas\n\n> 🔦 `Field.Schema(class)`\n\nAs an alternative for the above use of `schemaFrom` inside the `Field` decorator, you can do:\n\n```ts\n@Model()\nclass City extends Model.I {            \n  @Field.Schema(Location)\n  location: Location\n}\n```\n\n## Hooks\n\n### Pre hook\n\n> 🔦 `@PreHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.pre`](https://mongoosejs.com/docs/middleware#pre)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PreHook<User>('save', function(next) {\n  next()\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.pre<UserDocument>('save', function (doc, next) {\n  next()\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PreHook` API is a direct wrapper of Mongoose [Schema.pre method](https://mongoosejs.com/docs/api/schema#schema_Schema-pre), you can put in there everything that you used to.\n\nSuccessive `@PreHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n### Post hook\n\n> 🔦 `@PostHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.post`](https://mongoosejs.com/docs/middleware#post)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PostHook<User>('find', function(result) {\n  console.log(result)\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.post<UserDocument>('find', function (result) {\n  console.log(result)\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PostHook` API is a direct wrapper of Mongoose [Schema.post method](https://mongoosejs.com/docs/api/schema#schema_Schema-post), you can put in there everything that you used to.\n\nSuccessive `@PostHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n#### Post error handling middleware\n\nTo help the compiler accurately infer the [error handling middleware](https://mongoosejs.com/docs/middleware#error-handling-middleware) signature, pass a second type argument to `@PostHook`:\n\n```ts\n@Model()\n@PostHook<User, Error>('save', function(error, doc, next) {\n  if (error.name === 'MongoError' && error.code === 11000) {\n    next(new Error('There was a duplicate key error'))\n  } else {\n    next()\n  }\n})\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n```\n\n## Model discriminators\n\n> 🔦 `@Model.Discriminator(rootModel)`<br>\n> 💫 Related Mongoose method: [`model.discriminator`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Worker extends User {\n  @Field(String)\n  job: string\n\n  // No need to decorate the default discriminatorKey.\n  __t: 'Worker'\n\n  // You can strictly type the constructor of a discriminator model by using the Plain Helper (see below).\n  constructor(worker: Plain.Omit<Worker, '_id' | '__t'>) {\n    super() // required by the compiler.\n  }\n}\n\nconst worker = await Worker.create({ name: 'Jeremy', job: 'developer' })\n// { _id: '5d023ae14043262bcfd9b384', __t: 'Worker', name: 'Jeremy', job: 'developer' }\n```\n\nAs you know, `_t` is the default `discriminatorKey`, and its value will be the class name. If you want to customize both the key and the value, check out the following `@Kind` decorator.\n\n⚠️ `@Model.Discriminator` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model.Discriminator` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n### Kind / DiscriminatorKey\n\n> 🔦 `@Kind(value?)` alias `@DiscriminatorKey`<br>\n> 💫 Related Mongoose option property: [`discriminatorKey`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\nMongoose `discriminatorKey` is usually defined in the parent model options, and appears in the children model documents.\n`@Kind` (or its alias `@DiscriminatorKey`) exists to define `discriminatorKey` **directly** on the children class instead of the parent model.\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Developer extends User {\n  @Kind\n  kind: 'Developer' // Value will be the class name by default.\n}\n\n@Model.Discriminator(User)\nclass Doctor extends User {\n  @Kind('doctor') // Customize the discriminator value by passing a string.\n  kind: 'doctor'\n}\n\n// This is equivalent to setting `{ discriminatorKey: 'kind' }` on User schema options.\n```\n\nA mecanism will check and prevent you from defining a different `@Kind` key on sibling discriminators.\n\n## Embedded discriminators\n\n### Single nested discriminators\n\n> 🔦 `@Field.Union(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`SingleNestedPath.discriminator`](https://mongoosejs.com/docs/discriminators#single-nested-discriminators)\n\n`@Field.Union` allows you to embed discriminators on an single property.\n\n```ts\nabstract class Circle {\n  @Field(Number)\n  radius: number\n\n  __t: 'Circle'\n  // __t is the default discriminatorKey (no need to decorate).\n  // Value will be the class name.\n}\n\nabstract class Square {\n  @Field(Number)\n  side: number\n\n  __t: 'Square'\n}\n\n@Model()\nclass Shape extends Model.I {\n  @Field.Union([Circle, Square], { \n    required: true, // Make the field itself `shape` required.\n    strict: true // Make the discriminator key `__t` required and narrowed to its possible values.\n  })\n  shape: Circle | Square\n}\n\nconst circle = new Shape({ shape: { __t: 'Circle', radius: 5 } })\nconst square = new Shape({ shape: { __t: 'Square', side: 4 } })\n```\n\n### Embedded discriminators in arrays\n\n> 🔦 `@Field.ArrayOfUnion(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`DocumentArrayPath.discriminator`](https://mongoosejs.com/docs/discriminators#embedded-discriminators-in-arrays)\n\n`@Field.ArrayOfUnion` allows you to embed discriminators in an array.\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Clicked {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  element: string\n\n  @Kind\n  kind: 'Clicked'\n}\n\n@SchemaOptions({ _id: false })\nabstract class Purchased {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  product: string\n\n  @Kind\n  kind: 'Purchased'\n}\n\n@Model()\nclass Batch extends Model.I {\n  @Field.ArrayOfUnion([Clicked, Purchased], { \n    strict: true  // Make the discriminator key `kind` required and narrowed to its possible values.\n  })\n  events: (Clicked | Purchased)[]\n}\n\nconst batch = new Batch({\n  events: [\n    { kind: 'Clicked', element: '#hero', message: 'hello' },\n    { kind: 'Purchased', product: 'action-figure', message: 'world' },\n  ]\n})\n```\n\n## Populated virtuals\n\n> 🔦 `@Virtual(options)`<br>\n> 💫 Related Mongoose method: [`schema.virtual`](https://mongoosejs.com/docs/populate#populate-virtuals)\n\n```ts\n@Model()\nclass Person extends Model.I {\n  @Field(String)\n  name: string\n\n  @Field(String)\n  band: string\n}\n\n@Model()\n@SchemaOptions({\n  toObject: { virtuals: true },\n  toJson: { virtuals: true }\n})\nclass Band extends Model.I {\n  @Field(String)\n  name: string\n\n  @Virtual<Band, Person>({\n    ref: 'Person',\n    foreignField: 'band',\n    localField: 'name'\n  })\n  readonly members: string[]\n}\n\nconst bands = await Band.find({}).populate('members')\n```\n\n## Plain helper\n\n> 🔦 `Plain<class, options?>`\n\nReflet provides a generic type to discard Mongoose properties and methods from a Document.\n\n* `Plain<T>` removes inherited Mongoose properties (except `_id`) and all methods from `T`.\n* `Plain.Partial<T>` does the same as `Plain` and makes remaining properties of `T` optional.\n* `Plain.PartialDeep<T>` does the same as `Plain.Partial` recursively.\n\n`Plain` also has a second type argument to omit other properties and/or make them optional:\n\n* `Plain<T, { Omit: keyof T; Optional: keyof T } >`\n\n_These options exist as standalone generics as well: `Plain.Omit<T, keyof T>` and `Plain.Optional<T, keyof T>`._\n\nWith this you can narrow the return type of `toObject()` and `toJson()`:\n\n```ts\nconst userPlain = user.toObject({ getters: false }) as Plain.Omit<User, 'fullname'>\n```\n\n#### Allow `string` for `ObjectId`\n\n> 🔦 `Plain.AllowString<class, options?>`\n\nWhen creating or querying documents, you can pass `ObjectId` as `string`. To allow this, Reflet provides a generic type with the same API as `Plain`:\n\n* `Plain.AllowString<T, { Omit: keyof T; Optional: keyof T } >`\n* `Plain.AllowString.Partial<T>`\n* `Plain.AllowString.PartialDeep<T>`\n\n### One document, multiple shapes\n\nIn each of your models, some fields might be present when you read the document from the database, but optional or even absent when you create it. 😕\n\nGiven the following model:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field({ type: Boolean, default: () => false })\n  activated: boolean\n\n  @CreatedAt\n  createdAt: Date\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThis is how you can type `constructor` and `create` parameters:\n\n```ts\ntype NewUser = Plain.AllowString<User, { Omit: 'fullname' | 'createdAt'; Optional: '_id' | 'activated' }>\n\n@Model()\nclass User extends Model.I<typeof User>  {\n  // @ts-ignore implementation\n  constructor(doc?: NewUser, strict?: boolean | 'throw')\n}\n\nconst user = new User({ firstname: 'John', lastname: 'Doe' })\nawait user.save()\nawait User.create({ firstname: 'Jeremy', lastname: 'Doe', activated: true })\n```\n\nBy passing `typeof User` to `Model.I`, Reflet is now able to use the constructor signature to type the following static methods: `create`, `insertMany` and `replaceOne`.\n\n_The compiler checks `NewUser` as we need, so you can safely use ts-ignore on the `constructor` to avoid implementing an empty one (remember that `@Model` will replace it with mongoose Model constructor)._\n\n## Augmentations\n\nReflet comes with a dedicated global namespace `RefletMongoose`, so you can augment or narrow specific types.\n\n### SchemaType options augmentation\n\nIf you use plugins like [mongoose-autopopulate](https://github.com/mongodb-js/mongoose-autopopulate),\nyou can augment the global interface `SchemaTypeOptions` to have new options in the `@Field` API.\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface SchemaTypeOptions {\n      autopopulate?: boolean\n    }\n  }\n}\n```\n\nNow you have access to `autopopulate` option in your schemas:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: Company,\n    autopopulate: true\n  })\n  company: Company\n}\n```\n\n#### Virtual options\n\nThe same can be done with the `@Virtual` decorator:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface VirtualOptions {}\n  }\n}\n```\n\n### Model and Document augmentation\n\nYou can augment `Model` and `Document` interfaces with the dedicated global interfaces.\nHere is an example with the [@casl/mongoose](https://github.com/stalniy/casl/tree/master/packages/casl-mongoose) plugin:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface Model {\n      accessibleBy<T extends mongoose.Document>(ability: AnyMongoAbility, action?: string): mongoose.DocumentQuery<T[], T>\n    }\n    interface Document {}\n  }\n}\n```\n\n### References narrowing\n\n[SchemaType `ref` option](https://mongoosejs.com/docs/api#schematypeoptions_SchemaTypeOptions-ref) can be either a Model or a model name. With Reflet, by default, any class can be passed as a Model and any string can be passed as a model name.\n\nBy augmenting the global interface `Ref`, you can:\n\n* Narrow the class to an union of your models.\n* Narrow the string to an union of your models' names.\n\n```ts\n// company.model.ts\n@Model()\nclass Company extends Model.I {\n  @Field(String)\n  name: string\n}\n\n// You should augment the global interface in each of your models' files, to keep it close to the model.\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      Company: Company\n    }\n  }\n}\n```\n\n```ts\n// user.model.ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: 'Company',\n  })\n  company: Company\n}\n\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      User: User\n    }\n  }\n}\n```\n","licenseText":"MIT License\n\nCopyright (c) 2020 Jeremy Bensimon\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@reflet/mongoose@2.0.0-next.7","dist":{"shasum":"07c3cc8843cb392019e1edcfdf16537cf783a2a6","integrity":"sha512-m+dp7cSV3sr6fBBmKCcM7BuwY1dW9xwRD5UywwGtQfbg6Hb78Le1RwDcPKKvpF19B0AAzgZWFB2sa76wZC2cHQ==","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-2.0.0-next.7.tgz","fileCount":23,"unpackedSize":159743,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhlPP6CRA9TVsSAnZWagAA39IP+wfbeRVv/Fbbk/3IQ+Ib\n7U3322tDkwt8vqerSPsXPknRSumXM07rweqB/w1NmhE7zzODJnS2Hvi97VEa\nmbZ69Ywmj7REHxeuG7Sj0qMi9grJ/L0HbXMvo0k89r3Ow+N/xd0hEWXeImcr\nY54tS1rbfvoQ3gTHP+kAiS7EtHf7JZJmvRdIZAc2GgnD0T8hNhLfyy7AvULS\n8tmrWhS4w0Qm/HTkffoA32g+5y0QIHaUtn/8bS3fNv3TUqr+0gGrZyYaz5El\nOVQqCHfEdAzrLf0tu8QFOA2xIA6HZgn328K4C4PsF/EgnoLRnNCtYgqhtjnj\n5PfHcNie+O+yYMdPek0KLpYupmDu/hzxr8+Y+i6eDZ0NjpyVit2t1p1GYSdp\n0U0Nbxwr4/DjayEA128KMVv1HIOBabLPQpvNcbrg9ETpV2/4P0atpOpQ7vdN\nAXw3o8UpJdo1Q1Ee3fjDLNvNe0yrJY1dyBVrc4lu7k1khb7e1OpAHI8TtpKQ\ntP1T1k36/0ay3xcofpr599+EOJe/G4voD2cPxbxqMZcNG42YLC2a5vFZkyQb\nYPkH/UxKVf6C6hYiYhN62zdpJ1GHbxCgv8iFKYyZfcBq/iJWi8HnxSMzOA0L\n+FC4HNfjWHI2WxksmO1JwjGpPNvzUyrUKRviieYKEwtwl0bAMBH93NlUhHkt\nGxku\r\n=zP8b\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCJ+1OTojERU/Dug1k76OQbDzLE9CZy9BgRkrZPZoNtUgIhAIiGxupVVV2vt243vaTLI/40F1xaIyBD8nFjl4nB3h2Y"}]},"_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"directories":{},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_2.0.0-next.7_1637151738214_0.19767816236669877"},"_hasShrinkwrap":false},"2.0.0-next.9":{"name":"@reflet/mongoose","version":"2.0.0-next.9","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet.git","directory":"mongoose"},"homepage":"https://github.com/jeremyben/reflet/tree/master/mongoose#readme","description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=10"},"engineStrict":true,"peerDependencies":{"@types/node":">=10","mongoose":">=6","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^2.1.0","mongoose":"^6.0.12","mongoose-autopopulate":"^0.16.0"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build","publish:next":"yarn publish --tag next"},"readmeFilename":"README.MD","readme":"# `@reflet/mongoose` 🌠\n\n[![lines coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=lines&query=total.lines.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![statements coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=statements&query=total.statements.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![functions coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=functions&query=total.functions.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![branches coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=branches&query=total.branches.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n\nThe **best** decorators for [Mongoose](https://mongoosejs.com/). Have a look at [Reflet's philosophy](../README.MD#Philosophy-).\n\n* [Getting started](#getting-started)\n* [Schema definition](#schema-definition)\n* [Model](#model)\n* [Schema options](#schema-options)\n* [Schema retrieval](#schema-retrieval)\n* [Hooks](#hooks)\n* [Model discriminators](#model-discriminators)\n* [Embedded discriminators](#embedded-discriminators)\n* [Populated virtuals](#populated-virtuals)\n* [Plain helper](#plain-helper)\n* [Augmentations](#augmentations)\n\n## Getting started\n\n1. <details>\n    <summary>Make sure you have decorators enabled. (click for details)</summary>\n    <p>\n\n    * Enable them in your TypeScript compiler options.\n\n        ```json\n        \"experimentalDecorators\": true,\n        \"emitDecoratorMetadata\": true,\n        ```\n\n    * Install `reflect-metadata` shim.\n\n        ```sh\n        yarn add reflect-metadata\n        ```\n\n    * Import the shim in your program before everything else.\n\n        ```ts\n        import 'reflect-metadata'\n        ```\n\n    </p>\n    </details>\n\n2. Install the package along with peer dependencies.\n\n    ```sh\n    yarn add @reflet/mongoose mongoose && yarn add -D @types/mongoose @types/node\n    ```\n\n3. Create your decorated models.\n\n    ```ts\n    // user.model.ts\n    import { Model, Field } from '@reflet/mongoose'\n\n    @Model()\n    export class User extends Model.Interface {\n      static findByEmail(email) {\n        return this.findOne({ email });\n      }\n\n      @Fied({ type: String, required: true })\n      email: string\n\n      getProfileUrl() {\n        return `https://mysite.com/${this.email}`;\n      }\n    }\n    ```\n\n4. Connect to MongoDB and save your documents.\n\n    ```ts\n    // server.ts\n    import 'reflect-metadata'\n    import * as mongoose from 'mongoose'\n    import { User } from './user.model.ts'\n\n    mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true })\n\n    User.create({ email: 'jeremy@example.com' }).then((user) => {\n      console.log(`User ${user._id} has been saved.`)\n    })\n    ```\n\n### The Mongoose way\n\nConnect Mongoose in the way you already know. Models defined with Reflet will simply be attached to the default Mongoose connection.\nThis means you can **progressively** decorate your Mongoose models. 😉\n\n## Schema definition\n\n> 🔦 `@Field(schemaType)`<br>\n> 💫 Related Mongoose object: [SchemaTypes](https://mongoosejs.com/docs/schematypes)\n\nMongoose [already](https://mongoosejs.com/docs/api#schema_Schema-loadClass) allows you to load an ES6 class to attach getters, setters, instance and static methods to a schema.\nBut what about properties ? Enters the `@Field` decorator :\n\n```ts\nclass User {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field(Number)\n  age?: number\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThe `@Field` API is a direct wrapper of Mongoose [SchemaType](https://mongoosejs.com/docs/schematypes), you can put in there everything that you used to.\n\n### Nested properties\n\n> 🔦 `@Field.Nested(schemaTypes)`\n\n```ts\nclass User {\n  @Field.Nested({\n    street: { type: String, required: true },\n    city: { type: String, required: true },\n    country: { type: String, required: true },\n  })\n  address: {\n    street: string\n    city: string\n    country: string\n  }\n}\n```\n\n_`@Field.Nested` works the same as `@Field` at runtime. Its type is simply looser to allow nested objects._\n\n## Model\n\n> 🔦 `@Model(collection?, connection?)`<br>\n> 💫 Related Mongoose method: [`model`](https://mongoosejs.com/docs/models#compiling)\n\nTypeScript [class decorators](https://www.typescriptlang.org/docs/handbook/decorators#class-decorators) can modify and even replace class constructors. Reflet takes advantage of this feature and transforms a class directly into a Mongoose Model.\n\nThis means you don't have to deal with the procedural and separate creation of both schema and model anymore !\nAnd now your properties and methods are statically typed.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\nclass User extends Model.Interface {\n  @Field({ type: String, required: true })\n  email: string\n}\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  email: string\n}\n\nconst userSchema = new mongoose.Schema({\n  email: { type: String, required: true }\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nYour class needs to inherit a special empty class, **`Model.Interface`** or **`Model.I`**, to have Mongoose document properties and methods.\n\n⚠️ `@Model` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n#### Custom collection name\n\nBy default, Mongoose automatically creates a collection named as the plural, lowercased version of your model name. You can customize the collection name, with the first argument:\n\n```ts\n@Model('people')\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n#### Custom Mongoose connection\n\nYou can use a different database by creating a Mongoose connection and passing it as the second argument:\n\n```ts\nconst otherDb = mongoose.createConnection('mongodb://localhost/other', { useNewUrlParser: true })\n\n@Model(undefined, otherDb)\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n## Schema options\n\n> 🔦 `@SchemaOptions(options)`<br>\n> 💫 Related Mongoose object: [Schema options](https://mongoosejs.com/docs/guide#options)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({\n  autoIndex: false,\n  strict: 'throw'\n})\nclass User extends Model.I {           \n  @Field(String)\n  name: string\n}\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    autoIndex: false,\n    strict: 'throw'\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@SchemaOptions` API is a direct wrapper of Mongoose [schema options](https://mongoosejs.com/docs/guide#options), you can put in there everything that you used to.\n\n### Timestamps\n\n> 🔦 `@CreatedAt`, `@UpdatedAt`<br>\n> 💫 Related Mongoose option property: [`timestamps`](https://mongoosejs.com/docs/guide#timestamps)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({ minimize: false })\nclass User extends Model.I {             \n  @Field(String)\n  name: string\n\n  @CreatedAt\n  creationDate: Date\n\n  @UpdatedAt\n  updateDate: Date\n}\n\n\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n  creationDate: Date\n  updateDate: Date\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    minimize: false,\n    timestamps: {\n      createdAt: 'creationDate',\n      updatedAt: 'updateDate'\n    },\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n### Advanced schema manipulation\n\n> 🔦 `@SchemaCallback(callback)`<br>\n> 💫 Related Mongoose object: [`Schema`](https://mongoosejs.com/docs/api/schema)\n\nIf you need more advanced schema manipulation before `@Model` compiles it, you can use `@SchemaCallback`:\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaCallback((schema) => {\n  schema.index({ name: 1, type: -1 })\n})\nclass Animal extends Model.I {          \n  @Field(String)\n  name: string\n\n  @Field(String)\n  type: string\n}\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface AnimalDocument extends mongoose.Document {\n  name: string\n  type: string\n}\n\nconst userSchema = new mongoose.Schema({\n  name: String,\n  type: String\n})\n\nuserSchema.index({ name: 1, type: -1 })\n\nconst Animal = mongoose.model<AnimalDocument>('Animal', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n_Beware of defining hooks in the callback if your schema has embedded discriminators. Mongoose documentation recommends declaring hooks **before** embedded discriminators, the callback is applied **after** them. You should use the dedicated hooks decorators `@PreHook` and `@PostHook`._\n\n## Schema retrieval\n\n> 🔦 `schemaFrom(class)`\n\nYou can retrieve a schema from any decorated class, for advanced manipulation or embedded use in another schema.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Location {\n  @Field(Number)\n  lat: number\n\n  @Field(Number)\n  lng: number\n}\n\n@Model()\nclass City extends Model.I {            \n  @Field(String)\n  name: string\n\n  @Field(schemaFrom(Location))\n  location: Location\n}\n\nconst citySchema = schemaFrom(City)\n```\n\n  </td>\n  <td>\n\n```ts\ninterface CityDocument extends mongoose.Document {\n  name: string\n  location: {\n    lat: number,\n    lng: number\n  }\n}\n\nconst locationSchema = new mongoose.Schema(\n  { lat: Number, lng: Number },\n  { _id: false }\n)\n\nconst citySchema = new mongoose.Schema({\n  name: String,\n  location: locationSchema\n})\n\nconst City = mongoose.model<CityDocument>('City', citySchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n🗣️ As a good practice, you should make your schema-only classes `abstract`, so you don't instantiate them by mistake.\n\n\n### Sub schemas\n\n> 🔦 `Field.Schema(class)`\n\nAs an alternative for the above use of `schemaFrom` inside the `Field` decorator, you can do:\n\n```ts\n@Model()\nclass City extends Model.I {            \n  @Field.Schema(Location)\n  location: Location\n}\n```\n\n## Hooks\n\n### Pre hook\n\n> 🔦 `@PreHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.pre`](https://mongoosejs.com/docs/middleware#pre)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PreHook<User>('save', function(next) {\n  next()\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.pre<UserDocument>('save', function (doc, next) {\n  next()\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PreHook` API is a direct wrapper of Mongoose [Schema.pre method](https://mongoosejs.com/docs/api/schema#schema_Schema-pre), you can put in there everything that you used to.\n\nSuccessive `@PreHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n### Post hook\n\n> 🔦 `@PostHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.post`](https://mongoosejs.com/docs/middleware#post)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PostHook<User>('find', function(result) {\n  console.log(result)\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.post<UserDocument>('find', function (result) {\n  console.log(result)\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PostHook` API is a direct wrapper of Mongoose [Schema.post method](https://mongoosejs.com/docs/api/schema#schema_Schema-post), you can put in there everything that you used to.\n\nSuccessive `@PostHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n#### Post error handling middleware\n\nTo help the compiler accurately infer the [error handling middleware](https://mongoosejs.com/docs/middleware#error-handling-middleware) signature, pass a second type argument to `@PostHook`:\n\n```ts\n@Model()\n@PostHook<User, Error>('save', function(error, doc, next) {\n  if (error.name === 'MongoError' && error.code === 11000) {\n    next(new Error('There was a duplicate key error'))\n  } else {\n    next()\n  }\n})\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n```\n\n## Model discriminators\n\n> 🔦 `@Model.Discriminator(rootModel)`<br>\n> 💫 Related Mongoose method: [`model.discriminator`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Worker extends User {\n  @Field(String)\n  job: string\n\n  // No need to decorate the default discriminatorKey.\n  __t: 'Worker'\n\n  // You can strictly type the constructor of a discriminator model by using the Plain Helper (see below).\n  constructor(worker: Plain.Omit<Worker, '_id' | '__t'>) {\n    super() // required by the compiler.\n  }\n}\n\nconst worker = await Worker.create({ name: 'Jeremy', job: 'developer' })\n// { _id: '5d023ae14043262bcfd9b384', __t: 'Worker', name: 'Jeremy', job: 'developer' }\n```\n\nAs you know, `_t` is the default `discriminatorKey`, and its value will be the class name. If you want to customize both the key and the value, check out the following `@Kind` decorator.\n\n⚠️ `@Model.Discriminator` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model.Discriminator` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n### Kind / DiscriminatorKey\n\n> 🔦 `@Kind(value?)` alias `@DiscriminatorKey`<br>\n> 💫 Related Mongoose option property: [`discriminatorKey`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\nMongoose `discriminatorKey` is usually defined in the parent model options, and appears in the children model documents.\n`@Kind` (or its alias `@DiscriminatorKey`) exists to define `discriminatorKey` **directly** on the children class instead of the parent model.\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Developer extends User {\n  @Kind\n  kind: 'Developer' // Value will be the class name by default.\n}\n\n@Model.Discriminator(User)\nclass Doctor extends User {\n  @Kind('doctor') // Customize the discriminator value by passing a string.\n  kind: 'doctor'\n}\n\n// This is equivalent to setting `{ discriminatorKey: 'kind' }` on User schema options.\n```\n\nA mecanism will check and prevent you from defining a different `@Kind` key on sibling discriminators.\n\n## Embedded discriminators\n\n### Single nested discriminators\n\n> 🔦 `@Field.Union(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`SingleNestedPath.discriminator`](https://mongoosejs.com/docs/discriminators#single-nested-discriminators)\n\n`@Field.Union` allows you to embed discriminators on an single property.\n\n```ts\nabstract class Circle {\n  @Field(Number)\n  radius: number\n\n  __t: 'Circle'\n  // __t is the default discriminatorKey (no need to decorate).\n  // Value will be the class name.\n}\n\nabstract class Square {\n  @Field(Number)\n  side: number\n\n  __t: 'Square'\n}\n\n@Model()\nclass Shape extends Model.I {\n  @Field.Union([Circle, Square], { \n    required: true, // Make the field itself `shape` required.\n    strict: true // Make the discriminator key `__t` required and narrowed to its possible values.\n  })\n  shape: Circle | Square\n}\n\nconst circle = new Shape({ shape: { __t: 'Circle', radius: 5 } })\nconst square = new Shape({ shape: { __t: 'Square', side: 4 } })\n```\n\n### Embedded discriminators in arrays\n\n> 🔦 `@Field.ArrayOfUnion(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`DocumentArrayPath.discriminator`](https://mongoosejs.com/docs/discriminators#embedded-discriminators-in-arrays)\n\n`@Field.ArrayOfUnion` allows you to embed discriminators in an array.\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Clicked {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  element: string\n\n  @Kind\n  kind: 'Clicked'\n}\n\n@SchemaOptions({ _id: false })\nabstract class Purchased {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  product: string\n\n  @Kind\n  kind: 'Purchased'\n}\n\n@Model()\nclass Batch extends Model.I {\n  @Field.ArrayOfUnion([Clicked, Purchased], { \n    strict: true  // Make the discriminator key `kind` required and narrowed to its possible values.\n  })\n  events: (Clicked | Purchased)[]\n}\n\nconst batch = new Batch({\n  events: [\n    { kind: 'Clicked', element: '#hero', message: 'hello' },\n    { kind: 'Purchased', product: 'action-figure', message: 'world' },\n  ]\n})\n```\n\n## Populated virtuals\n\n> 🔦 `@Virtual(options)`<br>\n> 💫 Related Mongoose method: [`schema.virtual`](https://mongoosejs.com/docs/populate#populate-virtuals)\n\n```ts\n@Model()\nclass Person extends Model.I {\n  @Field(String)\n  name: string\n\n  @Field(String)\n  band: string\n}\n\n@Model()\n@SchemaOptions({\n  toObject: { virtuals: true },\n  toJson: { virtuals: true }\n})\nclass Band extends Model.I {\n  @Field(String)\n  name: string\n\n  @Virtual<Band, Person>({\n    ref: 'Person',\n    foreignField: 'band',\n    localField: 'name'\n  })\n  readonly members: string[]\n}\n\nconst bands = await Band.find({}).populate('members')\n```\n\n## Plain helper\n\n> 🔦 `Plain<class, options?>`\n\nReflet provides a generic type to discard Mongoose properties and methods from a Document.\n\n* `Plain<T>` removes inherited Mongoose properties (except `_id`) and all methods from `T`.\n* `Plain.Partial<T>` does the same as `Plain` and makes remaining properties of `T` optional.\n* `Plain.PartialDeep<T>` does the same as `Plain.Partial` recursively.\n\n`Plain` also has a second type argument to omit other properties and/or make them optional:\n\n* `Plain<T, { Omit: keyof T; Optional: keyof T } >`\n\n_These options exist as standalone generics as well: `Plain.Omit<T, keyof T>` and `Plain.Optional<T, keyof T>`._\n\nWith this you can narrow the return type of `toObject()` and `toJson()`:\n\n```ts\nconst userPlain = user.toObject({ getters: false }) as Plain.Omit<User, 'fullname'>\n```\n\n#### Allow `string` for `ObjectId`\n\n> 🔦 `Plain.AllowString<class, options?>`\n\nWhen creating or querying documents, you can pass `ObjectId` as `string`. To allow this, Reflet provides a generic type with the same API as `Plain`:\n\n* `Plain.AllowString<T, { Omit: keyof T; Optional: keyof T } >`\n* `Plain.AllowString.Partial<T>`\n* `Plain.AllowString.PartialDeep<T>`\n\n### One document, multiple shapes\n\nIn each of your models, some fields might be present when you read the document from the database, but optional or even absent when you create it. 😕\n\nGiven the following model:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field({ type: Boolean, default: () => false })\n  activated: boolean\n\n  @CreatedAt\n  createdAt: Date\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThis is how you can type `constructor` and `create` parameters:\n\n```ts\ntype NewUser = Plain.AllowString<User, { Omit: 'fullname' | 'createdAt'; Optional: '_id' | 'activated' }>\n\n@Model()\nclass User extends Model.I<typeof User>  {\n  // @ts-ignore implementation\n  constructor(doc?: NewUser, strict?: boolean | 'throw')\n}\n\nconst user = new User({ firstname: 'John', lastname: 'Doe' })\nawait user.save()\nawait User.create({ firstname: 'Jeremy', lastname: 'Doe', activated: true })\n```\n\nBy passing `typeof User` to `Model.I`, Reflet is now able to use the constructor signature to type the following static methods: `create`, `insertMany` and `replaceOne`.\n\n_The compiler checks `NewUser` as we need, so you can safely use ts-ignore on the `constructor` to avoid implementing an empty one (remember that `@Model` will replace it with mongoose Model constructor)._\n\n## Augmentations\n\nReflet comes with a dedicated global namespace `RefletMongoose`, so you can augment or narrow specific types.\n\n### SchemaType options augmentation\n\nIf you use plugins like [mongoose-autopopulate](https://github.com/mongodb-js/mongoose-autopopulate),\nyou can augment the global interface `SchemaTypeOptions` to have new options in the `@Field` API.\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface SchemaTypeOptions {\n      autopopulate?: boolean\n    }\n  }\n}\n```\n\nNow you have access to `autopopulate` option in your schemas:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: Company,\n    autopopulate: true\n  })\n  company: Company\n}\n```\n\n#### Virtual options\n\nThe same can be done with the `@Virtual` decorator:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface VirtualOptions {}\n  }\n}\n```\n\n### Model and Document augmentation\n\nYou can augment `Model` and `Document` interfaces with the dedicated global interfaces.\nHere is an example with the [@casl/mongoose](https://github.com/stalniy/casl/tree/master/packages/casl-mongoose) plugin:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface Model {\n      accessibleBy<T extends mongoose.Document>(ability: AnyMongoAbility, action?: string): mongoose.DocumentQuery<T[], T>\n    }\n    interface Document {}\n  }\n}\n```\n\n### References narrowing\n\n[SchemaType `ref` option](https://mongoosejs.com/docs/api#schematypeoptions_SchemaTypeOptions-ref) can be either a Model or a model name. With Reflet, by default, any class can be passed as a Model and any string can be passed as a model name.\n\nBy augmenting the global interface `Ref`, you can:\n\n* Narrow the class to an union of your models.\n* Narrow the string to an union of your models' names.\n\n```ts\n// company.model.ts\n@Model()\nclass Company extends Model.I {\n  @Field(String)\n  name: string\n}\n\n// You should augment the global interface in each of your models' files, to keep it close to the model.\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      Company: Company\n    }\n  }\n}\n```\n\n```ts\n// user.model.ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: 'Company',\n  })\n  company: Company\n}\n\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      User: User\n    }\n  }\n}\n```\n","licenseText":"MIT License\n\nCopyright (c) 2020 Jeremy Bensimon\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@reflet/mongoose@2.0.0-next.9","dist":{"shasum":"71793eb8f0b6c94bd7f27ccab6657e8c35f1eca5","integrity":"sha512-AqIntfrY4r0LRRuIrP5nZPY7VJjTioR2fbY39HIpE2dZguL3lvnjzxe+sAZLJXzDjkWquSKYm5OBVckTnZmCeQ==","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-2.0.0-next.9.tgz","fileCount":23,"unpackedSize":164163,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhqTXaCRA9TVsSAnZWagAAf08QAIPnOYXgIMYeWJSyzit5\nRPdkBOTkd0T8VfCzK2KkSflUUCsClazuHNyZw3yiSPYAOpSYW2X7I9PkOsvV\ngZbTpHlYv/Qi5akqdzEGWNA/aV5JfJVKlPI2sFSZ/jNW62jsa+ZxdWWy23bv\nvJ149d/st/KT75hhwJWxJ2MeD1FAc5vFmpudRJzjLcKC6rjeXbmg/8VWq1Lr\n2pFEWbocVGA6U88izc8htBQQccWV+HhEZ2qsPux7xwOgD2PG9e6J8p9NbxxO\nZHRnWKINbTVnYN0MVxVQz16RwOSha38T63PTrsEck7RQg5CUOlbJ1QriKwLQ\nA57be1PUvPazWZkxq8bgvGs2mgFJpX/emBKHmTD1KbmbdlgE9axs2rJMhuP+\nuwe+v9XvGoZKBnJZlmBRmX/QXZqmQGnFXaDo76j6ARdrmwLKgLipQCeYsMg2\niU06pmYLhKMU6g5O9BGjn2myPDERpDeY10vTz01iCz9V46Jq9ZY3zK98G+ic\n2Qs+Lm4lzkid0QwwkI3oKeOO7J/BBg2Wwg0N4gD3ShDQEynpJFETjFcF33uk\nxOCH6dIC3Dh20+s4W10mY2ukzwAdGvO6cOlRSu0eLOpO+O63R41zyzOBGaO8\nN15LUrFcoi7V1lT8xNLyY+DN2GvkhiwNa32V2xMsybEGDbjNrSZ8HvBFvLsm\nYxk5\r\n=HHYU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCatMf/MrL42v+GSi5+zE20J2qygZr3DkRUuenogtVTDgIhAPNNKlfC0OHObbwaQLNoatyBn/ArsuUafBmAF4y3aeRf"}]},"_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"directories":{},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_2.0.0-next.9_1638479322781_0.7540665294520783"},"_hasShrinkwrap":false},"2.0.0-next.10":{"name":"@reflet/mongoose","version":"2.0.0-next.10","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet.git","directory":"mongoose"},"homepage":"https://github.com/jeremyben/reflet/tree/master/mongoose#readme","description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=10"},"engineStrict":true,"peerDependencies":{"@types/node":">=10","mongoose":">=6.1.5","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^2.2.0","mongoose":"^6.1.6","mongoose-autopopulate":"^0.16.0"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build","publish:next":"yarn publish --tag next"},"readmeFilename":"README.MD","readme":"# `@reflet/mongoose` 🌠\n\n[![lines coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=lines&query=total.lines.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![statements coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=statements&query=total.statements.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![functions coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=functions&query=total.functions.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![branches coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=branches&query=total.branches.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n\nThe **best** decorators for [Mongoose](https://mongoosejs.com/). Have a look at [Reflet's philosophy](../README.MD#Philosophy-).\n\n* [Getting started](#getting-started)\n* [Schema definition](#schema-definition)\n* [Model](#model)\n* [Schema options](#schema-options)\n* [Schema retrieval](#schema-retrieval)\n* [Hooks](#hooks)\n* [Model discriminators](#model-discriminators)\n* [Embedded discriminators](#embedded-discriminators)\n* [Populated virtuals](#populated-virtuals)\n* [Plain helper](#plain-helper)\n* [Augmentations](#augmentations)\n\n## Getting started\n\n1. <details>\n    <summary>Make sure you have decorators enabled. (click for details)</summary>\n    <p>\n\n    * Enable them in your TypeScript compiler options.\n\n        ```json\n        \"experimentalDecorators\": true,\n        ```\n\n    * Install `reflect-metadata` shim.\n\n        ```sh\n        yarn add reflect-metadata\n        ```\n\n    * Import the shim in your program before everything else.\n\n        ```ts\n        import 'reflect-metadata'\n        ```\n\n    </p>\n    </details>\n\n2. Install the package along with peer dependencies.\n\n    ```sh\n    yarn add @reflet/mongoose mongoose && yarn add -D @types/mongoose @types/node\n    ```\n\n3. Create your decorated models.\n\n    ```ts\n    // user.model.ts\n    import { Model, Field } from '@reflet/mongoose'\n\n    @Model()\n    export class User extends Model.Interface {\n      static findByEmail(email) {\n        return this.findOne({ email });\n      }\n\n      @Fied({ type: String, required: true })\n      email: string\n\n      getProfileUrl() {\n        return `https://mysite.com/${this.email}`;\n      }\n    }\n    ```\n\n4. Connect to MongoDB and save your documents.\n\n    ```ts\n    // server.ts\n    import 'reflect-metadata'\n    import * as mongoose from 'mongoose'\n    import { User } from './user.model.ts'\n\n    mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true })\n\n    User.create({ email: 'jeremy@example.com' }).then((user) => {\n      console.log(`User ${user._id} has been saved.`)\n    })\n    ```\n\n### The Mongoose way\n\nConnect Mongoose in the way you already know. Models defined with Reflet will simply be attached to the default Mongoose connection.\nThis means you can **progressively** decorate your Mongoose models. 😉\n\n## Schema definition\n\n> 🔦 `@Field(schemaType)`<br>\n> 💫 Related Mongoose object: [SchemaTypes](https://mongoosejs.com/docs/schematypes)\n\nMongoose [already](https://mongoosejs.com/docs/api#schema_Schema-loadClass) allows you to load an ES6 class to attach getters, setters, instance and static methods to a schema.\nBut what about properties ? Enters the `@Field` decorator :\n\n```ts\nclass User {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field(Number)\n  age?: number\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThe `@Field` API is a direct wrapper of Mongoose [SchemaType](https://mongoosejs.com/docs/schematypes), you can put in there everything that you used to.\n\n### Nested properties\n\n> 🔦 `@Field.Nested(schemaTypes)`\n\n```ts\nclass User {\n  @Field.Nested({\n    street: { type: String, required: true },\n    city: { type: String, required: true },\n    country: { type: String, required: true },\n  })\n  address: {\n    street: string\n    city: string\n    country: string\n  }\n}\n```\n\n_`@Field.Nested` works the same as `@Field` at runtime. Its type is simply looser to allow nested objects._\n\n## Model\n\n> 🔦 `@Model(collection?, connection?)`<br>\n> 💫 Related Mongoose method: [`model`](https://mongoosejs.com/docs/models#compiling)\n\nTypeScript [class decorators](https://www.typescriptlang.org/docs/handbook/decorators#class-decorators) can modify and even replace class constructors. Reflet takes advantage of this feature and transforms a class directly into a Mongoose Model.\n\nThis means you don't have to deal with the procedural and separate creation of both schema and model anymore !\nAnd now your properties and methods are statically typed.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\nclass User extends Model.Interface {\n  @Field({ type: String, required: true })\n  email: string\n}\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  email: string\n}\n\nconst userSchema = new mongoose.Schema({\n  email: { type: String, required: true }\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nYour class needs to inherit a special empty class, **`Model.Interface`** or **`Model.I`**, to have Mongoose document properties and methods.\n\n⚠️ `@Model` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n#### Custom collection name\n\nBy default, Mongoose automatically creates a collection named as the plural, lowercased version of your model name. You can customize the collection name, with the first argument:\n\n```ts\n@Model('people')\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n#### Custom Mongoose connection\n\nYou can use a different database by creating a Mongoose connection and passing it as the second argument:\n\n```ts\nconst otherDb = mongoose.createConnection('mongodb://localhost/other', { useNewUrlParser: true })\n\n@Model(undefined, otherDb)\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n## Schema options\n\n> 🔦 `@SchemaOptions(options)`<br>\n> 💫 Related Mongoose object: [Schema options](https://mongoosejs.com/docs/guide#options)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({\n  autoIndex: false,\n  strict: 'throw'\n})\nclass User extends Model.I {           \n  @Field(String)\n  name: string\n}\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    autoIndex: false,\n    strict: 'throw'\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@SchemaOptions` API is a direct wrapper of Mongoose [schema options](https://mongoosejs.com/docs/guide#options), you can put in there everything that you used to.\n\n### Timestamps\n\n> 🔦 `@CreatedAt`, `@UpdatedAt`<br>\n> 💫 Related Mongoose option property: [`timestamps`](https://mongoosejs.com/docs/guide#timestamps)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({ minimize: false })\nclass User extends Model.I {             \n  @Field(String)\n  name: string\n\n  @CreatedAt\n  creationDate: Date\n\n  @UpdatedAt\n  updateDate: Date\n}\n\n\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n  creationDate: Date\n  updateDate: Date\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    minimize: false,\n    timestamps: {\n      createdAt: 'creationDate',\n      updatedAt: 'updateDate'\n    },\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n### Advanced schema manipulation\n\n> 🔦 `@SchemaCallback(callback)`<br>\n> 💫 Related Mongoose object: [`Schema`](https://mongoosejs.com/docs/api/schema)\n\nIf you need more advanced schema manipulation before `@Model` compiles it, you can use `@SchemaCallback`:\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaCallback((schema) => {\n  schema.index({ name: 1, type: -1 })\n})\nclass Animal extends Model.I {          \n  @Field(String)\n  name: string\n\n  @Field(String)\n  type: string\n}\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface AnimalDocument extends mongoose.Document {\n  name: string\n  type: string\n}\n\nconst userSchema = new mongoose.Schema({\n  name: String,\n  type: String\n})\n\nuserSchema.index({ name: 1, type: -1 })\n\nconst Animal = mongoose.model<AnimalDocument>('Animal', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n_Beware of defining hooks in the callback if your schema has embedded discriminators. Mongoose documentation recommends declaring hooks **before** embedded discriminators, the callback is applied **after** them. You should use the dedicated hooks decorators `@PreHook` and `@PostHook`._\n\n## Schema retrieval\n\n> 🔦 `schemaFrom(class)`\n\nYou can retrieve a schema from any decorated class, for advanced manipulation or embedded use in another schema.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Location {\n  @Field(Number)\n  lat: number\n\n  @Field(Number)\n  lng: number\n}\n\n@Model()\nclass City extends Model.I {            \n  @Field(String)\n  name: string\n\n  @Field(schemaFrom(Location))\n  location: Location\n}\n\nconst citySchema = schemaFrom(City)\n```\n\n  </td>\n  <td>\n\n```ts\ninterface CityDocument extends mongoose.Document {\n  name: string\n  location: {\n    lat: number,\n    lng: number\n  }\n}\n\nconst locationSchema = new mongoose.Schema(\n  { lat: Number, lng: Number },\n  { _id: false }\n)\n\nconst citySchema = new mongoose.Schema({\n  name: String,\n  location: locationSchema\n})\n\nconst City = mongoose.model<CityDocument>('City', citySchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n🗣️ As a good practice, you should make your schema-only classes `abstract`, so you don't instantiate them by mistake.\n\n\n### Sub schemas\n\n> 🔦 `Field.Schema(class)`\n\nAs an alternative for the above use of `schemaFrom` inside the `Field` decorator, you can do:\n\n```ts\n@Model()\nclass City extends Model.I {            \n  @Field.Schema(Location)\n  location: Location\n}\n```\n\n## Hooks\n\n### Pre hook\n\n> 🔦 `@PreHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.pre`](https://mongoosejs.com/docs/middleware#pre)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PreHook<User>('save', function(next) {\n  next()\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.pre<UserDocument>('save', function (doc, next) {\n  next()\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PreHook` API is a direct wrapper of Mongoose [Schema.pre method](https://mongoosejs.com/docs/api/schema#schema_Schema-pre), you can put in there everything that you used to.\n\nSuccessive `@PreHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n### Post hook\n\n> 🔦 `@PostHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.post`](https://mongoosejs.com/docs/middleware#post)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PostHook<User>('find', function(result) {\n  console.log(result)\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.post<UserDocument>('find', function (result) {\n  console.log(result)\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PostHook` API is a direct wrapper of Mongoose [Schema.post method](https://mongoosejs.com/docs/api/schema#schema_Schema-post), you can put in there everything that you used to.\n\nSuccessive `@PostHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n#### Post error handling middleware\n\nTo help the compiler accurately infer the [error handling middleware](https://mongoosejs.com/docs/middleware#error-handling-middleware) signature, pass a second type argument to `@PostHook`:\n\n```ts\n@Model()\n@PostHook<User, Error>('save', function(error, doc, next) {\n  if (error.name === 'MongoError' && error.code === 11000) {\n    next(new Error('There was a duplicate key error'))\n  } else {\n    next()\n  }\n})\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n```\n\n## Model discriminators\n\n> 🔦 `@Model.Discriminator(rootModel)`<br>\n> 💫 Related Mongoose method: [`model.discriminator`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Worker extends User {\n  @Field(String)\n  job: string\n\n  // No need to decorate the default discriminatorKey.\n  __t: 'Worker'\n\n  // You can strictly type the constructor of a discriminator model by using the Plain Helper (see below).\n  constructor(worker: Plain.Omit<Worker, '_id' | '__t'>) {\n    super() // required by the compiler.\n  }\n}\n\nconst worker = await Worker.create({ name: 'Jeremy', job: 'developer' })\n// { _id: '5d023ae14043262bcfd9b384', __t: 'Worker', name: 'Jeremy', job: 'developer' }\n```\n\nAs you know, `_t` is the default `discriminatorKey`, and its value will be the class name. If you want to customize both the key and the value, check out the following `@Kind` decorator.\n\n⚠️ `@Model.Discriminator` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model.Discriminator` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n### Kind / DiscriminatorKey\n\n> 🔦 `@Kind(value?)` alias `@DiscriminatorKey`<br>\n> 💫 Related Mongoose option property: [`discriminatorKey`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\nMongoose `discriminatorKey` is usually defined in the parent model options, and appears in the children model documents.\n`@Kind` (or its alias `@DiscriminatorKey`) exists to define `discriminatorKey` **directly** on the children class instead of the parent model.\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Developer extends User {\n  @Kind\n  kind: 'Developer' // Value will be the class name by default.\n}\n\n@Model.Discriminator(User)\nclass Doctor extends User {\n  @Kind('doctor') // Customize the discriminator value by passing a string.\n  kind: 'doctor'\n}\n\n// This is equivalent to setting `{ discriminatorKey: 'kind' }` on User schema options.\n```\n\nA mecanism will check and prevent you from defining a different `@Kind` key on sibling discriminators.\n\n## Embedded discriminators\n\n### Single nested discriminators\n\n> 🔦 `@Field.Union(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`SingleNestedPath.discriminator`](https://mongoosejs.com/docs/discriminators#single-nested-discriminators)\n\n`@Field.Union` allows you to embed discriminators on an single property.\n\n```ts\nabstract class Circle {\n  @Field(Number)\n  radius: number\n\n  __t: 'Circle'\n  // __t is the default discriminatorKey (no need to decorate).\n  // Value will be the class name.\n}\n\nabstract class Square {\n  @Field(Number)\n  side: number\n\n  __t: 'Square'\n}\n\n@Model()\nclass Shape extends Model.I {\n  @Field.Union([Circle, Square], { \n    required: true, // Make the field itself `shape` required.\n    strict: true // Make the discriminator key `__t` required and narrowed to its possible values.\n  })\n  shape: Circle | Square\n}\n\nconst circle = new Shape({ shape: { __t: 'Circle', radius: 5 } })\nconst square = new Shape({ shape: { __t: 'Square', side: 4 } })\n```\n\n### Embedded discriminators in arrays\n\n> 🔦 `@Field.ArrayOfUnion(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`DocumentArrayPath.discriminator`](https://mongoosejs.com/docs/discriminators#embedded-discriminators-in-arrays)\n\n`@Field.ArrayOfUnion` allows you to embed discriminators in an array.\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Clicked {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  element: string\n\n  @Kind\n  kind: 'Clicked'\n}\n\n@SchemaOptions({ _id: false })\nabstract class Purchased {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  product: string\n\n  @Kind\n  kind: 'Purchased'\n}\n\n@Model()\nclass Batch extends Model.I {\n  @Field.ArrayOfUnion([Clicked, Purchased], { \n    strict: true  // Make the discriminator key `kind` required and narrowed to its possible values.\n  })\n  events: (Clicked | Purchased)[]\n}\n\nconst batch = new Batch({\n  events: [\n    { kind: 'Clicked', element: '#hero', message: 'hello' },\n    { kind: 'Purchased', product: 'action-figure', message: 'world' },\n  ]\n})\n```\n\n## Populated virtuals\n\n> 🔦 `@Virtual(options)`<br>\n> 💫 Related Mongoose method: [`schema.virtual`](https://mongoosejs.com/docs/populate#populate-virtuals)\n\n```ts\n@Model()\nclass Person extends Model.I {\n  @Field(String)\n  name: string\n\n  @Field(String)\n  band: string\n}\n\n@Model()\n@SchemaOptions({\n  toObject: { virtuals: true },\n  toJson: { virtuals: true }\n})\nclass Band extends Model.I {\n  @Field(String)\n  name: string\n\n  @Virtual<Band, Person>({\n    ref: 'Person',\n    foreignField: 'band',\n    localField: 'name'\n  })\n  readonly members: string[]\n}\n\nconst bands = await Band.find({}).populate('members')\n```\n\n## Plain helper\n\n> 🔦 `Plain<class, options?>`\n\nReflet provides a generic type to discard Mongoose properties and methods from a Document.\n\n* `Plain<T>` removes inherited Mongoose properties (except `_id`) and all methods from `T`.\n* `Plain.Partial<T>` does the same as `Plain` and makes remaining properties of `T` optional.\n* `Plain.PartialDeep<T>` does the same as `Plain.Partial` recursively.\n\n`Plain` also has a second type argument to omit other properties and/or make them optional:\n\n* `Plain<T, { Omit: keyof T; Optional: keyof T } >`\n\n_These options exist as standalone generics as well: `Plain.Omit<T, keyof T>` and `Plain.Optional<T, keyof T>`._\n\nWith this you can narrow the return type of `toObject()` and `toJson()`:\n\n```ts\nconst userPlain = user.toObject({ getters: false }) as Plain.Omit<User, 'fullname'>\n```\n\n#### Allow `string` for `ObjectId`\n\n> 🔦 `Plain.AllowString<class, options?>`\n\nWhen creating or querying documents, you can pass `ObjectId` as `string`. To allow this, Reflet provides a generic type with the same API as `Plain`:\n\n* `Plain.AllowString<T, { Omit: keyof T; Optional: keyof T } >`\n* `Plain.AllowString.Partial<T>`\n* `Plain.AllowString.PartialDeep<T>`\n\n### One document, multiple shapes\n\nIn each of your models, some fields might be present when you read the document from the database, but optional or even absent when you create it. 😕\n\nGiven the following model:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field({ type: Boolean, default: () => false })\n  activated: boolean\n\n  @CreatedAt\n  createdAt: Date\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThis is how you can type `constructor` and `create` parameters:\n\n```ts\ntype NewUser = Plain.AllowString<User, { Omit: 'fullname' | 'createdAt'; Optional: '_id' | 'activated' }>\n\n@Model()\nclass User extends Model.I<typeof User>  {\n  // @ts-ignore implementation\n  constructor(doc?: NewUser, strict?: boolean | 'throw')\n}\n\nconst user = new User({ firstname: 'John', lastname: 'Doe' })\nawait user.save()\nawait User.create({ firstname: 'Jeremy', lastname: 'Doe', activated: true })\n```\n\nBy passing `typeof User` to `Model.I`, Reflet is now able to use the constructor signature to type the following static methods: `create`, `insertMany` and `replaceOne`.\n\n_The compiler checks `NewUser` as we need, so you can safely use ts-ignore on the `constructor` to avoid implementing an empty one (remember that `@Model` will replace it with mongoose Model constructor)._\n\n## Augmentations\n\nReflet comes with a dedicated global namespace `RefletMongoose`, so you can augment or narrow specific types.\n\n### SchemaType options augmentation\n\nIf you use plugins like [mongoose-autopopulate](https://github.com/mongodb-js/mongoose-autopopulate),\nyou can augment the global interface `SchemaTypeOptions` to have new options in the `@Field` API.\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface SchemaTypeOptions {\n      autopopulate?: boolean\n    }\n  }\n}\n```\n\nNow you have access to `autopopulate` option in your schemas:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: Company,\n    autopopulate: true\n  })\n  company: Company\n}\n```\n\n#### Virtual options\n\nThe same can be done with the `@Virtual` decorator:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface VirtualOptions {}\n  }\n}\n```\n\n### Model and Document augmentation\n\nYou can augment `Model` and `Document` interfaces with the dedicated global interfaces.\nHere is an example with the [@casl/mongoose](https://github.com/stalniy/casl/tree/master/packages/casl-mongoose) plugin:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface Model {\n      accessibleBy<T extends mongoose.Document>(ability: AnyMongoAbility, action?: string): mongoose.DocumentQuery<T[], T>\n    }\n    interface Document {}\n  }\n}\n```\n\n### References narrowing\n\n[SchemaType `ref` option](https://mongoosejs.com/docs/api#schematypeoptions_SchemaTypeOptions-ref) can be either a Model or a model name. With Reflet, by default, any class can be passed as a Model and any string can be passed as a model name.\n\nBy augmenting the global interface `Ref`, you can:\n\n* Narrow the class to an union of your models.\n* Narrow the string to an union of your models' names.\n\n```ts\n// company.model.ts\n@Model()\nclass Company extends Model.I {\n  @Field(String)\n  name: string\n}\n\n// You should augment the global interface in each of your models' files, to keep it close to the model.\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      Company: Company\n    }\n  }\n}\n```\n\n```ts\n// user.model.ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: 'Company',\n  })\n  company: Company\n}\n\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      User: User\n    }\n  }\n}\n```\n","licenseText":"MIT License\n\nCopyright (c) 2020 Jeremy Bensimon\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@reflet/mongoose@2.0.0-next.10","dist":{"shasum":"7c74cb4cd5edd3b233b30d4f617a97ad39c517ed","integrity":"sha512-VPt4qvwkUOIIYjCQh858K7kOZ5+7Fn6Ng1pXjhV+DsU3dBmzQ5TrgWREKX06FydvQ9FOvnFDm1mzl+XkVpc7Uw==","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-2.0.0-next.10.tgz","fileCount":22,"unpackedSize":153139,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh4BY/CRA9TVsSAnZWagAAE+8P/17kp3N0jIYddwHOWZln\nkdhg8nHgLOK+dIaMgFQ+ItFyt/t2x4oVOcPb0oG08Mn9jmDvWAXi8djGjFcR\njTHOA19iKeDEzxxFQzDKzHfZnjpKKQ++iHU0lBa6HEpOe4T0dssE7RXF1EUj\nFwxWZ792AYaNq1YHbxQ1aiIdCu0kC8poUlpUpNhEUfcHlS+S42NKPDv18wQV\nx9hBwCxfGPlLCd9gv9YtnfwRbROo/ue+IA+MGKliUZiJ9MtOLTmobaLIIXvh\nAELKYeItEsYA9WO64amF0FRWv0wdz/sMMRF5Ot+Pbm5CmluM8d/BTHlNN2rb\n/zJSAfCQpUruQjGvkvMpMotmZx5MF6MSgh8s3iyU9NTxOV+Dv79Qj3ATfPNK\nbwBcyFkM0EdmXAP1l7WO4P/DDC6B0f51SE+wyh989yyWjdcWBWMOWhh6VRGF\nuceX77Jy4l65rufS/foH0tnIvqcRkeIxmS58ESeziQfx3ENTokBv/6ArqsoG\nkcWEakHQWNe3KFByNAeryKi48LVveqa5MwZeKHUtqibj0nvuVXPsjt3l0LzV\noOL6v9LJkMSyz3LQ8Ux9N1NBzEKJJgc7zgmevTOrmU0yIg36c7c3G9SI1Dev\n91EDjxKohvRKDC2hLzntMG/D+5Fqb74t719iB+rqPYEWyo7cBhleHBphS+li\nilax\r\n=m8r8\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICpvqikhO9dMs4Cr3sfL/xWBPrDIinIfJ1bjsRsa+my3AiAUlVQaSrip5+034G7F0minP8ykpUWZo1LLlq4K7uDwaw=="}]},"_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"directories":{},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_2.0.0-next.10_1642075711446_0.35845659718899126"},"_hasShrinkwrap":false},"2.0.0-next.11":{"name":"@reflet/mongoose","version":"2.0.0-next.11","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet.git","directory":"mongoose"},"homepage":"https://github.com/jeremyben/reflet/tree/master/mongoose#readme","description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=10"},"engineStrict":true,"peerDependencies":{"@types/node":">=10","mongoose":">=6.1.5","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^2.2.0","mongoose":"^6.1.6","mongoose-autopopulate":"^0.16.0"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build","publish:next":"yarn publish --tag next"},"readmeFilename":"README.MD","readme":"# `@reflet/mongoose` 🌠\n\n[![lines coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=lines&query=total.lines.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![statements coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=statements&query=total.statements.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![functions coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=functions&query=total.functions.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![branches coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=branches&query=total.branches.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n\nThe **best** decorators for [Mongoose](https://mongoosejs.com/). Have a look at [Reflet's philosophy](../README.MD#Philosophy-).\n\n* [Getting started](#getting-started)\n* [Schema definition](#schema-definition)\n* [Model](#model)\n* [Schema options](#schema-options)\n* [Schema retrieval](#schema-retrieval)\n* [Hooks](#hooks)\n* [Model discriminators](#model-discriminators)\n* [Embedded discriminators](#embedded-discriminators)\n* [Populated virtuals](#populated-virtuals)\n* [Plain helper](#plain-helper)\n* [Augmentations](#augmentations)\n\n## Getting started\n\n1. <details>\n    <summary>Make sure you have decorators enabled. (click for details)</summary>\n    <p>\n\n    * Enable them in your TypeScript compiler options.\n\n        ```json\n        \"experimentalDecorators\": true,\n        ```\n\n    * Install `reflect-metadata` shim.\n\n        ```sh\n        yarn add reflect-metadata\n        ```\n\n    * Import the shim in your program before everything else.\n\n        ```ts\n        import 'reflect-metadata'\n        ```\n\n    </p>\n    </details>\n\n2. Install the package along with peer dependencies.\n\n    ```sh\n    yarn add @reflet/mongoose mongoose && yarn add -D @types/mongoose @types/node\n    ```\n\n3. Create your decorated models.\n\n    ```ts\n    // user.model.ts\n    import { Model, Field } from '@reflet/mongoose'\n\n    @Model()\n    export class User extends Model.Interface {\n      static findByEmail(email) {\n        return this.findOne({ email });\n      }\n\n      @Fied({ type: String, required: true })\n      email: string\n\n      getProfileUrl() {\n        return `https://mysite.com/${this.email}`;\n      }\n    }\n    ```\n\n4. Connect to MongoDB and save your documents.\n\n    ```ts\n    // server.ts\n    import 'reflect-metadata'\n    import * as mongoose from 'mongoose'\n    import { User } from './user.model.ts'\n\n    mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true })\n\n    User.create({ email: 'jeremy@example.com' }).then((user) => {\n      console.log(`User ${user._id} has been saved.`)\n    })\n    ```\n\n### The Mongoose way\n\nConnect Mongoose in the way you already know. Models defined with Reflet will simply be attached to the default Mongoose connection.\nThis means you can **progressively** decorate your Mongoose models. 😉\n\n## Schema definition\n\n> 🔦 `@Field(schemaType)`<br>\n> 💫 Related Mongoose object: [SchemaTypes](https://mongoosejs.com/docs/schematypes)\n\nMongoose [already](https://mongoosejs.com/docs/api#schema_Schema-loadClass) allows you to load an ES6 class to attach getters, setters, instance and static methods to a schema.\nBut what about properties ? Enters the `@Field` decorator :\n\n```ts\nclass User {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field(Number)\n  age?: number\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThe `@Field` API is a direct wrapper of Mongoose [SchemaType](https://mongoosejs.com/docs/schematypes), you can put in there everything that you used to.\n\n### Nested properties\n\n> 🔦 `@Field.Nested(schemaTypes)`\n\n```ts\nclass User {\n  @Field.Nested({\n    street: { type: String, required: true },\n    city: { type: String, required: true },\n    country: { type: String, required: true },\n  })\n  address: {\n    street: string\n    city: string\n    country: string\n  }\n}\n```\n\n_`@Field.Nested` works the same as `@Field` at runtime. Its type is simply looser to allow nested objects._\n\n## Model\n\n> 🔦 `@Model(collection?, connection?)`<br>\n> 💫 Related Mongoose method: [`model`](https://mongoosejs.com/docs/models#compiling)\n\nTypeScript [class decorators](https://www.typescriptlang.org/docs/handbook/decorators#class-decorators) can modify and even replace class constructors. Reflet takes advantage of this feature and transforms a class directly into a Mongoose Model.\n\nThis means you don't have to deal with the procedural and separate creation of both schema and model anymore !\nAnd now your properties and methods are statically typed.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\nclass User extends Model.Interface {\n  @Field({ type: String, required: true })\n  email: string\n}\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  email: string\n}\n\nconst userSchema = new mongoose.Schema({\n  email: { type: String, required: true }\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nYour class needs to inherit a special empty class, **`Model.Interface`** or **`Model.I`**, to have Mongoose document properties and methods.\n\n⚠️ `@Model` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n#### Custom collection name\n\nBy default, Mongoose automatically creates a collection named as the plural, lowercased version of your model name. You can customize the collection name, with the first argument:\n\n```ts\n@Model('people')\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n#### Custom Mongoose connection\n\nYou can use a different database by creating a Mongoose connection and passing it as the second argument:\n\n```ts\nconst otherDb = mongoose.createConnection('mongodb://localhost/other', { useNewUrlParser: true })\n\n@Model(undefined, otherDb)\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n## Schema options\n\n> 🔦 `@SchemaOptions(options)`<br>\n> 💫 Related Mongoose object: [Schema options](https://mongoosejs.com/docs/guide#options)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({\n  autoIndex: false,\n  strict: 'throw'\n})\nclass User extends Model.I {           \n  @Field(String)\n  name: string\n}\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    autoIndex: false,\n    strict: 'throw'\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@SchemaOptions` API is a direct wrapper of Mongoose [schema options](https://mongoosejs.com/docs/guide#options), you can put in there everything that you used to.\n\n### Timestamps\n\n> 🔦 `@CreatedAt`, `@UpdatedAt`<br>\n> 💫 Related Mongoose option property: [`timestamps`](https://mongoosejs.com/docs/guide#timestamps)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({ minimize: false })\nclass User extends Model.I {             \n  @Field(String)\n  name: string\n\n  @CreatedAt\n  creationDate: Date\n\n  @UpdatedAt\n  updateDate: Date\n}\n\n\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n  creationDate: Date\n  updateDate: Date\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    minimize: false,\n    timestamps: {\n      createdAt: 'creationDate',\n      updatedAt: 'updateDate'\n    },\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n### Advanced schema manipulation\n\n> 🔦 `@SchemaCallback(callback)`<br>\n> 💫 Related Mongoose object: [`Schema`](https://mongoosejs.com/docs/api/schema)\n\nIf you need more advanced schema manipulation before `@Model` compiles it, you can use `@SchemaCallback`:\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaCallback((schema) => {\n  schema.index({ name: 1, type: -1 })\n})\nclass Animal extends Model.I {          \n  @Field(String)\n  name: string\n\n  @Field(String)\n  type: string\n}\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface AnimalDocument extends mongoose.Document {\n  name: string\n  type: string\n}\n\nconst userSchema = new mongoose.Schema({\n  name: String,\n  type: String\n})\n\nuserSchema.index({ name: 1, type: -1 })\n\nconst Animal = mongoose.model<AnimalDocument>('Animal', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n_Beware of defining hooks in the callback if your schema has embedded discriminators. Mongoose documentation recommends declaring hooks **before** embedded discriminators, the callback is applied **after** them. You should use the dedicated hooks decorators `@PreHook` and `@PostHook`._\n\n## Schema retrieval\n\n> 🔦 `schemaFrom(class)`\n\nYou can retrieve a schema from any decorated class, for advanced manipulation or embedded use in another schema.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Location {\n  @Field(Number)\n  lat: number\n\n  @Field(Number)\n  lng: number\n}\n\n@Model()\nclass City extends Model.I {            \n  @Field(String)\n  name: string\n\n  @Field(schemaFrom(Location))\n  location: Location\n}\n\nconst citySchema = schemaFrom(City)\n```\n\n  </td>\n  <td>\n\n```ts\ninterface CityDocument extends mongoose.Document {\n  name: string\n  location: {\n    lat: number,\n    lng: number\n  }\n}\n\nconst locationSchema = new mongoose.Schema(\n  { lat: Number, lng: Number },\n  { _id: false }\n)\n\nconst citySchema = new mongoose.Schema({\n  name: String,\n  location: locationSchema\n})\n\nconst City = mongoose.model<CityDocument>('City', citySchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n🗣️ As a good practice, you should make your schema-only classes `abstract`, so you don't instantiate them by mistake.\n\n\n### Sub schemas\n\n> 🔦 `Field.Schema(class)`\n\nAs an alternative for the above use of `schemaFrom` inside the `Field` decorator, you can do:\n\n```ts\n@Model()\nclass City extends Model.I {            \n  @Field.Schema(Location)\n  location: Location\n}\n```\n\n## Hooks\n\n### Pre hook\n\n> 🔦 `@PreHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.pre`](https://mongoosejs.com/docs/middleware#pre)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PreHook<User>('save', function(next) {\n  next()\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.pre<UserDocument>('save', function (doc, next) {\n  next()\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PreHook` API is a direct wrapper of Mongoose [Schema.pre method](https://mongoosejs.com/docs/api/schema#schema_Schema-pre), you can put in there everything that you used to.\n\nSuccessive `@PreHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n### Post hook\n\n> 🔦 `@PostHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.post`](https://mongoosejs.com/docs/middleware#post)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PostHook<User>('find', function(result) {\n  console.log(result)\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.post<UserDocument>('find', function (result) {\n  console.log(result)\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PostHook` API is a direct wrapper of Mongoose [Schema.post method](https://mongoosejs.com/docs/api/schema#schema_Schema-post), you can put in there everything that you used to.\n\nSuccessive `@PostHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n#### Post error handling middleware\n\nTo help the compiler accurately infer the [error handling middleware](https://mongoosejs.com/docs/middleware#error-handling-middleware) signature, pass a second type argument to `@PostHook`:\n\n```ts\n@Model()\n@PostHook<User, Error>('save', function(error, doc, next) {\n  if (error.name === 'MongoError' && error.code === 11000) {\n    next(new Error('There was a duplicate key error'))\n  } else {\n    next()\n  }\n})\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n```\n\n## Model discriminators\n\n> 🔦 `@Model.Discriminator(rootModel)`<br>\n> 💫 Related Mongoose method: [`model.discriminator`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Worker extends User {\n  @Field(String)\n  job: string\n\n  // No need to decorate the default discriminatorKey.\n  __t: 'Worker'\n\n  // You can strictly type the constructor of a discriminator model by using the Plain Helper (see below).\n  constructor(worker: Plain.Omit<Worker, '_id' | '__t'>) {\n    super() // required by the compiler.\n  }\n}\n\nconst worker = await Worker.create({ name: 'Jeremy', job: 'developer' })\n// { _id: '5d023ae14043262bcfd9b384', __t: 'Worker', name: 'Jeremy', job: 'developer' }\n```\n\nAs you know, `_t` is the default `discriminatorKey`, and its value will be the class name. If you want to customize both the key and the value, check out the following `@Kind` decorator.\n\n⚠️ `@Model.Discriminator` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model.Discriminator` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n### Kind / DiscriminatorKey\n\n> 🔦 `@Kind(value?)` alias `@DiscriminatorKey`<br>\n> 💫 Related Mongoose option property: [`discriminatorKey`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\nMongoose `discriminatorKey` is usually defined in the parent model options, and appears in the children model documents.\n`@Kind` (or its alias `@DiscriminatorKey`) exists to define `discriminatorKey` **directly** on the children class instead of the parent model.\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Developer extends User {\n  @Kind\n  kind: 'Developer' // Value will be the class name by default.\n}\n\n@Model.Discriminator(User)\nclass Doctor extends User {\n  @Kind('doctor') // Customize the discriminator value by passing a string.\n  kind: 'doctor'\n}\n\n// This is equivalent to setting `{ discriminatorKey: 'kind' }` on User schema options.\n```\n\nA mecanism will check and prevent you from defining a different `@Kind` key on sibling discriminators.\n\n## Embedded discriminators\n\n### Single nested discriminators\n\n> 🔦 `@Field.Union(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`SingleNestedPath.discriminator`](https://mongoosejs.com/docs/discriminators#single-nested-discriminators)\n\n`@Field.Union` allows you to embed discriminators on an single property.\n\n```ts\nabstract class Circle {\n  @Field(Number)\n  radius: number\n\n  __t: 'Circle'\n  // __t is the default discriminatorKey (no need to decorate).\n  // Value will be the class name.\n}\n\nabstract class Square {\n  @Field(Number)\n  side: number\n\n  __t: 'Square'\n}\n\n@Model()\nclass Shape extends Model.I {\n  @Field.Union([Circle, Square], { \n    required: true, // Make the field itself `shape` required.\n    strict: true // Make the discriminator key `__t` required and narrowed to its possible values.\n  })\n  shape: Circle | Square\n}\n\nconst circle = new Shape({ shape: { __t: 'Circle', radius: 5 } })\nconst square = new Shape({ shape: { __t: 'Square', side: 4 } })\n```\n\n### Embedded discriminators in arrays\n\n> 🔦 `@Field.ArrayOfUnion(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`DocumentArrayPath.discriminator`](https://mongoosejs.com/docs/discriminators#embedded-discriminators-in-arrays)\n\n`@Field.ArrayOfUnion` allows you to embed discriminators in an array.\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Clicked {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  element: string\n\n  @Kind\n  kind: 'Clicked'\n}\n\n@SchemaOptions({ _id: false })\nabstract class Purchased {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  product: string\n\n  @Kind\n  kind: 'Purchased'\n}\n\n@Model()\nclass Batch extends Model.I {\n  @Field.ArrayOfUnion([Clicked, Purchased], { \n    strict: true  // Make the discriminator key `kind` required and narrowed to its possible values.\n  })\n  events: (Clicked | Purchased)[]\n}\n\nconst batch = new Batch({\n  events: [\n    { kind: 'Clicked', element: '#hero', message: 'hello' },\n    { kind: 'Purchased', product: 'action-figure', message: 'world' },\n  ]\n})\n```\n\n## Populated virtuals\n\n> 🔦 `@Virtual(options)`<br>\n> 💫 Related Mongoose method: [`schema.virtual`](https://mongoosejs.com/docs/populate#populate-virtuals)\n\n```ts\n@Model()\nclass Person extends Model.I {\n  @Field(String)\n  name: string\n\n  @Field(String)\n  band: string\n}\n\n@Model()\n@SchemaOptions({\n  toObject: { virtuals: true },\n  toJson: { virtuals: true }\n})\nclass Band extends Model.I {\n  @Field(String)\n  name: string\n\n  @Virtual<Band, Person>({\n    ref: 'Person',\n    foreignField: 'band',\n    localField: 'name'\n  })\n  readonly members: string[]\n}\n\nconst bands = await Band.find({}).populate('members')\n```\n\n## Plain helper\n\n> 🔦 `Plain<class, options?>`\n\nReflet provides a generic type to discard Mongoose properties and methods from a Document.\n\n* `Plain<T>` removes inherited Mongoose properties (except `_id`) and all methods from `T`.\n* `Plain.Partial<T>` does the same as `Plain` and makes remaining properties of `T` optional.\n* `Plain.PartialDeep<T>` does the same as `Plain.Partial` recursively.\n\n`Plain` also has a second type argument to omit other properties and/or make them optional:\n\n* `Plain<T, { Omit: keyof T; Optional: keyof T } >`\n\n_These options exist as standalone generics as well: `Plain.Omit<T, keyof T>` and `Plain.Optional<T, keyof T>`._\n\nWith this you can narrow the return type of `toObject()` and `toJson()`:\n\n```ts\nconst userPlain = user.toObject({ getters: false }) as Plain.Omit<User, 'fullname'>\n```\n\n#### Allow `string` for `ObjectId`\n\n> 🔦 `Plain.AllowString<class, options?>`\n\nWhen creating or querying documents, you can pass `ObjectId` as `string`. To allow this, Reflet provides a generic type with the same API as `Plain`:\n\n* `Plain.AllowString<T, { Omit: keyof T; Optional: keyof T } >`\n* `Plain.AllowString.Partial<T>`\n* `Plain.AllowString.PartialDeep<T>`\n\n### One document, multiple shapes\n\nIn each of your models, some fields might be present when you read the document from the database, but optional or even absent when you create it. 😕\n\nGiven the following model:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field({ type: Boolean, default: () => false })\n  activated: boolean\n\n  @CreatedAt\n  createdAt: Date\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThis is how you can type `constructor` and `create` parameters:\n\n```ts\ntype NewUser = Plain.AllowString<User, { Omit: 'fullname' | 'createdAt'; Optional: '_id' | 'activated' }>\n\n@Model()\nclass User extends Model.I<typeof User>  {\n  // @ts-ignore implementation\n  constructor(doc?: NewUser, strict?: boolean | 'throw')\n}\n\nconst user = new User({ firstname: 'John', lastname: 'Doe' })\nawait user.save()\nawait User.create({ firstname: 'Jeremy', lastname: 'Doe', activated: true })\n```\n\nBy passing `typeof User` to `Model.I`, Reflet is now able to use the constructor signature to type the following static methods: `create`, `insertMany` and `replaceOne`.\n\n_The compiler checks `NewUser` as we need, so you can safely use ts-ignore on the `constructor` to avoid implementing an empty one (remember that `@Model` will replace it with mongoose Model constructor)._\n\n## Augmentations\n\nReflet comes with a dedicated global namespace `RefletMongoose`, so you can augment or narrow specific types.\n\n### SchemaType options augmentation\n\nIf you use plugins like [mongoose-autopopulate](https://github.com/mongodb-js/mongoose-autopopulate),\nyou can augment the global interface `SchemaTypeOptions` to have new options in the `@Field` API.\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface SchemaTypeOptions {\n      autopopulate?: boolean\n    }\n  }\n}\n```\n\nNow you have access to `autopopulate` option in your schemas:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: Company,\n    autopopulate: true\n  })\n  company: Company\n}\n```\n\n#### Virtual options\n\nThe same can be done with the `@Virtual` decorator:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface VirtualOptions {}\n  }\n}\n```\n\n### Model and Document augmentation\n\nYou can augment `Model` and `Document` interfaces with the dedicated global interfaces.\nHere is an example with the [@casl/mongoose](https://github.com/stalniy/casl/tree/master/packages/casl-mongoose) plugin:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface Model {\n      accessibleBy<T extends mongoose.Document>(ability: AnyMongoAbility, action?: string): mongoose.DocumentQuery<T[], T>\n    }\n    interface Document {}\n  }\n}\n```\n\n### References narrowing\n\n[SchemaType `ref` option](https://mongoosejs.com/docs/api#schematypeoptions_SchemaTypeOptions-ref) can be either a Model or a model name. With Reflet, by default, any class can be passed as a Model and any string can be passed as a model name.\n\nBy augmenting the global interface `Ref`, you can:\n\n* Narrow the class to an union of your models.\n* Narrow the string to an union of your models' names.\n\n```ts\n// company.model.ts\n@Model()\nclass Company extends Model.I {\n  @Field(String)\n  name: string\n}\n\n// You should augment the global interface in each of your models' files, to keep it close to the model.\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      Company: Company\n    }\n  }\n}\n```\n\n```ts\n// user.model.ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: 'Company',\n  })\n  company: Company\n}\n\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      User: User\n    }\n  }\n}\n```\n","licenseText":"MIT License\n\nCopyright (c) 2020 Jeremy Bensimon\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@reflet/mongoose@2.0.0-next.11","dist":{"shasum":"2414fa5515e99fd4fddc39257dc67b66e9c198b3","integrity":"sha512-knphz+CZCkALGjB5JdE5v39nastWGVYjzCiVJ6WFefBGsz2kR5jTlZVIYY8E6r87E6AxkCXJqwCWbJSKwaIflQ==","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-2.0.0-next.11.tgz","fileCount":22,"unpackedSize":154486,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh79p5CRA9TVsSAnZWagAAQXEP/j3e1Pa4z2yGzrYh/JMg\nNoRiVEmlrARiYXbmO6z+JF+9ZQlchS4hsHWhO36FiXy0Ls2X7WStFahy28os\n/PECvwfDzCul3I8GzmMXYkZNnXBDwW5CaWfgZelB7cj4iT1H9Sl7E/tp6J9W\n/OgoewoHSiF+uCC/eRTR5F+imzkZPjUHP4ClbneN3xEkErcLdoPE7VlfTApe\njK8ecRxJJSogwWXMWYRYylYyoSbCZQeptddHovXYA9OWBEBwrEoeEDSOlmXz\n8y2LggB7Wq1gI5I3wOGW+yD3E/IX740C5Ymq4YgsKGljYRFID8S5zwhbmWsy\nBTFlajM9qnb5BBxvEZIBLBkcowoHyRw/Fz77bzZEYkbtQtwZYP4RnhA41/HC\nEKKkUXgfOJp+JkEAthNtaH8L7ze2vExYfi55JphziR+tYrfhhnMC5vp46duf\nt70bh0Ow+w4z4sJNbBjzvaFumzpN51oDQ2gPCbV3adYmb0WB40q41TtMAXYY\nHBOJge/nySj/Bivlh98fINJhLHoaMXklbwRSNYIGkqCgtnzndyxlM2x10ku+\nCGZVlq3xX0++kPeDvR+htS5dzlpMign/DxLCWvqy9B/LMS7wGE9B6bScd/xJ\nE6gRahv6fmWneHfc74VSEouIMUzjrBayac6bQcNAdaGPpG50UivWq4LtO5EB\nmhP2\r\n=2pj1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFdGrMkn5b+5iORpC8RxPUyvfzyg7u5LOxv/1aNun7dHAiAhJ2LcOO4CDypY7WzCDjO2l+VdBQ2ObfOhT+cJcnXH7w=="}]},"_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"directories":{},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_2.0.0-next.11_1643108985774_0.33844717637486355"},"_hasShrinkwrap":false},"2.0.0-next.12":{"name":"@reflet/mongoose","version":"2.0.0-next.12","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet.git","directory":"mongoose"},"homepage":"https://github.com/jeremyben/reflet/tree/master/mongoose#readme","description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=10"},"engineStrict":true,"peerDependencies":{"@types/node":">=10","mongoose":">=6.1.5","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^2.2.0","mongoose":"^6.2.1","mongoose-autopopulate":"^0.16.0"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build","publish:next":"yarn publish --tag next"},"readmeFilename":"README.MD","readme":"# `@reflet/mongoose` 🌠\n\n[![lines coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=lines&query=total.lines.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![statements coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=statements&query=total.statements.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![functions coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=functions&query=total.functions.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![branches coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=branches&query=total.branches.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n\nThe **best** decorators for [Mongoose](https://mongoosejs.com/). Have a look at [Reflet's philosophy](../README.MD#Philosophy-).\n\n* [Getting started](#getting-started)\n* [Schema definition](#schema-definition)\n* [Model](#model)\n* [Schema options](#schema-options)\n* [Schema retrieval](#schema-retrieval)\n* [Hooks](#hooks)\n* [Model discriminators](#model-discriminators)\n* [Embedded discriminators](#embedded-discriminators)\n* [Virtuals](#virtuals)\n* [Plain helper](#plain-helper)\n* [Augmentations](#augmentations)\n\n## Getting started\n\n1. <details>\n    <summary>Make sure you have decorators enabled. (click for details)</summary>\n    <p>\n\n    * Enable them in your TypeScript compiler options.\n\n        ```json\n        \"experimentalDecorators\": true,\n        ```\n\n    * Install `reflect-metadata` shim.\n\n        ```sh\n        yarn add reflect-metadata\n        ```\n\n    * Import the shim in your program before everything else.\n\n        ```ts\n        import 'reflect-metadata'\n        ```\n\n    </p>\n    </details>\n\n2. Install the package along with peer dependencies.\n\n    ```sh\n    yarn add @reflet/mongoose mongoose && yarn add -D @types/mongoose @types/node\n    ```\n\n3. Create your decorated models.\n\n    ```ts\n    // user.model.ts\n    import { Model, Field } from '@reflet/mongoose'\n\n    @Model()\n    export class User extends Model.I {\n      static findByEmail(email) {\n        return this.findOne({ email });\n      }\n\n      @Fied({ type: String, required: true })\n      email: string\n\n      getProfileUrl() {\n        return `https://mysite.com/${this.email}`;\n      }\n    }\n    ```\n\n4. Connect to MongoDB and save your documents.\n\n    ```ts\n    // server.ts\n    import 'reflect-metadata'\n    import * as mongoose from 'mongoose'\n    import { User } from './user.model.ts'\n\n    mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true })\n\n    User.create({ email: 'jeremy@example.com' }).then((user) => {\n      console.log(`User ${user._id} has been saved.`)\n    })\n    ```\n\n### The Mongoose way\n\nConnect Mongoose in the way you already know. Models defined with Reflet will simply be attached to the default Mongoose connection.\nThis means you can **progressively** decorate your Mongoose models. 😉\n\n## Schema definition\n\n> 🔦 `@Field(schemaType)`<br>\n> 💫 Related Mongoose object: [SchemaTypes](https://mongoosejs.com/docs/schematypes)\n\nMongoose [already](https://mongoosejs.com/docs/api#schema_Schema-loadClass) allows you to load an ES6 class to attach getters, setters, instance and static methods to a schema.\nBut what about properties ? Enters the `@Field` decorator :\n\n```ts\nclass User {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field(Number)\n  age?: number\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThe `@Field` API is a direct wrapper of Mongoose [SchemaType](https://mongoosejs.com/docs/schematypes), you can put in there everything that you used to.\n\n### Nested properties\n\n> 🔦 `@Field.Nested(schemaTypes)`\n\n```ts\nclass User {\n  @Field.Nested({\n    street: { type: String, required: true },\n    city: { type: String, required: true },\n    country: { type: String, required: true },\n  })\n  address: {\n    street: string\n    city: string\n    country: string\n  }\n}\n```\n\n_`@Field.Nested` works the same as `@Field` at runtime. Its type is simply looser to allow nested objects._\n\n## Model\n\n> 🔦 `@Model(collection?, connection?)`<br>\n> 💫 Related Mongoose method: [`model`](https://mongoosejs.com/docs/models#compiling)\n\nTypeScript [class decorators](https://www.typescriptlang.org/docs/handbook/decorators#class-decorators) can modify and even replace class constructors. Reflet takes advantage of this feature and transforms a class directly into a Mongoose Model.\n\nThis means you don't have to deal with the procedural and separate creation of both schema and model anymore !\nAnd now your properties and methods are statically typed.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\nclass User extends Model.Interface {\n  @Field({ type: String, required: true })\n  email: string\n}\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  email: string\n}\n\nconst userSchema = new mongoose.Schema({\n  email: { type: String, required: true }\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n⚠️ `@Model` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n#### Correct model and document interface\n\nYour class needs to inherit a special empty class, **`Model.Interface`** or **`Model.I`**, to have Mongoose document properties and methods.\n\n##### To callback or not to callback\n\n🗣️ To vastly simplify compiler hints, inherited **static methods don't have callback signatures**. You can still use callback style within `.exec()`.\n\nIf you actually need callback signatures within static methods, please inherit from empty class **`Model.InterfaceWithCallback`** or **`Model.ICb`**, which is on par with underlying mongoose typings.\n\n#### Custom collection name\n\nBy default, Mongoose automatically creates a collection named as the plural, lowercased version of your model name. You can customize the collection name, with the first argument:\n\n```ts\n@Model('people')\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n#### Custom Mongoose connection\n\nYou can use a different database by creating a Mongoose connection and passing it as the second argument:\n\n```ts\nconst otherDb = mongoose.createConnection('mongodb://localhost/other', { useNewUrlParser: true })\n\n@Model(undefined, otherDb)\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n## Schema options\n\n> 🔦 `@SchemaOptions(options)`<br>\n> 💫 Related Mongoose object: [Schema options](https://mongoosejs.com/docs/guide#options)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({\n  autoIndex: false,\n  strict: 'throw'\n})\nclass User extends Model.I {           \n  @Field(String)\n  name: string\n}\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    autoIndex: false,\n    strict: 'throw'\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@SchemaOptions` API is a direct wrapper of Mongoose [schema options](https://mongoosejs.com/docs/guide#options), you can put in there everything that you used to.\n\n### Timestamps\n\n> 🔦 `@CreatedAt`, `@UpdatedAt`<br>\n> 💫 Related Mongoose option property: [`timestamps`](https://mongoosejs.com/docs/guide#timestamps)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({ minimize: false })\nclass User extends Model.I {             \n  @Field(String)\n  name: string\n\n  @CreatedAt\n  creationDate: Date\n\n  @UpdatedAt\n  updateDate: Date\n}\n\n\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n  creationDate: Date\n  updateDate: Date\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    minimize: false,\n    timestamps: {\n      createdAt: 'creationDate',\n      updatedAt: 'updateDate'\n    },\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n### Advanced schema manipulation\n\n> 🔦 `@SchemaCallback(callback)`<br>\n> 💫 Related Mongoose object: [`Schema`](https://mongoosejs.com/docs/api/schema)\n\nIf you need more advanced schema manipulation before `@Model` compiles it, you can use `@SchemaCallback`:\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaCallback((schema) => {\n  schema.index({ name: 1, type: -1 })\n})\nclass Animal extends Model.I {          \n  @Field(String)\n  name: string\n\n  @Field(String)\n  type: string\n}\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface AnimalDocument extends mongoose.Document {\n  name: string\n  type: string\n}\n\nconst userSchema = new mongoose.Schema({\n  name: String,\n  type: String\n})\n\nuserSchema.index({ name: 1, type: -1 })\n\nconst Animal = mongoose.model<AnimalDocument>('Animal', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n_Beware of defining hooks in the callback if your schema has embedded discriminators. Mongoose documentation recommends declaring hooks **before** embedded discriminators, the callback is applied **after** them. You should use the dedicated hooks decorators `@PreHook` and `@PostHook`._\n\n## Schema retrieval\n\n> 🔦 `schemaFrom(class)`\n\nYou can retrieve a schema from any decorated class, for advanced manipulation or embedded use in another schema.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Location {\n  @Field(Number)\n  lat: number\n\n  @Field(Number)\n  lng: number\n}\n\n@Model()\nclass City extends Model.I {            \n  @Field(String)\n  name: string\n\n  @Field(schemaFrom(Location))\n  location: Location\n}\n\nconst citySchema = schemaFrom(City)\n```\n\n  </td>\n  <td>\n\n```ts\ninterface CityDocument extends mongoose.Document {\n  name: string\n  location: {\n    lat: number,\n    lng: number\n  }\n}\n\nconst locationSchema = new mongoose.Schema(\n  { lat: Number, lng: Number },\n  { _id: false }\n)\n\nconst citySchema = new mongoose.Schema({\n  name: String,\n  location: locationSchema\n})\n\nconst City = mongoose.model<CityDocument>('City', citySchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n🗣️ As a good practice, you should make your schema-only classes `abstract`, so you don't instantiate them by mistake.\n\n\n### Sub schemas\n\n> 🔦 `Field.Schema(class)`\n\nAs an alternative for the above use of `schemaFrom` inside the `Field` decorator, you can do:\n\n```ts\n@Model()\nclass City extends Model.I {            \n  @Field.Schema(Location)\n  location: Location\n}\n```\n\n## Hooks\n\n### Pre hook\n\n> 🔦 `@PreHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.pre`](https://mongoosejs.com/docs/middleware#pre)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PreHook<User>('save', function(next) {\n  next()\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.pre<UserDocument>('save', function (doc, next) {\n  next()\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PreHook` API is a direct wrapper of Mongoose [Schema.pre method](https://mongoosejs.com/docs/api/schema#schema_Schema-pre), you can put in there everything that you used to.\n\nSuccessive `@PreHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n### Post hook\n\n> 🔦 `@PostHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.post`](https://mongoosejs.com/docs/middleware#post)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PostHook<User>('find', function(result) {\n  console.log(result)\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.post<UserDocument>('find', function (result) {\n  console.log(result)\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PostHook` API is a direct wrapper of Mongoose [Schema.post method](https://mongoosejs.com/docs/api/schema#schema_Schema-post), you can put in there everything that you used to.\n\nSuccessive `@PostHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n#### Post error handling middleware\n\nTo help the compiler accurately infer the [error handling middleware](https://mongoosejs.com/docs/middleware#error-handling-middleware) signature, pass a second type argument to `@PostHook`:\n\n```ts\n@Model()\n@PostHook<User, Error>('save', function(error, doc, next) {\n  if (error.name === 'MongoError' && error.code === 11000) {\n    next(new Error('There was a duplicate key error'))\n  } else {\n    next()\n  }\n})\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n```\n\n## Model discriminators\n\n> 🔦 `@Model.Discriminator(rootModel)`<br>\n> 💫 Related Mongoose method: [`model.discriminator`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Worker extends User {\n  @Field(String)\n  job: string\n\n  // No need to decorate the default discriminatorKey.\n  __t: 'Worker'\n\n  // You can strictly type the constructor of a discriminator model by using the Plain Helper (see below).\n  constructor(worker: Plain.Omit<Worker, '_id' | '__t'>) {\n    super() // required by the compiler.\n  }\n}\n\nconst worker = await Worker.create({ name: 'Jeremy', job: 'developer' })\n// { _id: '5d023ae14043262bcfd9b384', __t: 'Worker', name: 'Jeremy', job: 'developer' }\n```\n\nAs you know, `_t` is the default `discriminatorKey`, and its value will be the class name. If you want to customize both the key and the value, check out the following `@Kind` decorator.\n\n⚠️ `@Model.Discriminator` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model.Discriminator` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n### Kind / DiscriminatorKey\n\n> 🔦 `@Kind(value?)` alias `@DiscriminatorKey`<br>\n> 💫 Related Mongoose option property: [`discriminatorKey`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\nMongoose `discriminatorKey` is usually defined in the parent model options, and appears in the children model documents.\n`@Kind` (or its alias `@DiscriminatorKey`) exists to define `discriminatorKey` **directly** on the children class instead of the parent model.\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Developer extends User {\n  @Kind\n  kind: 'Developer' // Value will be the class name by default.\n}\n\n@Model.Discriminator(User)\nclass Doctor extends User {\n  @Kind('doctor') // Customize the discriminator value by passing a string.\n  kind: 'doctor'\n}\n\n// This is equivalent to setting `{ discriminatorKey: 'kind' }` on User schema options.\n```\n\nA mecanism will check and prevent you from defining a different `@Kind` key on sibling discriminators.\n\n## Embedded discriminators\n\n### Single nested discriminators\n\n> 🔦 `@Field.Union(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`SingleNestedPath.discriminator`](https://mongoosejs.com/docs/discriminators#single-nested-discriminators)\n\n`@Field.Union` allows you to embed discriminators on an single property.\n\n```ts\nabstract class Circle {\n  @Field(Number)\n  radius: number\n\n  __t: 'Circle'\n  // __t is the default discriminatorKey (no need to decorate).\n  // Value will be the class name.\n}\n\nabstract class Square {\n  @Field(Number)\n  side: number\n\n  __t: 'Square'\n}\n\n@Model()\nclass Shape extends Model.I {\n  @Field.Union([Circle, Square], { \n    required: true, // Make the field itself `shape` required.\n    strict: true // Make the discriminator key `__t` required and narrowed to its possible values.\n  })\n  shape: Circle | Square\n}\n\nconst circle = new Shape({ shape: { __t: 'Circle', radius: 5 } })\nconst square = new Shape({ shape: { __t: 'Square', side: 4 } })\n```\n\n### Embedded discriminators in arrays\n\n> 🔦 `@Field.ArrayOfUnion(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`DocumentArrayPath.discriminator`](https://mongoosejs.com/docs/discriminators#embedded-discriminators-in-arrays)\n\n`@Field.ArrayOfUnion` allows you to embed discriminators in an array.\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Clicked {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  element: string\n\n  @Kind\n  kind: 'Clicked'\n}\n\n@SchemaOptions({ _id: false })\nabstract class Purchased {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  product: string\n\n  @Kind\n  kind: 'Purchased'\n}\n\n@Model()\nclass Batch extends Model.I {\n  @Field.ArrayOfUnion([Clicked, Purchased], { \n    strict: true  // Make the discriminator key `kind` required and narrowed to its possible values.\n  })\n  events: (Clicked | Purchased)[]\n}\n\nconst batch = new Batch({\n  events: [\n    { kind: 'Clicked', element: '#hero', message: 'hello' },\n    { kind: 'Purchased', product: 'action-figure', message: 'world' },\n  ]\n})\n```\n\n## Virtuals\n\n> 🔦 `@Virtual`<br>\n> 💫 Related Mongoose method: [`schema.virtual`](https://mongoosejs.com/docs/guide.html#virtuals)\n\n`@Virtual` helps you define a writable [virtual property](https://mongoosejs.com/docs/guide.html#virtuals) (both a getter and a setter), which is properly serialized with `toJson: { virtuals: true }`, and not saved to the database.<br>_Can be used with or without invokation._\n\n```ts\n@Model()\n@SchemaOptions({ \n  toObject: { virtuals: true },\n  toJson: { virtuals: true }\n})\nclass S3File extends Model.I {\n  @Field(String)\n  key: string\n\n  @Virtual\n  url: string\n}\n\nconst photo = await S3File.findOne({ key })\nphoto.url = await getSignedUrl(photo.key)\nres.send(photo)\n```\n\n### Populated virtuals\n\n> 🔦 `@Virtual.Populate(options)`<br>\n> 💫 Related Mongoose method: [`schema.virtual`](https://mongoosejs.com/docs/populate#populate-virtuals)\n\n`@Virtual.Populate` helps you define [populate virtuals](https://mongoosejs.com/docs/populate#populate-virtuals).\n\n```ts\n@Model()\nclass Person extends Model.I {\n  @Field(String)\n  name: string\n\n  @Field(String)\n  band: string\n}\n\n@Model()\n@SchemaOptions({\n  toObject: { virtuals: true },\n  toJson: { virtuals: true }\n})\nclass Band extends Model.I {\n  @Field(String)\n  name: string\n\n  @Virtual.Populate<Band, Person>({\n    ref: 'Person',\n    foreignField: 'band',\n    localField: 'name'\n  })\n  readonly members: string[]\n}\n\nconst bands = await Band.find({}).populate('members')\n```\n\n## Plain helper\n\n> 🔦 `Plain<class, options?>`\n\nReflet provides a generic type to discard Mongoose properties and methods from a Document.\n\n* `Plain<T>` removes inherited Mongoose properties (except `_id`) and all methods from `T`.\n* `Plain.Partial<T>` does the same as `Plain` and makes remaining properties of `T` optional.\n* `Plain.PartialDeep<T>` does the same as `Plain.Partial` recursively.\n\n`Plain` also has a second type argument to omit other properties and/or make them optional:\n\n* `Plain<T, { Omit: keyof T; Optional: keyof T } >`\n\n_These options exist as standalone generics as well: `Plain.Omit<T, keyof T>` and `Plain.Optional<T, keyof T>`._\n\nWith this you can narrow the return type of `toObject()` and `toJson()`:\n\n```ts\nconst userPlain = user.toObject({ getters: false }) as Plain.Omit<User, 'fullname'>\n```\n\n#### Allow `string` for `ObjectId`\n\n> 🔦 `Plain.AllowString<class, options?>`\n\nWhen creating or querying documents, you can pass `ObjectId` as `string`. To allow this, Reflet provides a generic type with the same API as `Plain`:\n\n* `Plain.AllowString<T, { Omit: keyof T; Optional: keyof T } >`\n* `Plain.AllowString.Partial<T>`\n* `Plain.AllowString.PartialDeep<T>`\n\n### One document, multiple shapes\n\nIn each of your models, some fields might be present when you read the document from the database, but optional or even absent when you create it. 😕\n\nGiven the following model:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field({ type: Boolean, default: () => false })\n  activated: boolean\n\n  @CreatedAt\n  createdAt: Date\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThis is how you can type `constructor` and `create` parameters:\n\n```ts\ntype NewUser = Plain.AllowString<User, { Omit: 'fullname' | 'createdAt'; Optional: '_id' | 'activated' }>\n\n@Model()\nclass User extends Model.I<typeof User>  {\n  // @ts-ignore implementation\n  constructor(doc?: NewUser, strict?: boolean | 'throw')\n}\n\nconst user = new User({ firstname: 'John', lastname: 'Doe' })\nawait user.save()\nawait User.create({ firstname: 'Jeremy', lastname: 'Doe', activated: true })\n```\n\nBy passing `typeof User` to `Model.I`, Reflet is now able to use the constructor signature to type the following static methods: `create`, `insertMany` and `replaceOne`.\n\n_The compiler checks `NewUser` as we need, so you can safely use ts-ignore on the `constructor` to avoid implementing an empty one (remember that `@Model` will replace it with mongoose Model constructor)._\n\n## Augmentations\n\nReflet comes with a dedicated global namespace `RefletMongoose`, so you can augment or narrow specific types.\n\n### SchemaType options augmentation\n\nIf you use plugins like [mongoose-autopopulate](https://github.com/mongodb-js/mongoose-autopopulate),\nyou can augment the global interface `SchemaTypeOptions` to have new options in the `@Field` API.\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface SchemaTypeOptions {\n      autopopulate?: boolean\n    }\n  }\n}\n```\n\nNow you have access to `autopopulate` option in your schemas:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: Company,\n    autopopulate: true\n  })\n  company: Company\n}\n```\n\n#### Virtual options\n\nThe same can be done with the `@Virtual` decorator:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface VirtualOptions {}\n  }\n}\n```\n\n### Model and Document augmentation\n\nYou can augment `Model` and `Document` interfaces with the dedicated global interfaces.\nHere is an example with the [@casl/mongoose](https://github.com/stalniy/casl/tree/master/packages/casl-mongoose) plugin:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface Model {\n      accessibleBy<T extends mongoose.Document>(ability: AnyMongoAbility, action?: string): mongoose.DocumentQuery<T[], T>\n    }\n    interface Document {}\n  }\n}\n```\n\n### References narrowing\n\n[SchemaType `ref` option](https://mongoosejs.com/docs/api#schematypeoptions_SchemaTypeOptions-ref) can be either a Model or a model name. With Reflet, by default, any class can be passed as a Model and any string can be passed as a model name.\n\nBy augmenting the global interface `Ref`, you can:\n\n* Narrow the class to an union of your models.\n* Narrow the string to an union of your models' names.\n\n```ts\n// company.model.ts\n@Model()\nclass Company extends Model.I {\n  @Field(String)\n  name: string\n}\n\n// You should augment the global interface in each of your models' files, to keep it close to the model.\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      Company: Company\n    }\n  }\n}\n```\n\n```ts\n// user.model.ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: 'Company',\n  })\n  company: Company\n}\n\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      User: User\n    }\n  }\n}\n```\n","licenseText":"MIT License\n\nCopyright (c) 2020 Jeremy Bensimon\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@reflet/mongoose@2.0.0-next.12","dist":{"shasum":"91562b6dd768300acc905d1b326b7f1eea9b5a8c","integrity":"sha512-hpfigQFcZeHleurhQrdVbPfM88+T0a/369b1QsvVOiMdbGvMHgnG7JP6hlv9gGdebUv5QfsNA15rv0scOneqUA==","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-2.0.0-next.12.tgz","fileCount":22,"unpackedSize":167454,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJiBR+tCRA9TVsSAnZWagAAiaIP/RjpADVtQfohPMVydG5o\ne65QSH0rK1skjoZufIH3ojKPd59zXU0NnEkQQ2zxEX7jAsF08JfO2D2oRzUg\n8gquJ7AjDurmNgy/z4yBcgFRXT5NF94pEdZpMvHi6RT5L4K1FLOQWREkU5kh\na4l4tz+g4fdDKQRgPejaQJbFHLnClPpQXGxt1SEbV7tfFqBWsi78psAJyLSe\nls6yKOgREBNn+FBMIEut+W3GldiCX0BNccOrthSLqxchKCy8HF9K3uxVCA+K\nECQbImBlwOwM+IrAxusbXrIH9r5CX/o5ketEjJU3Lji0sw0hyweeuQWZq9Gm\nI1QdSxMOeheFh3UHTTPlWePEKxDLfPxTTOVIz+8/exiqmPmF7B6kV1YGiVNl\nVKmEvNPpV9JDvCfUL5L9LiGR53i3cmd/0saDkkUkaoxNu7ypAkgd0/6zfpG4\niEo3yRsRRx/r8/4Kni3JBAtWhwTm4XfXMnuU1JdcI8BTYGH5cLNCaTZG7uzB\nP61nNbO/ykox2x17GnWFMSwRqcwjIrCLAq5RQTgIOJWdYGNGqpcJYDYUmRLk\ns4qn7VaiSYFxX5h+WqusFIiJ9Y1ho2L2/8f+5SUeIxsSSBxQYqwcREhwsa4j\n49vI91BjGOZy3Du6tkACE9OQySrOxDqOekBdPx3qS8LC8S0G+riQY48jvuGk\nxxCG\r\n=DuX8\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBRmaH22JCJZnDYH7y9bIbZgD9Y+ae3F+kPhMmb1vMl7AiEAzb+kuvgXZOBuNIV6hcohQeJ/f6sTxkd+vvyi66ar7NM="}]},"_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"directories":{},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_2.0.0-next.12_1644502957077_0.5401410830740065"},"_hasShrinkwrap":false},"2.0.0-next.13":{"name":"@reflet/mongoose","version":"2.0.0-next.13","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet.git","directory":"mongoose"},"homepage":"https://github.com/jeremyben/reflet/tree/master/mongoose#readme","description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=10"},"engineStrict":true,"peerDependencies":{"@types/node":">=10","mongoose":">=6.1.5","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^2.2.0","mongoose":"^6.2.4","mongoose-autopopulate":"^0.16.0"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build","publish:next":"yarn publish --tag next"},"readmeFilename":"README.MD","readme":"# `@reflet/mongoose` 🌠\n\n[![lines coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=lines&query=total.lines.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![statements coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=statements&query=total.statements.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![functions coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=functions&query=total.functions.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![branches coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=branches&query=total.branches.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n\nThe **best** decorators for [Mongoose](https://mongoosejs.com/). Have a look at [Reflet's philosophy](../README.MD#Philosophy-).\n\n* [Getting started](#getting-started)\n* [Schema definition](#schema-definition)\n* [Model](#model)\n* [Schema options](#schema-options)\n* [Schema retrieval](#schema-retrieval)\n* [Hooks](#hooks)\n* [Model discriminators](#model-discriminators)\n* [Embedded discriminators](#embedded-discriminators)\n* [Virtuals](#virtuals)\n* [Plain helper](#plain-helper)\n* [Augmentations](#augmentations)\n\n## Getting started\n\n1. <details>\n    <summary>Make sure you have decorators enabled. (click for details)</summary>\n    <p>\n\n    * Enable them in your TypeScript compiler options.\n\n        ```json\n        \"experimentalDecorators\": true,\n        ```\n\n    * Install `reflect-metadata` shim.\n\n        ```sh\n        yarn add reflect-metadata\n        ```\n\n    * Import the shim in your program before everything else.\n\n        ```ts\n        import 'reflect-metadata'\n        ```\n\n    </p>\n    </details>\n\n2. Install the package along with peer dependencies.\n\n    ```sh\n    yarn add @reflet/mongoose mongoose && yarn add -D @types/mongoose @types/node\n    ```\n\n3. Create your decorated models.\n\n    ```ts\n    // user.model.ts\n    import { Model, Field } from '@reflet/mongoose'\n\n    @Model()\n    export class User extends Model.I {\n      static findByEmail(email) {\n        return this.findOne({ email });\n      }\n\n      @Fied({ type: String, required: true })\n      email: string\n\n      getProfileUrl() {\n        return `https://mysite.com/${this.email}`;\n      }\n    }\n    ```\n\n4. Connect to MongoDB and save your documents.\n\n    ```ts\n    // server.ts\n    import 'reflect-metadata'\n    import * as mongoose from 'mongoose'\n    import { User } from './user.model.ts'\n\n    mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true })\n\n    User.create({ email: 'jeremy@example.com' }).then((user) => {\n      console.log(`User ${user._id} has been saved.`)\n    })\n    ```\n\n### The Mongoose way\n\nConnect Mongoose in the way you already know. Models defined with Reflet will simply be attached to the default Mongoose connection.\nThis means you can **progressively** decorate your Mongoose models. 😉\n\n## Schema definition\n\n> 🔦 `@Field(schemaType)`<br>\n> 💫 Related Mongoose object: [SchemaTypes](https://mongoosejs.com/docs/schematypes)\n\nMongoose [already](https://mongoosejs.com/docs/api#schema_Schema-loadClass) allows you to load an ES6 class to attach getters, setters, instance and static methods to a schema.\nBut what about properties ? Enters the `@Field` decorator :\n\n```ts\nclass User {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field(Number)\n  age?: number\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThe `@Field` API is a direct wrapper of Mongoose [SchemaType](https://mongoosejs.com/docs/schematypes), you can put in there everything that you used to.\n\n### Nested properties\n\n> 🔦 `@Field.Nested(schemaTypes)`\n\n```ts\nclass User {\n  @Field.Nested({\n    street: { type: String, required: true },\n    city: { type: String, required: true },\n    country: { type: String, required: true },\n  })\n  address: {\n    street: string\n    city: string\n    country: string\n  }\n}\n```\n\n_`@Field.Nested` works the same as `@Field` at runtime. Its type is simply looser to allow nested objects._\n\n## Model\n\n> 🔦 `@Model(collection?, connection?)`<br>\n> 💫 Related Mongoose method: [`model`](https://mongoosejs.com/docs/models#compiling)\n\nTypeScript [class decorators](https://www.typescriptlang.org/docs/handbook/decorators#class-decorators) can modify and even replace class constructors. Reflet takes advantage of this feature and transforms a class directly into a Mongoose Model.\n\nThis means you don't have to deal with the procedural and separate creation of both schema and model anymore !\nAnd now your properties and methods are statically typed.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\nclass User extends Model.Interface {\n  @Field({ type: String, required: true })\n  email: string\n}\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  email: string\n}\n\nconst userSchema = new mongoose.Schema({\n  email: { type: String, required: true }\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n⚠️ `@Model` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n#### Correct model and document interface\n\nYour class needs to inherit a special empty class, **`Model.Interface`** or **`Model.I`**, to have Mongoose document properties and methods.\n\n##### To callback or not to callback\n\n🗣️ To vastly simplify compiler hints, inherited **static methods don't have callback signatures**. You can still use callback style within `.exec()`.\n\nIf you actually need callback signatures within static methods, please inherit from empty class **`Model.InterfaceWithCallback`** or **`Model.ICb`**, which is on par with underlying mongoose typings.\n\n#### Custom collection name\n\nBy default, Mongoose automatically creates a collection named as the plural, lowercased version of your model name. You can customize the collection name, with the first argument:\n\n```ts\n@Model('people')\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n#### Custom Mongoose connection\n\nYou can use a different database by creating a Mongoose connection and passing it as the second argument:\n\n```ts\nconst otherDb = mongoose.createConnection('mongodb://localhost/other', { useNewUrlParser: true })\n\n@Model(undefined, otherDb)\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n## Schema options\n\n> 🔦 `@SchemaOptions(options)`<br>\n> 💫 Related Mongoose object: [Schema options](https://mongoosejs.com/docs/guide#options)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({\n  autoIndex: false,\n  strict: 'throw'\n})\nclass User extends Model.I {           \n  @Field(String)\n  name: string\n}\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    autoIndex: false,\n    strict: 'throw'\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@SchemaOptions` API is a direct wrapper of Mongoose [schema options](https://mongoosejs.com/docs/guide#options), you can put in there everything that you used to.\n\n### Timestamps\n\n> 🔦 `@CreatedAt`, `@UpdatedAt`<br>\n> 💫 Related Mongoose option property: [`timestamps`](https://mongoosejs.com/docs/guide#timestamps)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({ minimize: false })\nclass User extends Model.I {             \n  @Field(String)\n  name: string\n\n  @CreatedAt\n  creationDate: Date\n\n  @UpdatedAt\n  updateDate: Date\n}\n\n\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n  creationDate: Date\n  updateDate: Date\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    minimize: false,\n    timestamps: {\n      createdAt: 'creationDate',\n      updatedAt: 'updateDate'\n    },\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n### Advanced schema manipulation\n\n> 🔦 `@SchemaCallback(callback)`<br>\n> 💫 Related Mongoose object: [`Schema`](https://mongoosejs.com/docs/api/schema)\n\nIf you need more advanced schema manipulation before `@Model` compiles it, you can use `@SchemaCallback`:\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaCallback((schema) => {\n  schema.index({ name: 1, type: -1 })\n})\nclass Animal extends Model.I {          \n  @Field(String)\n  name: string\n\n  @Field(String)\n  type: string\n}\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface AnimalDocument extends mongoose.Document {\n  name: string\n  type: string\n}\n\nconst userSchema = new mongoose.Schema({\n  name: String,\n  type: String\n})\n\nuserSchema.index({ name: 1, type: -1 })\n\nconst Animal = mongoose.model<AnimalDocument>('Animal', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n_Beware of defining hooks in the callback if your schema has embedded discriminators. Mongoose documentation recommends declaring hooks **before** embedded discriminators, the callback is applied **after** them. You should use the dedicated hooks decorators `@PreHook` and `@PostHook`._\n\n## Schema retrieval\n\n> 🔦 `schemaFrom(class)`\n\nYou can retrieve a schema from any decorated class, for advanced manipulation or embedded use in another schema.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Location {\n  @Field(Number)\n  lat: number\n\n  @Field(Number)\n  lng: number\n}\n\n@Model()\nclass City extends Model.I {            \n  @Field(String)\n  name: string\n\n  @Field(schemaFrom(Location))\n  location: Location\n}\n\nconst citySchema = schemaFrom(City)\n```\n\n  </td>\n  <td>\n\n```ts\ninterface CityDocument extends mongoose.Document {\n  name: string\n  location: {\n    lat: number,\n    lng: number\n  }\n}\n\nconst locationSchema = new mongoose.Schema(\n  { lat: Number, lng: Number },\n  { _id: false }\n)\n\nconst citySchema = new mongoose.Schema({\n  name: String,\n  location: locationSchema\n})\n\nconst City = mongoose.model<CityDocument>('City', citySchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n🗣️ As a good practice, you should make your schema-only classes `abstract`, so you don't instantiate them by mistake.\n\n\n### Sub schemas\n\n> 🔦 `Field.Schema(class)`\n\nAs an alternative for the above use of `schemaFrom` inside the `Field` decorator, you can do:\n\n```ts\n@Model()\nclass City extends Model.I {            \n  @Field.Schema(Location)\n  location: Location\n}\n```\n\n## Hooks\n\n### Pre hook\n\n> 🔦 `@PreHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.pre`](https://mongoosejs.com/docs/middleware#pre)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PreHook<User>('save', function(next) {\n  next()\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.pre<UserDocument>('save', function (doc, next) {\n  next()\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PreHook` API is a direct wrapper of Mongoose [Schema.pre method](https://mongoosejs.com/docs/api/schema#schema_Schema-pre), you can put in there everything that you used to.\n\nSuccessive `@PreHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n### Post hook\n\n> 🔦 `@PostHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.post`](https://mongoosejs.com/docs/middleware#post)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PostHook<User>('find', function(result) {\n  console.log(result)\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.post<UserDocument>('find', function (result) {\n  console.log(result)\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PostHook` API is a direct wrapper of Mongoose [Schema.post method](https://mongoosejs.com/docs/api/schema#schema_Schema-post), you can put in there everything that you used to.\n\nSuccessive `@PostHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n#### Post error handling middleware\n\nTo help the compiler accurately infer the [error handling middleware](https://mongoosejs.com/docs/middleware#error-handling-middleware) signature, pass a second type argument to `@PostHook`:\n\n```ts\n@Model()\n@PostHook<User, Error>('save', function(error, doc, next) {\n  if (error.name === 'MongoError' && error.code === 11000) {\n    next(new Error('There was a duplicate key error'))\n  } else {\n    next()\n  }\n})\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n```\n\n## Model discriminators\n\n> 🔦 `@Model.Discriminator(rootModel)`<br>\n> 💫 Related Mongoose method: [`model.discriminator`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Worker extends User {\n  @Field(String)\n  job: string\n\n  // No need to decorate the default discriminatorKey.\n  __t: 'Worker'\n\n  // You can strictly type the constructor of a discriminator model by using the Plain Helper (see below).\n  constructor(worker: Plain.Omit<Worker, '_id' | '__t'>) {\n    super() // required by the compiler.\n  }\n}\n\nconst worker = await Worker.create({ name: 'Jeremy', job: 'developer' })\n// { _id: '5d023ae14043262bcfd9b384', __t: 'Worker', name: 'Jeremy', job: 'developer' }\n```\n\nAs you know, `_t` is the default `discriminatorKey`, and its value will be the class name. If you want to customize both the key and the value, check out the following `@Kind` decorator.\n\n⚠️ `@Model.Discriminator` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model.Discriminator` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n### Kind / DiscriminatorKey\n\n> 🔦 `@Kind(value?)` alias `@DiscriminatorKey`<br>\n> 💫 Related Mongoose option property: [`discriminatorKey`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\nMongoose `discriminatorKey` is usually defined in the parent model options, and appears in the children model documents.\n`@Kind` (or its alias `@DiscriminatorKey`) exists to define `discriminatorKey` **directly** on the children class instead of the parent model.\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Developer extends User {\n  @Kind\n  kind: 'Developer' // Value will be the class name by default.\n}\n\n@Model.Discriminator(User)\nclass Doctor extends User {\n  @Kind('doctor') // Customize the discriminator value by passing a string.\n  kind: 'doctor'\n}\n\n// This is equivalent to setting `{ discriminatorKey: 'kind' }` on User schema options.\n```\n\nA mecanism will check and prevent you from defining a different `@Kind` key on sibling discriminators.\n\n## Embedded discriminators\n\n### Single nested discriminators\n\n> 🔦 `@Field.Union(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`SingleNestedPath.discriminator`](https://mongoosejs.com/docs/discriminators#single-nested-discriminators)\n\n`@Field.Union` allows you to embed discriminators on an single property.\n\n```ts\nabstract class Circle {\n  @Field(Number)\n  radius: number\n\n  __t: 'Circle'\n  // __t is the default discriminatorKey (no need to decorate).\n  // Value will be the class name.\n}\n\nabstract class Square {\n  @Field(Number)\n  side: number\n\n  __t: 'Square'\n}\n\n@Model()\nclass Shape extends Model.I {\n  @Field.Union([Circle, Square], { \n    required: true, // Make the field itself `shape` required.\n    strict: true // Make the discriminator key `__t` required and narrowed to its possible values.\n  })\n  shape: Circle | Square\n}\n\nconst circle = new Shape({ shape: { __t: 'Circle', radius: 5 } })\nconst square = new Shape({ shape: { __t: 'Square', side: 4 } })\n```\n\n### Embedded discriminators in arrays\n\n> 🔦 `@Field.ArrayOfUnion(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`DocumentArrayPath.discriminator`](https://mongoosejs.com/docs/discriminators#embedded-discriminators-in-arrays)\n\n`@Field.ArrayOfUnion` allows you to embed discriminators in an array.\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Clicked {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  element: string\n\n  @Kind\n  kind: 'Clicked'\n}\n\n@SchemaOptions({ _id: false })\nabstract class Purchased {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  product: string\n\n  @Kind\n  kind: 'Purchased'\n}\n\n@Model()\nclass Batch extends Model.I {\n  @Field.ArrayOfUnion([Clicked, Purchased], { \n    strict: true  // Make the discriminator key `kind` required and narrowed to its possible values.\n  })\n  events: (Clicked | Purchased)[]\n}\n\nconst batch = new Batch({\n  events: [\n    { kind: 'Clicked', element: '#hero', message: 'hello' },\n    { kind: 'Purchased', product: 'action-figure', message: 'world' },\n  ]\n})\n```\n\n## Virtuals\n\n> 🔦 `@Virtual`<br>\n> 💫 Related Mongoose method: [`schema.virtual`](https://mongoosejs.com/docs/guide.html#virtuals)\n\n`@Virtual` helps you define a writable [virtual property](https://mongoosejs.com/docs/guide.html#virtuals) (both a getter and a setter), which is properly serialized with `toJson: { virtuals: true }`, and not saved to the database.<br>_Can be used with or without invokation._\n\n```ts\n@Model()\n@SchemaOptions({ \n  toObject: { virtuals: true },\n  toJson: { virtuals: true }\n})\nclass S3File extends Model.I {\n  @Field(String)\n  key: string\n\n  @Virtual\n  url: string\n}\n\nconst photo = await S3File.findOne({ key })\nphoto.url = await getSignedUrl(photo.key)\nres.send(photo)\n```\n\n### Populated virtuals\n\n> 🔦 `@Virtual.Populate(options)`<br>\n> 💫 Related Mongoose method: [`schema.virtual`](https://mongoosejs.com/docs/populate#populate-virtuals)\n\n`@Virtual.Populate` helps you define [populate virtuals](https://mongoosejs.com/docs/populate#populate-virtuals).\n\n```ts\n@Model()\nclass Person extends Model.I {\n  @Field(String)\n  name: string\n\n  @Field(String)\n  band: string\n}\n\n@Model()\n@SchemaOptions({\n  toObject: { virtuals: true },\n  toJson: { virtuals: true }\n})\nclass Band extends Model.I {\n  @Field(String)\n  name: string\n\n  @Virtual.Populate<Band, Person>({\n    ref: 'Person',\n    foreignField: 'band',\n    localField: 'name'\n  })\n  readonly members: string[]\n}\n\nconst bands = await Band.find({}).populate('members')\n```\n\n## Plain helper\n\n> 🔦 `Plain<class, options?>`\n\nReflet provides a generic type to discard Mongoose properties and methods from a Document.\n\n* `Plain<T>` removes inherited Mongoose properties (except `_id`) and all methods from `T`.\n* `Plain.Partial<T>` does the same as `Plain` and makes remaining properties of `T` optional.\n* `Plain.PartialDeep<T>` does the same as `Plain.Partial` recursively.\n\n`Plain` also has a second type argument to omit other properties and/or make them optional:\n\n* `Plain<T, { Omit: keyof T; Optional: keyof T } >`\n\n_These options exist as standalone generics as well: `Plain.Omit<T, keyof T>` and `Plain.Optional<T, keyof T>`._\n\nWith this you can narrow the return type of `toObject()` and `toJson()`:\n\n```ts\nconst userPlain = user.toObject({ getters: false }) as Plain.Omit<User, 'fullname'>\n```\n\n#### Allow `string` for `ObjectId`\n\n> 🔦 `Plain.AllowString<class, options?>`\n\nWhen creating or querying documents, you can pass `ObjectId` as `string`. To allow this, Reflet provides a generic type with the same API as `Plain`:\n\n* `Plain.AllowString<T, { Omit: keyof T; Optional: keyof T } >`\n* `Plain.AllowString.Partial<T>`\n* `Plain.AllowString.PartialDeep<T>`\n\n### One document, multiple shapes\n\nIn each of your models, some fields might be present when you read the document from the database, but optional or even absent when you create it. 😕\n\nGiven the following model:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field({ type: Boolean, default: () => false })\n  activated: boolean\n\n  @CreatedAt\n  createdAt: Date\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThis is how you can type `constructor` and `create` parameters:\n\n```ts\ntype NewUser = Plain.AllowString<User, { Omit: 'fullname' | 'createdAt'; Optional: '_id' | 'activated' }>\n\n@Model()\nclass User extends Model.I<typeof User>  {\n  // @ts-ignore implementation\n  constructor(doc?: NewUser, strict?: boolean | 'throw')\n}\n\nconst user = new User({ firstname: 'John', lastname: 'Doe' })\nawait user.save()\nawait User.create({ firstname: 'Jeremy', lastname: 'Doe', activated: true })\n```\n\nBy passing `typeof User` to `Model.I`, Reflet is now able to use the constructor signature to type the following static methods: `create`, `insertMany` and `replaceOne`.\n\n_The compiler checks `NewUser` as we need, so you can safely use ts-ignore on the `constructor` to avoid implementing an empty one (remember that `@Model` will replace it with mongoose Model constructor)._\n\n## Augmentations\n\nReflet comes with a dedicated global namespace `RefletMongoose`, so you can augment or narrow specific types.\n\n### SchemaType options augmentation\n\nIf you use plugins like [mongoose-autopopulate](https://github.com/mongodb-js/mongoose-autopopulate),\nyou can augment the global interface `SchemaTypeOptions` to have new options in the `@Field` API.\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface SchemaTypeOptions {\n      autopopulate?: boolean\n    }\n  }\n}\n```\n\nNow you have access to `autopopulate` option in your schemas:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: Company,\n    autopopulate: true\n  })\n  company: Company\n}\n```\n\n#### Virtual options\n\nThe same can be done with the `@Virtual` decorator:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface VirtualOptions {}\n  }\n}\n```\n\n### Model and Document augmentation\n\nYou can augment `Model` and `Document` interfaces with the dedicated global interfaces.\nHere is an example with the [@casl/mongoose](https://github.com/stalniy/casl/tree/master/packages/casl-mongoose) plugin:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface Model {\n      accessibleBy<T extends mongoose.Document>(ability: AnyMongoAbility, action?: string): mongoose.DocumentQuery<T[], T>\n    }\n    interface Document {}\n  }\n}\n```\n\n### References narrowing\n\n[SchemaType `ref` option](https://mongoosejs.com/docs/api#schematypeoptions_SchemaTypeOptions-ref) can be either a Model or a model name. With Reflet, by default, any class can be passed as a Model and any string can be passed as a model name.\n\nBy augmenting the global interface `Ref`, you can:\n\n* Narrow the class to an union of your models.\n* Narrow the string to an union of your models' names.\n\n```ts\n// company.model.ts\n@Model()\nclass Company extends Model.I {\n  @Field(String)\n  name: string\n}\n\n// You should augment the global interface in each of your models' files, to keep it close to the model.\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      Company: Company\n    }\n  }\n}\n```\n\n```ts\n// user.model.ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: 'Company',\n  })\n  company: Company\n}\n\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      User: User\n    }\n  }\n}\n```\n","licenseText":"MIT License\n\nCopyright (c) 2020 Jeremy Bensimon\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@reflet/mongoose@2.0.0-next.13","dist":{"shasum":"a58698455c781accac15255675027c7a56782ed6","integrity":"sha512-5FB5NRhzRczzhvhRirQiUFlALiPEx0GUOHNIUqPForo7fz3aXEKcV0yaBZO+70Lb31Y4BmevwBe9VXUyEsOt0w==","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-2.0.0-next.13.tgz","fileCount":22,"unpackedSize":167484,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiHifyACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrUNA/9F1uoPzx8ywrv16wwbhKND5EdtDbuJg7Z+1VH/qTV+dh2CT32\r\n5Xe3lYyINxfSpejfBGdDreG9Fx9NmzFl5KW6oVhyt3djlr/wgK/e31JeZTKx\r\nFrno2KPYTcHbnYmPsUlUcgt2MyjLfQ8I2I4WfUNXxaLZk92AgBFkU8/Tsm2+\r\nJJGtu0JIjqaDpxp+tQvFKIQoK+nNOx34kInI9x2+1d2SMu78glcjsgXdpeok\r\nMcXKWZvFOBuJJ53ulidibcMA2yhxfPoNb7+t9LoWvNS7J7ClChBRzv79l0dD\r\n/g5oCemnBLHJC6Bxtbm0q7S0QUI9TZ7feS45IpwoqdOPhMBjgDbNMBra1Zc0\r\niaKv57smcfkzCTgD/BQhWqJNwc6F1fzDpIwt5YQk3a6x1f1UlJYGh3RrqBG7\r\nNtulURAOLiBsy7vfniWbli2Sc5QhiwiojaxkhTv6lCuBS+lA/htu3oI8oxbX\r\nZbCjxZTWKAvVld//rL1gX+4MU1Li8vJSF/08VNoL65CFJVEIfACClnuXnS2a\r\niu3HdrntwDxgLCo0j1AWTrmxQ/r+jgMvdx6KFfVN72/xV7HUNxXNxftFC3jy\r\nWZU8QwyFNX4tfdt1RErb/13abEQ9lXiRDcaJQq8fbL4X6Au4opdp79sz8Gl6\r\nKJ5C/UTcI7yN6zRgtHQOMGnWnCd2mrl+OQY=\r\n=spJ9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEXDN4dfF8V48h7PrZAro3x5UTRUmlAiec+v0vypJ4aTAiBmaJFIrwv4xwJ6hf1j8+D3PV4u07vCDhNwZqtKi5t7QQ=="}]},"_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"directories":{},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_2.0.0-next.13_1646143474475_0.15191662308461495"},"_hasShrinkwrap":false},"2.0.0-next.14":{"name":"@reflet/mongoose","version":"2.0.0-next.14","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"https://github.com/jeremyben/reflet.git","directory":"mongoose"},"homepage":"https://github.com/jeremyben/reflet/tree/master/mongoose#readme","description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=10"},"engineStrict":true,"peerDependencies":{"@types/node":">=10","mongoose":">=6.1.5","reflect-metadata":"^0.1.13"},"devDependencies":{"@shelf/jest-mongodb":"^2.2.0","mongoose":"^6.2.4","mongoose-autopopulate":"^0.16.0"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build","publish:next":"yarn publish --tag next"},"readmeFilename":"README.MD","readme":"# `@reflet/mongoose` 🌠\n\n[![lines coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=lines&query=total.lines.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![statements coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=statements&query=total.statements.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![functions coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=functions&query=total.functions.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![branches coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=branches&query=total.branches.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n\nThe **best** decorators for [Mongoose](https://mongoosejs.com/). Have a look at [Reflet's philosophy](../README.MD#Philosophy-).\n\n* [Getting started](#getting-started)\n* [Schema definition](#schema-definition)\n* [Model](#model)\n* [Schema options](#schema-options)\n* [Schema retrieval](#schema-retrieval)\n* [Hooks](#hooks)\n* [Model discriminators](#model-discriminators)\n* [Embedded discriminators](#embedded-discriminators)\n* [Virtuals](#virtuals)\n* [Plain helper](#plain-helper)\n* [Augmentations](#augmentations)\n\n## Getting started\n\n1. <details>\n    <summary>Make sure you have decorators enabled. (click for details)</summary>\n    <p>\n\n    * Enable them in your TypeScript compiler options.\n\n        ```json\n        \"experimentalDecorators\": true,\n        ```\n\n    * Install `reflect-metadata` shim.\n\n        ```sh\n        yarn add reflect-metadata\n        ```\n\n    * Import the shim in your program before everything else.\n\n        ```ts\n        import 'reflect-metadata'\n        ```\n\n    </p>\n    </details>\n\n2. Install the package along with peer dependencies.\n\n    ```sh\n    yarn add @reflet/mongoose mongoose && yarn add -D @types/mongoose @types/node\n    ```\n\n3. Create your decorated models.\n\n    ```ts\n    // user.model.ts\n    import { Model, Field } from '@reflet/mongoose'\n\n    @Model()\n    export class User extends Model.I {\n      static findByEmail(email) {\n        return this.findOne({ email });\n      }\n\n      @Fied({ type: String, required: true })\n      email: string\n\n      getProfileUrl() {\n        return `https://mysite.com/${this.email}`;\n      }\n    }\n    ```\n\n4. Connect to MongoDB and save your documents.\n\n    ```ts\n    // server.ts\n    import 'reflect-metadata'\n    import * as mongoose from 'mongoose'\n    import { User } from './user.model.ts'\n\n    mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true })\n\n    User.create({ email: 'jeremy@example.com' }).then((user) => {\n      console.log(`User ${user._id} has been saved.`)\n    })\n    ```\n\n### The Mongoose way\n\nConnect Mongoose in the way you already know. Models defined with Reflet will simply be attached to the default Mongoose connection.\nThis means you can **progressively** decorate your Mongoose models. 😉\n\n## Schema definition\n\n> 🔦 `@Field(schemaType)`<br>\n> 💫 Related Mongoose object: [SchemaTypes](https://mongoosejs.com/docs/schematypes)\n\nMongoose [already](https://mongoosejs.com/docs/api#schema_Schema-loadClass) allows you to load an ES6 class to attach getters, setters, instance and static methods to a schema.\nBut what about properties ? Enters the `@Field` decorator :\n\n```ts\nclass User {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field(Number)\n  age?: number\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThe `@Field` API is a direct wrapper of Mongoose [SchemaType](https://mongoosejs.com/docs/schematypes), you can put in there everything that you used to.\n\n### Nested properties\n\n> 🔦 `@Field.Nested(schemaTypes)`\n\n```ts\nclass User {\n  @Field.Nested({\n    street: { type: String, required: true },\n    city: { type: String, required: true },\n    country: { type: String, required: true },\n  })\n  address: {\n    street: string\n    city: string\n    country: string\n  }\n}\n```\n\n_`@Field.Nested` works the same as `@Field` at runtime. Its type is simply looser to allow nested objects._\n\n## Model\n\n> 🔦 `@Model(collection?, connection?)`<br>\n> 💫 Related Mongoose method: [`model`](https://mongoosejs.com/docs/models#compiling)\n\nTypeScript [class decorators](https://www.typescriptlang.org/docs/handbook/decorators#class-decorators) can modify and even replace class constructors. Reflet takes advantage of this feature and transforms a class directly into a Mongoose Model.\n\nThis means you don't have to deal with the procedural and separate creation of both schema and model anymore !\nAnd now your properties and methods are statically typed.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\nclass User extends Model.Interface {\n  @Field({ type: String, required: true })\n  email: string\n}\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  email: string\n}\n\nconst userSchema = new mongoose.Schema({\n  email: { type: String, required: true }\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n⚠️ `@Model` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n#### Correct model and document interface\n\nYour class needs to inherit a special empty class, **`Model.Interface`** or **`Model.I`**, to have Mongoose document properties and methods.\n\n##### To callback or not to callback\n\n🗣️ To vastly simplify compiler hints, inherited **static methods don't have callback signatures**. You can still use callback style within `.exec()`.\n\nIf you actually need callback signatures within static methods, please inherit from empty class **`Model.InterfaceWithCallback`** or **`Model.ICb`**, which is on par with underlying mongoose typings.\n\n#### Custom collection name\n\nBy default, Mongoose automatically creates a collection named as the plural, lowercased version of your model name. You can customize the collection name, with the first argument:\n\n```ts\n@Model('people')\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n#### Custom Mongoose connection\n\nYou can use a different database by creating a Mongoose connection and passing it as the second argument:\n\n```ts\nconst otherDb = mongoose.createConnection('mongodb://localhost/other', { useNewUrlParser: true })\n\n@Model(undefined, otherDb)\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n## Schema options\n\n> 🔦 `@SchemaOptions(options)`<br>\n> 💫 Related Mongoose object: [Schema options](https://mongoosejs.com/docs/guide#options)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({\n  autoIndex: false,\n  strict: 'throw'\n})\nclass User extends Model.I {           \n  @Field(String)\n  name: string\n}\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    autoIndex: false,\n    strict: 'throw'\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@SchemaOptions` API is a direct wrapper of Mongoose [schema options](https://mongoosejs.com/docs/guide#options), you can put in there everything that you used to.\n\n### Timestamps\n\n> 🔦 `@CreatedAt`, `@UpdatedAt`<br>\n> 💫 Related Mongoose option property: [`timestamps`](https://mongoosejs.com/docs/guide#timestamps)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({ minimize: false })\nclass User extends Model.I {             \n  @Field(String)\n  name: string\n\n  @CreatedAt\n  creationDate: Date\n\n  @UpdatedAt\n  updateDate: Date\n}\n\n\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n  creationDate: Date\n  updateDate: Date\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    minimize: false,\n    timestamps: {\n      createdAt: 'creationDate',\n      updatedAt: 'updateDate'\n    },\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n### Advanced schema manipulation\n\n> 🔦 `@SchemaCallback(callback)`<br>\n> 💫 Related Mongoose object: [`Schema`](https://mongoosejs.com/docs/api/schema)\n\nIf you need more advanced schema manipulation before `@Model` compiles it, you can use `@SchemaCallback`:\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaCallback((schema) => {\n  schema.index({ name: 1, type: -1 })\n})\nclass Animal extends Model.I {          \n  @Field(String)\n  name: string\n\n  @Field(String)\n  type: string\n}\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface AnimalDocument extends mongoose.Document {\n  name: string\n  type: string\n}\n\nconst userSchema = new mongoose.Schema({\n  name: String,\n  type: String\n})\n\nuserSchema.index({ name: 1, type: -1 })\n\nconst Animal = mongoose.model<AnimalDocument>('Animal', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n_Beware of defining hooks in the callback if your schema has embedded discriminators. Mongoose documentation recommends declaring hooks **before** embedded discriminators, the callback is applied **after** them. You should use the dedicated hooks decorators `@PreHook` and `@PostHook`._\n\n## Schema retrieval\n\n> 🔦 `schemaFrom(class)`\n\nYou can retrieve a schema from any decorated class, for advanced manipulation or embedded use in another schema.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Location {\n  @Field(Number)\n  lat: number\n\n  @Field(Number)\n  lng: number\n}\n\n@Model()\nclass City extends Model.I {            \n  @Field(String)\n  name: string\n\n  @Field(schemaFrom(Location))\n  location: Location\n}\n\nconst citySchema = schemaFrom(City)\n```\n\n  </td>\n  <td>\n\n```ts\ninterface CityDocument extends mongoose.Document {\n  name: string\n  location: {\n    lat: number,\n    lng: number\n  }\n}\n\nconst locationSchema = new mongoose.Schema(\n  { lat: Number, lng: Number },\n  { _id: false }\n)\n\nconst citySchema = new mongoose.Schema({\n  name: String,\n  location: locationSchema\n})\n\nconst City = mongoose.model<CityDocument>('City', citySchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n🗣️ As a good practice, you should make your schema-only classes `abstract`, so you don't instantiate them by mistake.\n\n\n### Sub schemas\n\n> 🔦 `Field.Schema(class)`\n\nAs an alternative for the above use of `schemaFrom` inside the `Field` decorator, you can do:\n\n```ts\n@Model()\nclass City extends Model.I {            \n  @Field.Schema(Location)\n  location: Location\n}\n```\n\n## Hooks\n\n### Pre hook\n\n> 🔦 `@PreHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.pre`](https://mongoosejs.com/docs/middleware#pre)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PreHook<User>('save', function(next) {\n  next()\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.pre<UserDocument>('save', function (doc, next) {\n  next()\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PreHook` API is a direct wrapper of Mongoose [Schema.pre method](https://mongoosejs.com/docs/api/schema#schema_Schema-pre), you can put in there everything that you used to.\n\nSuccessive `@PreHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n### Post hook\n\n> 🔦 `@PostHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.post`](https://mongoosejs.com/docs/middleware#post)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PostHook<User>('find', function(result) {\n  console.log(result)\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.post<UserDocument>('find', function (result) {\n  console.log(result)\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PostHook` API is a direct wrapper of Mongoose [Schema.post method](https://mongoosejs.com/docs/api/schema#schema_Schema-post), you can put in there everything that you used to.\n\nSuccessive `@PostHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n#### Post error handling middleware\n\nTo help the compiler accurately infer the [error handling middleware](https://mongoosejs.com/docs/middleware#error-handling-middleware) signature, pass a second type argument to `@PostHook`:\n\n```ts\n@Model()\n@PostHook<User, Error>('save', function(error, doc, next) {\n  if (error.name === 'MongoError' && error.code === 11000) {\n    next(new Error('There was a duplicate key error'))\n  } else {\n    next()\n  }\n})\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n```\n\n## Model discriminators\n\n> 🔦 `@Model.Discriminator(rootModel)`<br>\n> 💫 Related Mongoose method: [`model.discriminator`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Worker extends User {\n  @Field(String)\n  job: string\n\n  // No need to decorate the default discriminatorKey.\n  __t: 'Worker'\n\n  // You can strictly type the constructor of a discriminator model by using the Plain Helper (see below).\n  constructor(worker: Plain.Omit<Worker, '_id' | '__t'>) {\n    super() // required by the compiler.\n  }\n}\n\nconst worker = await Worker.create({ name: 'Jeremy', job: 'developer' })\n// { _id: '5d023ae14043262bcfd9b384', __t: 'Worker', name: 'Jeremy', job: 'developer' }\n```\n\nAs you know, `_t` is the default `discriminatorKey`, and its value will be the class name. If you want to customize both the key and the value, check out the following `@Kind` decorator.\n\n⚠️ `@Model.Discriminator` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model.Discriminator` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n### Kind / DiscriminatorKey\n\n> 🔦 `@Kind(value?)` alias `@DiscriminatorKey`<br>\n> 💫 Related Mongoose option property: [`discriminatorKey`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\nMongoose `discriminatorKey` is usually defined in the parent model options, and appears in the children model documents.\n`@Kind` (or its alias `@DiscriminatorKey`) exists to define `discriminatorKey` **directly** on the children class instead of the parent model.\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Developer extends User {\n  @Kind\n  kind: 'Developer' // Value will be the class name by default.\n}\n\n@Model.Discriminator(User)\nclass Doctor extends User {\n  @Kind('doctor') // Customize the discriminator value by passing a string.\n  kind: 'doctor'\n}\n\n// This is equivalent to setting `{ discriminatorKey: 'kind' }` on User schema options.\n```\n\nA mecanism will check and prevent you from defining a different `@Kind` key on sibling discriminators.\n\n## Embedded discriminators\n\n### Single nested discriminators\n\n> 🔦 `@Field.Union(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`SingleNestedPath.discriminator`](https://mongoosejs.com/docs/discriminators#single-nested-discriminators)\n\n`@Field.Union` allows you to embed discriminators on an single property.\n\n```ts\nabstract class Circle {\n  @Field(Number)\n  radius: number\n\n  __t: 'Circle'\n  // __t is the default discriminatorKey (no need to decorate).\n  // Value will be the class name.\n}\n\nabstract class Square {\n  @Field(Number)\n  side: number\n\n  __t: 'Square'\n}\n\n@Model()\nclass Shape extends Model.I {\n  @Field.Union([Circle, Square], { \n    required: true, // Make the field itself `shape` required.\n    strict: true // Make the discriminator key `__t` required and narrowed to its possible values.\n  })\n  shape: Circle | Square\n}\n\nconst circle = new Shape({ shape: { __t: 'Circle', radius: 5 } })\nconst square = new Shape({ shape: { __t: 'Square', side: 4 } })\n```\n\n### Embedded discriminators in arrays\n\n> 🔦 `@Field.ArrayOfUnion(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`DocumentArrayPath.discriminator`](https://mongoosejs.com/docs/discriminators#embedded-discriminators-in-arrays)\n\n`@Field.ArrayOfUnion` allows you to embed discriminators in an array.\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Clicked {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  element: string\n\n  @Kind\n  kind: 'Clicked'\n}\n\n@SchemaOptions({ _id: false })\nabstract class Purchased {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  product: string\n\n  @Kind\n  kind: 'Purchased'\n}\n\n@Model()\nclass Batch extends Model.I {\n  @Field.ArrayOfUnion([Clicked, Purchased], { \n    strict: true  // Make the discriminator key `kind` required and narrowed to its possible values.\n  })\n  events: (Clicked | Purchased)[]\n}\n\nconst batch = new Batch({\n  events: [\n    { kind: 'Clicked', element: '#hero', message: 'hello' },\n    { kind: 'Purchased', product: 'action-figure', message: 'world' },\n  ]\n})\n```\n\n## Virtuals\n\n> 🔦 `@Virtual`<br>\n> 💫 Related Mongoose method: [`schema.virtual`](https://mongoosejs.com/docs/guide.html#virtuals)\n\n`@Virtual` helps you define a writable [virtual property](https://mongoosejs.com/docs/guide.html#virtuals) (both a getter and a setter), which is properly serialized with `toJson: { virtuals: true }`, and not saved to the database.<br>_Can be used with or without invokation._\n\n```ts\n@Model()\n@SchemaOptions({ \n  toObject: { virtuals: true },\n  toJson: { virtuals: true }\n})\nclass S3File extends Model.I {\n  @Field(String)\n  key: string\n\n  @Virtual\n  url: string\n}\n\nconst photo = await S3File.findOne({ key })\nphoto.url = await getSignedUrl(photo.key)\nres.send(photo)\n```\n\n### Populated virtuals\n\n> 🔦 `@Virtual.Populate(options)`<br>\n> 💫 Related Mongoose method: [`schema.virtual`](https://mongoosejs.com/docs/populate#populate-virtuals)\n\n`@Virtual.Populate` helps you define [populate virtuals](https://mongoosejs.com/docs/populate#populate-virtuals).\n\n```ts\n@Model()\nclass Person extends Model.I {\n  @Field(String)\n  name: string\n\n  @Field(String)\n  band: string\n}\n\n@Model()\n@SchemaOptions({\n  toObject: { virtuals: true },\n  toJson: { virtuals: true }\n})\nclass Band extends Model.I {\n  @Field(String)\n  name: string\n\n  @Virtual.Populate<Band, Person>({\n    ref: 'Person',\n    foreignField: 'band',\n    localField: 'name'\n  })\n  readonly members: string[]\n}\n\nconst bands = await Band.find({}).populate('members')\n```\n\n## Plain helper\n\n> 🔦 `Plain<class, options?>`\n\nReflet provides a generic type to discard Mongoose properties and methods from a Document.\n\n* `Plain<T>` removes inherited Mongoose properties (except `_id`) and all methods from `T`.\n* `Plain.Partial<T>` does the same as `Plain` and makes remaining properties of `T` optional.\n* `Plain.PartialDeep<T>` does the same as `Plain.Partial` recursively.\n\n`Plain` also has a second type argument to omit other properties and/or make them optional:\n\n* `Plain<T, { Omit: keyof T; Optional: keyof T } >`\n\n_These options exist as standalone generics as well: `Plain.Omit<T, keyof T>` and `Plain.Optional<T, keyof T>`._\n\nWith this you can narrow the return type of `toObject()` and `toJson()`:\n\n```ts\nconst userPlain = user.toObject({ getters: false }) as Plain.Omit<User, 'fullname'>\n```\n\n#### Allow `string` for `ObjectId`\n\n> 🔦 `Plain.AllowString<class, options?>`\n\nWhen creating or querying documents, you can pass `ObjectId` as `string`. To allow this, Reflet provides a generic type with the same API as `Plain`:\n\n* `Plain.AllowString<T, { Omit: keyof T; Optional: keyof T } >`\n* `Plain.AllowString.Partial<T>`\n* `Plain.AllowString.PartialDeep<T>`\n\n### One document, multiple shapes\n\nIn each of your models, some fields might be present when you read the document from the database, but optional or even absent when you create it. 😕\n\nGiven the following model:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field({ type: Boolean, default: () => false })\n  activated: boolean\n\n  @CreatedAt\n  createdAt: Date\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThis is how you can type `constructor` and `create` parameters:\n\n```ts\ntype NewUser = Plain.AllowString<User, { Omit: 'fullname' | 'createdAt'; Optional: '_id' | 'activated' }>\n\n@Model()\nclass User extends Model.I<typeof User>  {\n  // @ts-ignore implementation\n  constructor(doc?: NewUser, strict?: boolean | 'throw')\n}\n\nconst user = new User({ firstname: 'John', lastname: 'Doe' })\nawait user.save()\nawait User.create({ firstname: 'Jeremy', lastname: 'Doe', activated: true })\n```\n\nBy passing `typeof User` to `Model.I`, Reflet is now able to use the constructor signature to type the following static methods: `create`, `insertMany` and `replaceOne`.\n\n_The compiler checks `NewUser` as we need, so you can safely use ts-ignore on the `constructor` to avoid implementing an empty one (remember that `@Model` will replace it with mongoose Model constructor)._\n\n## Augmentations\n\nReflet comes with a dedicated global namespace `RefletMongoose`, so you can augment or narrow specific types.\n\n### SchemaType options augmentation\n\nIf you use plugins like [mongoose-autopopulate](https://github.com/mongodb-js/mongoose-autopopulate),\nyou can augment the global interface `SchemaTypeOptions` to have new options in the `@Field` API.\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface SchemaTypeOptions {\n      autopopulate?: boolean\n    }\n  }\n}\n```\n\nNow you have access to `autopopulate` option in your schemas:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: Company,\n    autopopulate: true\n  })\n  company: Company\n}\n```\n\n#### Virtual options\n\nThe same can be done with the `@Virtual` decorator:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface VirtualOptions {}\n  }\n}\n```\n\n### Model and Document augmentation\n\nYou can augment `Model` and `Document` interfaces with the dedicated global interfaces.\nHere is an example with the [@casl/mongoose](https://github.com/stalniy/casl/tree/master/packages/casl-mongoose) plugin:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface Model {\n      accessibleBy<T extends mongoose.Document>(ability: AnyMongoAbility, action?: string): mongoose.DocumentQuery<T[], T>\n    }\n    interface Document {}\n  }\n}\n```\n\n### References narrowing\n\n[SchemaType `ref` option](https://mongoosejs.com/docs/api#schematypeoptions_SchemaTypeOptions-ref) can be either a Model or a model name. With Reflet, by default, any class can be passed as a Model and any string can be passed as a model name.\n\nBy augmenting the global interface `Ref`, you can:\n\n* Narrow the class to an union of your models.\n* Narrow the string to an union of your models' names.\n\n```ts\n// company.model.ts\n@Model()\nclass Company extends Model.I {\n  @Field(String)\n  name: string\n}\n\n// You should augment the global interface in each of your models' files, to keep it close to the model.\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      Company: Company\n    }\n  }\n}\n```\n\n```ts\n// user.model.ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: 'Company',\n  })\n  company: Company\n}\n\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      User: User\n    }\n  }\n}\n```\n","licenseText":"MIT License\n\nCopyright (c) 2020 Jeremy Bensimon\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@reflet/mongoose@2.0.0-next.14","dist":{"shasum":"ea999bb7eb234f4f95a1679cfbb03f49a8fd8538","integrity":"sha512-XJVYdfk8c1sDzFw4DJAsYjc6Tvk/ur/4mWLm2+KkTJdpFQF87Mys9Frpc8LQQst0Etm/nWnPVo5HnsV2C89sQA==","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-2.0.0-next.14.tgz","fileCount":22,"unpackedSize":167481,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiOfAaACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrANQ//RoOva1z0eFrFCm/meF9pj2x5DasQUwCD1J5NWQVXAwjFQxY8\r\nUjZBpxJ1+wgVyQ/PLnNf/GKNMc6RRPOU/1+OTi4/xgYf0SPdug/LJBI4fxEI\r\nemMhkGJhGmhTiVUJMsim3THkBl/isFKt8CTl97P9yy3DesYBhULNK3oUWsGQ\r\nMEv0EfHz5iWNT7cbrQ3GFqx6VxksY9OfIyf0lOdqj4grrfSiP0S+bXdZj2n0\r\nuTh9Vb/dAyQ66Thn5pWctbW1w3Tts/atm5ANkRPBDuxswM5Y23mbi76eS5Bf\r\nl2Vwi/I6NUtkHlpphGXefqSOQR4dhBKugW3BcbzHsys66hKLsXlJnTIoupH/\r\nJxRDfmdMnbuGvGd50BzQm0ZmnV8r3gEFWDzccA6z2sPsVOP/ZjaiOdSN77Qm\r\nPhSHGyMPH1jrQevbWDOF/vC8jeHR3gbow2zviXcrplFnen70VK2uT0GfGzfq\r\nII9tRy9VFit0i6mvMBpDE4OP1AwgoWoHfUeBkLuLHfD3ol9hxQSdE7Rutp5e\r\n0BtgeqOwXAqie8fLTgH2sWZqPddgsl2J0X/i6s5+KR4wg5yDiUi9dESOIUKr\r\n8j+wZpSI6YhkCNwTSWf9jhZEyOfUj2CGai7YevjnrhkZBZlHmrrGVXD2ycFK\r\nFXFRij5Ay+jxkRzu9L4BJrQyeAwd8JaJ0PQ=\r\n=YTns\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCnmANHktFhblVIU8LbynJXSSQWvaJiU5ncyRj8Cf0MbAIhAJ1JmSpTUczDrO2wxBVGseeSDI7Fz0aoD235nSdQv/WJ"}]},"_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"directories":{},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_2.0.0-next.14_1647964186176_0.05310532762842013"},"_hasShrinkwrap":false},"2.0.0":{"name":"@reflet/mongoose","version":"2.0.0","author":{"name":"Jeremy Bensimon"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/jeremyben/reflet.git","directory":"mongoose"},"homepage":"https://github.com/jeremyben/reflet/tree/master/mongoose#readme","description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"engines":{"node":">=14"},"engineStrict":true,"peerDependencies":{"mongoose":">=7"},"devDependencies":{"@commitlint/cli":"^17.6.7","@commitlint/config-conventional":"^17.6.7","@commitlint/config-lerna-scopes":"^17.6.6","@shelf/jest-mongodb":"^4.1.7","@types/jest":"^29.5.3","jest":"^29.6.2","mongoose":"^7.4.1","mongoose-autopopulate":"^1.0.1","ts-jest":"^29.1.1"},"scripts":{"build":"ts-node -T ../build.ts","test":"jest --config jest.config.js","test:watch":"yarn test --watch --verbose false","test:file":"yarn test --testPathPattern","preversion":"yarn test --coverage && ts-node -T ../testing/summary.ts && git add coverage-summary.json","prepublishOnly":"yarn run build","publish:next":"yarn publish --tag next"},"gitHead":"e8c4725ae9051728c87ceddef5cd031c0b65b7e2","bugs":{"url":"https://github.com/jeremyben/reflet/issues"},"_id":"@reflet/mongoose@2.0.0","_nodeVersion":"18.14.2","_npmVersion":"lerna/7.1.4/node@v18.14.2+x64 (win32)","dist":{"integrity":"sha512-1a7/ymLyk1Jy2CbwD3xFCWle2A5D+QeGG3ovRtxEUhawwUGGYch8M7vbDPbD42gAGxvNhd7RrMBUJbpyfO0big==","shasum":"f1b959b82b1c328957d38403b4e51452249b872d","tarball":"https://registry.npmjs.org/@reflet/mongoose/-/mongoose-2.0.0.tgz","fileCount":20,"unpackedSize":144966,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEYjDa1ZTeLdqTHVOrNEoZnKNJupSJWHuLCmagl0FRVBAiA4FMSM9MkmiRoZQ4T9GY+Pm65GhZt/7XBquAINONKxJA=="}]},"_npmUser":{"name":"jeben","email":"bensimon.jeremy@gmail.com"},"directories":{},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongoose_2.0.0_1690745439861_0.16058654058995891"},"_hasShrinkwrap":false}},"time":{"created":"2020-04-07T09:57:45.392Z","1.0.0":"2020-04-07T09:57:46.039Z","modified":"2023-07-30T19:30:40.164Z","1.0.1":"2020-04-16T18:47:59.442Z","1.0.2":"2020-04-17T13:41:18.256Z","1.0.3":"2020-04-19T15:56:50.472Z","1.0.4":"2020-04-20T14:56:13.702Z","1.0.5":"2020-04-30T08:24:48.212Z","1.0.6":"2020-04-30T15:58:40.220Z","1.0.7":"2020-04-30T17:54:17.744Z","1.0.8":"2020-05-24T22:55:51.039Z","1.0.9":"2020-06-13T19:33:56.934Z","1.1.0":"2020-06-15T15:51:24.522Z","1.2.0":"2020-08-28T21:56:52.983Z","1.2.1":"2020-10-11T13:30:37.255Z","1.3.0":"2020-12-20T21:01:45.134Z","1.4.0":"2020-12-22T00:16:46.957Z","1.4.1":"2021-01-07T10:13:53.211Z","1.4.2":"2021-03-04T15:23:34.645Z","1.4.3":"2021-03-11T23:05:01.145Z","2.0.0-next.0":"2021-06-06T17:29:06.387Z","2.0.0-next.1":"2021-06-07T20:32:26.664Z","2.0.0-next.2":"2021-09-23T21:18:56.340Z","2.0.0-next.3":"2021-10-04T22:35:39.932Z","2.0.0-next.4":"2021-11-11T17:12:54.141Z","2.0.0-next.5":"2021-11-12T18:35:38.442Z","2.0.0-next.6":"2021-11-14T21:29:44.011Z","2.0.0-next.7":"2021-11-17T12:22:18.367Z","2.0.0-next.8":"2021-12-02T21:05:10.145Z","2.0.0-next.9":"2021-12-02T21:08:42.985Z","2.0.0-next.10":"2022-01-13T12:08:31.616Z","2.0.0-next.11":"2022-01-25T11:09:45.981Z","2.0.0-next.12":"2022-02-10T14:22:37.231Z","2.0.0-next.13":"2022-03-01T14:04:34.655Z","2.0.0-next.14":"2022-03-22T15:49:46.317Z","2.0.0":"2023-07-30T19:30:40.037Z"},"maintainers":[{"name":"jeben","email":"bensimon.jeremy@gmail.com"}],"description":"Well-defined and well-typed mongoose decorators","keywords":["mongoose","mongodb","decorators","typescript"],"repository":{"type":"git","url":"git+https://github.com/jeremyben/reflet.git","directory":"mongoose"},"author":{"name":"Jeremy Bensimon"},"license":"MIT","readme":"# `@reflet/mongoose` 🌠\n\n[![lines coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=lines&query=total.lines.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![statements coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=statements&query=total.statements.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![functions coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=functions&query=total.functions.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n[![branches coverage](https://img.shields.io/badge/dynamic/json?url=https://raw.githubusercontent.com/jeremyben/reflet/master/mongoose/coverage-summary.json&label=branches&query=total.branches.pct&color=brightgreen&suffix=%&logo=jest)](./coverage-summary.json)\n\n> [!IMPORTANT]  \n> Upgrade from **v1** to **v2** : [Migration guide](../mongoose/MIGRATION.md)\n\nThe **best** decorators for [Mongoose](https://mongoosejs.com/). Have a look at [Reflet's philosophy](../README.MD#Philosophy-).\n\n* [Getting started](#getting-started)\n* [Schema definition](#schema-definition)\n* [Model](#model)\n* [Schema options](#schema-options)\n* [Schema retrieval](#schema-retrieval)\n* [Hooks](#hooks)\n* [Model discriminators](#model-discriminators)\n* [Embedded discriminators](#embedded-discriminators)\n* [Virtuals](#virtuals)\n* [Plain helper](#plain-helper)\n* [Augmentations](#augmentations)\n\n## Getting started\n\n1. Enable experimental decorators in TypeScript compiler options.<br>_No need to install \"reflect-metadata\"._\n\n    ```json\n    \"experimentalDecorators\": true,\n    ```\n\n2. Install the package along with peer dependencies.\n\n    ```sh\n    npm i @reflet/mongoose mongoose\n    ```\n\n3. Create your decorated models.\n\n    ```ts\n    // user.model.ts\n    import { Model, Field } from '@reflet/mongoose'\n\n    @Model()\n    export class User extends Model.I {\n      static findByEmail(email) {\n        return this.findOne({ email });\n      }\n\n      @Fied({ type: String, required: true })\n      email: string\n\n      getProfileUrl() {\n        return `https://mysite.com/${this.email}`;\n      }\n    }\n    ```\n\n4. Connect to MongoDB and save your documents.\n\n    ```ts\n    // server.ts\n    import 'reflect-metadata'\n    import * as mongoose from 'mongoose'\n    import { User } from './user.model.ts'\n\n    mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true })\n\n    User.create({ email: 'jeremy@example.com' }).then((user) => {\n      console.log(`User ${user._id} has been saved.`)\n    })\n    ```\n\n### The Mongoose way\n\nConnect Mongoose in the way you already know. Models defined with Reflet will simply be attached to the default Mongoose connection.\nThis means you can **progressively** decorate your Mongoose models. 😉\n\n## Schema definition\n\n> 🔦 `@Field(schemaType)`<br>\n> 💫 Related Mongoose object: [SchemaTypes](https://mongoosejs.com/docs/schematypes)\n\nMongoose [already](https://mongoosejs.com/docs/api#schema_Schema-loadClass) allows you to load an ES6 class to attach getters, setters, instance and static methods to a schema.\nBut what about properties ? Enters the `@Field` decorator :\n\n```ts\nclass User {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field(Number)\n  age?: number\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThe `@Field` API is a direct wrapper of Mongoose [SchemaType](https://mongoosejs.com/docs/schematypes), you can put in there everything that you used to.\n\n### Nested properties\n\n> 🔦 `@Field.Nested(schemaTypes)`\n\n```ts\nclass User {\n  @Field.Nested({\n    street: { type: String, required: true },\n    city: { type: String, required: true },\n    country: { type: String, required: true },\n  })\n  address: {\n    street: string\n    city: string\n    country: string\n  }\n}\n```\n\n_`@Field.Nested` works the same as `@Field` at runtime. Its type is simply looser to allow nested objects._\n\n## Model\n\n> 🔦 `@Model(collection?, connection?)`<br>\n> 💫 Related Mongoose method: [`model`](https://mongoosejs.com/docs/models#compiling)\n\nTypeScript [class decorators](https://www.typescriptlang.org/docs/handbook/decorators#class-decorators) can modify and even replace class constructors. Reflet takes advantage of this feature and transforms a class directly into a Mongoose Model.\n\nThis means you don't have to deal with the procedural and separate creation of both schema and model anymore !\nAnd now your properties and methods are statically typed.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\nclass User extends Model.Interface {\n  @Field({ type: String, required: true })\n  email: string\n}\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  email: string\n}\n\nconst userSchema = new mongoose.Schema({\n  email: { type: String, required: true }\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n\nconst user = await User.create({\n  email: 'jeremy@example.com '\n})\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n⚠️ `@Model` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n#### Correct model and document interface\n\nYour class needs to inherit a special empty class, **`Model.Interface`** or **`Model.I`**, to have Mongoose document properties and methods.\n\n#### Custom collection name\n\nBy default, Mongoose automatically creates a collection named as the plural, lowercased version of your model name. You can customize the collection name, with the first argument:\n\n```ts\n@Model('people')\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n#### Custom Mongoose connection\n\nYou can use a different database by creating a Mongoose connection and passing it as the second argument:\n\n```ts\nconst otherDb = mongoose.createConnection('mongodb://localhost/other', { useNewUrlParser: true })\n\n@Model(undefined, otherDb)\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  email: string\n}\n```\n\n## Schema options\n\n> 🔦 `@SchemaOptions(options)`<br>\n> 💫 Related Mongoose object: [Schema options](https://mongoosejs.com/docs/guide#options)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({\n  autoIndex: false,\n  strict: 'throw'\n})\nclass User extends Model.I {           \n  @Field(String)\n  name: string\n}\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    autoIndex: false,\n    strict: 'throw'\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@SchemaOptions` API is a direct wrapper of Mongoose [schema options](https://mongoosejs.com/docs/guide#options), you can put in there everything that you used to.\n\n### Timestamps\n\n> 🔦 `@CreatedAt`, `@UpdatedAt`<br>\n> 💫 Related Mongoose option property: [`timestamps`](https://mongoosejs.com/docs/guide#timestamps)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaOptions({ minimize: false })\nclass User extends Model.I {             \n  @Field(String)\n  name: string\n\n  @CreatedAt\n  creationDate: Date\n\n  @UpdatedAt\n  updateDate: Date\n}\n\n\n\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n  creationDate: Date\n  updateDate: Date\n}\n\nconst userSchema = new mongoose.Schema(\n  { name: String },\n  {\n    minimize: false,\n    timestamps: {\n      createdAt: 'creationDate',\n      updatedAt: 'updateDate'\n    },\n  }\n)\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n### Advanced schema manipulation\n\n> 🔦 `@SchemaCallback(callback)`<br>\n> 💫 Related Mongoose object: [`Schema`](https://mongoosejs.com/docs/api/schema)\n\nIf you need more advanced schema manipulation before `@Model` compiles it, you can use `@SchemaCallback`:\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@SchemaCallback((schema) => {\n  schema.index({ name: 1, type: -1 })\n})\nclass Animal extends Model.I {          \n  @Field(String)\n  name: string\n\n  @Field(String)\n  type: string\n}\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface AnimalDocument extends mongoose.Document {\n  name: string\n  type: string\n}\n\nconst userSchema = new mongoose.Schema({\n  name: String,\n  type: String\n})\n\nuserSchema.index({ name: 1, type: -1 })\n\nconst Animal = mongoose.model<AnimalDocument>('Animal', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n_Beware of defining hooks in the callback if your schema has embedded discriminators. Mongoose documentation recommends declaring hooks **before** embedded discriminators, the callback is applied **after** them. You should use the dedicated hooks decorators `@PreHook` and `@PostHook`._\n\n## Schema retrieval\n\n> 🔦 `schemaFrom(class)`\n\nYou can retrieve a schema from any decorated class, for advanced manipulation or embedded use in another schema.\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Location {\n  @Field(Number)\n  lat: number\n\n  @Field(Number)\n  lng: number\n}\n\n@Model()\nclass City extends Model.I {            \n  @Field(String)\n  name: string\n\n  @Field(schemaFrom(Location))\n  location: Location\n}\n\nconst citySchema = schemaFrom(City)\n```\n\n  </td>\n  <td>\n\n```ts\ninterface CityDocument extends mongoose.Document {\n  name: string\n  location: {\n    lat: number,\n    lng: number\n  }\n}\n\nconst locationSchema = new mongoose.Schema(\n  { lat: Number, lng: Number },\n  { _id: false }\n)\n\nconst citySchema = new mongoose.Schema({\n  name: String,\n  location: locationSchema\n})\n\nconst City = mongoose.model<CityDocument>('City', citySchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\n🗣️ As a good practice, you should make your schema-only classes `abstract`, so you don't instantiate them by mistake.\n\n\n### Sub schemas\n\n> 🔦 `Field.Schema(class)`\n\nAs an alternative for the above use of `schemaFrom` inside the `Field` decorator, you can do:\n\n```ts\n@Model()\nclass City extends Model.I {            \n  @Field.Schema(Location)\n  location: Location\n}\n```\n\n## Hooks\n\n### Pre hook\n\n> 🔦 `@PreHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.pre`](https://mongoosejs.com/docs/middleware#pre)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PreHook<User>('save', function(next) {\n  next()\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.pre<UserDocument>('save', function (doc, next) {\n  next()\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PreHook` API is a direct wrapper of Mongoose [Schema.pre method](https://mongoosejs.com/docs/api/schema#schema_Schema-pre), you can put in there everything that you used to.\n\nSuccessive `@PreHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n### Post hook\n\n> 🔦 `@PostHook(method, callback)`<br>\n> 💫 Related Mongoose method: [`schema.post`](https://mongoosejs.com/docs/middleware#post)\n\n<table>\n<thead>\n<tr>\n  <th>Reflet</th>\n  <th>Mongoose equivalent</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n  <td>\n\n```ts\n@Model()\n@PostHook<User>('find', function(result) {\n  console.log(result)\n})\nclass User extends Model.I {     \n  @Field(String)\n  name: string\n}\n\n\n\n```\n\n  </td>\n  <td>\n\n```ts\ninterface UserDocument extends mongoose.Document {\n  name: string\n}\n\nconst userSchema = new mongoose.Schema({ name: String })\n\nuserSchema.post<UserDocument>('find', function (result) {\n  console.log(result)\n})\n\nconst User = mongoose.model<UserDocument>('User', userSchema)\n```\n\n  </td>\n</tr>\n<tbody>\n</table>\n\nThe `@PostHook` API is a direct wrapper of Mongoose [Schema.post method](https://mongoosejs.com/docs/api/schema#schema_Schema-post), you can put in there everything that you used to.\n\nSuccessive `@PostHook` will be applied in the order they are written, even though decorator functions in JS are executed in a bottom-up way (due to their _wrapping_ nature).\n\n#### Post error handling middleware\n\nTo help the compiler accurately infer the [error handling middleware](https://mongoosejs.com/docs/middleware#error-handling-middleware) signature, pass a second type argument to `@PostHook`:\n\n```ts\n@Model()\n@PostHook<User, Error>('save', function(error, doc, next) {\n  if (error.name === 'MongoError' && error.code === 11000) {\n    next(new Error('There was a duplicate key error'))\n  } else {\n    next()\n  }\n})\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n```\n\n## Model discriminators\n\n> 🔦 `@Model.Discriminator(rootModel)`<br>\n> 💫 Related Mongoose method: [`model.discriminator`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Worker extends User {\n  @Field(String)\n  job: string\n\n  // No need to decorate the default discriminatorKey.\n  __t: 'Worker'\n\n  // You can strictly type the constructor of a discriminator model by using the Plain Helper (see below).\n  constructor(worker: Plain.Omit<Worker, '_id' | '__t'>) {\n    super() // required by the compiler.\n  }\n}\n\nconst worker = await Worker.create({ name: 'Jeremy', job: 'developer' })\n// { _id: '5d023ae14043262bcfd9b384', __t: 'Worker', name: 'Jeremy', job: 'developer' }\n```\n\nAs you know, `_t` is the default `discriminatorKey`, and its value will be the class name. If you want to customize both the key and the value, check out the following `@Kind` decorator.\n\n⚠️ `@Model.Discriminator` should always be at the top of your class decorators. _Why? Because decorators are executed bottom to top, so if `@Model.Discriminator` directly compiles your class into a Mongooose Model, other class decorators won't be properly applied. Reflet will warn you with its own decorators._\n\n### Kind / DiscriminatorKey\n\n> 🔦 `@Kind(value?)` alias `@DiscriminatorKey`<br>\n> 💫 Related Mongoose option property: [`discriminatorKey`](https://mongoosejs.com/docs/discriminators#the-model-discriminator-function)\n\nMongoose `discriminatorKey` is usually defined in the parent model options, and appears in the children model documents.\n`@Kind` (or its alias `@DiscriminatorKey`) exists to define `discriminatorKey` **directly** on the children class instead of the parent model.\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field(String)\n  name: string\n}\n\n@Model.Discriminator(User)\nclass Developer extends User {\n  @Kind\n  kind: 'Developer' // Value will be the class name by default.\n}\n\n@Model.Discriminator(User)\nclass Doctor extends User {\n  @Kind('doctor') // Customize the discriminator value by passing a string.\n  kind: 'doctor'\n}\n\n// This is equivalent to setting `{ discriminatorKey: 'kind' }` on User schema options.\n```\n\nA mecanism will check and prevent you from defining a different `@Kind` key on sibling discriminators.\n\n## Embedded discriminators\n\n### Single nested discriminators\n\n> 🔦 `@Field.Union(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`SingleNestedPath.discriminator`](https://mongoosejs.com/docs/discriminators#single-nested-discriminators)\n\n`@Field.Union` allows you to embed discriminators on an single property.\n\n```ts\nabstract class Circle {\n  @Field(Number)\n  radius: number\n\n  __t: 'Circle'\n  // __t is the default discriminatorKey (no need to decorate).\n  // Value will be the class name.\n}\n\nabstract class Square {\n  @Field(Number)\n  side: number\n\n  __t: 'Square'\n}\n\n@Model()\nclass Shape extends Model.I {\n  @Field.Union([Circle, Square], { \n    required: true, // Make the field itself `shape` required.\n    strict: true // Make the discriminator key `__t` required and narrowed to its possible values.\n  })\n  shape: Circle | Square\n}\n\nconst circle = new Shape({ shape: { __t: 'Circle', radius: 5 } })\nconst square = new Shape({ shape: { __t: 'Square', side: 4 } })\n```\n\n### Embedded discriminators in arrays\n\n> 🔦 `@Field.ArrayOfUnion(classes[], options?)`<br>\n> 💫 Related Mongoose method: [`DocumentArrayPath.discriminator`](https://mongoosejs.com/docs/discriminators#embedded-discriminators-in-arrays)\n\n`@Field.ArrayOfUnion` allows you to embed discriminators in an array.\n\n```ts\n@SchemaOptions({ _id: false })\nabstract class Clicked {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  element: string\n\n  @Kind\n  kind: 'Clicked'\n}\n\n@SchemaOptions({ _id: false })\nabstract class Purchased {\n  @Field({ type: String, required: true })\n  message: string\n\n  @Field({ type: String, required: true })\n  product: string\n\n  @Kind\n  kind: 'Purchased'\n}\n\n@Model()\nclass Batch extends Model.I {\n  @Field.ArrayOfUnion([Clicked, Purchased], { \n    strict: true  // Make the discriminator key `kind` required and narrowed to its possible values.\n  })\n  events: (Clicked | Purchased)[]\n}\n\nconst batch = new Batch({\n  events: [\n    { kind: 'Clicked', element: '#hero', message: 'hello' },\n    { kind: 'Purchased', product: 'action-figure', message: 'world' },\n  ]\n})\n```\n\n## Virtuals\n\n> 🔦 `@Virtual`<br>\n> 💫 Related Mongoose method: [`schema.virtual`](https://mongoosejs.com/docs/guide.html#virtuals)\n\n`@Virtual` helps you define a writable [virtual property](https://mongoosejs.com/docs/guide.html#virtuals) (both a getter and a setter), which is properly serialized with `toJson: { virtuals: true }`, and not saved to the database.<br>_Can be used with or without invokation._\n\n```ts\n@Model()\n@SchemaOptions({ \n  toObject: { virtuals: true },\n  toJson: { virtuals: true }\n})\nclass S3File extends Model.I {\n  @Field(String)\n  key: string\n\n  @Virtual\n  url: string\n}\n\nconst photo = await S3File.findOne({ key })\nphoto.url = await getSignedUrl(photo.key)\nres.send(photo)\n```\n\n### Populated virtuals\n\n> 🔦 `@Virtual.Populate(options)`<br>\n> 💫 Related Mongoose method: [`schema.virtual`](https://mongoosejs.com/docs/populate#populate-virtuals)\n\n`@Virtual.Populate` helps you define [populate virtuals](https://mongoosejs.com/docs/populate#populate-virtuals).\n\n```ts\n@Model()\nclass Person extends Model.I {\n  @Field(String)\n  name: string\n\n  @Field(String)\n  band: string\n}\n\n@Model()\n@SchemaOptions({\n  toObject: { virtuals: true },\n  toJson: { virtuals: true }\n})\nclass Band extends Model.I {\n  @Field(String)\n  name: string\n\n  @Virtual.Populate<Band, Person>({\n    ref: 'Person',\n    foreignField: 'band',\n    localField: 'name'\n  })\n  readonly members: string[]\n}\n\nconst bands = await Band.find({}).populate('members')\n```\n\n## Plain helper\n\n> 🔦 `Plain<class, options?>`\n\nReflet provides a generic type to discard Mongoose properties and methods from a Document.\n\n* `Plain<T>` removes inherited Mongoose properties (except `_id`) and all methods from `T`.\n* `Plain.Partial<T>` does the same as `Plain` and makes remaining properties of `T` optional.\n* `Plain.PartialDeep<T>` does the same as `Plain.Partial` recursively.\n\n`Plain` also has a second type argument to omit other properties and/or make them optional:\n\n* `Plain<T, { Omit: keyof T; Optional: keyof T } >`\n\n_These options exist as standalone generics as well: `Plain.Omit<T, keyof T>` and `Plain.Optional<T, keyof T>`._\n\nWith this you can narrow the return type of `toObject()` and `toJson()`:\n\n```ts\nconst userPlain = user.toObject({ getters: false }) as Plain.Omit<User, 'fullname'>\n```\n\n#### Allow `string` for `ObjectId`\n\n> 🔦 `Plain.AllowString<class, options?>`\n\nWhen creating or querying documents, you can pass `ObjectId` as `string`. To allow this, Reflet provides a generic type with the same API as `Plain`:\n\n* `Plain.AllowString<T, { Omit: keyof T; Optional: keyof T } >`\n* `Plain.AllowString.Partial<T>`\n* `Plain.AllowString.PartialDeep<T>`\n\n### One document, multiple shapes\n\nIn each of your models, some fields might be present when you read the document from the database, but optional or even absent when you create it. 😕\n\nGiven the following model:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({ type: String, required: true })\n  firstname: string\n\n  @Field({ type: String, required: true })\n  lastname: string\n\n  @Field({ type: Boolean, default: () => false })\n  activated: boolean\n\n  @CreatedAt\n  createdAt: Date\n\n  get fullname() {\n    return `${this.firstname} ${this.lastname}`\n  }\n}\n```\n\nThis is how you can type `constructor` and `create` parameters:\n\n```ts\ntype NewUser = Plain.AllowString<User, { Omit: 'fullname' | 'createdAt'; Optional: '_id' | 'activated' }>\n\n@Model()\nclass User extends Model.I<typeof User>  {\n  // @ts-ignore implementation\n  constructor(doc?: NewUser, strict?: boolean | 'throw')\n}\n\nconst user = new User({ firstname: 'John', lastname: 'Doe' })\nawait user.save()\nawait User.create({ firstname: 'Jeremy', lastname: 'Doe', activated: true })\n```\n\nBy passing `typeof User` to `Model.I`, Reflet is now able to use the constructor signature to type the following static methods: `create`, `insertMany` and `replaceOne`.\n\n_The compiler checks `NewUser` as we need, so you can safely use ts-ignore on the `constructor` to avoid implementing an empty one (remember that `@Model` will replace it with mongoose Model constructor)._\n\n## Augmentations\n\nReflet comes with a dedicated global namespace `RefletMongoose`, so you can augment or narrow specific types.\n\n### SchemaType options augmentation\n\nIf you use plugins like [mongoose-autopopulate](https://github.com/mongodb-js/mongoose-autopopulate),\nyou can augment the global interface `SchemaTypeOptions` to have new options in the `@Field` API.\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface SchemaTypeOptions {\n      autopopulate?: boolean\n    }\n  }\n}\n```\n\nNow you have access to `autopopulate` option in your schemas:\n\n```ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: Company,\n    autopopulate: true\n  })\n  company: Company\n}\n```\n\n#### Virtual options\n\nThe same can be done with the `@Virtual` decorator:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface VirtualOptions {}\n  }\n}\n```\n\n### Model and Document augmentation\n\nYou can augment `Model` and `Document` interfaces with the dedicated global interfaces.\nHere is an example with the [@casl/mongoose](https://github.com/stalniy/casl/tree/master/packages/casl-mongoose) plugin:\n\n```ts\ndeclare global {\n  namespace RefletMongoose {\n    interface Model {\n      accessibleBy<T extends mongoose.Document>(ability: AnyMongoAbility, action?: string): mongoose.DocumentQuery<T[], T>\n    }\n    interface Document {}\n  }\n}\n```\n\n### References narrowing\n\n[SchemaType `ref` option](https://mongoosejs.com/docs/api#schematypeoptions_SchemaTypeOptions-ref) can be either a Model or a model name. With Reflet, by default, any class can be passed as a Model and any string can be passed as a model name.\n\nBy augmenting the global interface `Ref`, you can:\n\n* Narrow the class to an union of your models.\n* Narrow the string to an union of your models' names.\n\n```ts\n// company.model.ts\n@Model()\nclass Company extends Model.I {\n  @Field(String)\n  name: string\n}\n\n// You should augment the global interface in each of your models' files, to keep it close to the model.\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      Company: Company\n    }\n  }\n}\n```\n\n```ts\n// user.model.ts\n@Model()\nclass User extends Model.I {\n  @Field({\n    type: mongoose.Schema.Types.ObjectId,\n    ref: 'Company',\n  })\n  company: Company\n}\n\ndeclare global {\n  namespace RefletMongoose {\n    interface Ref {\n      User: User\n    }\n  }\n}\n```\n","readmeFilename":"README.MD","homepage":"https://github.com/jeremyben/reflet/tree/master/mongoose#readme","bugs":{"url":"https://github.com/jeremyben/reflet/issues"}}