Compare commits
111 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d746f451dd | |||
| 5a7936aac4 | |||
| 64a4fa5383 | |||
| bf7f9db63d | |||
| 71837428dd | |||
| 12d62d873b | |||
| 61cc32381b | |||
| 42b3b8375a | |||
| bdab2c5395 | |||
| d6b8e91f06 | |||
| 8bb7665af5 | |||
| 644ccc237d | |||
| 84a2c821e9 | |||
| 386c7dac05 | |||
| 1bec7a703d | |||
| 0b575fa322 | |||
| 4c5a0345a8 | |||
| ea7c7b02d6 | |||
| 9296ae7d78 | |||
| 549b2f30be | |||
| 4bc07425b4 | |||
| b0fb2edc24 | |||
| 9b63877eaa | |||
| ba845931da | |||
| 3d7503e227 | |||
| c570597d06 | |||
| e7c7beb8fd | |||
| 037920620e | |||
| 0f73464afe | |||
| 5bf554fbdf | |||
| b566196c96 | |||
| 4da24986ee | |||
| ced2c77427 | |||
| 431d3784fe | |||
| 033380e051 | |||
| 0db6bddbc4 | |||
| 0dfad07399 | |||
| e6b8b7d0fa | |||
| 0cdba0d764 | |||
| 9c0e0baf95 | |||
| 925d382f2f | |||
| 3ff97569f5 | |||
| 52a5ae9180 | |||
| 4647fbda16 | |||
| 647d26db85 | |||
| 40b8ca91ee | |||
| d92a58b2ad | |||
| 5a43ebe06f | |||
| 56259adaf7 | |||
| 470f272183 | |||
| e2d37c2efe | |||
| 487cca530b | |||
| 9e867fc0b3 | |||
| 23ec1989f7 | |||
| 1c3608743e | |||
| 33bb3cc550 | |||
| fe1807fcd5 | |||
| aaef56cb29 | |||
| 32846c1e44 | |||
| 771e071005 | |||
| 2ba8bdadfc | |||
| 6c057d4cd7 | |||
| 00259fc865 | |||
| 3356ffd052 | |||
| 6ca94dc574 | |||
| 182b760404 | |||
| 66c08e5d52 | |||
| 774d4b6243 | |||
| 86c3c2954e | |||
| 205435e546 | |||
| cf48c2b6df | |||
| ac24680bd4 | |||
| d381058591 | |||
| cfc7ea59b8 | |||
| b4fa9f5617 | |||
| c967d0bb16 | |||
| c8bcc9c488 | |||
| f00819768e | |||
| e0f56dfa38 | |||
| ecac456a4a | |||
| 3d4d959422 | |||
| d6a524f5f5 | |||
| e9b764b72f | |||
| 260eadd837 | |||
| ad0c5b2d40 | |||
| 3ac731c5ee | |||
| f40c48370c | |||
| 8d8eed3e75 | |||
| e354318b55 | |||
| 798a324f17 | |||
| a2cf4656eb | |||
| cfc255c33b | |||
| 150954290c | |||
| 58ca500acc | |||
| d152597155 | |||
| 01f2c149fa | |||
| 5de7715356 | |||
| a95cb78c6a | |||
| 0e6efb4c81 | |||
| e43eecb6f9 | |||
| 2234826810 | |||
| c2fc88292f | |||
| ce9cad3362 | |||
| 904404130a | |||
| f8a073ff6b | |||
| 711d15926f | |||
| c8b8583ae9 | |||
| 85f1547150 | |||
| 49a08979d8 | |||
| 366a07c5b0 | |||
| 7df0af10f2 |
@ -1,2 +1,5 @@
|
||||
dist
|
||||
node_modules
|
||||
docs
|
||||
.github
|
||||
.vscode
|
||||
|
||||
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
github: [arashsheyda]
|
||||
82
.github/workflows/studio.yml
vendored
Normal file
82
.github/workflows/studio.yml
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
|
||||
name: studio-nuxt-build
|
||||
run-name: studio nuxt build
|
||||
|
||||
on:
|
||||
# Runs on pushes targeting the default branch
|
||||
push:
|
||||
branches: ["main"]
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
# Add write workflow permissions
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
# Allow one concurrent deployment
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# Build job
|
||||
build-and-deploy:
|
||||
if: startsWith(github.event.head_commit.message, 'docs:')
|
||||
runs-on: ${{ matrix.os }}
|
||||
defaults:
|
||||
run:
|
||||
working-directory: docs
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
node: [18]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Identify package manager
|
||||
id: pkgman
|
||||
run: |
|
||||
cache=`[ -f "docs/pnpm-lock.yaml" ] && echo "pnpm" || ([ -f "docs/package-lock.json" ] && echo "npm" || ([ -f "docs/yarn.lock" ] && echo "yarn" || echo ""))`
|
||||
package_manager=`[ ! -z "$cache" ] && echo "$cache" || echo "pnpm"`
|
||||
echo "cache=$cache" >> $GITHUB_OUTPUT
|
||||
echo "package_manager=$package_manager" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: pnpm/action-setup@v2.2.4
|
||||
if: ${{ steps.pkgman.outputs.package_manager == 'pnpm' }}
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 7
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
version: ${{ matrix.node }}
|
||||
cache: ${{ steps.pkgman.outputs.cache }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: ${{ steps.pkgman.outputs.package_manager }} install --no-frozen-lockfile
|
||||
|
||||
- name: Install @nuxthq/studio
|
||||
run: ${{ steps.pkgman.outputs.package_manager }} add -D @nuxthq/studio
|
||||
|
||||
- name: Create .nuxtrc
|
||||
run: echo 'modules[]=@nuxthq/studio' > .nuxtrc
|
||||
|
||||
- name: Generate
|
||||
run: ${{ steps.pkgman.outputs.package_manager }} nuxi generate
|
||||
env:
|
||||
NUXT_PUBLIC_STUDIO_API_URL: https://api.nuxt.studio
|
||||
NUXT_PUBLIC_STUDIO_TOKENS: 6222c5e49391ad99e20e3c1b1a475c656436e8b0877c32021147d8727205c440
|
||||
|
||||
- name: Add .nojekyll file
|
||||
run: touch .output/public/.nojekyll
|
||||
|
||||
# Deployment job
|
||||
- name: Deploy 🚀
|
||||
uses: JamesIves/github-pages-deploy-action@v4
|
||||
with:
|
||||
folder: docs/.output/public
|
||||
4
.nuxtrc
4
.nuxtrc
@ -1,2 +1,2 @@
|
||||
imports.autoImport=false
|
||||
typescript.includeWorkspace=true
|
||||
# enable TypeScript bundler module resolution - https://www.typescriptlang.org/docs/handbook/modules/reference.html#bundler
|
||||
experimental.typescriptBundlerResolution=true
|
||||
|
||||
16
.vscode/settings.json
vendored
16
.vscode/settings.json
vendored
@ -1,16 +0,0 @@
|
||||
{
|
||||
"editor.tabSize": 2,
|
||||
"files.exclude": {
|
||||
"**/.git": true,
|
||||
"**/.svn": true,
|
||||
"**/.hg": true,
|
||||
"**/CVS": true,
|
||||
"**/.DS_Store": true,
|
||||
"**/Thumbs.db": true,
|
||||
"**/node_modules": true,
|
||||
"**/.nuxt": true,
|
||||
"**/.output": true,
|
||||
"**/dist": true,
|
||||
"**/.nuxtrc": true
|
||||
}
|
||||
}
|
||||
318
CHANGELOG.md
318
CHANGELOG.md
@ -1,5 +1,323 @@
|
||||
# Changelog
|
||||
|
||||
|
||||
## v1.0.5
|
||||
|
||||
[compare changes](https://github.com/arashsheyda/nuxt-mongoose/compare/v1.0.4...v1.0.5)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Replace consola with logger ([5a7936a](https://github.com/arashsheyda/nuxt-mongoose/commit/5a7936a))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- **release:** V1.0.4 ([64a4fa5](https://github.com/arashsheyda/nuxt-mongoose/commit/64a4fa5))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Arash <arashi.sheyda@gmail.com>
|
||||
|
||||
## v1.0.4
|
||||
|
||||
[compare changes](https://github.com/arashsheyda/nuxt-mongoose/compare/v1.0.3...v1.0.5)
|
||||
|
||||
### 💅 Refactors
|
||||
|
||||
- Split services into individual files ([d6b8e91](https://github.com/arashsheyda/nuxt-mongoose/commit/d6b8e91))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Update dependencies ([12d62d8](https://github.com/arashsheyda/nuxt-mongoose/commit/12d62d8))
|
||||
- Update dependencies ([7183742](https://github.com/arashsheyda/nuxt-mongoose/commit/7183742))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Test bundler module resolution ([#36](https://github.com/arashsheyda/nuxt-mongoose/pull/36))
|
||||
- Update dependencies ([#38](https://github.com/arashsheyda/nuxt-mongoose/pull/38))
|
||||
- Update dependencies ([bdab2c5](https://github.com/arashsheyda/nuxt-mongoose/commit/bdab2c5))
|
||||
- Update playground ([42b3b83](https://github.com/arashsheyda/nuxt-mongoose/commit/42b3b83))
|
||||
- Update cover ([61cc323](https://github.com/arashsheyda/nuxt-mongoose/commit/61cc323))
|
||||
- Update cover ([bf7f9db](https://github.com/arashsheyda/nuxt-mongoose/commit/bf7f9db))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Arash
|
||||
- Amir H. Moayeri
|
||||
- Daniel Roe <daniel@roe.dev>
|
||||
|
||||
## v1.0.3
|
||||
|
||||
[compare changes](https://github.com/arashsheyda/nuxt-mongoose/compare/v1.0.2...v1.0.3)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Add schema type ([4bc0742](https://github.com/arashsheyda/nuxt-mongoose/commit/4bc0742))
|
||||
|
||||
### 💅 Refactors
|
||||
|
||||
- Update to DevTools v1 ([1bec7a7](https://github.com/arashsheyda/nuxt-mongoose/commit/1bec7a7))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Update ui ([9296ae7](https://github.com/arashsheyda/nuxt-mongoose/commit/9296ae7))
|
||||
- Fix playground path ([ea7c7b0](https://github.com/arashsheyda/nuxt-mongoose/commit/ea7c7b0))
|
||||
- Fix install workflow ([4c5a034](https://github.com/arashsheyda/nuxt-mongoose/commit/4c5a034))
|
||||
- Update link ([0b575fa](https://github.com/arashsheyda/nuxt-mongoose/commit/0b575fa))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Remove comment ([549b2f3](https://github.com/arashsheyda/nuxt-mongoose/commit/549b2f3))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Arash
|
||||
|
||||
## v1.0.2
|
||||
|
||||
[compare changes](https://github.com/arashsheyda/nuxt-mongoose/compare/v1.0.1...v1.0.2)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Resolve build stuck issue with nitro pre-render enabled ([#26](https://github.com/arashsheyda/nuxt-mongoose/pull/26))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Default connection ([e7c7beb](https://github.com/arashsheyda/nuxt-mongoose/commit/e7c7beb))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- **release:** V1.0.2 ([ba8459](https://github.com/arashsheyda/nuxt-mongoose/commit/ba8459))
|
||||
- Lint ([3d7503e](https://github.com/arashsheyda/nuxt-mongoose/commit/3d7503e))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Arash Sheyda <sheidaeearash1999@gmail.com>
|
||||
- Arash
|
||||
|
||||
## v1.0.1
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- **release:** V1.0.0 ([b566196](https://github.com/arashsheyda/nuxt-mongoose/commit/b566196))
|
||||
- **release:** V1.0.1 ([5bf554f](https://github.com/arashsheyda/nuxt-mongoose/commit/5bf554f))
|
||||
- Update dependencies ([0f73464](https://github.com/arashsheyda/nuxt-mongoose/commit/0f73464))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Arash Sheyda <sheidaeearash1999@gmail.com>
|
||||
|
||||
## v1.0.0
|
||||
|
||||
[compare changes](https://github.com/arashsheyda/nuxt-mongoose/compare/v0.0.9...v1.0.0)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- Version 1.0.0 ([#21](https://github.com/arashsheyda/nuxt-mongoose/pull/21))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Update docus ([0db6bdd](https://github.com/arashsheyda/nuxt-mongoose/commit/0db6bdd))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Arashsheyda <sheidaeearash1999@gmail.com>
|
||||
|
||||
## v0.0.9
|
||||
|
||||
[compare changes](https://github.com/arashsheyda/nuxt-mongoose/compare/v0.0.8...v0.0.9)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- Add possibility to type mongoose model ([#8](https://github.com/arashsheyda/nuxt-mongoose/pull/8))
|
||||
- Mongoose schema hooks ([d92a58b](https://github.com/arashsheyda/nuxt-mongoose/commit/d92a58b))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Update connection message in logger ([#10](https://github.com/arashsheyda/nuxt-mongoose/pull/10))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- **utils:** Add hooks and improve documentation ([647d26d](https://github.com/arashsheyda/nuxt-mongoose/commit/647d26d))
|
||||
- **utils:** Fix model options type ([3ff9756](https://github.com/arashsheyda/nuxt-mongoose/commit/3ff9756))
|
||||
- Add types link ([9c0e0ba](https://github.com/arashsheyda/nuxt-mongoose/commit/9c0e0ba))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Fix defineNitroPlugin patch ([#9](https://github.com/arashsheyda/nuxt-mongoose/pull/9))
|
||||
- Example env ([40b8ca9](https://github.com/arashsheyda/nuxt-mongoose/commit/40b8ca9))
|
||||
- Fix defineNitroPlugin patch " ([#9](https://github.com/arashsheyda/nuxt-mongoose/pull/9))
|
||||
- Update dependencies ([925d382](https://github.com/arashsheyda/nuxt-mongoose/commit/925d382))
|
||||
- Lint ([0cdba0d](https://github.com/arashsheyda/nuxt-mongoose/commit/0cdba0d))
|
||||
- Fix tsconfig for build time ([e6b8b7d](https://github.com/arashsheyda/nuxt-mongoose/commit/e6b8b7d))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Arash Sheyda <sheidaeearash1999@gmail.com>
|
||||
- Amir-al-mohamad111
|
||||
- Oumar Barry ([@oumarbarry](http://github.com/oumarbarry))
|
||||
|
||||
## v0.0.8
|
||||
|
||||
[compare changes](https://github.com/arashsheyda/nuxt-mongoose/compare/v0.0.7...v0.0.8)
|
||||
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- Documentation ([6ca94dc](https://github.com/arashsheyda/nuxt-mongoose/commit/6ca94dc))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Module options type ([182b760](https://github.com/arashsheyda/nuxt-mongoose/commit/182b760))
|
||||
- Run studio action only for docs ([33bb3cc](https://github.com/arashsheyda/nuxt-mongoose/commit/33bb3cc))
|
||||
- Resource generator modelsDir output ([1c36087](https://github.com/arashsheyda/nuxt-mongoose/commit/1c36087))
|
||||
|
||||
### 💅 Refactors
|
||||
|
||||
- Reuse vite's websocket ([aaef56c](https://github.com/arashsheyda/nuxt-mongoose/commit/aaef56c))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Remove devtools ([6c057d4](https://github.com/arashsheyda/nuxt-mongoose/commit/6c057d4))
|
||||
- **devtools:** Demo video ([2ba8bda](https://github.com/arashsheyda/nuxt-mongoose/commit/2ba8bda))
|
||||
- Style ([23ec198](https://github.com/arashsheyda/nuxt-mongoose/commit/23ec198))
|
||||
- Favicon ([9e867fc](https://github.com/arashsheyda/nuxt-mongoose/commit/9e867fc))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Playground example ([3356ffd](https://github.com/arashsheyda/nuxt-mongoose/commit/3356ffd))
|
||||
- **deployment:** Add workflow file ([00259fc](https://github.com/arashsheyda/nuxt-mongoose/commit/00259fc))
|
||||
- Update cover ([487cca5](https://github.com/arashsheyda/nuxt-mongoose/commit/487cca5))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Arash
|
||||
- Arash Sheyda <sheidaeearash1999@gmail.com>
|
||||
- Arashsheyda <sheidaeearash1999@gmail.com>
|
||||
|
||||
## v0.0.7
|
||||
|
||||
[compare changes](https://github.com/arashsheyda/nuxt-mongoose/compare/v0.0.6...v0.0.7)
|
||||
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- Auto-import schema files ([205435e](https://github.com/arashsheyda/nuxt-mongoose/commit/205435e))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Mongoose config ([cf48c2b](https://github.com/arashsheyda/nuxt-mongoose/commit/cf48c2b))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Improve logger message ([86c3c29](https://github.com/arashsheyda/nuxt-mongoose/commit/86c3c29))
|
||||
- Update dependencies ([774d4b6](https://github.com/arashsheyda/nuxt-mongoose/commit/774d4b6))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Arashsheyda <sheidaeearash1999@gmail.com>
|
||||
|
||||
## v0.0.6
|
||||
|
||||
[compare changes](https://github.com/arashsheyda/nuxt-mongoose/compare/v0.0.5...v0.0.6)
|
||||
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Remove useMongoose composable ([d381058](https://github.com/arashsheyda/nuxt-mongoose/commit/d381058))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Arashsheyda <sheidaeearash1999@gmail.com>
|
||||
|
||||
## v0.0.5
|
||||
|
||||
[compare changes](https://github.com/arashsheyda/nuxt-mongoose/compare/v0.0.4...v0.0.5)
|
||||
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Update readme ([e0f56df](https://github.com/arashsheyda/nuxt-mongoose/commit/e0f56df))
|
||||
- Add brackets ([f008197](https://github.com/arashsheyda/nuxt-mongoose/commit/f008197))
|
||||
- Update logo ([c8bcc9c](https://github.com/arashsheyda/nuxt-mongoose/commit/c8bcc9c))
|
||||
- Update icon link ([c967d0b](https://github.com/arashsheyda/nuxt-mongoose/commit/c967d0b))
|
||||
- Update icon link ([b4fa9f5](https://github.com/arashsheyda/nuxt-mongoose/commit/b4fa9f5))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Update dependencies ([ecac456](https://github.com/arashsheyda/nuxt-mongoose/commit/ecac456))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Arashsheyda <sheidaeearash1999@gmail.com>
|
||||
- Arash
|
||||
|
||||
## v0.0.4
|
||||
|
||||
[compare changes](https://github.com/arashsheyda/nuxt-mongoose/compare/v0.0.3...v0.0.4)
|
||||
|
||||
## v0.0.3
|
||||
|
||||
[compare changes](https://github.com/arashsheyda/nuxt-mongoose/compare/v0.0.2...v0.0.3)
|
||||
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- Duplicate document ([f40c483](https://github.com/arashsheyda/nuxt-mongoose/commit/f40c483))
|
||||
- Initial pagination ([3ac731c](https://github.com/arashsheyda/nuxt-mongoose/commit/3ac731c))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Initial pagination ([ad0c5b2](https://github.com/arashsheyda/nuxt-mongoose/commit/ad0c5b2))
|
||||
- Handle errors ([e9b764b](https://github.com/arashsheyda/nuxt-mongoose/commit/e9b764b))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Move readyState ([260eadd](https://github.com/arashsheyda/nuxt-mongoose/commit/260eadd))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Arashsheyda <sheidaeearash1999@gmail.com>
|
||||
|
||||
## v0.0.2
|
||||
|
||||
[compare changes](https://github.com/arashsheyda/nuxt-mongoose/compare/v0.0.1...v0.0.2)
|
||||
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- Initial setup for nuxt devtools ([7df0af1](https://github.com/arashsheyda/nuxt-mongoose/commit/7df0af1))
|
||||
- Client rpc ([49a0897](https://github.com/arashsheyda/nuxt-mongoose/commit/49a0897))
|
||||
- Splitpanes ([85f1547](https://github.com/arashsheyda/nuxt-mongoose/commit/85f1547))
|
||||
- Database server-rpc ([c8b8583](https://github.com/arashsheyda/nuxt-mongoose/commit/c8b8583))
|
||||
- Initial database ui ([711d159](https://github.com/arashsheyda/nuxt-mongoose/commit/711d159))
|
||||
- Global styles ([9044041](https://github.com/arashsheyda/nuxt-mongoose/commit/9044041))
|
||||
- Create document ([ce9cad3](https://github.com/arashsheyda/nuxt-mongoose/commit/ce9cad3))
|
||||
- Navbar component ([c2fc882](https://github.com/arashsheyda/nuxt-mongoose/commit/c2fc882))
|
||||
- Default layout ([0e6efb4](https://github.com/arashsheyda/nuxt-mongoose/commit/0e6efb4))
|
||||
- Experimental generate resource ([5de7715](https://github.com/arashsheyda/nuxt-mongoose/commit/5de7715))
|
||||
- Mongodb readyState ([1509542](https://github.com/arashsheyda/nuxt-mongoose/commit/1509542))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Type.d.ts ([366a07c](https://github.com/arashsheyda/nuxt-mongoose/commit/366a07c))
|
||||
- Fix border line ([f8a073f](https://github.com/arashsheyda/nuxt-mongoose/commit/f8a073f))
|
||||
- Fix mongoose import ([a95cb78](https://github.com/arashsheyda/nuxt-mongoose/commit/a95cb78))
|
||||
- Fix mongoose connection ([01f2c14](https://github.com/arashsheyda/nuxt-mongoose/commit/01f2c14))
|
||||
- Auto-import models ([d152597](https://github.com/arashsheyda/nuxt-mongoose/commit/d152597))
|
||||
- Add useMongoose composable ([58ca500](https://github.com/arashsheyda/nuxt-mongoose/commit/58ca500))
|
||||
- Styling ([cfc255c](https://github.com/arashsheyda/nuxt-mongoose/commit/cfc255c))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Ui ([2234826](https://github.com/arashsheyda/nuxt-mongoose/commit/2234826))
|
||||
- Fix ui ([e43eecb](https://github.com/arashsheyda/nuxt-mongoose/commit/e43eecb))
|
||||
- Refactor ([a2cf465](https://github.com/arashsheyda/nuxt-mongoose/commit/a2cf465))
|
||||
- Styling ([798a324](https://github.com/arashsheyda/nuxt-mongoose/commit/798a324))
|
||||
- Remove unused code ([e354318](https://github.com/arashsheyda/nuxt-mongoose/commit/e354318))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Arashsheyda <sheidaeearash1999@gmail.com>
|
||||
|
||||
## v0.0.1
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
<div align="center">
|
||||
<h1>Nuxt Mongoose</h1>
|
||||
@ -10,7 +10,7 @@
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pnpm add nuxt-mongoose mongoose
|
||||
pnpm add nuxt-mongoose
|
||||
```
|
||||
|
||||
## Usage
|
||||
@ -36,10 +36,13 @@ export default defineNuxtConfig({
|
||||
mongoose: {
|
||||
uri: 'process.env.MONGODB_URI',
|
||||
options: {},
|
||||
modelsDir: 'models',
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
by default, `nuxt-mongoose` will auto-import your schemas from the `models` directory from `server` directory. You can change this behavior by setting the `modelsDir` option.
|
||||
|
||||
* for more information about the options, please refer to the [Mongoose documentation](https://mongoosejs.com/docs/connections.html#options). *
|
||||
|
||||
## API
|
||||
|
||||
1
client/.nuxtrc
Normal file
1
client/.nuxtrc
Normal file
@ -0,0 +1 @@
|
||||
imports.autoImport=true
|
||||
15
client/app.vue
Normal file
15
client/app.vue
Normal file
@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<Html>
|
||||
<Body h-screen>
|
||||
<NuxtLayout>
|
||||
<NuxtPage />
|
||||
</NuxtLayout>
|
||||
</Body>
|
||||
</Html>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
#__nuxt {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
54
client/components/Connection.vue
Normal file
54
client/components/Connection.vue
Normal file
@ -0,0 +1,54 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
code: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
})
|
||||
|
||||
const connections = [
|
||||
{
|
||||
color: 'text-red-5',
|
||||
border: 'border-red-5',
|
||||
status: 'Not Connected',
|
||||
description: 'Please Check Your Connection!',
|
||||
},
|
||||
{
|
||||
color: 'text-green-5',
|
||||
border: 'border-green-5',
|
||||
status: 'Connected',
|
||||
description: 'Everything is Working Perfectly!',
|
||||
},
|
||||
{
|
||||
color: 'text-yellow-5',
|
||||
border: 'border-yellow-5',
|
||||
status: 'Connecting',
|
||||
description: 'Just a Moment, We"re Getting There!',
|
||||
},
|
||||
{
|
||||
color: 'text-orange-5',
|
||||
border: 'border-orange-5',
|
||||
status: 'Disconnecting',
|
||||
description: 'Preparing to Safely Disconnect!',
|
||||
},
|
||||
]
|
||||
|
||||
const connection = computed(() => connections[props.code])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NPanelGrids>
|
||||
<div flex="~ gap-2" animate-pulse items-center text-lg font-bold :class="connection.color">
|
||||
({{ code }}):
|
||||
{{ connection.status }},
|
||||
{{ connection.description }}
|
||||
</div>
|
||||
<div absolute bottom-10 left-10 right-10 flex justify-around>
|
||||
<NCard v-for="item, index of connections" :key="index" p2 :class="[item.color, item.status === connection.status ? item.border : '']">
|
||||
({{ index }}): {{ item.status }}
|
||||
</NCard>
|
||||
</div>
|
||||
</NPanelGrids>
|
||||
</template>
|
||||
262
client/components/CreateResource.vue
Normal file
262
client/components/CreateResource.vue
Normal file
@ -0,0 +1,262 @@
|
||||
<script lang="ts" setup>
|
||||
import { useRouter } from 'nuxt/app'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { rpc } from '../composables/rpc'
|
||||
|
||||
interface ColumnInterface {
|
||||
name: string
|
||||
type: string
|
||||
required: boolean
|
||||
unique: boolean
|
||||
default: any
|
||||
}
|
||||
|
||||
const emit = defineEmits(['refresh'])
|
||||
const router = useRouter()
|
||||
|
||||
const schema = ref(true)
|
||||
const bread = reactive({
|
||||
browse: {
|
||||
active: true,
|
||||
type: 'index',
|
||||
},
|
||||
read: {
|
||||
active: true,
|
||||
type: 'show',
|
||||
by: '_id',
|
||||
},
|
||||
edit: {
|
||||
active: true,
|
||||
type: 'put',
|
||||
by: '_id',
|
||||
},
|
||||
add: {
|
||||
active: true,
|
||||
type: 'create',
|
||||
},
|
||||
delete: {
|
||||
active: true,
|
||||
type: 'delete',
|
||||
by: '_id',
|
||||
},
|
||||
})
|
||||
|
||||
const hasBread = computed({
|
||||
get() {
|
||||
return bread.browse.active || bread.read.active || bread.edit.active || bread.add.active || bread.delete.active
|
||||
},
|
||||
set(value: boolean) {
|
||||
bread.browse.active = value
|
||||
bread.read.active = value
|
||||
bread.edit.active = value
|
||||
bread.add.active = value
|
||||
bread.delete.active = value
|
||||
},
|
||||
})
|
||||
|
||||
const collection = ref('')
|
||||
const fields = ref<ColumnInterface[]>([
|
||||
{
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
required: true,
|
||||
unique: false,
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
name: 'slug',
|
||||
type: 'string',
|
||||
required: true,
|
||||
unique: true,
|
||||
default: '',
|
||||
},
|
||||
])
|
||||
|
||||
const allFields = computed(() => {
|
||||
return [{ name: '_id', type: 'ObjectId', required: true, unique: true, default: '' }, ...fields.value]
|
||||
})
|
||||
|
||||
const fieldsLabels = ['name', 'type', 'required', 'unique', 'default']
|
||||
const mongoTypes = [
|
||||
'string',
|
||||
'number',
|
||||
'boolean',
|
||||
'date',
|
||||
'object',
|
||||
'array',
|
||||
'ObjectId',
|
||||
]
|
||||
|
||||
function addField(index: number) {
|
||||
fields.value.splice(index + 1, 0, {
|
||||
name: '',
|
||||
type: 'string',
|
||||
required: false,
|
||||
unique: false,
|
||||
default: '',
|
||||
})
|
||||
}
|
||||
|
||||
function removeField(index: number) {
|
||||
fields.value.splice(index, 1)
|
||||
}
|
||||
|
||||
const convertedBread = computed(() => {
|
||||
const breads: any = []
|
||||
// add active breads
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
for (const [key, value] of Object.entries(bread) as any) {
|
||||
if (value.active) {
|
||||
breads.push({
|
||||
type: value.type,
|
||||
by: value?.by,
|
||||
})
|
||||
}
|
||||
}
|
||||
return breads
|
||||
})
|
||||
|
||||
const formattedFields = computed(() => {
|
||||
return fields.value.map((field) => {
|
||||
for (const [key, value] of Object.entries(field)) {
|
||||
if (!value)
|
||||
delete field[key]
|
||||
}
|
||||
|
||||
return field
|
||||
})
|
||||
})
|
||||
|
||||
async function generate() {
|
||||
await rpc.value?.generateResource(
|
||||
{
|
||||
name: collection.value,
|
||||
fields: schema.value ? formattedFields.value : undefined,
|
||||
},
|
||||
convertedBread.value,
|
||||
).then(() => {
|
||||
emit('refresh')
|
||||
router.push(`/?table=${collection.value}`)
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: remove this
|
||||
const toggleSchema = computed({
|
||||
get() {
|
||||
if (hasBread.value)
|
||||
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
||||
return schema.value = true
|
||||
return schema.value
|
||||
},
|
||||
set(value: boolean) {
|
||||
schema.value = value
|
||||
if (!schema.value)
|
||||
return hasBread.value = false
|
||||
hasBread.value = true
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div relative h-full>
|
||||
<div sticky top-0 px8 py4 glass-effect z-1>
|
||||
<div mb2 flex items-center>
|
||||
<span text-2xl font-bold mt1>
|
||||
<NCheckbox v-model="hasBread" n="green">
|
||||
BREAD
|
||||
|
|
||||
</NCheckbox>
|
||||
</span>
|
||||
<span flex gap4 mt2 ml2>
|
||||
<NCheckbox v-model="bread.browse.active" n="blue">
|
||||
Browse
|
||||
</NCheckbox>
|
||||
<div flex gap2>
|
||||
<NCheckbox v-model="bread.read.active" n="cyan">
|
||||
Read
|
||||
</NCheckbox>
|
||||
<NSelect v-if="bread.read.active" v-model="bread.read.by">
|
||||
<option v-for="field in allFields" :key="field.name" :value="field.name">
|
||||
{{ field.name }}
|
||||
</option>
|
||||
</NSelect>
|
||||
</div>
|
||||
<div flex gap2>
|
||||
<NCheckbox v-model="bread.edit.active" n="purple">
|
||||
Edit
|
||||
</NCheckbox>
|
||||
<NSelect v-if="bread.edit.active" v-model="bread.edit.by">
|
||||
<option v-for="field in allFields" :key="field.name" :value="field.name">
|
||||
{{ field.name }}
|
||||
</option>
|
||||
</NSelect>
|
||||
</div>
|
||||
<NCheckbox v-model="bread.add.active" n="green">
|
||||
Add
|
||||
</NCheckbox>
|
||||
<div flex gap2>
|
||||
<NCheckbox v-model="bread.delete.active" n="red">
|
||||
Delete
|
||||
</NCheckbox>
|
||||
<NSelect v-if="bread.delete.active" v-model="bread.delete.by">
|
||||
<option v-for="field in allFields" :key="field.name" :value="field.name">
|
||||
{{ field.name }}
|
||||
</option>
|
||||
</NSelect>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
<div flex gap4>
|
||||
<NTextInput v-model="collection" flex-auto placeholder="Collection name" />
|
||||
<NCheckbox v-model="toggleSchema" n="green">
|
||||
Generate Schema
|
||||
</NCheckbox>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="schema" px8>
|
||||
<div grid="~ cols-1" gap-2 my4>
|
||||
<div grid="~ cols-6" text-center>
|
||||
<div v-for="label in fieldsLabels" :key="label">
|
||||
{{ label }}
|
||||
</div>
|
||||
<div>
|
||||
Actions
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="(column, index) in fields" :key="index" grid="~ cols-6" items-center text-center gap4>
|
||||
<div>
|
||||
<NTextInput v-model="column.name" />
|
||||
</div>
|
||||
<div>
|
||||
<NSelect v-model="column.type">
|
||||
<option v-for="mongoType of mongoTypes" :key="mongoType" :value="mongoType">
|
||||
{{ mongoType }}
|
||||
</option>
|
||||
</NSelect>
|
||||
</div>
|
||||
<div>
|
||||
<NCheckbox v-model="column.required" n="green" />
|
||||
</div>
|
||||
<div>
|
||||
<NCheckbox v-model="column.unique" n="cyan" />
|
||||
</div>
|
||||
<div>
|
||||
<NTextInput v-if="column.type === 'string'" v-model="column.default" type="string" n="orange" />
|
||||
<NTextInput v-else-if="column.type === 'number'" v-model="column.default" type="number" n="orange" />
|
||||
<NCheckbox v-else-if="column.type === 'boolean'" v-model="column.default" n="orange" />
|
||||
<NTextInput v-else-if="column.type === 'date'" v-model="column.default" type="date" n="orange" />
|
||||
<NTextInput v-else-if="column.type === 'ObjectId'" placeholder="no-default" disabled n="orange" />
|
||||
<NTextInput v-else v-model="column.default" n="orange" />
|
||||
</div>
|
||||
<div flex justify-center gap2>
|
||||
<NButton icon="carbon-add" n="cyan" @click="addField(index)" />
|
||||
<NButton icon="carbon-trash-can" n="red" @click="removeField(index)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<NButton glass-effect fixed right-10 bottom-8 px8 py2 icon="carbon-magic-wand-filled" n="green" @click="generate">
|
||||
Create
|
||||
</NButton>
|
||||
</div>
|
||||
</template>
|
||||
286
client/components/DatabaseDetail.vue
Normal file
286
client/components/DatabaseDetail.vue
Normal file
@ -0,0 +1,286 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, reactive, ref, watch } from 'vue'
|
||||
import { computedAsync } from '@vueuse/core'
|
||||
import { rpc } from '../composables/rpc'
|
||||
import { useCopy } from '../composables/editor'
|
||||
|
||||
const props = defineProps({
|
||||
collection: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
// TODO: save in local storage
|
||||
const pagination = reactive({ limit: 20, page: 1 })
|
||||
|
||||
const countDocuments = computedAsync(async () => {
|
||||
return await rpc.value?.countDocuments(props.collection)
|
||||
})
|
||||
|
||||
const documents = computedAsync(async () => {
|
||||
return await rpc.value?.listDocuments(props.collection, pagination)
|
||||
})
|
||||
|
||||
watch(pagination, async () => {
|
||||
documents.value = await rpc.value?.listDocuments(props.collection, pagination)
|
||||
})
|
||||
|
||||
const schema = computedAsync<any>(async () => {
|
||||
return await rpc.value?.resourceSchema(props.collection)
|
||||
})
|
||||
|
||||
const fields = computed(() => {
|
||||
if (documents.value && documents.value.length > 0)
|
||||
return Object.keys(documents.value[0])
|
||||
if (schema.value)
|
||||
return Object.keys(schema.value)
|
||||
return []
|
||||
})
|
||||
|
||||
const search = ref('')
|
||||
const editing = ref(false)
|
||||
const dbContainer = ref<HTMLElement>()
|
||||
const selectedDocument = ref()
|
||||
|
||||
const filtered = computed(() => {
|
||||
if (!search.value)
|
||||
return documents.value
|
||||
return documents.value.filter((document: any) => {
|
||||
for (const field of fields.value) {
|
||||
if (document[field].toString().toLowerCase().includes(search.value.toLowerCase()))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
})
|
||||
|
||||
function addDocument() {
|
||||
// TODO: validate & show errors
|
||||
if (editing.value)
|
||||
return
|
||||
editing.value = true
|
||||
selectedDocument.value = {}
|
||||
if (schema.value) {
|
||||
for (const field of Object.keys(schema.value))
|
||||
selectedDocument.value[field] = ''
|
||||
}
|
||||
else {
|
||||
for (const field of fields.value) {
|
||||
if (field !== '_id')
|
||||
selectedDocument.value[field] = ''
|
||||
}
|
||||
}
|
||||
|
||||
const parent = dbContainer.value?.parentElement
|
||||
parent?.scrollTo(0, parent.scrollHeight)
|
||||
}
|
||||
|
||||
function editDocument(document: any) {
|
||||
if (editing.value)
|
||||
return
|
||||
editing.value = true
|
||||
selectedDocument.value = { ...document }
|
||||
}
|
||||
|
||||
async function saveDocument(document: any, create = true) {
|
||||
const method = create ? rpc.value?.createDocument : rpc.value?.updateDocument
|
||||
if (!method)
|
||||
return
|
||||
const newDocument = await method(props.collection, document)
|
||||
// TODO: show toast
|
||||
if (newDocument?.error)
|
||||
return
|
||||
|
||||
if (create) {
|
||||
if (!documents.value.length) {
|
||||
documents.value = await rpc.value?.listDocuments(props.collection, pagination)
|
||||
return discardEditing()
|
||||
}
|
||||
documents.value.push({ _id: newDocument.insertedId, ...document })
|
||||
}
|
||||
else {
|
||||
const index = documents.value.findIndex((doc: any) => doc._id === newDocument.value._id)
|
||||
documents.value[index] = document
|
||||
}
|
||||
discardEditing()
|
||||
}
|
||||
|
||||
function discardEditing() {
|
||||
editing.value = false
|
||||
selectedDocument.value = null
|
||||
}
|
||||
|
||||
async function deleteDocument(document: any) {
|
||||
const newDocument = await rpc.value?.deleteDocument(props.collection, document._id)
|
||||
// TODO: show toast
|
||||
if (newDocument.deletedCount === 0)
|
||||
return
|
||||
|
||||
documents.value = documents.value.filter((doc: any) => doc._id !== document._id)
|
||||
}
|
||||
|
||||
const copy = useCopy()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="dbContainer" :class="{ 'h-full': !documents?.length }">
|
||||
<NNavbar v-model:search="search" sticky top-0 px4 py2 backdrop-blur z-10>
|
||||
<template #actions>
|
||||
<NButton icon="carbon:add" n="green" @click="addDocument">
|
||||
Add Document
|
||||
</NButton>
|
||||
</template>
|
||||
<div v-if="countDocuments" flex items-center>
|
||||
<div op50>
|
||||
<span v-if="search">{{ filtered.length }} matched · </span>
|
||||
<span>{{ documents?.length }} of {{ countDocuments }} documents in total</span>
|
||||
</div>
|
||||
<div flex-auto />
|
||||
<div flex gap-2>
|
||||
<NSelect v-if="pagination.limit !== 0" v-model="pagination.page">
|
||||
<option v-for="i in Math.ceil(countDocuments / pagination.limit)" :key="i" :value="i">
|
||||
page:
|
||||
{{ i }}
|
||||
</option>
|
||||
</NSelect>
|
||||
<NSelect v-model="pagination.limit">
|
||||
<option v-for="i in [1, 2, 3, 4, 5]" :key="i" :value="i * 10">
|
||||
show:
|
||||
{{ i * 10 }}
|
||||
</option>
|
||||
<option :value="0">
|
||||
show all
|
||||
</option>
|
||||
</NSelect>
|
||||
</div>
|
||||
</div>
|
||||
</NNavbar>
|
||||
<table v-if="documents?.length || selectedDocument" w-full mb10 :class="{ 'editing-mode': editing }">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="field of fields" :key="field" text-start>
|
||||
{{ field }}
|
||||
</th>
|
||||
<th text-center>
|
||||
Actions
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="document in filtered" :key="document._id" :class="{ isEditing: editing && selectedDocument._id === document._id }">
|
||||
<td v-for="field of fields" :key="field" @dblclick="editDocument(document)">
|
||||
<template v-if="editing && selectedDocument._id === document._id">
|
||||
<input v-model="selectedDocument[field]" :disabled="field === '_id'">
|
||||
</template>
|
||||
<span v-else>
|
||||
{{ document[field] }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<div flex justify-center gap2 class="group">
|
||||
<template v-if="editing && selectedDocument._id === document._id">
|
||||
<NButton title="Save" icon="carbon-save" n="blue" @click="saveDocument(selectedDocument, false)" />
|
||||
<NButton title="Cancel" icon="carbon-close" n="red" @click="discardEditing" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<NButton title="Edit" icon="carbon-edit" n="blue" @click="editDocument(document)" />
|
||||
<NButton title="Delete" icon="carbon-trash-can" n="red" @click="deleteDocument(document)" />
|
||||
<NButton title="Duplicate" icon="carbon-document-multiple-02" n="cyan" @click="saveDocument(document)" />
|
||||
<NButton title="Copy" n="xs purple" absolute right-4 opacity-0 group-hover="opacity-100" transition-all icon="carbon-copy" @click="copy(JSON.stringify(document))" />
|
||||
</template>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="editing && !selectedDocument?._id" :class="{ isEditing: editing && !selectedDocument?._id }">
|
||||
<td v-for="field of fields" :key="field">
|
||||
<input v-if="field !== '_id'" v-model="selectedDocument[field]" :placeholder="field">
|
||||
<input v-else placeholder="ObjectId(_id)" disabled>
|
||||
</td>
|
||||
<td flex="~ justify-center gap2">
|
||||
<NButton title="Save" icon="carbon-save" n="green" @click="saveDocument(selectedDocument)" />
|
||||
<NButton title="Cancel" icon="carbon-close" n="red" @click="discardEditing" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div v-else flex="~ justify-center items-center" h-full text-2xl>
|
||||
<NIcon icon="carbon-document" mr1 />
|
||||
No documents found
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
table {
|
||||
table-layout: fixed;
|
||||
tr {
|
||||
width: 100%;
|
||||
td, th {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
input {
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
width: 100%;
|
||||
&::placeholder {
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
th {
|
||||
border-right: 1px solid #272727;
|
||||
border-left: 1px solid #272727;
|
||||
border-top: 1px solid #272727;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
td {
|
||||
border: 1px solid #272727;
|
||||
&:last-child {
|
||||
border-left: none;
|
||||
}
|
||||
padding: 5px 10px;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.editing-mode {
|
||||
tr {
|
||||
&:not(.isEditing) {
|
||||
opacity: 0.3;
|
||||
position: relative;
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #000;
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
&.isEditing {
|
||||
opacity: 1;
|
||||
color: #fff;
|
||||
input {
|
||||
&::placeholder {
|
||||
color: #3ede80;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
14
client/composables/editor.ts
Normal file
14
client/composables/editor.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
// import { } from '@nuxt/devtools-ui-kit'
|
||||
|
||||
export function useCopy() {
|
||||
const clipboard = useClipboard()
|
||||
|
||||
return (text: string) => {
|
||||
clipboard.copy(text)
|
||||
// devtoolsUiShowNotification({
|
||||
// message: 'Copied to clipboard',
|
||||
// icon: 'carbon-copy',
|
||||
// })
|
||||
}
|
||||
}
|
||||
18
client/composables/rpc.ts
Normal file
18
client/composables/rpc.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { onDevtoolsClientConnected } from '@nuxt/devtools-kit/iframe-client'
|
||||
import type { BirpcReturn } from 'birpc'
|
||||
import { ref } from 'vue'
|
||||
import type { NuxtDevtoolsClient } from '@nuxt/devtools-kit/dist/types'
|
||||
import type { ClientFunctions, ServerFunctions } from '../../src/types'
|
||||
import { RPC_NAMESPACE } from '../../src/constants'
|
||||
|
||||
export const devtools = ref<NuxtDevtoolsClient>()
|
||||
export const devtoolsRpc = ref<NuxtDevtoolsClient['rpc']>()
|
||||
export const rpc = ref<BirpcReturn<ServerFunctions, ClientFunctions>>()
|
||||
|
||||
onDevtoolsClientConnected(async (client) => {
|
||||
devtoolsRpc.value = client.devtools.rpc
|
||||
devtools.value = client.devtools
|
||||
|
||||
rpc.value = client.devtools.extendClientRpc<ServerFunctions, ClientFunctions>(RPC_NAMESPACE, {
|
||||
})
|
||||
})
|
||||
1
client/composables/state.ts
Normal file
1
client/composables/state.ts
Normal file
@ -0,0 +1 @@
|
||||
export const selectedCollection = useState('mongo:collection', () => '')
|
||||
13
client/layouts/default.vue
Normal file
13
client/layouts/default.vue
Normal file
@ -0,0 +1,13 @@
|
||||
<script lang="ts" setup>
|
||||
import { computedAsync } from '@vueuse/core'
|
||||
import { rpc } from '../composables/rpc'
|
||||
|
||||
const readyState = computedAsync(async () => await rpc.value?.readyState())
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div h-full of-auto>
|
||||
<slot v-if="readyState === 1" />
|
||||
<Connection v-else :code="readyState" />
|
||||
</div>
|
||||
</template>
|
||||
27
client/nuxt.config.ts
Normal file
27
client/nuxt.config.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { resolve } from 'pathe'
|
||||
import { CLIENT_PATH } from '../src/constants'
|
||||
|
||||
export default defineNuxtConfig({
|
||||
ssr: false,
|
||||
modules: [
|
||||
'@nuxt/devtools-ui-kit',
|
||||
],
|
||||
unocss: {
|
||||
shortcuts: {
|
||||
'bg-base': 'bg-white dark:bg-[#151515]',
|
||||
'bg-active': 'bg-gray:5',
|
||||
'bg-hover': 'bg-gray:3',
|
||||
'border-base': 'border-gray/20',
|
||||
'glass-effect': 'backdrop-blur-6 bg-white/80 dark:bg-[#151515]/90',
|
||||
'navbar-glass': 'sticky z-10 top-0 glass-effect',
|
||||
},
|
||||
},
|
||||
nitro: {
|
||||
output: {
|
||||
publicDir: resolve(__dirname, '../dist/client'),
|
||||
},
|
||||
},
|
||||
app: {
|
||||
baseURL: CLIENT_PATH,
|
||||
},
|
||||
})
|
||||
4
client/package.json
Normal file
4
client/package.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "nuxt-mongoose-client",
|
||||
"private": true
|
||||
}
|
||||
85
client/pages/index.vue
Normal file
85
client/pages/index.vue
Normal file
@ -0,0 +1,85 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import { computedAsync } from '@vueuse/core'
|
||||
import { useRouter } from 'nuxt/app'
|
||||
import { rpc } from '../composables/rpc'
|
||||
import { selectedCollection } from '../composables/state'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const drawer = ref(false)
|
||||
const search = ref('')
|
||||
|
||||
const collections = computedAsync(async () => {
|
||||
return await rpc.value?.listCollections()
|
||||
})
|
||||
|
||||
const filtered = computed(() => {
|
||||
if (!search.value)
|
||||
return collections.value
|
||||
return collections.value.filter((c: any) => c.name.toLowerCase().includes(search.value.toLowerCase()))
|
||||
})
|
||||
|
||||
async function dropCollection(table: any) {
|
||||
await rpc.value?.dropCollection(table.name)
|
||||
collections.value = await rpc.value?.listCollections()
|
||||
if (selectedCollection.value === table.name) {
|
||||
selectedCollection.value = ''
|
||||
router.push({ name: 'index' })
|
||||
}
|
||||
}
|
||||
|
||||
async function refresh() {
|
||||
collections.value = await rpc.value?.listCollections()
|
||||
drawer.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NSplitPane :min-left="13" :max-left="20">
|
||||
<template #left>
|
||||
<div px4>
|
||||
<NNavbar v-model:search="search" :placeholder="`${collections?.length ?? '-'} collection in total`" mt2 no-padding>
|
||||
<div flex items-center gap2>
|
||||
<NButton n="blue" w-full mb1.5 icon="carbon-reset" title="Refresh" @click="refresh" />
|
||||
<!-- <NButton w-full mb1.5 icon="carbon-data-base" title="Default" n="green" /> -->
|
||||
<NButton n="green" w-full mb1.5 icon="carbon-add" title="Create Collection" @click="drawer = true" />
|
||||
</div>
|
||||
</NNavbar>
|
||||
<div grid gird-cols-1 my2 mx1>
|
||||
<NuxtLink
|
||||
v-for="table in filtered"
|
||||
:key="table.name"
|
||||
:to="{ name: 'index', query: { table: table.name } }"
|
||||
flex items-center justify-between p2 my1 hover-bg-green hover-bg-opacity-5 hover-text-green rounded-lg
|
||||
:class="{ 'bg-green bg-opacity-5 text-green': selectedCollection === table.name }"
|
||||
@click="selectedCollection = table.name"
|
||||
>
|
||||
<span>
|
||||
<NIcon icon="carbon-db2-database" />
|
||||
{{ table.name }}
|
||||
</span>
|
||||
<div flex="~ items-center gap-2">
|
||||
<NButton :border="false" n="red" icon="carbon-trash-can" @click="dropCollection(table)" />
|
||||
<!-- <NButton :border="false" icon="carbon-overflow-menu-horizontal" /> -->
|
||||
</div>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #right>
|
||||
<DatabaseDetail v-if="selectedCollection" :collection="selectedCollection" />
|
||||
<div v-else class="n-panel-grids-center">
|
||||
<div class="n-card n-card-base" px6 py2>
|
||||
<span op75 flex items-center>
|
||||
<NIcon icon="carbon:db2-buffer-pool" mr2 />
|
||||
Select a collection to start
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</NSplitPane>
|
||||
<NDrawer v-model="drawer" style="width: calc(80.5%);" auto-close @close="drawer = false" z-20>
|
||||
<CreateResource @refresh="refresh" />
|
||||
</NDrawer>
|
||||
</template>
|
||||
12
docs/.gitignore
vendored
Normal file
12
docs/.gitignore
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
node_modules
|
||||
*.iml
|
||||
.idea
|
||||
*.log*
|
||||
.nuxt
|
||||
.vscode
|
||||
.DS_Store
|
||||
coverage
|
||||
dist
|
||||
sw.*
|
||||
.env
|
||||
.output
|
||||
2
docs/.npmrc
Normal file
2
docs/.npmrc
Normal file
@ -0,0 +1,2 @@
|
||||
shamefully-hoist=true
|
||||
strict-peer-dependencies=false
|
||||
36
docs/app.config.ts
Normal file
36
docs/app.config.ts
Normal file
@ -0,0 +1,36 @@
|
||||
export default defineAppConfig({
|
||||
docus: {
|
||||
title: 'Nuxt Mongoose',
|
||||
description: 'A Nuxt module for simplifying the use of Mongoose in your project.',
|
||||
image: '/cover.jpg',
|
||||
socials: {
|
||||
twitter: 'arash_sheyda',
|
||||
github: 'arashsheyda/nuxt-mongoose',
|
||||
},
|
||||
github: {
|
||||
dir: 'docs/content',
|
||||
branch: 'main',
|
||||
repo: 'nuxt-mongoose',
|
||||
owner: 'arashsheyda',
|
||||
edit: true,
|
||||
},
|
||||
aside: {
|
||||
level: 1,
|
||||
collapsed: false,
|
||||
exclude: [],
|
||||
},
|
||||
header: {
|
||||
logo: true,
|
||||
showLinkIcon: true,
|
||||
exclude: [],
|
||||
},
|
||||
footer: {
|
||||
iconLinks: [
|
||||
{
|
||||
href: 'https://nuxt.com',
|
||||
icon: 'simple-icons:nuxtdotjs',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
295
docs/components/content/Illustration.vue
Normal file
295
docs/components/content/Illustration.vue
Normal file
@ -0,0 +1,295 @@
|
||||
<template>
|
||||
<svg
|
||||
width="403"
|
||||
height="226"
|
||||
viewBox="0 0 403 226"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g clip-path="url(#clip0_1180_138)">
|
||||
<g opacity="0.54">
|
||||
<path
|
||||
d="M0 12C0 5.37259 5.37258 0 12 0H391C397.627 0 403 5.37258 403 12V214C403 220.627 397.627 226 391 226H12C5.37259 226 0 220.627 0 214V12Z"
|
||||
fill="url(#paint0_linear_1180_138)"
|
||||
fill-opacity="0.3"
|
||||
/>
|
||||
<path
|
||||
d="M12 0.5H391C397.351 0.5 402.5 5.64873 402.5 12V214C402.5 220.351 397.351 225.5 391 225.5H12C5.64873 225.5 0.5 220.351 0.5 214V12C0.5 5.64873 5.64873 0.5 12 0.5Z"
|
||||
stroke="url(#paint1_linear_1180_138)"
|
||||
stroke-opacity="0.4"
|
||||
/>
|
||||
</g>
|
||||
<path
|
||||
opacity="0.54"
|
||||
d="M49.7811 28H57.5876C57.8356 28 58.0792 27.9354 58.2939 27.8125C58.5086 27.6896 58.6869 27.5128 58.8108 27.3C58.9347 27.0871 58.9999 26.8457 58.9998 26.5999C58.9997 26.3542 58.9343 26.1128 58.8102 25.9001L53.5676 16.9001C53.4437 16.6873 53.2654 16.5105 53.0507 16.3877C52.836 16.2648 52.5925 16.2001 52.3446 16.2001C52.0967 16.2001 51.8532 16.2648 51.6385 16.3877C51.4238 16.5105 51.2455 16.6873 51.1216 16.9001L49.7811 19.2028L47.1602 14.6998C47.0361 14.487 46.8578 14.3104 46.6431 14.1875C46.4283 14.0647 46.1847 14 45.9368 14C45.6889 14 45.4453 14.0647 45.2305 14.1875C45.0158 14.3104 44.8375 14.487 44.7134 14.6998L38.1896 25.9001C38.0655 26.1128 38.0001 26.3542 38 26.5999C37.9999 26.8457 38.0651 27.0871 38.189 27.3C38.3129 27.5128 38.4912 27.6896 38.7059 27.8125C38.9207 27.9354 39.1643 28 39.4122 28H44.3125C46.254 28 47.6859 27.1547 48.6711 25.5057L51.063 21.4001L52.3442 19.2028L56.1893 25.8028H51.063L49.7811 28ZM44.2326 25.8005L40.8128 25.7998L45.9391 17.0004L48.4969 21.4001L46.7843 24.3407C46.13 25.4107 45.3867 25.8005 44.2326 25.8005Z"
|
||||
fill="white"
|
||||
fill-opacity="0.1"
|
||||
/>
|
||||
<line
|
||||
opacity="0.54"
|
||||
x1="43.5"
|
||||
y1="75.5"
|
||||
x2="84.5"
|
||||
y2="75.5"
|
||||
stroke="white"
|
||||
stroke-opacity="0.1"
|
||||
stroke-width="5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<line
|
||||
opacity="0.54"
|
||||
x1="43.5"
|
||||
y1="147.5"
|
||||
x2="63.5"
|
||||
y2="147.5"
|
||||
stroke="white"
|
||||
stroke-opacity="0.1"
|
||||
stroke-width="5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<line
|
||||
opacity="0.54"
|
||||
x1="172.5"
|
||||
y1="147.5"
|
||||
x2="192.899"
|
||||
y2="147.5"
|
||||
stroke="white"
|
||||
stroke-opacity="0.1"
|
||||
stroke-width="5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<line
|
||||
opacity="0.54"
|
||||
x1="301.5"
|
||||
y1="147.5"
|
||||
x2="321.5"
|
||||
y2="147.5"
|
||||
stroke="white"
|
||||
stroke-opacity="0.1"
|
||||
stroke-width="5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<line
|
||||
opacity="0.54"
|
||||
x1="143.5"
|
||||
y1="20.5"
|
||||
x2="167.5"
|
||||
y2="20.5"
|
||||
stroke="white"
|
||||
stroke-opacity="0.1"
|
||||
stroke-width="5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<line
|
||||
opacity="0.54"
|
||||
x1="184.5"
|
||||
y1="20.5"
|
||||
x2="208.5"
|
||||
y2="20.5"
|
||||
stroke="white"
|
||||
stroke-opacity="0.1"
|
||||
stroke-width="5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<line
|
||||
opacity="0.54"
|
||||
x1="225.5"
|
||||
y1="20.5"
|
||||
x2="249.5"
|
||||
y2="20.5"
|
||||
stroke="white"
|
||||
stroke-opacity="0.1"
|
||||
stroke-width="5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<line
|
||||
opacity="0.54"
|
||||
x1="43.5"
|
||||
y1="93.5"
|
||||
x2="178.5"
|
||||
y2="93.5"
|
||||
stroke="white"
|
||||
stroke-opacity="0.1"
|
||||
stroke-width="5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<line
|
||||
opacity="0.54"
|
||||
x1="43.5"
|
||||
y1="162.5"
|
||||
x2="115.544"
|
||||
y2="162.5"
|
||||
stroke="white"
|
||||
stroke-opacity="0.1"
|
||||
stroke-width="5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<line
|
||||
opacity="0.54"
|
||||
x1="172.5"
|
||||
y1="162.5"
|
||||
x2="244.5"
|
||||
y2="162.5"
|
||||
stroke="white"
|
||||
stroke-opacity="0.1"
|
||||
stroke-width="5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<line
|
||||
opacity="0.54"
|
||||
x1="301.5"
|
||||
y1="162.5"
|
||||
x2="373.5"
|
||||
y2="162.5"
|
||||
stroke="white"
|
||||
stroke-opacity="0.1"
|
||||
stroke-width="5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<line
|
||||
opacity="0.54"
|
||||
x1="43.5"
|
||||
y1="111.5"
|
||||
x2="178.5"
|
||||
y2="111.5"
|
||||
stroke="white"
|
||||
stroke-opacity="0.1"
|
||||
stroke-width="5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<line
|
||||
opacity="0.54"
|
||||
x1="43.5"
|
||||
y1="177.5"
|
||||
x2="115.5"
|
||||
y2="177.5"
|
||||
stroke="white"
|
||||
stroke-opacity="0.1"
|
||||
stroke-width="5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<line
|
||||
opacity="0.54"
|
||||
x1="172.5"
|
||||
y1="177.5"
|
||||
x2="244.5"
|
||||
y2="177.5"
|
||||
stroke="white"
|
||||
stroke-opacity="0.1"
|
||||
stroke-width="5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<line
|
||||
opacity="0.54"
|
||||
x1="301.5"
|
||||
y1="177.5"
|
||||
x2="373.5"
|
||||
y2="177.5"
|
||||
stroke="white"
|
||||
stroke-opacity="0.1"
|
||||
stroke-width="5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<rect
|
||||
opacity="0.54"
|
||||
x="335.465"
|
||||
y="17.619"
|
||||
width="41.1089"
|
||||
height="11.7454"
|
||||
rx="2.93635"
|
||||
fill="white"
|
||||
fill-opacity="0.1"
|
||||
/>
|
||||
<rect
|
||||
opacity="0.54"
|
||||
x="212"
|
||||
y="70"
|
||||
width="164"
|
||||
height="44"
|
||||
rx="5"
|
||||
fill="url(#paint2_linear_1180_138)"
|
||||
fill-opacity="0.1"
|
||||
/>
|
||||
<!-- Mongo Logo -->
|
||||
<g transform="translate(170, 80) scale(2)">
|
||||
<rect width="32" height="32" rx="7.5" style="fill:#023430" />
|
||||
<path d="M21.4,13.4C20.1,7.6,17.3,6.1,16.6,5a10.1,10.1,0,0,1-.7-1.5,1.6,1.6,0,0,1-.6,1.2,14.1,14.1,0,0,0-4.9,10.5c-.3,6.1,4.5,9.9,5.1,10.3a1.4,1.4,0,0,0,1.4-.2,12.1,12.1,0,0,0,4.5-11.9" style="fill:#10aa50" />
|
||||
<path d="M16.1,22.2a17.8,17.8,0,0,1-.5,3.3s.2,1.5.3,3h.5a30.6,30.6,0,0,1,.5-3.2C16.3,25,16.1,23.6,16.1,22.2Z" style="fill:#b8c4c2" />
|
||||
<path d="M16.9,25.3c-.6-.3-.8-1.7-.8-3.1s.2-4.3.1-6.5,0-10.7-.3-12.1L16.6,5c.7,1.1,3.5,2.6,4.8,8.4A12,12,0,0,1,16.9,25.3Z" style="fill:#12924f" />
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<filter
|
||||
id="filter0_d_1180_138"
|
||||
x="162.895"
|
||||
y="74.8947"
|
||||
width="76.2105"
|
||||
height="76.2105"
|
||||
filterUnits="userSpaceOnUse"
|
||||
color-interpolation-filters="sRGB"
|
||||
>
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix" />
|
||||
<feColorMatrix
|
||||
in="SourceAlpha"
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
||||
result="hardAlpha"
|
||||
/>
|
||||
<feOffset dy="4" />
|
||||
<feGaussianBlur stdDeviation="2" />
|
||||
<feComposite in2="hardAlpha" operator="out" />
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.44 0"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="BackgroundImageFix"
|
||||
result="effect1_dropShadow_1180_138"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="effect1_dropShadow_1180_138"
|
||||
result="shape"
|
||||
/>
|
||||
</filter>
|
||||
<linearGradient
|
||||
id="paint0_linear_1180_138"
|
||||
x1="201.5"
|
||||
y1="0"
|
||||
x2="201.5"
|
||||
y2="102.822"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="white" />
|
||||
<stop offset="1" stop-color="white" stop-opacity="0" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear_1180_138"
|
||||
x1="201.5"
|
||||
y1="-1.34109e-07"
|
||||
x2="201.527"
|
||||
y2="153.598"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="white" />
|
||||
<stop offset="1" stop-color="white" stop-opacity="0" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint2_linear_1180_138"
|
||||
x1="294"
|
||||
y1="70"
|
||||
x2="294"
|
||||
y2="114"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="white" />
|
||||
<stop offset="1" stop-color="white" stop-opacity="0" />
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_1180_138">
|
||||
<rect width="403" height="226" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
</template>
|
||||
18
docs/components/content/Logo.vue
Normal file
18
docs/components/content/Logo.vue
Normal file
@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<svg id="NuxtMongooseLogo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 235.5 33.2">
|
||||
<rect width="32" height="32" rx="7.5" style="fill:#023430" />
|
||||
<path d="M21.4,13.4C20.1,7.6,17.3,6.1,16.6,5a10.1,10.1,0,0,1-.7-1.5,1.6,1.6,0,0,1-.6,1.2,14.1,14.1,0,0,0-4.9,10.5c-.3,6.1,4.5,9.9,5.1,10.3a1.4,1.4,0,0,0,1.4-.2,12.1,12.1,0,0,0,4.5-11.9" style="fill:#10aa50" />
|
||||
<path d="M16.1,22.2a17.8,17.8,0,0,1-.5,3.3s.2,1.5.3,3h.5a30.6,30.6,0,0,1,.5-3.2C16.3,25,16.1,23.6,16.1,22.2Z" style="fill:#b8c4c2" />
|
||||
<path d="M16.9,25.3c-.6-.3-.8-1.7-.8-3.1s.2-4.3.1-6.5,0-10.7-.3-12.1L16.6,5c.7,1.1,3.5,2.6,4.8,8.4A12,12,0,0,1,16.9,25.3Z" style="fill:#12924f" />
|
||||
<text transform="translate(32.8 25.6)" style="font-size:25.818214416503906px;font-family:var(--font-sans);font-weight:700">
|
||||
<tspan fill="currentColor" x="4" y="0">Nuxt</tspan>
|
||||
<tspan x="67.8" y="0" style="fill:#10aa50">Mongoose</tspan>
|
||||
</text>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.NuxtMongooseLogo {
|
||||
font-family: serif;
|
||||
}
|
||||
</style>
|
||||
78
docs/content/0.index.md
Normal file
78
docs/content/0.index.md
Normal file
@ -0,0 +1,78 @@
|
||||
---
|
||||
title: Home
|
||||
navigation: false
|
||||
layout: page
|
||||
main:
|
||||
fluid: false
|
||||
---
|
||||
|
||||
:ellipsis{right=0px width=75% blur=150px}
|
||||
|
||||
::block-hero
|
||||
---
|
||||
cta:
|
||||
- Get started
|
||||
- /docs/getting-started/setup
|
||||
secondary:
|
||||
- Open on GitHub →
|
||||
- https://github.com/arashsheyda/nuxt-mongoose
|
||||
---
|
||||
|
||||
#title
|
||||
Nuxt [Mongoose]{style="color: var(--color-primary-500)"}
|
||||
|
||||
#description
|
||||
A Nuxt module for simplifying the use of [Mongoose](https://mongoosejs.com/) in your project.
|
||||
|
||||
#support
|
||||
:illustration
|
||||
::
|
||||
|
||||
::card-grid
|
||||
#title
|
||||
<h1 class="center">Elevate Your <br/> <span class=highlight> Developer Experience</span></h1>
|
||||
|
||||
#root
|
||||
:ellipsis{left=15rem width=40rem top=10rem blur=140px}
|
||||
|
||||
#default
|
||||
::card{icon=tabler:code}
|
||||
#title
|
||||
Nuxt DevTools Support
|
||||
#description
|
||||
Dive into your database with confidence. Benefit from Nuxt Devtools support, allowing you to inspect and debug your DB operations seamlessly.
|
||||
::
|
||||
|
||||
::card{icon=tabler:cloud-bolt}
|
||||
#title
|
||||
Auto Connection
|
||||
#description
|
||||
Forget about manual connection hassles. This module seamlessly handles the connection to your Mongoose database, making setup a breeze.
|
||||
::
|
||||
|
||||
::card{icon=tabler:plug}
|
||||
#title
|
||||
Extendable & hackable
|
||||
#description
|
||||
This module grants you access to the full spectrum of Mongoose functionalities. Leverage the power of Mongoose in your project.
|
||||
::
|
||||
|
||||
::
|
||||
|
||||
<style>
|
||||
.highlight {
|
||||
color: var(--color-primary-500);
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
.card svg {
|
||||
height: 3rem!important;
|
||||
width: 3rem!important;
|
||||
}
|
||||
.support {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
56
docs/content/1.docs/1.getting-started/1.setup.md
Normal file
56
docs/content/1.docs/1.getting-started/1.setup.md
Normal file
@ -0,0 +1,56 @@
|
||||
# Setup
|
||||
|
||||
A Nuxt module for simplifying the use of Mongoose in your project.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Install `nuxt-mongoose` to your dependencies.
|
||||
|
||||
::code-group
|
||||
|
||||
```bash [pnpm]
|
||||
pnpm add nuxt-mongoose -D
|
||||
```
|
||||
|
||||
```bash [npm]
|
||||
npm install nuxt-mongoose -D
|
||||
```
|
||||
|
||||
```bash [yarn]
|
||||
yarn add nuxt-mongoose -D
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
2. Add `nuxt-mongoose` to the `modules` section of your `nuxt.config` file.
|
||||
|
||||
```ts [nuxt.config]
|
||||
export default defineNuxtConfig({
|
||||
modules: [
|
||||
'nuxt-mongoose',
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
::alert{ type=success }
|
||||
That's it! You can now use Mongoose in your Nuxt app ✨
|
||||
::
|
||||
|
||||
|
||||
## Options
|
||||
|
||||
You can configure the module by adding a `mongoose` section to your `nuxt.config` file.
|
||||
read more about [Mongoose options](/docs/getting-started/configuration).
|
||||
|
||||
```ts [nuxt.config]
|
||||
export default defineNuxtConfig({
|
||||
mongoose: {
|
||||
// Options
|
||||
},
|
||||
})
|
||||
```
|
||||
If you want to configure only the `uri` just add `MONGODB_URI` in your `.env` file.
|
||||
|
||||
```env
|
||||
MONGODB_URI=YOUR_MONGO_URI
|
||||
```
|
||||
21
docs/content/1.docs/1.getting-started/2.configuration.md
Normal file
21
docs/content/1.docs/1.getting-started/2.configuration.md
Normal file
@ -0,0 +1,21 @@
|
||||
# Configuration
|
||||
|
||||
Configure Nuxt Mongoose with the `mongoose` property.
|
||||
|
||||
```ts [nuxt.config]
|
||||
export default defineNuxtConfig({
|
||||
mongoose: {
|
||||
uri: 'process.env.MONGODB_URI',
|
||||
options: {},
|
||||
modelsDir: 'models',
|
||||
devtools: true,
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
| **Key** | **Type** | **Default** | **Description** |
|
||||
| ---------------------------- | ---------- | ----------------------- | ---------------------------------------------------------------------------------------------------- |
|
||||
| `uri` | `string` | process.env.MONGODB_URI | Connection Uri String |
|
||||
| `options` | `ConnectOptions` | { } | Connection Options |
|
||||
| `modelsDir` | `string` | models | The models(schema) directory located in `server` for auto-import |
|
||||
| `devtools` | `boolean` | true | Enable Mongoose module in [`Nuxt Devtools`](https://github.com/nuxt/devtools) |
|
||||
2
docs/content/1.docs/1.getting-started/_dir.yml
Normal file
2
docs/content/1.docs/1.getting-started/_dir.yml
Normal file
@ -0,0 +1,2 @@
|
||||
icon: tabler:brand-mongodb
|
||||
navigation.redirect: /getting-started/setup
|
||||
74
docs/content/1.docs/2.api/1.utils.md
Normal file
74
docs/content/1.docs/2.api/1.utils.md
Normal file
@ -0,0 +1,74 @@
|
||||
# Utils
|
||||
|
||||
Discover all available utils.
|
||||
|
||||
## `defineMongooseModel`
|
||||
|
||||
This function creates a new Mongoose model with schema. Example usage:
|
||||
|
||||
::code-group
|
||||
|
||||
```ts [named parameters]
|
||||
export const User = defineMongooseModel({
|
||||
name: 'User',
|
||||
schema: {
|
||||
email: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
unique: true,
|
||||
},
|
||||
},
|
||||
options: {
|
||||
|
||||
},
|
||||
hooks(schema) {
|
||||
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
```ts [positional parameters]
|
||||
import { defineMongooseModel } from '#nuxt/mongoose'
|
||||
|
||||
export const User = defineMongooseModel('User', {
|
||||
email: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
unique: true,
|
||||
},
|
||||
}, {
|
||||
|
||||
}, (schema) => {
|
||||
|
||||
})
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
|
||||
| **Key** | **Type** | **Require** | **Description** |
|
||||
| ---------------------------- | ----------- | ----------- | ----- |
|
||||
| `name` | `string` | true | Name of Model |
|
||||
| `schema` | [`SchemaDefinition`](https://mongoosejs.com/docs/schematypes.html) | true | Schema Definition of Model |
|
||||
| `options` | [`SchemaOptions`](https://mongoosejs.com/docs/guide.html#options) | false | Schema Options for Model |
|
||||
| `hooks` | [`(schema: Schema<T>) => void`](https://mongoosejs.com/docs/middleware.html) | false | Schema Hooks Function to customize Model |
|
||||
|
||||
|
||||
::alert
|
||||
you can access the default connection with importing it from mongoose:
|
||||
::
|
||||
```
|
||||
import { connection } from 'mongoose'
|
||||
```
|
||||
|
||||
## `defineMongooseConnection`
|
||||
This function creates a new Mongoose connection.
|
||||
- `nuxt-mongoose` provides a default connection for you, it auto-register a plugin in nitro, so you don't need to use this function unless you want to create a new connection. more info [here](https://github.com/arashsheyda/nuxt-mongoose/blob/main/src/runtime/server/plugins/mongoose.db.ts).
|
||||
|
||||
Example usage:
|
||||
|
||||
```ts
|
||||
import { defineMongooseConnection } from '#nuxt/mongoose'
|
||||
|
||||
export const connection = defineMongooseConnection('mongodb://127.0.0.1/nuxt-mongoose')
|
||||
```
|
||||
8
docs/content/1.docs/2.api/2.devtools.md
Normal file
8
docs/content/1.docs/2.api/2.devtools.md
Normal file
@ -0,0 +1,8 @@
|
||||
# Devtools (beta)
|
||||
|
||||
`nuxt-mongoose` comes with a [Nuxt Devtools](https://github.com/nuxt/devtools) module that allows you to manage your collections and generate api-endpoints & schemas...
|
||||
|
||||
Here is a demo video:
|
||||
|
||||
:video-player{src="https://www.youtube.com/watch?v=hK0npSfr_Vs"}
|
||||
|
||||
5
docs/content/1.docs/2.api/3.examples.md
Normal file
5
docs/content/1.docs/2.api/3.examples.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Examples
|
||||
|
||||
Here are a few examples:
|
||||
|
||||
- Nuxt Mongoose Minimal: [:icon{name="tabler:brand-github"} Github](https://github.com/arashsheyda/nuxt-mongoose-minimal) [:icon{name="tabler:world"} Website](https://nuxt-mongoose-minimal.vercel.app/)
|
||||
2
docs/content/1.docs/2.api/_dir.yml
Normal file
2
docs/content/1.docs/2.api/_dir.yml
Normal file
@ -0,0 +1,2 @@
|
||||
title: API
|
||||
icon: tabler:book
|
||||
1
docs/content/1.docs/_dir.yml
Normal file
1
docs/content/1.docs/_dir.yml
Normal file
@ -0,0 +1 @@
|
||||
icon: tabler:file-description
|
||||
5
docs/content/2.playground/1.index.md
Normal file
5
docs/content/2.playground/1.index.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Playground
|
||||
|
||||
:ellipsis{right=0px width=75% blur=150px}
|
||||
|
||||
:sandbox{src="https://stackblitz.com/github/arashsheyda/nuxt-mongoose-minimal"}
|
||||
1
docs/content/2.playground/_dir.yml
Normal file
1
docs/content/2.playground/_dir.yml
Normal file
@ -0,0 +1 @@
|
||||
icon: tabler:play-volleyball
|
||||
3
docs/content/3.releases/_dir.yml
Normal file
3
docs/content/3.releases/_dir.yml
Normal file
@ -0,0 +1,3 @@
|
||||
title: Releases
|
||||
icon: tabler:clipboard-text
|
||||
navigation.redirect: https://github.com/arashsheyda/nuxt-mongoose/releases
|
||||
0
docs/content/3.releases/index.md
Normal file
0
docs/content/3.releases/index.md
Normal file
19
docs/nuxt.config.ts
Normal file
19
docs/nuxt.config.ts
Normal file
@ -0,0 +1,19 @@
|
||||
export default defineNuxtConfig({
|
||||
extends: '@nuxt-themes/docus',
|
||||
|
||||
app: {
|
||||
head: {
|
||||
link: [
|
||||
{
|
||||
rel: 'icon',
|
||||
type: 'image/x-icon',
|
||||
href: '/mongoose-icon.svg',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
modules: [
|
||||
'@nuxthq/studio',
|
||||
],
|
||||
})
|
||||
17
docs/package.json
Normal file
17
docs/package.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "nuxt-mongoose-docs",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "nuxi dev",
|
||||
"build": "nuxi build",
|
||||
"generate": "nuxi generate",
|
||||
"preview": "nuxi preview",
|
||||
"lint": "eslint ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt-themes/docus": "^1.15.0",
|
||||
"@nuxthq/studio": "^1.0.8",
|
||||
"nuxt": "^3.9.3"
|
||||
}
|
||||
}
|
||||
8363
docs/pnpm-lock.yaml
generated
Normal file
8363
docs/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
BIN
docs/public/cover.jpg
Normal file
BIN
docs/public/cover.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 237 KiB |
1
docs/public/mongoose-icon.svg
Normal file
1
docs/public/mongoose-icon.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 256 256"><g fill="none"><rect width="256" height="256" fill="#023430" rx="60"/><path fill="#10AA50" d="M171.173 107.591c-10.537-46.481-32.497-58.855-38.099-67.602A99.398 99.398 0 0 1 126.949 28c-.296 4.13-.84 6.73-4.35 9.862c-7.047 6.283-36.977 30.673-39.496 83.486c-2.347 49.242 36.2 79.605 41.292 82.744c3.916 1.927 8.685.041 11.012-1.728c18.581-12.752 43.969-46.75 35.786-94.773"/><path fill="#B8C4C2" d="M128.545 177.871c-.97 12.188-1.665 19.27-4.129 26.235c0 0 1.617 11.603 2.753 23.894h4.019a223.446 223.446 0 0 1 4.384-25.732c-5.203-2.56-6.827-13.702-7.027-24.397Z"/><path fill="#12924F" d="M135.565 202.275c-5.258-2.429-6.779-13.806-7.013-24.404a499.824 499.824 0 0 0 1.136-52.545c-.276-9.194.13-85.158-2.265-96.28a92.425 92.425 0 0 0 5.651 10.936c5.602 8.754 27.569 21.128 38.099 67.609c8.203 47.941-17.047 81.849-35.608 94.684Z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 926 B |
@ -1,26 +1 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 914.6 296.6" style="enable-background:new 0 0 914.6 296.6;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#880000;}
|
||||
.st1{fill:#00DC82;}
|
||||
</style>
|
||||
<path class="st0" d="M620,225.4c-47.8-6.5-96.2,6.6-134.1,36.4c-9.7-24.4-21.2-48-34.1-70.8c-10.8-19.1-18.1-29.1-28.6-29.9
|
||||
c-10.5-0.8-21.3,9.9-25.3,15c-2.4-6.3-11.1-27-25.7-28.6c-14.6-1.6-26.7,16.2-41.7,38c-12.2,17.8-22,37.1-29.3,57.4
|
||||
c-4.9-14.1-18.2-46.7-51.4-69.3c-42.6-28.9-100.8-29.7-151.2-3.2c82.8-70,172.3-122.4,284.9-120c10.8,56.5,46.3,100.5,79.8,105.9
|
||||
c-14.4-13.7-33.3-29-48.6-47.3c-13.2-15.6-21.3-34.8-21-56.6c0.2-12.6,5.8-19.8,17.5-18.2c23.3,3.5,46.3,8.9,69.3,13.6
|
||||
c2.5,0.5,4.9,1.7,8.4,0.5l-23.2-11.5c0.4-1.4,0.7-2.8,1.1-4.2c114.6-5.8,221.8,26,328.4,65.5c-1.4,7.4-2.5,12.9-3.6,18.4l1.5,0.6
|
||||
l7.1-14c16.3,2.2,18.3,6.4,14.1,20.7c-7.4,25.7-24.1,39.2-50,44.1c-41.3,7.9-82.2,17.2-123.5,25.3
|
||||
C614.3,198.5,613.4,199.4,620,225.4z M481.1,94.6c-16.8-20-51.7-37.3-67.5-34.9c-2.3,22.4,34.4,68.2,57.8,71.7
|
||||
c-2.7-4.4-5.3-8.4-7.8-12.6l6.4-3.5c-4.6-6-8.8-11.4-15.2-19.8l18.7,7.9l-6.6-13.7L481.1,94.6z M672,98.1l0.2-4.8l-90.4-17.4
|
||||
l-1.3,4.5c14.2,7,27.8,16.7,42.8,20.2C639.4,104.2,656.2,103.4,672,98.1L672,98.1z M659.4,162.1l-1.6-4.3
|
||||
c-20.4,8.3-41.2,15.8-61,25.3c-11.1,5.3-10.9,14-3,22.5C601.6,170.5,636.4,174.7,659.4,162.1L659.4,162.1z"/>
|
||||
<path class="st1" d="M399.5,264.6H459c1.9,0,3.8-0.5,5.4-1.4c3.3-1.9,5.3-5.4,5.3-9.3c0-1.9-0.5-3.7-1.4-5.3l-40-68.7
|
||||
c-0.9-1.6-2.3-2.9-3.9-3.8c-3.4-2-7.5-2-10.8,0c-1.6,0.9-3,2.3-3.9,3.8l-10.2,17.6l-20-34.4c-1-1.6-2.4-2.9-4-3.8
|
||||
c-3.3-2-7.5-2-10.7,0c-1.6,0.9-3,2.3-3.9,3.8L311,248.6c-0.9,1.6-1.5,3.5-1.5,5.3c0.1,3.8,2.1,7.3,5.4,9.3c1.6,0.9,3.5,1.4,5.4,1.4
|
||||
h37.4c14.7,0,25.7-6.4,33.3-19l18.2-31.4l9.8-16.7l29.3,50.4h-39.1L399.5,264.6z M357.1,247.8H331l39.1-67.1l19.5,33.6l-13.1,22.4
|
||||
C371.6,244.9,365.9,247.8,357.1,247.8z"/>
|
||||
<path class="st1" d="M672,98.1l0.2-4.8l-90.4-17.4l-1.3,4.5c14.2,7,27.8,16.7,42.8,20.2C639.4,104.2,656.2,103.4,672,98.1L672,98.1z
|
||||
"/>
|
||||
</svg>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 235.5 33.2"><rect width="32" height="32" rx="7.5" style="fill:#023430"/><path d="M21.4,13.4C20.1,7.6,17.3,6.1,16.6,5a10.1,10.1,0,0,1-.7-1.5,1.6,1.6,0,0,1-.6,1.2,14.1,14.1,0,0,0-4.9,10.5c-.3,6.1,4.5,9.9,5.1,10.3a1.4,1.4,0,0,0,1.4-.2,12.1,12.1,0,0,0,4.5-11.9" style="fill:#10aa50"/><path d="M16.1,22.2a17.8,17.8,0,0,1-.5,3.3s.2,1.5.3,3h.5a30.6,30.6,0,0,1,.5-3.2C16.3,25,16.1,23.6,16.1,22.2Z" style="fill:#b8c4c2"/><path d="M16.9,25.3c-.6-.3-.8-1.7-.8-3.1s.2-4.3.1-6.5,0-10.7-.3-12.1L16.6,5c.7,1.1,3.5,2.6,4.8,8.4A12,12,0,0,1,16.9,25.3Z" style="fill:#12924f"/><text transform="translate(32.8 25.6)" style="font-size:25.818214416503906px;font-family:OpenSans-Bold, Open Sans;font-weight:700">Nuxt <tspan x="70.8" y="0" style="fill:#10aa50">Mongoose</tspan></text></svg>
|
||||
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 851 B |
8
docs/renovate.json
Normal file
8
docs/renovate.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": [
|
||||
"@nuxtjs"
|
||||
],
|
||||
"lockFileMaintenance": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
18
docs/tokens.config.ts
Normal file
18
docs/tokens.config.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { defineTheme } from 'pinceau'
|
||||
|
||||
export default defineTheme({
|
||||
color: {
|
||||
primary: {
|
||||
50: '#e8f5e9',
|
||||
100: '#c8e6c9',
|
||||
200: '#a5d6a7',
|
||||
300: '#81c784',
|
||||
400: '#66bb6a',
|
||||
500: '#10a74f',
|
||||
600: '#10a74f',
|
||||
700: '#388e3c',
|
||||
800: '#2e7d32',
|
||||
900: '#1b5e20',
|
||||
},
|
||||
},
|
||||
})
|
||||
3
docs/tsconfig.json
Normal file
3
docs/tsconfig.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "./.nuxt/tsconfig.json"
|
||||
}
|
||||
74
package.json
74
package.json
@ -1,52 +1,74 @@
|
||||
{
|
||||
"name": "nuxt-mongoose",
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"version": "1.0.5",
|
||||
"private": false,
|
||||
"packageManager": "pnpm@8.7.4",
|
||||
"description": "Nuxt 3 module for MongoDB with Mongoose",
|
||||
"license": "MIT",
|
||||
"funding": "https://github.com/sponsors/arashsheyda",
|
||||
"homepage": "https://nuxt-mongoose.nuxt.space",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/arashsheyda/nuxt-mongoose"
|
||||
"url": "git+https://github.com/arashsheyda/nuxt-mongoose"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/arashsheyda/nuxt-mongoose/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"nuxt",
|
||||
"mongoose",
|
||||
"mongodb",
|
||||
"devtools"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/types.d.ts",
|
||||
"require": "./dist/module.cjs",
|
||||
"import": "./dist/module.mjs"
|
||||
"import": "./dist/module.mjs",
|
||||
"require": "./dist/module.cjs"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"externals": [
|
||||
"ofetch"
|
||||
]
|
||||
},
|
||||
"main": "./dist/module.cjs",
|
||||
"types": "./dist/types.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"prepack": "nuxt-module-build",
|
||||
"build": "nuxt-module-build && npm run build:client",
|
||||
"build:client": "nuxi generate client",
|
||||
"dev": "nuxi dev playground",
|
||||
"dev:build": "nuxi build playground",
|
||||
"dev:prepare": "nuxt-module-build --stub && nuxi prepare playground",
|
||||
"release": "npm run lint && npm run prepack && changelogen --release && npm publish && git push --follow-tags",
|
||||
"lint": "eslint .",
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest watch"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"mongoose": "^7.0.3",
|
||||
"nuxt": "^3.4.1"
|
||||
"dev:prepare": "nuxt-module-build && nuxi prepare client",
|
||||
"dev:client": "nuxi dev client --port 3300",
|
||||
"dev:prod": "npm run build && npm run dev",
|
||||
"release": "npm run lint && npm run build && changelogen --release && npm publish",
|
||||
"lint": "eslint . --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/kit": "^3.4.1",
|
||||
"defu": "^6.1.2",
|
||||
"mongoose": "^7.0.3"
|
||||
"@nuxt/devtools-kit": "1.0.8",
|
||||
"@nuxt/devtools-ui-kit": "1.0.8",
|
||||
"@nuxt/kit": "^3.9.3",
|
||||
"@vueuse/core": "^10.7.2",
|
||||
"defu": "^6.1.4",
|
||||
"fs-extra": "^11.2.0",
|
||||
"mongoose": "^8.1.0",
|
||||
"ofetch": "^1.3.3",
|
||||
"pathe": "^1.1.2",
|
||||
"pluralize": "^8.0.0",
|
||||
"sirv": "^2.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "^0.38.4",
|
||||
"@nuxt/module-builder": "^0.3.0",
|
||||
"@nuxt/schema": "^3.4.1",
|
||||
"@nuxt/test-utils": "^3.4.1",
|
||||
"changelogen": "^0.5.3",
|
||||
"eslint": "^8.38.0",
|
||||
"nuxt": "^3.4.1",
|
||||
"vitest": "^0.30.1"
|
||||
"@antfu/eslint-config": "2.6.3",
|
||||
"@nuxt/module-builder": "^0.5.5",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/pluralize": "^0.0.33",
|
||||
"changelogen": "^0.5.5",
|
||||
"eslint": "8.56.0",
|
||||
"nuxt": "^3.9.3",
|
||||
"sass": "^1.69.7"
|
||||
}
|
||||
}
|
||||
1
playground/.env.example
Normal file
1
playground/.env.example
Normal file
@ -0,0 +1 @@
|
||||
MONGODB_URI="mongodb://localhost:27017/nuxt-mongoose"
|
||||
@ -1,8 +1,14 @@
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
const { data } = await useFetch('/api/users')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
Nuxt module playground!
|
||||
<br>
|
||||
<pre
|
||||
v-html="JSON.stringify(data, null, 2)"
|
||||
style="background: #131313;color: #4EA65A;padding: 20px;border-radius: 7px;text-shadow: 0px 0px 10px #00ff22;"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -1,7 +1,33 @@
|
||||
export default defineNuxtConfig({
|
||||
modules: ['../src/module'],
|
||||
import { resolve } from 'node:path'
|
||||
import { defineNuxtConfig } from 'nuxt/config'
|
||||
import { defineNuxtModule } from '@nuxt/kit'
|
||||
import { startSubprocess } from '@nuxt/devtools-kit'
|
||||
import { CLIENT_PORT } from '../src/constants'
|
||||
|
||||
mongoose: {
|
||||
uri: 'mongodb://127.0.0.1/nuxt-mongoose',
|
||||
export default defineNuxtConfig({
|
||||
devtools: {
|
||||
enabled: true,
|
||||
},
|
||||
|
||||
modules: [
|
||||
'../src/module',
|
||||
defineNuxtModule({
|
||||
setup(_, nuxt) {
|
||||
if (!nuxt.options.dev)
|
||||
return
|
||||
|
||||
startSubprocess(
|
||||
{
|
||||
command: 'npx',
|
||||
args: ['nuxi', 'dev', '--port', CLIENT_PORT.toString()],
|
||||
cwd: resolve(__dirname, '../client'),
|
||||
},
|
||||
{
|
||||
id: 'nuxt-mongoose:client',
|
||||
name: 'Nuxt Mongoose Client Dev',
|
||||
},
|
||||
)
|
||||
},
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
5
playground/server/api/hi.get.ts
Normal file
5
playground/server/api/hi.get.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export default defineEventHandler(async () => {
|
||||
return {
|
||||
message: 'hi',
|
||||
}
|
||||
})
|
||||
@ -1,5 +0,0 @@
|
||||
import { User } from '~/server/models/user.schema'
|
||||
|
||||
export default defineEventHandler(() => {
|
||||
return User.find()
|
||||
})
|
||||
8
playground/server/api/users/[_id].delete.ts
Normal file
8
playground/server/api/users/[_id].delete.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
return await UserSchema.findOneAndDelete({ _id: event.context.params?._id })
|
||||
}
|
||||
catch (error) {
|
||||
return error
|
||||
}
|
||||
})
|
||||
8
playground/server/api/users/[_id].get.ts
Normal file
8
playground/server/api/users/[_id].get.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
return await UserSchema.findOne({ _id: event.context.params?._id })
|
||||
}
|
||||
catch (error) {
|
||||
return error
|
||||
}
|
||||
})
|
||||
9
playground/server/api/users/[_id].put.ts
Normal file
9
playground/server/api/users/[_id].put.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export default defineEventHandler(async (event) => {
|
||||
const body = await readBody(event)
|
||||
try {
|
||||
return await UserSchema.findOneAndUpdate({ _id: event.context.params?._id }, body, { new: true })
|
||||
}
|
||||
catch (error) {
|
||||
return error
|
||||
}
|
||||
})
|
||||
9
playground/server/api/users/create.post.ts
Normal file
9
playground/server/api/users/create.post.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export default defineEventHandler(async (event) => {
|
||||
const body = await readBody(event)
|
||||
try {
|
||||
return await new UserSchema(body).save()
|
||||
}
|
||||
catch (error) {
|
||||
return error
|
||||
}
|
||||
})
|
||||
8
playground/server/api/users/index.get.ts
Normal file
8
playground/server/api/users/index.get.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export default defineEventHandler(async () => {
|
||||
try {
|
||||
return await UserSchema.find({})
|
||||
}
|
||||
catch (error) {
|
||||
return error
|
||||
}
|
||||
})
|
||||
@ -1,18 +1,26 @@
|
||||
import { defineMongooseModel } from '#nuxt/mongoose'
|
||||
|
||||
export const User = defineMongooseModel({
|
||||
export const UserSchema = defineMongooseModel({
|
||||
name: 'User',
|
||||
schema: {
|
||||
name: {
|
||||
type: String,
|
||||
type: 'string',
|
||||
required: true,
|
||||
},
|
||||
email: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
unique: false,
|
||||
},
|
||||
password: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
hooks(schema) {
|
||||
schema.pre('save', function (this, next) {
|
||||
this.password = `hash.${this.password}.${Math.random()}`
|
||||
next()
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
// export const User = defineMongooseModel('User', {
|
||||
// name: {
|
||||
// type: String,
|
||||
// required: true,
|
||||
// },
|
||||
// })
|
||||
|
||||
3
playground/server/tsconfig.json
Normal file
3
playground/server/tsconfig.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "../.nuxt/tsconfig.server.json"
|
||||
}
|
||||
13198
pnpm-lock.yaml
generated
13198
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
3
src/constants/index.ts
Normal file
3
src/constants/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export const CLIENT_PATH = '/__nuxt-mongoose'
|
||||
export const CLIENT_PORT = 3300
|
||||
export const RPC_NAMESPACE = 'nuxt-mongoose-rpc'
|
||||
56
src/devtools.ts
Normal file
56
src/devtools.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import { existsSync } from 'node:fs'
|
||||
import type { Nuxt } from 'nuxt/schema'
|
||||
import type { Resolver } from '@nuxt/kit'
|
||||
import { extendServerRpc, onDevToolsInitialized } from '@nuxt/devtools-kit'
|
||||
import type { ClientFunctions, ServerFunctions } from './types'
|
||||
import type { ModuleOptions } from './module'
|
||||
import { useViteWebSocket } from './utils'
|
||||
|
||||
import { setupRPC } from './rpc'
|
||||
import { CLIENT_PATH, CLIENT_PORT, RPC_NAMESPACE } from './constants'
|
||||
|
||||
export function setupDevToolsUI(options: ModuleOptions, resolve: Resolver['resolve'], nuxt: Nuxt) {
|
||||
const clientPath = resolve('./client')
|
||||
const isProductionBuild = existsSync(clientPath)
|
||||
|
||||
if (isProductionBuild) {
|
||||
nuxt.hook('vite:serverCreated', async (server) => {
|
||||
const sirv = await import('sirv').then(r => r.default || r)
|
||||
server.middlewares.use(
|
||||
CLIENT_PATH,
|
||||
sirv(clientPath, { dev: true, single: true }),
|
||||
)
|
||||
})
|
||||
}
|
||||
else {
|
||||
nuxt.hook('vite:extendConfig', (config) => {
|
||||
config.server = config.server || {}
|
||||
config.server.proxy = config.server.proxy || {}
|
||||
config.server.proxy[CLIENT_PATH] = {
|
||||
target: `http://localhost:${CLIENT_PORT}${CLIENT_PATH}`,
|
||||
changeOrigin: true,
|
||||
followRedirects: true,
|
||||
rewrite: path => path.replace(CLIENT_PATH, ''),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
nuxt.hook('devtools:customTabs', (tabs) => {
|
||||
tabs.push({
|
||||
name: 'nuxt-mongoose',
|
||||
title: 'Mongoose',
|
||||
icon: 'skill-icons:mongodb',
|
||||
view: {
|
||||
type: 'iframe',
|
||||
src: CLIENT_PATH,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
const wsServer = useViteWebSocket(nuxt)
|
||||
onDevToolsInitialized(async () => {
|
||||
const rpcFunctions = setupRPC({ options, wsServer, nuxt })
|
||||
|
||||
extendServerRpc<ClientFunctions, ServerFunctions>(RPC_NAMESPACE, rpcFunctions)
|
||||
})
|
||||
}
|
||||
@ -1,10 +1,46 @@
|
||||
import { addServerPlugin, addTemplate, createResolver, defineNuxtModule } from '@nuxt/kit'
|
||||
import { defu } from 'defu'
|
||||
import {
|
||||
addServerPlugin,
|
||||
addTemplate,
|
||||
createResolver,
|
||||
defineNuxtModule,
|
||||
logger,
|
||||
} from '@nuxt/kit'
|
||||
import type { ConnectOptions } from 'mongoose'
|
||||
import defu from 'defu'
|
||||
import { join } from 'pathe'
|
||||
import mongoose from 'mongoose'
|
||||
import { $fetch } from 'ofetch'
|
||||
import { version } from '../package.json'
|
||||
import { setupDevToolsUI } from './devtools'
|
||||
|
||||
export interface ModuleOptions {
|
||||
uri?: string
|
||||
/**
|
||||
* The MongoDB URI connection
|
||||
*
|
||||
* @default process.env.MONGODB_URI
|
||||
*
|
||||
*/
|
||||
uri: string | undefined
|
||||
/**
|
||||
* Nuxt DevTools
|
||||
*
|
||||
* @default true
|
||||
*
|
||||
*/
|
||||
devtools: boolean
|
||||
/**
|
||||
* Mongoose Connections
|
||||
*
|
||||
* @default {}
|
||||
*/
|
||||
options?: ConnectOptions
|
||||
/**
|
||||
* Models Directory for auto-import
|
||||
*
|
||||
* @default 'models'
|
||||
*
|
||||
*/
|
||||
modelsDir?: string
|
||||
}
|
||||
|
||||
export default defineNuxtModule<ModuleOptions>({
|
||||
@ -13,30 +49,54 @@ export default defineNuxtModule<ModuleOptions>({
|
||||
configKey: 'mongoose',
|
||||
},
|
||||
defaults: {
|
||||
// eslint-disable-next-line n/prefer-global/process
|
||||
uri: process.env.MONGODB_URI as string,
|
||||
devtools: true,
|
||||
options: {},
|
||||
modelsDir: 'models',
|
||||
},
|
||||
setup(options, nuxt) {
|
||||
hooks: {
|
||||
close: () => {
|
||||
mongoose.disconnect()
|
||||
},
|
||||
},
|
||||
async setup(options, nuxt) {
|
||||
if (nuxt.options.dev) {
|
||||
$fetch('https://registry.npmjs.org/nuxt-mongoose/latest').then((release) => {
|
||||
if (release.version > version)
|
||||
logger.info(`A new version of Nuxt Mongoose (v${release.version}) is available: https://github.com/arashsheyda/nuxt-mongoose/releases/latest`)
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
if (!options.uri) {
|
||||
logger.warn('Missing MongoDB URI. You can set it in your `nuxt.config` or in your `.env` as `MONGODB_URI`')
|
||||
return
|
||||
}
|
||||
|
||||
const { resolve } = createResolver(import.meta.url)
|
||||
const config = nuxt.options.runtimeConfig as any
|
||||
|
||||
if (!options.uri)
|
||||
console.warn('Missing `MONGODB_URI` in `.env`')
|
||||
|
||||
// Public runtimeConfig
|
||||
nuxt.options.runtimeConfig.public.mongoose = defu(nuxt.options.runtimeConfig.public.mongoose || {}, {
|
||||
config.mongoose = defu(config.mongoose || {}, {
|
||||
uri: options.uri,
|
||||
options: options.options,
|
||||
devtools: options.devtools,
|
||||
modelsDir: join(nuxt.options.serverDir, options.modelsDir!),
|
||||
})
|
||||
|
||||
// virtual imports
|
||||
nuxt.hook('nitro:config', (nitroConfig) => {
|
||||
nitroConfig.alias = nitroConfig.alias || {}
|
||||
nuxt.hook('nitro:config', (_config) => {
|
||||
_config.alias = _config.alias || {}
|
||||
|
||||
// Inline module runtime in Nitro bundle
|
||||
nitroConfig.externals = defu(typeof nitroConfig.externals === 'object' ? nitroConfig.externals : {}, {
|
||||
_config.externals = defu(typeof _config.externals === 'object' ? _config.externals : {}, {
|
||||
inline: [resolve('./runtime')],
|
||||
})
|
||||
nitroConfig.alias['#nuxt/mongoose'] = resolve('./runtime/server/services')
|
||||
_config.alias['#nuxt/mongoose'] = resolve('./runtime/server/services')
|
||||
|
||||
if (_config.imports) {
|
||||
_config.imports.dirs = _config.imports.dirs || []
|
||||
_config.imports.dirs?.push(config.mongoose.modelsDir)
|
||||
}
|
||||
})
|
||||
|
||||
addTemplate({
|
||||
@ -53,7 +113,13 @@ export default defineNuxtModule<ModuleOptions>({
|
||||
options.references.push({ path: resolve(nuxt.options.buildDir, 'types/nuxt-mongoose.d.ts') })
|
||||
})
|
||||
|
||||
const isDevToolsEnabled = typeof nuxt.options.devtools === 'boolean' ? nuxt.options.devtools : nuxt.options.devtools.enabled
|
||||
if (nuxt.options.dev && isDevToolsEnabled)
|
||||
setupDevToolsUI(options, resolve, nuxt)
|
||||
|
||||
// Add server-plugin for database connection
|
||||
addServerPlugin(resolve('./runtime/server/plugins/mongoose.db'))
|
||||
|
||||
logger.success('`nuxt-mongoose` is ready!')
|
||||
},
|
||||
})
|
||||
|
||||
102
src/rpc/database.ts
Normal file
102
src/rpc/database.ts
Normal file
@ -0,0 +1,102 @@
|
||||
import mongoose from 'mongoose'
|
||||
import type { DevtoolsServerContext, ServerFunctions } from '../types'
|
||||
|
||||
// eslint-disable-next-line no-empty-pattern
|
||||
export function setupDatabaseRPC({}: DevtoolsServerContext) {
|
||||
return {
|
||||
async readyState() {
|
||||
return mongoose.connection.readyState
|
||||
},
|
||||
async createCollection(name: string) {
|
||||
try {
|
||||
return await mongoose.connection.db.createCollection(name)
|
||||
}
|
||||
catch (error) {
|
||||
return ErrorIT(error)
|
||||
}
|
||||
},
|
||||
async listCollections() {
|
||||
try {
|
||||
return await mongoose.connection.db.listCollections().toArray()
|
||||
}
|
||||
catch (error) {
|
||||
return ErrorIT(error)
|
||||
}
|
||||
},
|
||||
async getCollection(name: string) {
|
||||
try {
|
||||
return await mongoose.connection.db.collection(name).findOne()
|
||||
}
|
||||
catch (error) {
|
||||
return ErrorIT(error)
|
||||
}
|
||||
},
|
||||
async dropCollection(name: string) {
|
||||
try {
|
||||
return await mongoose.connection.db.dropCollection(name)
|
||||
}
|
||||
catch (error) {
|
||||
return ErrorIT(error)
|
||||
}
|
||||
},
|
||||
|
||||
async createDocument(collection: string, data: any) {
|
||||
const { _id, ...rest } = data
|
||||
try {
|
||||
return await mongoose.connection.db.collection(collection).insertOne(rest)
|
||||
}
|
||||
catch (error: any) {
|
||||
return ErrorIT(error)
|
||||
}
|
||||
},
|
||||
async countDocuments(collection: string) {
|
||||
try {
|
||||
return await mongoose.connection.db.collection(collection).countDocuments()
|
||||
}
|
||||
catch (error) {
|
||||
return ErrorIT(error)
|
||||
}
|
||||
},
|
||||
async listDocuments(collection: string, options: { page: number; limit: number } = { page: 1, limit: 10 }) {
|
||||
const skip = (options.page - 1) * options.limit
|
||||
const cursor = mongoose.connection.db.collection(collection).find().skip(skip)
|
||||
if (options.limit !== 0)
|
||||
cursor?.limit(options.limit)
|
||||
return await cursor?.toArray()
|
||||
},
|
||||
async getDocument(collection: string, document: any) {
|
||||
try {
|
||||
return await mongoose.connection.db.collection(collection).findOne({ document })
|
||||
}
|
||||
catch (error) {
|
||||
return ErrorIT(error)
|
||||
}
|
||||
},
|
||||
async updateDocument(collection: string, data: any) {
|
||||
const { _id, ...rest } = data
|
||||
try {
|
||||
return await mongoose.connection.db.collection(collection).findOneAndUpdate({ _id: new mongoose.Types.ObjectId(_id) }, { $set: rest })
|
||||
}
|
||||
catch (error) {
|
||||
return ErrorIT(error)
|
||||
}
|
||||
},
|
||||
async deleteDocument(collection: string, id: string) {
|
||||
try {
|
||||
return await mongoose.connection.db.collection(collection).deleteOne({ _id: new mongoose.Types.ObjectId(id) })
|
||||
}
|
||||
catch (error) {
|
||||
return ErrorIT(error)
|
||||
}
|
||||
},
|
||||
} satisfies Partial<ServerFunctions>
|
||||
}
|
||||
|
||||
function ErrorIT(error: any) {
|
||||
return {
|
||||
error: {
|
||||
message: error?.message,
|
||||
code: error?.code,
|
||||
},
|
||||
}
|
||||
}
|
||||
23
src/rpc/index.ts
Normal file
23
src/rpc/index.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import mongoose from 'mongoose'
|
||||
import type { DevtoolsServerContext, ServerFunctions } from '../types'
|
||||
|
||||
import { setupDatabaseRPC } from './database'
|
||||
import { setupResourceRPC } from './resource'
|
||||
|
||||
export function setupRPC(ctx: DevtoolsServerContext): ServerFunctions {
|
||||
mongoose.connect(ctx.options.uri, ctx.options.options)
|
||||
|
||||
return {
|
||||
getOptions() {
|
||||
return ctx.options
|
||||
},
|
||||
|
||||
...setupDatabaseRPC(ctx),
|
||||
...setupResourceRPC(ctx),
|
||||
|
||||
async reset() {
|
||||
const ws = await ctx.wsServer
|
||||
ws.send('nuxt-mongoose:reset')
|
||||
},
|
||||
}
|
||||
}
|
||||
66
src/rpc/resource.ts
Normal file
66
src/rpc/resource.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import fs from 'fs-extra'
|
||||
import { join } from 'pathe'
|
||||
import mongoose from 'mongoose'
|
||||
import type { Collection, DevtoolsServerContext, Resource, ServerFunctions } from '../types'
|
||||
import { capitalize, generateApiRoute, generateSchemaFile, pluralize, singularize } from '../utils'
|
||||
|
||||
export function setupResourceRPC({ nuxt }: DevtoolsServerContext): any {
|
||||
const config = nuxt.options.runtimeConfig.mongoose
|
||||
|
||||
return {
|
||||
async generateResource(collection: Collection, resources: Resource[]) {
|
||||
const singular = singularize(collection.name).toLowerCase()
|
||||
const plural = pluralize(collection.name).toLowerCase()
|
||||
const dbName = capitalize(singular)
|
||||
|
||||
if (collection.fields) {
|
||||
const schemaPath = join(config.modelsDir, `${singular}.schema.ts`)
|
||||
if (!fs.existsSync(schemaPath)) {
|
||||
fs.ensureDirSync(config.modelsDir)
|
||||
fs.writeFileSync(schemaPath, generateSchemaFile(dbName, collection.fields))
|
||||
}
|
||||
|
||||
const model = { name: dbName, path: `${singular}.schema` }
|
||||
|
||||
// create resources
|
||||
const routeTypes = {
|
||||
index: 'index.get.ts',
|
||||
create: 'create.post.ts',
|
||||
show: (by: string) => `[${by}].get.ts`,
|
||||
put: (by: string) => `[${by}].put.ts`,
|
||||
delete: (by: string) => `[${by}].delete.ts`,
|
||||
}
|
||||
resources.forEach((route: Resource) => {
|
||||
const fileName = typeof routeTypes[route.type] === 'function'
|
||||
? (routeTypes[route.type] as any)(route.by)
|
||||
: routeTypes[route.type]
|
||||
|
||||
const filePath = join(nuxt.options.serverDir, 'api', plural, fileName)
|
||||
if (!fs.existsSync(filePath)) {
|
||||
fs.ensureDirSync(join(nuxt.options.serverDir, `api/${plural}`))
|
||||
const content = generateApiRoute(route.type, { model, by: route.by })
|
||||
fs.writeFileSync(filePath, content)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// create collection if not exists
|
||||
const collections = await mongoose.connection.db.listCollections().toArray()
|
||||
if (!collections.find((c: any) => c.name === plural))
|
||||
return await mongoose.connection.db.createCollection(plural)
|
||||
},
|
||||
async resourceSchema(collection: string) {
|
||||
const singular = singularize(collection).toLowerCase()
|
||||
const schemaPath = join(config.modelsDir, `${singular}.schema.ts`)
|
||||
if (fs.existsSync(schemaPath)) {
|
||||
const content = fs.readFileSync(schemaPath, 'utf-8').match(/schema: \{(.|\n)*\}/g)
|
||||
if (content) {
|
||||
const schemaString = content[0].replace('schema: ', '').slice(0, -3)
|
||||
// eslint-disable-next-line no-eval
|
||||
const schema = eval(`(${schemaString})`)
|
||||
return schema
|
||||
}
|
||||
}
|
||||
},
|
||||
} satisfies Partial<ServerFunctions>
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
/**
|
||||
* Due to an upstream bug in Nuxt 3 we need to stub the plugin here, track:https://github.com/nuxt/nuxt/issues/18556
|
||||
* */
|
||||
*/
|
||||
import type { NitroApp } from 'nitropack'
|
||||
import { defineMongooseConnection } from '../services/mongoose'
|
||||
import { defineMongooseConnection } from '../services'
|
||||
|
||||
type NitroAppPlugin = (nitro: NitroApp) => void
|
||||
|
||||
|
||||
21
src/runtime/server/services/connection.ts
Normal file
21
src/runtime/server/services/connection.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import type { ConnectOptions } from 'mongoose'
|
||||
import { consola } from 'consola'
|
||||
import { colors } from 'consola/utils'
|
||||
import mongoose from 'mongoose'
|
||||
|
||||
// @ts-ignore
|
||||
import { useRuntimeConfig } from '#imports'
|
||||
|
||||
export async function defineMongooseConnection({ uri, options }: { uri?: string; options?: ConnectOptions } = {}): Promise<void> {
|
||||
const config = useRuntimeConfig().mongoose
|
||||
const mongooseUri = uri || config.uri
|
||||
const mongooseOptions = options || config.options
|
||||
|
||||
try {
|
||||
await mongoose.connect(mongooseUri, { ...mongooseOptions })
|
||||
consola.success('Connected to MongoDB')
|
||||
}
|
||||
catch (err) {
|
||||
consola.error(colors.red(`Error connecting to MongoDB: ${err}`))
|
||||
}
|
||||
}
|
||||
@ -1 +1,2 @@
|
||||
export { defineMongooseConnection, defineMongooseModel } from './mongoose'
|
||||
export { defineMongooseConnection } from './connection'
|
||||
export { defineMongooseModel } from './model'
|
||||
|
||||
32
src/runtime/server/services/model.ts
Normal file
32
src/runtime/server/services/model.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import type { Model, SchemaDefinition, SchemaOptions } from 'mongoose'
|
||||
import mongoose from 'mongoose'
|
||||
|
||||
export function defineMongooseModel<T>(
|
||||
nameOrOptions: string | {
|
||||
name: string
|
||||
schema: SchemaDefinition<T>
|
||||
options?: SchemaOptions
|
||||
hooks?: (schema: mongoose.Schema<T>) => void
|
||||
},
|
||||
schema?: SchemaDefinition<T>,
|
||||
options?: SchemaOptions,
|
||||
hooks?: (schema: mongoose.Schema<T>) => void,
|
||||
): Model<T> {
|
||||
let name: string
|
||||
if (typeof nameOrOptions === 'string') {
|
||||
name = nameOrOptions
|
||||
}
|
||||
else {
|
||||
name = nameOrOptions.name
|
||||
schema = nameOrOptions.schema
|
||||
options = nameOrOptions.options
|
||||
hooks = nameOrOptions.hooks
|
||||
}
|
||||
|
||||
const newSchema = new mongoose.Schema<T>(schema, options as any)
|
||||
|
||||
if (hooks)
|
||||
hooks(newSchema)
|
||||
|
||||
return mongoose.model<T>(name, newSchema)
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
import type { ConnectOptions, Model, SchemaDefinition, SchemaOptions } from 'mongoose'
|
||||
import { Schema, connect, model } from 'mongoose'
|
||||
import { logger } from '@nuxt/kit'
|
||||
|
||||
import { useRuntimeConfig } from '#imports'
|
||||
|
||||
export async function defineMongooseConnection({ uri, options }: { uri?: string; options?: ConnectOptions } = {}): Promise<void> {
|
||||
const config = useRuntimeConfig().public.mongoose
|
||||
const mongooseUri = uri || config.uri
|
||||
const mongooseOptions = options || config.options
|
||||
|
||||
try {
|
||||
await connect(mongooseUri, { ...mongooseOptions })
|
||||
logger.info('Connected to database')
|
||||
}
|
||||
catch (err) {
|
||||
logger.error('Error connecting to database', err)
|
||||
}
|
||||
}
|
||||
|
||||
export function defineMongooseModel(nameOrOptions: string | { name: string; schema: SchemaDefinition; options?: SchemaOptions }, schema?: SchemaDefinition, options?: SchemaOptions): Model<any> {
|
||||
let name: string
|
||||
if (typeof nameOrOptions === 'string') {
|
||||
name = nameOrOptions
|
||||
}
|
||||
else {
|
||||
name = nameOrOptions.name
|
||||
schema = nameOrOptions.schema
|
||||
options = nameOrOptions.options
|
||||
}
|
||||
|
||||
const newSchema = new Schema({
|
||||
...schema,
|
||||
}, { ...options })
|
||||
return model(name, newSchema)
|
||||
}
|
||||
47
src/types/index.ts
Normal file
47
src/types/index.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import type { Nuxt } from 'nuxt/schema'
|
||||
import type { WebSocketServer } from 'vite'
|
||||
import type { ModuleOptions } from '../module'
|
||||
|
||||
export interface ServerFunctions {
|
||||
getOptions(): ModuleOptions
|
||||
|
||||
// Database - collections
|
||||
readyState(): Promise<any>
|
||||
createCollection(name: string): Promise<any>
|
||||
listCollections(): Promise<any>
|
||||
getCollection(name: string): Promise<any>
|
||||
dropCollection(name: string): Promise<any>
|
||||
|
||||
// Database - documents
|
||||
createDocument(collection: string, data: any): Promise<any>
|
||||
countDocuments(collection: string): Promise<any>
|
||||
listDocuments(collection: string, options: any): Promise<any>
|
||||
getDocument(collection: string, id: string): Promise<any>
|
||||
updateDocument(collection: string, data: any): Promise<any>
|
||||
deleteDocument(collection: string, id: string): Promise<any>
|
||||
|
||||
// Resource - api-routes & models
|
||||
generateResource(collection: Collection, resources: Resource[]): Promise<any>
|
||||
resourceSchema(collection: string): Promise<any>
|
||||
|
||||
reset(): void
|
||||
}
|
||||
|
||||
export interface ClientFunctions {
|
||||
}
|
||||
|
||||
export interface DevtoolsServerContext {
|
||||
nuxt: Nuxt
|
||||
options: ModuleOptions
|
||||
wsServer: Promise<WebSocketServer>
|
||||
}
|
||||
|
||||
export interface Collection {
|
||||
name: string
|
||||
fields?: object[]
|
||||
}
|
||||
|
||||
export interface Resource {
|
||||
type: 'index' | 'create' | 'show' | 'put' | 'delete'
|
||||
by?: string
|
||||
}
|
||||
79
src/utils/index.ts
Normal file
79
src/utils/index.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import type { WebSocketServer } from 'vite'
|
||||
import type { Nuxt } from 'nuxt/schema'
|
||||
import plrz from 'pluralize'
|
||||
|
||||
export function useViteWebSocket(nuxt: Nuxt) {
|
||||
return new Promise<WebSocketServer>((_resolve) => {
|
||||
nuxt.hooks.hook('vite:serverCreated', (viteServer) => {
|
||||
_resolve(viteServer.ws)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export function normalizeToKebabOrSnakeCase(str: string) {
|
||||
const STRING_DASHERIZE_REGEXP = /\s/g
|
||||
const STRING_DECAMELIZE_REGEXP = /([a-z\d])([A-Z])/g
|
||||
return str
|
||||
.replace(STRING_DECAMELIZE_REGEXP, '$1-$2')
|
||||
.toLowerCase()
|
||||
.replace(STRING_DASHERIZE_REGEXP, '-')
|
||||
}
|
||||
|
||||
export function pluralize(str: string) {
|
||||
return plrz.plural(str)
|
||||
}
|
||||
|
||||
export function singularize(str: string) {
|
||||
return plrz.singular(str)
|
||||
}
|
||||
|
||||
export function capitalize(str: string) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1)
|
||||
}
|
||||
|
||||
export function generateSchemaFile(name: string, fields: any) {
|
||||
name = capitalize(name)
|
||||
// TODO: fix spacing
|
||||
const outputObject = JSON.stringify(
|
||||
fields.reduce((acc: any, curr: any) => {
|
||||
const { name, ...rest } = curr
|
||||
acc[name] = rest
|
||||
return acc
|
||||
}, {}),
|
||||
null, 2)
|
||||
.replace(/"([^"]+)":/g, '$1:')
|
||||
.replace(/"(\w+)":/g, '$1:')
|
||||
.replace(/\s*"\w+":/g, match => match.trim())
|
||||
.replace(/"string"/g, '\'string\'')
|
||||
|
||||
return `import { defineMongooseModel } from '#nuxt/mongoose'
|
||||
|
||||
export const ${name}Schema = defineMongooseModel({
|
||||
name: '${name}',
|
||||
schema: ${outputObject},
|
||||
})
|
||||
`
|
||||
}
|
||||
|
||||
export function generateApiRoute(action: string, { model, by }: { model: { name: string; path: string }; by?: string }) {
|
||||
const modelName = capitalize(model.name)
|
||||
const operation = {
|
||||
index: `return await ${modelName}Schema.find({})`,
|
||||
create: `return await new ${modelName}Schema(body).save()`,
|
||||
show: `return await ${modelName}Schema.findOne({ ${by}: event.context.params?.${by} })`,
|
||||
put: `return await ${modelName}Schema.findOneAndUpdate({ ${by}: event.context.params?.${by} }, body, { new: true })`,
|
||||
delete: `return await ${modelName}Schema.findOneAndDelete({ ${by}: event.context.params?.${by} })`,
|
||||
}[action]
|
||||
|
||||
const main = `try {
|
||||
${operation}
|
||||
}
|
||||
catch (error) {
|
||||
return error
|
||||
}`
|
||||
|
||||
return `export default defineEventHandler(async (event) => {
|
||||
${(action === 'create' || action === 'put') ? `const body = await readBody(event)\n ${main}` : main}
|
||||
})
|
||||
`
|
||||
}
|
||||
Reference in New Issue
Block a user