Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

wrfighting/lowcode-controller

Open more actions menu
 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

lowcode-controller

English | 简体中文

lowcode-controller builds common Sequelize CRUD controller logic from a declarative configuration object. It supports paginated, list, and single-item queries, creation, updates, soft or physical deletion, validation, lifecycle hooks, and custom response fields.

The package is written in strict TypeScript and publishes CommonJS JavaScript, source maps, and generated type declarations. Existing JavaScript consumers can continue to use require().

Installation

npm install lowcode-controller

Basic usage

import path from 'node:path'
import {
    LowCodeController,
    type LowCodeControllerConfig,
} from 'lowcode-controller'

import CatModel from '../model/cat_model'

LowCodeController.setGlobalDBPath(path.join(__dirname, '../db/mysql'))
LowCodeController.setUserNameField('username')

const config: LowCodeControllerConfig = {
    pageQuery: {
        query: {
            cat_name: { value: 'cat_name', like: true },
            age: { type: 'constant', value: 2 },
        },
        extraOptions: {
            order: [['cat_name', 'DESC']],
            attributes: ['cat_name', 'age', 'job'],
        },
    },
    getList: {
        query: {
            birthday: {
                type: 'varTime',
                value: ['start', 'end'],
            },
        },
        afterQueryHook: async results =>
            results.map(item => ({ ...item, description: 'cute cat' })),
    },
    create: {
        validate: {
            cat_name: { name: 'cat name', rule: 'required' },
        },
        constantCreate: { age: 2 },
        enableBatch: true,
    },
    update: {
        pick: ['job'],
        afterUpdateHook: async updateItem => {
            if (updateItem.job === 'rollback') {
                throw new Error('roll back')
            }
        },
    },
}

class CatsController extends LowCodeController {
    public constructor() {
        super(CatModel, config, null, {
            creatorField: 'creator',
            updatorField: 'updator',
        })
    }
}

export default new CatsController()

JavaScript usage remains unchanged:

const { LowCodeController, utils } = require('lowcode-controller')

Koa routes

Controller methods are bound to their instance and can be passed directly to a router.

const router = require('koa-router')()
const Cat = require('./controller/cats')

router.get('/api/cats', Cat.pageQuery)
router.get('/api/cats/list', Cat.getList)
router.get('/api/cats/:id', Cat.getSingle)
router.post('/api/cats', Cat.create)
router.put('/api/cats', Cat.update)
router.put('/api/cats/:id', Cat.update)
router.delete('/api/cats/:id', Cat.delete)

Global configuration

setGlobalDBPath(dbPath)

Loads the module exporting the default Sequelize instance. Call it before constructing a controller.

setUserNameField(field)

Sets the context path used for creator and updater audit values. Nested paths such as state.user.name are supported.

setCustomResField(code, message, data)

Changes the keys used by generated responses. The default response shape is:

{
    "errno": 0,
    "errmsg": "success",
    "data": null
}

Constructor

new LowCodeController(model, config, db, options)
Parameter Description
model Sequelize model used by generated handlers
config Per-handler configuration described below
db Optional Sequelize instance; the global instance is the default
options.creatorField Model field populated from the username path on create
options.updatorField Model field populated on create, update, and soft delete
options.defaultQuery Conditions merged into normal queries; default: { delete_flag: 1 }
options.updateDelete Values written during soft delete; default: { delete_flag: 0 }

Query DSL

Each key is a model field. value normally identifies the request field from which the condition is read.

const query = {
    cat_name: {
        value: 'cat_name',
        like: true,
        require: true,
    },
    age: {
        type: 'constant',
        value: 2,
    },
    creator: {
        type: 'constant',
        ctxField: 'username',
    },
    color: {
        type: 'varArray',
        value: 'colors',
    },
    birthday: {
        type: 'varTime',
        value: ['startTime', 'endTime'],
    },
    tags: {
        value: 'tag',
        json: true,
    },
    $or: {
        status: {
            type: 'constant',
            operator: '$in',
            value: ['ready', 'done'],
        },
        height: {
            type: 'constant',
            operator: '$ne',
            value: 30,
        },
    },
}

Supported options are constant, varArray, varTime, $in, $ne, $time, like, json, parseNumber, ctxField, and require.

Handler configuration

pageQuery

Reads size and page from ctx.query. The offset is size * page, so page numbering starts at zero. Response data is { list, total }.

  • query: query DSL configuration.
  • extraOptions: merged into Sequelize findAndCountAll options.
  • filter: synchronous mapper applied to each row.
  • beforeQueryHook(query, extraOptions, ctx): a truthy return stops handling.
  • afterQueryHook(results, query, extraOptions, ctx): a truthy return becomes response data.

getList and getSingle

getList uses the same query hooks and calls findAll. getSingle uses the route id when present, otherwise it builds a query and calls findOne.

create

  • validate: Validator.js rules in { field: { name, rule } } form.
  • constantCreate: values assigned over request values.
  • pickCreate: maps destination fields to source request fields.
  • enableBatch: uses bulkCreate when the body is an array.
  • extraOptions: passed to Sequelize.
  • beforeInsertHook(createItem, ctx): a truthy return stops handling.
  • afterInsertHook(insertItem, transaction, ctx): runs in a managed transaction and must be async.

update

An id route parameter is used when present. Otherwise the configured query is built from ctx.request.body.

  • query, validate, extraOptions: query, validation, and Sequelize options.
  • pick: allowlist of fields that may be updated.
  • itemBlock: requires current model fields to match configured values.
  • beforeUpdateHook(updateItem, item, ctx): a truthy return stops handling.
  • afterUpdateHook(updateItem, item, raw, transaction, ctx): runs in a managed transaction and must be async.

delete

Deletion is soft by default. physicDelete: true uses Sequelize destroy. The handler supports query, extraOptions, beforeDeleteHook, and an async transactional afterDeleteHook.

Utilities

import { utils } from 'lowcode-controller'

utils.resSuccess(data)
utils.resFail(1, 'message')
utils.timeQuery(['2024-01-01', '2024-12-31'])
utils.validator.validateJson(data, rules)
utils.curdHelper.findByList(model, options)

Development and publishing

npm install
npm run typecheck
npm test
npm run build
npm pack --dry-run

npm publish runs the verification suite through prepublishOnly and rebuilds dist through prepack. The existing MySQL-backed example suite is available with npm run test:integration and uses test/instance/config.js.

License

ISC

About

a low-code controller for nodejs, you can use json write your controller code

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Morty Proxy This is a proxified and sanitized view of the page, visit original site.