@akanjs/cli 0.0.142 → 0.0.144
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/cjs/index.js +2437 -3204
- package/cjs/src/guidelines/___library/sharedUiStructureDescription.en.md +786 -0
- package/cjs/src/guidelines/___library/utilUiStructureDescription.en.md +395 -0
- package/cjs/src/guidelines/___lint/lintRuleDescription.en.md +64 -0
- package/cjs/src/guidelines/___module/moduleStructureDescription.en.md +80 -0
- package/cjs/src/guidelines/componentRule/componentRule.instruction.md +732 -0
- package/cjs/src/guidelines/databaseModule/databaseModule.instruction.md +691 -0
- package/cjs/src/guidelines/enumConstant/enumConstant.instruction.md +232 -0
- package/cjs/src/guidelines/fieldDecorator/fieldDecorator.instruction.md +611 -0
- package/cjs/src/guidelines/framework/framework.instruction.md +1112 -0
- package/cjs/src/guidelines/modelConstant/modelConstant.instruction.md +958 -0
- package/cjs/src/guidelines/modelDictionary/modelDictionary.instruction.md +583 -0
- package/cjs/src/guidelines/modelDocument/modelDocument.instruction.md +683 -0
- package/cjs/src/guidelines/modelService/modelService.instruction.md +935 -0
- package/cjs/src/guidelines/modelSignal/modelSignal.instruction.md +588 -0
- package/cjs/src/guidelines/modelStore/modelStore.instruction.md +591 -0
- package/cjs/src/guidelines/modelTemplate/modelTemplate.instruction.md +577 -0
- package/cjs/src/guidelines/modelUnit/modelUnit.instruction.md +833 -0
- package/cjs/src/guidelines/modelUtil/modelUtil.instruction.md +752 -0
- package/cjs/src/guidelines/modelView/modelView.instruction.md +1005 -0
- package/cjs/src/guidelines/modelZone/modelZone.instruction.md +528 -0
- package/cjs/src/guidelines/scalarConstant/scalarConstant.instruction.md +489 -0
- package/cjs/src/guidelines/scalarDictionary/scalarDictionary.instruction.md +347 -0
- package/cjs/src/guidelines/sharedUiUsage/sharedUiUsage.instruction.md +318 -0
- package/cjs/src/guidelines/utilUiUsage/utilUiUsage.instruction.md +339 -0
- package/cjs/src/templates/module/__model__.dictionary.js +4 -5
- package/esm/index.js +2524 -3286
- package/esm/src/guidelines/___library/sharedUiStructureDescription.en.md +786 -0
- package/esm/src/guidelines/___library/utilUiStructureDescription.en.md +395 -0
- package/esm/src/guidelines/___lint/lintRuleDescription.en.md +64 -0
- package/esm/src/guidelines/___module/moduleStructureDescription.en.md +80 -0
- package/esm/src/guidelines/componentRule/componentRule.instruction.md +732 -0
- package/esm/src/guidelines/databaseModule/databaseModule.instruction.md +691 -0
- package/esm/src/guidelines/enumConstant/enumConstant.instruction.md +232 -0
- package/esm/src/guidelines/fieldDecorator/fieldDecorator.instruction.md +611 -0
- package/esm/src/guidelines/framework/framework.instruction.md +1112 -0
- package/esm/src/guidelines/modelConstant/modelConstant.instruction.md +958 -0
- package/esm/src/guidelines/modelDictionary/modelDictionary.instruction.md +583 -0
- package/esm/src/guidelines/modelDocument/modelDocument.instruction.md +683 -0
- package/esm/src/guidelines/modelService/modelService.instruction.md +935 -0
- package/esm/src/guidelines/modelSignal/modelSignal.instruction.md +588 -0
- package/esm/src/guidelines/modelStore/modelStore.instruction.md +591 -0
- package/esm/src/guidelines/modelTemplate/modelTemplate.instruction.md +577 -0
- package/esm/src/guidelines/modelUnit/modelUnit.instruction.md +833 -0
- package/esm/src/guidelines/modelUtil/modelUtil.instruction.md +752 -0
- package/esm/src/guidelines/modelView/modelView.instruction.md +1005 -0
- package/esm/src/guidelines/modelZone/modelZone.instruction.md +528 -0
- package/esm/src/guidelines/scalarConstant/scalarConstant.instruction.md +489 -0
- package/esm/src/guidelines/scalarDictionary/scalarDictionary.instruction.md +347 -0
- package/esm/src/guidelines/sharedUiUsage/sharedUiUsage.instruction.md +318 -0
- package/esm/src/guidelines/utilUiUsage/utilUiUsage.instruction.md +339 -0
- package/esm/src/templates/module/__model__.dictionary.js +4 -5
- package/package.json +3 -1
- package/src/guideline/guideline.command.d.ts +7 -0
- package/src/guideline/guideline.prompt.d.ts +15 -0
- package/src/guideline/guideline.runner.d.ts +5 -0
- package/src/guideline/guideline.script.d.ts +6 -0
- package/src/guidelines/___library/sharedUiStructureDescription.en.md +786 -0
- package/src/guidelines/___library/utilUiStructureDescription.en.md +395 -0
- package/src/guidelines/___lint/lintRuleDescription.en.md +64 -0
- package/src/guidelines/___module/moduleStructureDescription.en.md +80 -0
- package/src/guidelines/componentRule/componentRule.instruction.md +732 -0
- package/src/guidelines/databaseModule/databaseModule.instruction.md +691 -0
- package/src/guidelines/enumConstant/enumConstant.instruction.md +232 -0
- package/src/guidelines/fieldDecorator/fieldDecorator.instruction.md +611 -0
- package/src/guidelines/framework/framework.instruction.md +1112 -0
- package/src/guidelines/modelConstant/modelConstant.instruction.md +958 -0
- package/src/guidelines/modelDictionary/modelDictionary.instruction.md +583 -0
- package/src/guidelines/modelDocument/modelDocument.instruction.md +683 -0
- package/src/guidelines/modelService/modelService.instruction.md +935 -0
- package/src/guidelines/modelSignal/modelSignal.instruction.md +588 -0
- package/src/guidelines/modelStore/modelStore.instruction.md +591 -0
- package/src/guidelines/modelTemplate/modelTemplate.instruction.md +577 -0
- package/src/guidelines/modelUnit/modelUnit.instruction.md +833 -0
- package/src/guidelines/modelUtil/modelUtil.instruction.md +752 -0
- package/src/guidelines/modelView/modelView.instruction.md +1005 -0
- package/src/guidelines/modelZone/modelZone.instruction.md +528 -0
- package/src/guidelines/scalarConstant/scalarConstant.instruction.md +489 -0
- package/src/guidelines/scalarDictionary/scalarDictionary.instruction.md +347 -0
- package/src/guidelines/sharedUiUsage/sharedUiUsage.instruction.md +318 -0
- package/src/guidelines/utilUiUsage/utilUiUsage.instruction.md +339 -0
- package/src/module/module.command.d.ts +6 -8
- package/src/module/module.prompt.d.ts +2 -15
- package/src/module/module.request.d.ts +22 -18
- package/src/module/module.runner.d.ts +4 -20
- package/src/module/module.script.d.ts +6 -7
- package/src/scalar/scalar.command.d.ts +7 -0
- package/src/scalar/scalar.prompt.d.ts +23 -0
- package/src/scalar/scalar.runner.d.ts +13 -0
- package/src/scalar/scalar.script.d.ts +6 -0
- package/cjs/src/templates/app/app/[lang]/(__appName__)/(public)/forgotpassword/page.js +0 -47
- package/cjs/src/templates/app/app/[lang]/(__appName__)/(public)/page.js +0 -128
- package/cjs/src/templates/app/app/[lang]/(__appName__)/(public)/privacy/page.js +0 -42
- package/cjs/src/templates/app/app/[lang]/(__appName__)/(public)/signin/page.js +0 -50
- package/cjs/src/templates/app/app/[lang]/(__appName__)/(public)/termsofservice/page.js +0 -41
- package/cjs/src/templates/app/app/[lang]/(__appName__)/(public)/unknown/page.js +0 -51
- package/cjs/src/templates/app/app/[lang]/(__appName__)/(user)/layout.js +0 -43
- package/cjs/src/templates/app/app/[lang]/(__appName__)/(user)/self/page.js +0 -60
- package/cjs/src/templates/app/app/[lang]/(__appName__)/layout.js +0 -54
- package/cjs/src/templates/app/app/[lang]/(__appName__)/styles.css.template +0 -19
- package/cjs/src/templates/app/app/[lang]/admin/layout.js +0 -54
- package/cjs/src/templates/app/app/[lang]/admin/page.js +0 -63
- package/cjs/src/templates/app/app/csr.js +0 -34
- package/cjs/src/templates/app/app/index.html.template +0 -13
- package/cjs/src/templates/app/app/layout.js +0 -38
- package/cjs/src/templates/app/capacitor.config.ts.template +0 -8
- package/cjs/src/templates/app/env/env.client.debug.ts.template +0 -7
- package/cjs/src/templates/app/env/env.client.develop.ts.template +0 -7
- package/cjs/src/templates/app/env/env.client.local.ts.template +0 -7
- package/cjs/src/templates/app/env/env.client.main.ts.template +0 -7
- package/cjs/src/templates/app/env/env.client.testing.ts.template +0 -7
- package/cjs/src/templates/app/env/env.server.debug.ts.template +0 -15
- package/cjs/src/templates/app/env/env.server.develop.ts.template +0 -15
- package/cjs/src/templates/app/env/env.server.local.ts.template +0 -15
- package/cjs/src/templates/app/env/env.server.main.ts.template +0 -15
- package/cjs/src/templates/app/env/env.server.testing.ts.template +0 -7
- package/cjs/src/templates/app/lib/setting/Setting.Template.js +0 -57
- package/cjs/src/templates/app/lib/setting/Setting.Unit.js +0 -38
- package/cjs/src/templates/app/lib/setting/Setting.Util.js +0 -34
- package/cjs/src/templates/app/lib/setting/Setting.View.js +0 -51
- package/cjs/src/templates/app/lib/setting/Setting.Zone.js +0 -80
- package/cjs/src/templates/app/lib/setting/index.js +0 -61
- package/cjs/src/templates/app/lib/summary/Summary.Template.js +0 -43
- package/cjs/src/templates/app/lib/summary/Summary.Unit.js +0 -38
- package/cjs/src/templates/app/lib/summary/Summary.Util.js +0 -33
- package/cjs/src/templates/app/lib/summary/Summary.View.js +0 -51
- package/cjs/src/templates/app/lib/summary/Summary.Zone.js +0 -62
- package/cjs/src/templates/app/lib/summary/index.js +0 -67
- package/cjs/src/templates/app/lib/user/User.Template.js +0 -65
- package/cjs/src/templates/app/lib/user/User.Unit.js +0 -38
- package/cjs/src/templates/app/lib/user/User.Util.js +0 -94
- package/cjs/src/templates/app/lib/user/User.View.js +0 -66
- package/cjs/src/templates/app/lib/user/User.Zone.js +0 -74
- package/cjs/src/templates/app/lib/user/index.js +0 -61
- package/cjs/src/templates/app/page.test.ts.template +0 -10
- package/cjs/src/templates/app/playwright.config.ts.template +0 -6
- package/cjs/src/templates/app/postcss.config.js.template +0 -10
- package/cjs/src/templates/app/public/manifest.json.template +0 -67
- package/cjs/src/templates/app/tsconfig.json.template +0 -22
- package/cjs/src/templates/app/tsconfig.spec.json.template +0 -7
- package/cjs/src/templates/app/ui/Footer.js +0 -67
- package/cjs/src/templates/app/ui/MainHeader.js +0 -131
- package/cjs/src/templates/crudPages/[__model__Id]/edit/page.js +0 -73
- package/cjs/src/templates/crudPages/[__model__Id]/page.js +0 -83
- package/cjs/src/templates/crudPages/new/page.js +0 -70
- package/cjs/src/templates/crudPages/page.js +0 -71
- package/cjs/src/templates/libRoot/.gitignore.template +0 -15
- package/cjs/src/templates/libRoot/env/env.server.example.ts.template +0 -7
- package/cjs/src/templates/libRoot/env/env.server.testing.ts.template +0 -7
- package/cjs/src/templates/libRoot/lib/setting/Setting.Template.js +0 -57
- package/cjs/src/templates/libRoot/lib/setting/Setting.Unit.js +0 -38
- package/cjs/src/templates/libRoot/lib/setting/Setting.Util.js +0 -34
- package/cjs/src/templates/libRoot/lib/setting/Setting.View.js +0 -51
- package/cjs/src/templates/libRoot/lib/setting/Setting.Zone.js +0 -80
- package/cjs/src/templates/libRoot/lib/setting/index.js +0 -61
- package/cjs/src/templates/libRoot/lib/summary/Summary.Template.js +0 -43
- package/cjs/src/templates/libRoot/lib/summary/Summary.Unit.js +0 -38
- package/cjs/src/templates/libRoot/lib/summary/Summary.Util.js +0 -33
- package/cjs/src/templates/libRoot/lib/summary/Summary.View.js +0 -51
- package/cjs/src/templates/libRoot/lib/summary/Summary.Zone.js +0 -62
- package/cjs/src/templates/libRoot/lib/summary/index.js +0 -67
- package/cjs/src/templates/libRoot/lib/user/User.Template.js +0 -65
- package/cjs/src/templates/libRoot/lib/user/User.Unit.js +0 -38
- package/cjs/src/templates/libRoot/lib/user/User.Util.js +0 -94
- package/cjs/src/templates/libRoot/lib/user/User.View.js +0 -66
- package/cjs/src/templates/libRoot/lib/user/User.Zone.js +0 -74
- package/cjs/src/templates/libRoot/lib/user/index.js +0 -61
- package/cjs/src/templates/libRoot/package.json.template +0 -4
- package/cjs/src/templates/libRoot/tsconfig.json.template +0 -13
- package/cjs/src/templates/libRoot/tsconfig.spec.json.template +0 -7
- package/cjs/src/templates/localDev/docker-compose.yaml.template +0 -36
- package/cjs/src/templates/module/__Model__.Template.js +0 -54
- package/cjs/src/templates/module/__Model__.Unit.js +0 -42
- package/cjs/src/templates/module/__Model__.Util.js +0 -70
- package/cjs/src/templates/module/__Model__.View.js +0 -48
- package/cjs/src/templates/module/__Model__.Zone.js +0 -83
- package/cjs/src/templates/module/index.js +0 -61
- package/cjs/src/templates/pkgRoot/tsconfig.json.template +0 -15
- package/cjs/src/templates/workspaceRoot/.env.template +0 -20
- package/cjs/src/templates/workspaceRoot/.gitignore.template +0 -118
- package/cjs/src/templates/workspaceRoot/.prettierignore.template +0 -10
- package/cjs/src/templates/workspaceRoot/.prettierrc.json.template +0 -6
- package/cjs/src/templates/workspaceRoot/.swcrc.template +0 -9
- package/cjs/src/templates/workspaceRoot/.vscode/settings.json.template +0 -13
- package/cjs/src/templates/workspaceRoot/README.md.template +0 -37
- package/cjs/src/templates/workspaceRoot/eslint.config.ts.template +0 -3
- package/cjs/src/templates/workspaceRoot/package.json.template +0 -43
- package/cjs/src/templates/workspaceRoot/tsconfig.json.template +0 -29
- package/esm/src/templates/app/app/[lang]/(__appName__)/(public)/forgotpassword/page.js +0 -27
- package/esm/src/templates/app/app/[lang]/(__appName__)/(public)/page.js +0 -108
- package/esm/src/templates/app/app/[lang]/(__appName__)/(public)/privacy/page.js +0 -22
- package/esm/src/templates/app/app/[lang]/(__appName__)/(public)/signin/page.js +0 -30
- package/esm/src/templates/app/app/[lang]/(__appName__)/(public)/termsofservice/page.js +0 -21
- package/esm/src/templates/app/app/[lang]/(__appName__)/(public)/unknown/page.js +0 -31
- package/esm/src/templates/app/app/[lang]/(__appName__)/(user)/layout.js +0 -23
- package/esm/src/templates/app/app/[lang]/(__appName__)/(user)/self/page.js +0 -40
- package/esm/src/templates/app/app/[lang]/(__appName__)/layout.js +0 -34
- package/esm/src/templates/app/app/[lang]/(__appName__)/styles.css.template +0 -19
- package/esm/src/templates/app/app/[lang]/admin/layout.js +0 -34
- package/esm/src/templates/app/app/[lang]/admin/page.js +0 -43
- package/esm/src/templates/app/app/csr.js +0 -14
- package/esm/src/templates/app/app/index.html.template +0 -13
- package/esm/src/templates/app/app/layout.js +0 -18
- package/esm/src/templates/app/capacitor.config.ts.template +0 -8
- package/esm/src/templates/app/env/env.client.debug.ts.template +0 -7
- package/esm/src/templates/app/env/env.client.develop.ts.template +0 -7
- package/esm/src/templates/app/env/env.client.local.ts.template +0 -7
- package/esm/src/templates/app/env/env.client.main.ts.template +0 -7
- package/esm/src/templates/app/env/env.client.testing.ts.template +0 -7
- package/esm/src/templates/app/env/env.server.debug.ts.template +0 -15
- package/esm/src/templates/app/env/env.server.develop.ts.template +0 -15
- package/esm/src/templates/app/env/env.server.local.ts.template +0 -15
- package/esm/src/templates/app/env/env.server.main.ts.template +0 -15
- package/esm/src/templates/app/env/env.server.testing.ts.template +0 -7
- package/esm/src/templates/app/lib/setting/Setting.Template.js +0 -37
- package/esm/src/templates/app/lib/setting/Setting.Unit.js +0 -18
- package/esm/src/templates/app/lib/setting/Setting.Util.js +0 -14
- package/esm/src/templates/app/lib/setting/Setting.View.js +0 -31
- package/esm/src/templates/app/lib/setting/Setting.Zone.js +0 -60
- package/esm/src/templates/app/lib/setting/index.js +0 -41
- package/esm/src/templates/app/lib/summary/Summary.Template.js +0 -23
- package/esm/src/templates/app/lib/summary/Summary.Unit.js +0 -18
- package/esm/src/templates/app/lib/summary/Summary.Util.js +0 -13
- package/esm/src/templates/app/lib/summary/Summary.View.js +0 -31
- package/esm/src/templates/app/lib/summary/Summary.Zone.js +0 -42
- package/esm/src/templates/app/lib/summary/index.js +0 -47
- package/esm/src/templates/app/lib/user/User.Template.js +0 -45
- package/esm/src/templates/app/lib/user/User.Unit.js +0 -18
- package/esm/src/templates/app/lib/user/User.Util.js +0 -74
- package/esm/src/templates/app/lib/user/User.View.js +0 -46
- package/esm/src/templates/app/lib/user/User.Zone.js +0 -54
- package/esm/src/templates/app/lib/user/index.js +0 -41
- package/esm/src/templates/app/page.test.ts.template +0 -10
- package/esm/src/templates/app/playwright.config.ts.template +0 -6
- package/esm/src/templates/app/postcss.config.js.template +0 -10
- package/esm/src/templates/app/public/manifest.json.template +0 -67
- package/esm/src/templates/app/tsconfig.json.template +0 -22
- package/esm/src/templates/app/tsconfig.spec.json.template +0 -7
- package/esm/src/templates/app/ui/Footer.js +0 -47
- package/esm/src/templates/app/ui/MainHeader.js +0 -111
- package/esm/src/templates/crudPages/[__model__Id]/edit/page.js +0 -53
- package/esm/src/templates/crudPages/[__model__Id]/page.js +0 -63
- package/esm/src/templates/crudPages/new/page.js +0 -50
- package/esm/src/templates/crudPages/page.js +0 -51
- package/esm/src/templates/libRoot/.gitignore.template +0 -15
- package/esm/src/templates/libRoot/env/env.server.example.ts.template +0 -7
- package/esm/src/templates/libRoot/env/env.server.testing.ts.template +0 -7
- package/esm/src/templates/libRoot/lib/setting/Setting.Template.js +0 -37
- package/esm/src/templates/libRoot/lib/setting/Setting.Unit.js +0 -18
- package/esm/src/templates/libRoot/lib/setting/Setting.Util.js +0 -14
- package/esm/src/templates/libRoot/lib/setting/Setting.View.js +0 -31
- package/esm/src/templates/libRoot/lib/setting/Setting.Zone.js +0 -60
- package/esm/src/templates/libRoot/lib/setting/index.js +0 -41
- package/esm/src/templates/libRoot/lib/summary/Summary.Template.js +0 -23
- package/esm/src/templates/libRoot/lib/summary/Summary.Unit.js +0 -18
- package/esm/src/templates/libRoot/lib/summary/Summary.Util.js +0 -13
- package/esm/src/templates/libRoot/lib/summary/Summary.View.js +0 -31
- package/esm/src/templates/libRoot/lib/summary/Summary.Zone.js +0 -42
- package/esm/src/templates/libRoot/lib/summary/index.js +0 -47
- package/esm/src/templates/libRoot/lib/user/User.Template.js +0 -45
- package/esm/src/templates/libRoot/lib/user/User.Unit.js +0 -18
- package/esm/src/templates/libRoot/lib/user/User.Util.js +0 -74
- package/esm/src/templates/libRoot/lib/user/User.View.js +0 -46
- package/esm/src/templates/libRoot/lib/user/User.Zone.js +0 -54
- package/esm/src/templates/libRoot/lib/user/index.js +0 -41
- package/esm/src/templates/libRoot/package.json.template +0 -4
- package/esm/src/templates/libRoot/tsconfig.json.template +0 -13
- package/esm/src/templates/libRoot/tsconfig.spec.json.template +0 -7
- package/esm/src/templates/localDev/docker-compose.yaml.template +0 -36
- package/esm/src/templates/module/__Model__.Template.js +0 -34
- package/esm/src/templates/module/__Model__.Unit.js +0 -22
- package/esm/src/templates/module/__Model__.Util.js +0 -50
- package/esm/src/templates/module/__Model__.View.js +0 -28
- package/esm/src/templates/module/__Model__.Zone.js +0 -63
- package/esm/src/templates/module/index.js +0 -41
- package/esm/src/templates/pkgRoot/tsconfig.json.template +0 -15
- package/esm/src/templates/workspaceRoot/.env.template +0 -20
- package/esm/src/templates/workspaceRoot/.gitignore.template +0 -118
- package/esm/src/templates/workspaceRoot/.prettierignore.template +0 -10
- package/esm/src/templates/workspaceRoot/.prettierrc.json.template +0 -6
- package/esm/src/templates/workspaceRoot/.swcrc.template +0 -9
- package/esm/src/templates/workspaceRoot/.vscode/settings.json.template +0 -13
- package/esm/src/templates/workspaceRoot/README.md.template +0 -37
- package/esm/src/templates/workspaceRoot/eslint.config.ts.template +0 -3
- package/esm/src/templates/workspaceRoot/package.json.template +0 -43
- package/esm/src/templates/workspaceRoot/tsconfig.json.template +0 -29
- package/src/application/application.prompt.d.ts +0 -2
- package/src/templates/app/app/[lang]/(__appName__)/(public)/forgotpassword/page.d.ts +0 -9
- package/src/templates/app/app/[lang]/(__appName__)/(public)/page.d.ts +0 -9
- package/src/templates/app/app/[lang]/(__appName__)/(public)/privacy/page.d.ts +0 -9
- package/src/templates/app/app/[lang]/(__appName__)/(public)/signin/page.d.ts +0 -9
- package/src/templates/app/app/[lang]/(__appName__)/(public)/termsofservice/page.d.ts +0 -10
- package/src/templates/app/app/[lang]/(__appName__)/(public)/unknown/page.d.ts +0 -9
- package/src/templates/app/app/[lang]/(__appName__)/(user)/layout.d.ts +0 -9
- package/src/templates/app/app/[lang]/(__appName__)/(user)/self/page.d.ts +0 -9
- package/src/templates/app/app/[lang]/(__appName__)/layout.d.ts +0 -9
- package/src/templates/app/app/[lang]/admin/layout.d.ts +0 -9
- package/src/templates/app/app/[lang]/admin/page.d.ts +0 -9
- package/src/templates/app/app/csr.d.ts +0 -9
- package/src/templates/app/app/layout.d.ts +0 -9
- package/src/templates/app/lib/setting/Setting.Template.d.ts +0 -9
- package/src/templates/app/lib/setting/Setting.Unit.d.ts +0 -9
- package/src/templates/app/lib/setting/Setting.Util.d.ts +0 -9
- package/src/templates/app/lib/setting/Setting.View.d.ts +0 -9
- package/src/templates/app/lib/setting/Setting.Zone.d.ts +0 -9
- package/src/templates/app/lib/setting/index.d.ts +0 -9
- package/src/templates/app/lib/summary/Summary.Template.d.ts +0 -9
- package/src/templates/app/lib/summary/Summary.Unit.d.ts +0 -9
- package/src/templates/app/lib/summary/Summary.Util.d.ts +0 -9
- package/src/templates/app/lib/summary/Summary.View.d.ts +0 -9
- package/src/templates/app/lib/summary/Summary.Zone.d.ts +0 -9
- package/src/templates/app/lib/summary/index.d.ts +0 -9
- package/src/templates/app/lib/user/User.Template.d.ts +0 -9
- package/src/templates/app/lib/user/User.Unit.d.ts +0 -9
- package/src/templates/app/lib/user/User.Util.d.ts +0 -9
- package/src/templates/app/lib/user/User.View.d.ts +0 -9
- package/src/templates/app/lib/user/User.Zone.d.ts +0 -9
- package/src/templates/app/lib/user/index.d.ts +0 -9
- package/src/templates/app/ui/Footer.d.ts +0 -9
- package/src/templates/app/ui/MainHeader.d.ts +0 -10
- package/src/templates/crudPages/[__model__Id]/edit/page.d.ts +0 -11
- package/src/templates/crudPages/[__model__Id]/page.d.ts +0 -11
- package/src/templates/crudPages/new/page.d.ts +0 -11
- package/src/templates/crudPages/page.d.ts +0 -11
- package/src/templates/libRoot/lib/setting/Setting.Template.d.ts +0 -9
- package/src/templates/libRoot/lib/setting/Setting.Unit.d.ts +0 -9
- package/src/templates/libRoot/lib/setting/Setting.Util.d.ts +0 -9
- package/src/templates/libRoot/lib/setting/Setting.View.d.ts +0 -9
- package/src/templates/libRoot/lib/setting/Setting.Zone.d.ts +0 -9
- package/src/templates/libRoot/lib/setting/index.d.ts +0 -9
- package/src/templates/libRoot/lib/summary/Summary.Template.d.ts +0 -9
- package/src/templates/libRoot/lib/summary/Summary.Unit.d.ts +0 -9
- package/src/templates/libRoot/lib/summary/Summary.Util.d.ts +0 -9
- package/src/templates/libRoot/lib/summary/Summary.View.d.ts +0 -9
- package/src/templates/libRoot/lib/summary/Summary.Zone.d.ts +0 -9
- package/src/templates/libRoot/lib/summary/index.d.ts +0 -9
- package/src/templates/libRoot/lib/user/User.Template.d.ts +0 -9
- package/src/templates/libRoot/lib/user/User.Unit.d.ts +0 -9
- package/src/templates/libRoot/lib/user/User.Util.d.ts +0 -9
- package/src/templates/libRoot/lib/user/User.View.d.ts +0 -9
- package/src/templates/libRoot/lib/user/User.Zone.d.ts +0 -9
- package/src/templates/libRoot/lib/user/index.d.ts +0 -9
- package/src/templates/module/__Model__.Template.d.ts +0 -11
- package/src/templates/module/__Model__.Unit.d.ts +0 -11
- package/src/templates/module/__Model__.Util.d.ts +0 -11
- package/src/templates/module/__Model__.View.d.ts +0 -11
- package/src/templates/module/__Model__.Zone.d.ts +0 -11
- package/src/templates/module/index.d.ts +0 -11
|
@@ -0,0 +1,683 @@
|
|
|
1
|
+
# Akan.js Model Document Implementation Guide
|
|
2
|
+
|
|
3
|
+
## Purpose and Role of model.document.ts Files
|
|
4
|
+
|
|
5
|
+
`model.document.ts` files are essential components in the Akan.js framework that define MongoDB data models and their associated behaviors. These files serve as the bridge between your application's data structure and MongoDB, providing:
|
|
6
|
+
|
|
7
|
+
1. **Schema Definition** - Define the structure and validation for MongoDB documents
|
|
8
|
+
2. **Business Logic** - Implement domain-specific operations through document methods
|
|
9
|
+
3. **Query Patterns** - Create reusable database queries with model statics
|
|
10
|
+
4. **Lifecycle Hooks** - Add middleware for handling events during document operations
|
|
11
|
+
5. **Performance Optimization** - Configure indexes and implement DataLoader for efficient querying
|
|
12
|
+
6. **Caching Integration** - Seamlessly integrate with Redis for high-performance data access
|
|
13
|
+
7. **Search Capabilities** - Connect with Meilisearch for full-text search functionality
|
|
14
|
+
|
|
15
|
+
## File Structure
|
|
16
|
+
|
|
17
|
+
A `model.document.ts` file is structured into four distinct classes, each with a specific responsibility:
|
|
18
|
+
|
|
19
|
+
### 1. Input Class
|
|
20
|
+
|
|
21
|
+
Defines the data structure for create/update operations:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
@Database.Input(() => cnst.ExampleInput)
|
|
25
|
+
export class ExampleInput extends by(cnst.ExampleInput) {}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 2. Document Class
|
|
29
|
+
|
|
30
|
+
Represents a MongoDB document with instance methods:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
@Database.Document(() => cnst.Example)
|
|
34
|
+
export class Example extends by(cnst.Example) {
|
|
35
|
+
// Document methods here
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 3. Model Class
|
|
40
|
+
|
|
41
|
+
Represents the MongoDB collection with static methods:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
@Database.Model(() => cnst.Example)
|
|
45
|
+
export class ExampleModel extends into(Example, cnst.exampleCnst) {
|
|
46
|
+
// Model statics here
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 4. Middleware Class
|
|
51
|
+
|
|
52
|
+
Defines schema hooks and indexes:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
@Database.Middleware(() => cnst.Example)
|
|
56
|
+
export class ExampleMiddleware extends beyond(ExampleModel, Example) {
|
|
57
|
+
onSchema(schema) {
|
|
58
|
+
// Middleware and indexes here
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## How to Use Document Methods
|
|
64
|
+
|
|
65
|
+
Document methods operate on individual document instances and typically follow these patterns:
|
|
66
|
+
|
|
67
|
+
### Characteristics of Document Methods:
|
|
68
|
+
|
|
69
|
+
- They operate on the current document instance (`this`)
|
|
70
|
+
- They typically return `this` to enable method chaining
|
|
71
|
+
- They're often synchronous, but can be asynchronous when needed
|
|
72
|
+
- They handle document-level operations and transformations
|
|
73
|
+
|
|
74
|
+
### Example of Document Methods:
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
@Database.Document(() => cnst.User)
|
|
78
|
+
export class User extends by(cnst.User) {
|
|
79
|
+
// Simple transformation method (synchronous)
|
|
80
|
+
addRole(role: string) {
|
|
81
|
+
if (!this.roles.includes(role)) {
|
|
82
|
+
this.roles = [...this.roles, role];
|
|
83
|
+
}
|
|
84
|
+
return this;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Remove item method (synchronous)
|
|
88
|
+
removeRole(role: string) {
|
|
89
|
+
this.roles = this.roles.filter((r) => r !== role);
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Complex operation with save (asynchronous)
|
|
94
|
+
async updateProfile(data: Partial<UserProfile>) {
|
|
95
|
+
Object.assign(this.profile, data);
|
|
96
|
+
this.lastUpdatedAt = new Date();
|
|
97
|
+
return await this.save();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## How to Use Model Statics
|
|
103
|
+
|
|
104
|
+
Model statics operate on the entire collection and are typically asynchronous. They implement reusable query patterns and business operations.
|
|
105
|
+
|
|
106
|
+
### Characteristics of Model Statics:
|
|
107
|
+
|
|
108
|
+
- They operate on the entire collection, not a single document
|
|
109
|
+
- They're almost always asynchronous, returning Promises
|
|
110
|
+
- They often use built-in Mongoose methods like `find`, `findOne`, etc.
|
|
111
|
+
- They can implement complex business logic involving multiple documents
|
|
112
|
+
|
|
113
|
+
### Example of Model Statics:
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
@Database.Model(() => cnst.Order)
|
|
117
|
+
export class OrderModel extends into(Order, cnst.orderCnst) {
|
|
118
|
+
// Query by specific criteria
|
|
119
|
+
async findPendingOrders(userId: string) {
|
|
120
|
+
return this.Order.find({
|
|
121
|
+
user: userId,
|
|
122
|
+
status: "pending",
|
|
123
|
+
}).sort({ createdAt: -1 });
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Complex operation with multiple steps
|
|
127
|
+
async processRefund(orderId: string, amount: number) {
|
|
128
|
+
const order = await this.Order.pickById(orderId);
|
|
129
|
+
|
|
130
|
+
if (order.status !== "completed") {
|
|
131
|
+
throw new Error("Cannot refund an incomplete order");
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (order.totalAmount < amount) {
|
|
135
|
+
throw new Error("Refund amount exceeds order total");
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return await order
|
|
139
|
+
.set({
|
|
140
|
+
refundAmount: amount,
|
|
141
|
+
status: "refunded",
|
|
142
|
+
})
|
|
143
|
+
.save();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Aggregation example
|
|
147
|
+
async getOrderStatsByUser(userId: string) {
|
|
148
|
+
const result = await this.Order.aggregate([
|
|
149
|
+
{ $match: { user: userId } },
|
|
150
|
+
{
|
|
151
|
+
$group: {
|
|
152
|
+
_id: "$status",
|
|
153
|
+
count: { $sum: 1 },
|
|
154
|
+
totalAmount: { $sum: "$totalAmount" },
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
]);
|
|
158
|
+
|
|
159
|
+
return result.reduce((acc, item) => {
|
|
160
|
+
acc[item._id] = {
|
|
161
|
+
count: item.count,
|
|
162
|
+
totalAmount: item.totalAmount,
|
|
163
|
+
};
|
|
164
|
+
return acc;
|
|
165
|
+
}, {});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Built-in Model Functions
|
|
171
|
+
|
|
172
|
+
Akan.js provides several built-in methods that are available on all models:
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
// Direct access to Mongoose model
|
|
176
|
+
await userModel.User.find({...});
|
|
177
|
+
|
|
178
|
+
// Common operations
|
|
179
|
+
const user = await userModel.getUser(userId); // Get by ID or throw error
|
|
180
|
+
const maybeUser = await userModel.loadUser(userId); // Get by ID or return null
|
|
181
|
+
const users = await userModel.loadUserMany([userId1, userId2]); // Get multiple by IDs
|
|
182
|
+
|
|
183
|
+
// CRUD operations
|
|
184
|
+
const newUser = await userModel.createUser(userData); // Create new document
|
|
185
|
+
const updated = await userModel.updateUser(userId, userData); // Update document
|
|
186
|
+
const removed = await userModel.removeUser(userId); // Soft delete (sets removedAt)
|
|
187
|
+
|
|
188
|
+
// Search operations (when Meilisearch is configured)
|
|
189
|
+
const { docs, count } = await userModel.searchUser("john"); // Full-text search
|
|
190
|
+
const users = await userModel.searchDocsUser("john"); // Just get documents
|
|
191
|
+
const total = await userModel.searchCountUser("john"); // Just get count
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## How to Apply Middleware
|
|
195
|
+
|
|
196
|
+
Middleware allows you to intercept and modify document operations at various lifecycle stages.
|
|
197
|
+
|
|
198
|
+
### Common Middleware Hooks:
|
|
199
|
+
|
|
200
|
+
- `pre('save')` - Before saving a document
|
|
201
|
+
- `post('save')` - After saving a document
|
|
202
|
+
- `pre('remove')` - Before removing a document
|
|
203
|
+
- `pre('validate')` - Before validation
|
|
204
|
+
- `pre('findOneAndUpdate')` - Before findOneAndUpdate operations
|
|
205
|
+
|
|
206
|
+
### Example Middleware Implementation:
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
@Database.Middleware(() => cnst.User)
|
|
210
|
+
export class UserMiddleware extends beyond(UserModel, User) {
|
|
211
|
+
onSchema(schema: SchemaOf<UserModel, User>) {
|
|
212
|
+
// Pre-save hook for password hashing
|
|
213
|
+
schema.pre<User>("save", async function (next) {
|
|
214
|
+
// Only hash the password if it's modified
|
|
215
|
+
if (this.isModified("password") && this.password) {
|
|
216
|
+
try {
|
|
217
|
+
this.password = await hashPassword(this.password);
|
|
218
|
+
next();
|
|
219
|
+
} catch (error) {
|
|
220
|
+
next(error);
|
|
221
|
+
}
|
|
222
|
+
} else {
|
|
223
|
+
next();
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// Post-save hook for logging
|
|
228
|
+
schema.post<User>("save", function (doc) {
|
|
229
|
+
console.log(`User ${doc.id} was saved`);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// Pre-remove hook for cleanup
|
|
233
|
+
schema.pre<User>("remove", async function (next) {
|
|
234
|
+
try {
|
|
235
|
+
// Perform cleanup operations
|
|
236
|
+
await someCleanupFunction(this.id);
|
|
237
|
+
next();
|
|
238
|
+
} catch (error) {
|
|
239
|
+
next(error);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## How to Apply Indexes
|
|
247
|
+
|
|
248
|
+
Indexes are crucial for query performance. Define them in the Middleware's `onSchema` method:
|
|
249
|
+
|
|
250
|
+
### Types of Indexes:
|
|
251
|
+
|
|
252
|
+
- **Single field index** - Optimize queries on a single field
|
|
253
|
+
- **Compound index** - Optimize queries that filter or sort on multiple fields
|
|
254
|
+
- **Text index** - Enable full-text search on specified fields
|
|
255
|
+
- **Unique index** - Ensure field values are unique across the collection
|
|
256
|
+
- **Sparse index** - Only include documents that have the indexed field
|
|
257
|
+
|
|
258
|
+
### Example Index Implementation:
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
@Database.Middleware(() => cnst.Product)
|
|
262
|
+
export class ProductMiddleware extends beyond(ProductModel, Product) {
|
|
263
|
+
onSchema(schema: SchemaOf<ProductModel, Product>) {
|
|
264
|
+
// Single field index (1=ascending, -1=descending)
|
|
265
|
+
schema.index({ createdAt: -1 });
|
|
266
|
+
|
|
267
|
+
// Compound index
|
|
268
|
+
schema.index({ category: 1, price: -1 });
|
|
269
|
+
|
|
270
|
+
// Unique index
|
|
271
|
+
schema.index({ sku: 1 }, { unique: true });
|
|
272
|
+
|
|
273
|
+
// Text search index
|
|
274
|
+
schema.index({ name: "text", description: "text" });
|
|
275
|
+
|
|
276
|
+
// Sparse index (only indexes docs with the field)
|
|
277
|
+
schema.index(
|
|
278
|
+
{ promotionCode: 1 },
|
|
279
|
+
{
|
|
280
|
+
sparse: true,
|
|
281
|
+
}
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
// Partial index with filter expression
|
|
285
|
+
schema.index(
|
|
286
|
+
{ status: 1 },
|
|
287
|
+
{
|
|
288
|
+
partialFilterExpression: { status: { $exists: true } },
|
|
289
|
+
}
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
// Time-to-live index (auto-expire documents)
|
|
293
|
+
schema.index(
|
|
294
|
+
{ expiresAt: 1 },
|
|
295
|
+
{
|
|
296
|
+
expireAfterSeconds: 0,
|
|
297
|
+
}
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## How to Use MongoDB Model
|
|
304
|
+
|
|
305
|
+
The Akan.js framework provides direct access to the Mongoose model, allowing you to perform standard MongoDB operations:
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
// Find operations
|
|
309
|
+
const product = await productModel.Product.findById(id);
|
|
310
|
+
const activeProducts = await productModel.Product.find({ status: "active" });
|
|
311
|
+
|
|
312
|
+
// Update operations
|
|
313
|
+
await productModel.Product.updateMany({ category: "electronics" }, { $set: { onSale: true } });
|
|
314
|
+
|
|
315
|
+
// Aggregation
|
|
316
|
+
const stats = await productModel.Product.aggregate([
|
|
317
|
+
{ $match: { status: "active" } },
|
|
318
|
+
{
|
|
319
|
+
$group: {
|
|
320
|
+
_id: "$category",
|
|
321
|
+
count: { $sum: 1 },
|
|
322
|
+
avgPrice: { $avg: "$price" },
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
]);
|
|
326
|
+
|
|
327
|
+
// Advanced querying
|
|
328
|
+
const products = await productModel.Product.find({
|
|
329
|
+
price: { $gte: 100, $lte: 500 },
|
|
330
|
+
category: { $in: ["electronics", "gadgets"] },
|
|
331
|
+
})
|
|
332
|
+
.sort({ rating: -1 })
|
|
333
|
+
.limit(10);
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## How to Use DataLoader
|
|
337
|
+
|
|
338
|
+
DataLoader batches and caches database requests to optimize performance, especially for resolving relationships between documents.
|
|
339
|
+
|
|
340
|
+
### Types of Loaders:
|
|
341
|
+
|
|
342
|
+
- `@Loader.ByField(fieldName)` - Load documents by a specific field value
|
|
343
|
+
- `@Loader.ByArrayField(fieldName)` - Load documents that contain a value in an array field
|
|
344
|
+
- `@Loader.ByQuery(queryKeys)` - Load documents by complex query criteria
|
|
345
|
+
|
|
346
|
+
### Example DataLoader Implementation:
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
@Database.Model(() => cnst.Order)
|
|
350
|
+
export class OrderModel extends into(Order, cnst.orderCnst) {
|
|
351
|
+
// Load orders by user ID
|
|
352
|
+
@Loader.ByField("userId")
|
|
353
|
+
userOrdersLoader: Loader<string, Order[]>;
|
|
354
|
+
|
|
355
|
+
// Load orders by status
|
|
356
|
+
@Loader.ByField("status")
|
|
357
|
+
statusOrdersLoader: Loader<string, Order[]>;
|
|
358
|
+
|
|
359
|
+
// Load orders by tag (array field)
|
|
360
|
+
@Loader.ByArrayField("tags")
|
|
361
|
+
tagOrdersLoader: Loader<string, Order[]>;
|
|
362
|
+
|
|
363
|
+
// Load order by complex query
|
|
364
|
+
@Loader.ByQuery(["userId", "orderNumber"])
|
|
365
|
+
specificOrderLoader: Loader<{ userId: string; orderNumber: string }, Order>;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Usage:
|
|
369
|
+
const userOrders = await orderModel.userOrdersLoader.load(userId);
|
|
370
|
+
const pendingOrders = await orderModel.statusOrdersLoader.load("pending");
|
|
371
|
+
const taggedOrders = await orderModel.tagOrdersLoader.load("priority");
|
|
372
|
+
const specificOrder = await orderModel.specificOrderLoader.load({
|
|
373
|
+
userId: "user123",
|
|
374
|
+
orderNumber: "ORD-12345",
|
|
375
|
+
});
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
## How to Use Cache with Redis
|
|
379
|
+
|
|
380
|
+
Akan.js integrates Redis caching through the model's cache instance, providing simple methods for storing and retrieving data:
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
// Set cache
|
|
384
|
+
await userModel.UserCache.set(
|
|
385
|
+
"session", // Topic/category
|
|
386
|
+
userId, // Key
|
|
387
|
+
sessionData, // Value
|
|
388
|
+
{ expireAt: dayjs().add(1, "hour") } // Options
|
|
389
|
+
);
|
|
390
|
+
|
|
391
|
+
// Get cache
|
|
392
|
+
const session = await userModel.UserCache.get("session", userId);
|
|
393
|
+
|
|
394
|
+
// Delete cache
|
|
395
|
+
await userModel.UserCache.delete("session", userId);
|
|
396
|
+
|
|
397
|
+
// Example: Caching expensive computation
|
|
398
|
+
async function getUserStats(userId: string) {
|
|
399
|
+
// Try to get from cache first
|
|
400
|
+
const cachedStats = await userModel.UserCache.get("stats", userId);
|
|
401
|
+
if (cachedStats) return JSON.parse(cachedStats);
|
|
402
|
+
|
|
403
|
+
// If not in cache, compute and store
|
|
404
|
+
const stats = await computeExpensiveUserStats(userId);
|
|
405
|
+
await userModel.UserCache.set("stats", userId, JSON.stringify(stats), { expireAt: dayjs().add(30, "minute") });
|
|
406
|
+
|
|
407
|
+
return stats;
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
## How to Use Search with Meilisearch
|
|
412
|
+
|
|
413
|
+
Akan.js provides Meilisearch integration for full-text search capabilities:
|
|
414
|
+
|
|
415
|
+
```typescript
|
|
416
|
+
// Basic search with pagination
|
|
417
|
+
const { docs, count } = await productModel.searchProduct("wireless headphones", {
|
|
418
|
+
skip: 0,
|
|
419
|
+
limit: 10,
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
// Search with filtering
|
|
423
|
+
const { docs, count } = await productModel.searchProduct("wireless headphones", {
|
|
424
|
+
filter: "category=electronics AND price<=100",
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
// Search with sorting
|
|
428
|
+
const { docs, count } = await productModel.searchProduct("wireless headphones", {
|
|
429
|
+
sort: ["rating:desc", "price:asc"],
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
// Just get the documents
|
|
433
|
+
const products = await productModel.searchDocsProduct("wireless headphones");
|
|
434
|
+
|
|
435
|
+
// Just get the count
|
|
436
|
+
const resultCount = await productModel.searchCountProduct("wireless headphones");
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
## Best Practices
|
|
440
|
+
|
|
441
|
+
### 1. Document Methods vs. Model Statics
|
|
442
|
+
|
|
443
|
+
- Use **document methods** for operations on a single document
|
|
444
|
+
- Use **model statics** for operations on multiple documents or complex business logic
|
|
445
|
+
|
|
446
|
+
### 2. Efficient Querying
|
|
447
|
+
|
|
448
|
+
- Add indexes for frequently used queries
|
|
449
|
+
- Use projection (`select`) to limit fields returned
|
|
450
|
+
- Use `lean()` when you don't need full Mongoose documents
|
|
451
|
+
- Implement DataLoader for relationship fields
|
|
452
|
+
|
|
453
|
+
### 3. Error Handling
|
|
454
|
+
|
|
455
|
+
- Use `pickOne` and `pickById` when you expect a document to exist
|
|
456
|
+
- Implement custom error classes for domain-specific errors
|
|
457
|
+
- Validate inputs before database operations
|
|
458
|
+
|
|
459
|
+
### 4. Transactions
|
|
460
|
+
|
|
461
|
+
Use transactions for operations that need to be atomic:
|
|
462
|
+
|
|
463
|
+
```typescript
|
|
464
|
+
@Database.Model(() => cnst.Order)
|
|
465
|
+
export class OrderModel extends into(Order, cnst.orderCnst) {
|
|
466
|
+
@Transaction()
|
|
467
|
+
async createOrderWithItems(orderData, items) {
|
|
468
|
+
const order = await this.createOrder(orderData);
|
|
469
|
+
await Promise.all(items.map((item) => itemModel.createItem({ ...item, orderId: order.id })));
|
|
470
|
+
return order;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### 5. Soft Deletes
|
|
476
|
+
|
|
477
|
+
Akan.js implements soft deletes by default:
|
|
478
|
+
|
|
479
|
+
```typescript
|
|
480
|
+
// Soft delete (sets removedAt field)
|
|
481
|
+
await userModel.removeUser(userId);
|
|
482
|
+
|
|
483
|
+
// To query only non-deleted documents
|
|
484
|
+
const users = await userModel.User.find({ removedAt: { $exists: false } });
|
|
485
|
+
|
|
486
|
+
// To permanently delete (rarely needed)
|
|
487
|
+
await userModel.User.findByIdAndDelete(userId);
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
## Complete Example
|
|
491
|
+
|
|
492
|
+
Here's a complete example integrating multiple features:
|
|
493
|
+
|
|
494
|
+
```typescript
|
|
495
|
+
// product.document.ts
|
|
496
|
+
import { dayjs } from "@akanjs/base";
|
|
497
|
+
import { beyond, by, Database, into, Loader, SchemaOf } from "@akanjs/document";
|
|
498
|
+
import { cnst } from "../cnst";
|
|
499
|
+
|
|
500
|
+
@Database.Input(() => cnst.ProductInput)
|
|
501
|
+
export class ProductInput extends by(cnst.ProductInput) {}
|
|
502
|
+
|
|
503
|
+
@Database.Document(() => cnst.Product)
|
|
504
|
+
export class Product extends by(cnst.Product) {
|
|
505
|
+
applyDiscount(percentage: number) {
|
|
506
|
+
if (percentage < 0 || percentage > 100) {
|
|
507
|
+
throw new Error("Discount percentage must be between 0 and 100");
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const discount = (this.price * percentage) / 100;
|
|
511
|
+
this.discountedPrice = this.price - discount;
|
|
512
|
+
this.discountPercentage = percentage;
|
|
513
|
+
|
|
514
|
+
return this;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
isInStock() {
|
|
518
|
+
return this.stockCount > 0;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
decreaseStock(quantity = 1) {
|
|
522
|
+
if (this.stockCount < quantity) {
|
|
523
|
+
throw new Error("Not enough stock");
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
this.stockCount -= quantity;
|
|
527
|
+
|
|
528
|
+
return this;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
@Database.Model(() => cnst.Product)
|
|
533
|
+
export class ProductModel extends into(Product, cnst.productCnst) {
|
|
534
|
+
@Loader.ByField("category")
|
|
535
|
+
categoryProductsLoader: Loader<string, Product[]>;
|
|
536
|
+
|
|
537
|
+
@Loader.ByArrayField("tags")
|
|
538
|
+
tagProductsLoader: Loader<string, Product[]>;
|
|
539
|
+
|
|
540
|
+
async findPopularProducts(limit = 10) {
|
|
541
|
+
return this.Product.find({
|
|
542
|
+
status: "active",
|
|
543
|
+
popularity: { $gte: 4 },
|
|
544
|
+
})
|
|
545
|
+
.sort({ popularity: -1 })
|
|
546
|
+
.limit(limit);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
async updatePrices(categoryId: string, increasePercentage: number) {
|
|
550
|
+
const products = await this.Product.find({ category: categoryId });
|
|
551
|
+
|
|
552
|
+
const updates = products.map((product) => {
|
|
553
|
+
const newPrice = product.price * (1 + increasePercentage / 100);
|
|
554
|
+
return product.set({ price: newPrice }).save();
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
return Promise.all(updates);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
async getCategoryStats() {
|
|
561
|
+
const result = await this.Product.aggregate([
|
|
562
|
+
{ $match: { status: "active" } },
|
|
563
|
+
{
|
|
564
|
+
$group: {
|
|
565
|
+
_id: "$category",
|
|
566
|
+
count: { $sum: 1 },
|
|
567
|
+
avgPrice: { $avg: "$price" },
|
|
568
|
+
minPrice: { $min: "$price" },
|
|
569
|
+
maxPrice: { $max: "$price" },
|
|
570
|
+
},
|
|
571
|
+
},
|
|
572
|
+
{ $sort: { count: -1 } },
|
|
573
|
+
]);
|
|
574
|
+
|
|
575
|
+
// Cache the results
|
|
576
|
+
await this.ProductCache.set("stats", "categories", JSON.stringify(result), { expireAt: dayjs().add(1, "hour") });
|
|
577
|
+
|
|
578
|
+
return result;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
@Database.Middleware(() => cnst.Product)
|
|
583
|
+
export class ProductMiddleware extends beyond(ProductModel, Product) {
|
|
584
|
+
onSchema(schema: SchemaOf<ProductModel, Product>) {
|
|
585
|
+
// Update stock status on save
|
|
586
|
+
schema.pre<Product>("save", function (next) {
|
|
587
|
+
if (this.isModified("stockCount")) {
|
|
588
|
+
this.stockStatus = this.stockCount > 0 ? "in_stock" : "out_of_stock";
|
|
589
|
+
}
|
|
590
|
+
next();
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
// Create slug from name
|
|
594
|
+
schema.pre<Product>("save", function (next) {
|
|
595
|
+
if (this.isNew || this.isModified("name")) {
|
|
596
|
+
this.slug = this.name
|
|
597
|
+
.toLowerCase()
|
|
598
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
599
|
+
.replace(/^-|-$/g, "");
|
|
600
|
+
}
|
|
601
|
+
next();
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
// Indexes
|
|
605
|
+
schema.index({ category: 1, status: 1 });
|
|
606
|
+
schema.index({ name: "text", description: "text" });
|
|
607
|
+
schema.index({ slug: 1 }, { unique: true });
|
|
608
|
+
schema.index({ createdAt: -1 });
|
|
609
|
+
schema.index({ price: 1 });
|
|
610
|
+
schema.index({ "meta.specifications.key": 1, "meta.specifications.value": 1 });
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
## Integration with NestJS
|
|
616
|
+
|
|
617
|
+
When using Akan.js with NestJS, models are injected using the service provider system:
|
|
618
|
+
|
|
619
|
+
```typescript
|
|
620
|
+
// product.service.ts
|
|
621
|
+
import { Injectable } from "@nestjs/common";
|
|
622
|
+
import { getModel } from "@akanjs/nest";
|
|
623
|
+
import { ProductModel } from "./product.document";
|
|
624
|
+
|
|
625
|
+
@Injectable()
|
|
626
|
+
export class ProductService {
|
|
627
|
+
private productModel = getModel(ProductModel);
|
|
628
|
+
|
|
629
|
+
async getProductById(id: string) {
|
|
630
|
+
return this.productModel.getProduct(id);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
async searchProducts(query: string, options = {}) {
|
|
634
|
+
return this.productModel.searchProduct(query, options);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
async createProduct(data) {
|
|
638
|
+
return this.productModel.createProduct(data);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
async applyDiscount(productId: string, percentage: number) {
|
|
642
|
+
const product = await this.productModel.getProduct(productId);
|
|
643
|
+
return product.applyDiscount(percentage).save();
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
## Client-Side Usage
|
|
649
|
+
|
|
650
|
+
On the client side, you'll typically interact with models through GraphQL or REST APIs:
|
|
651
|
+
|
|
652
|
+
```typescript
|
|
653
|
+
// Using model-generated GraphQL operations
|
|
654
|
+
const { data } = await client.query({
|
|
655
|
+
query: gql`
|
|
656
|
+
query GetProduct($id: ID!) {
|
|
657
|
+
getProduct(id: $id) {
|
|
658
|
+
id
|
|
659
|
+
name
|
|
660
|
+
price
|
|
661
|
+
description
|
|
662
|
+
category
|
|
663
|
+
status
|
|
664
|
+
stockCount
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
`,
|
|
668
|
+
variables: { id: productId },
|
|
669
|
+
});
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
## Summary
|
|
673
|
+
|
|
674
|
+
The `model.document.ts` files in Akan.js provide a comprehensive system for defining and working with MongoDB data. By properly implementing these files, you can:
|
|
675
|
+
|
|
676
|
+
1. Define clear data structures with validation
|
|
677
|
+
2. Implement business logic at both document and collection levels
|
|
678
|
+
3. Optimize database performance with indexes and DataLoader
|
|
679
|
+
4. Leverage caching for high-performance operations
|
|
680
|
+
5. Implement full-text search capabilities
|
|
681
|
+
6. Create a maintainable and scalable data layer
|
|
682
|
+
|
|
683
|
+
Following the patterns and best practices outlined in this guide will help you build robust and efficient data-driven applications with Akan.js.
|