diff --git a/packages/app/src/components/form.fields/filter/index.tsx b/packages/app/src/components/form.fields/filter/index.tsx index e5ef09753..ef81caf22 100644 --- a/packages/app/src/components/form.fields/filter/index.tsx +++ b/packages/app/src/components/form.fields/filter/index.tsx @@ -171,12 +171,12 @@ const OP_MAP = { {label: '为空', value: '$null'}, ], datetime: [ - {label: '等于', value: 'eq', selected: true}, - {label: '不等于', value: 'neq'}, - {label: '大于', value: 'gt'}, - {label: '大于等于', value: 'gte'}, - {label: '小于', value: 'lt'}, - {label: '小于等于', value: 'lte'}, + {label: '等于', value: '$dateOn', selected: true}, + {label: '不等于', value: '$dateNotOn'}, + {label: '早于', value: '$dateBefore'}, + {label: '晚于', value: '$dateAfter'}, + {label: '不早于', value: '$dateNotBefore'}, + {label: '不晚于', value: '$dateNotAfter'}, // {label: '介于', value: 'between'}, {label: '非空', value: '$notNull'}, {label: '为空', value: '$null'}, @@ -257,15 +257,20 @@ const controls = { function DateControl(props: any) { const { field, value, onChange, ...restProps } = props; let format = field.dateFormat; - if (field.showTime) { - format += ` ${field.timeFormat}`; - } + // if (field.showTime) { + // format += ` ${field.timeFormat}`; + // } const m = moment(value, format); return ( - { - onChange(value ? value.format(field.showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD') : null) + { + onChange(value ? value.format('YYYY-MM-DD') : null) }}/> ); + // return ( + // { + // onChange(value ? value.format(field.showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD') : null) + // }}/> + // ); } function TimeControl(props: any) { diff --git a/packages/database/package.json b/packages/database/package.json index bf61bdd94..d478f6f9d 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -4,8 +4,7 @@ "description": "", "main": "./lib/index.js", "types": "./lib/index.d.ts", - "scripts": { - }, + "scripts": {}, "license": "MIT", "dependencies": { "bcrypt": "^5.0.0", diff --git a/packages/database/src/__tests__/index.ts b/packages/database/src/__tests__/index.ts index d9b9b4842..4c8753191 100644 --- a/packages/database/src/__tests__/index.ts +++ b/packages/database/src/__tests__/index.ts @@ -24,7 +24,7 @@ const config = { }, }, }, - logging: process.env.DB_LOG_SQL === 'on' + logging: process.env.DB_LOG_SQL === 'on' ? console.log : false }; export function getDatabase() { diff --git a/packages/database/src/__tests__/utils/op.test.ts b/packages/database/src/__tests__/utils/op.test.ts new file mode 100644 index 000000000..755838f7f --- /dev/null +++ b/packages/database/src/__tests__/utils/op.test.ts @@ -0,0 +1,197 @@ +import { Op } from 'sequelize'; +import Database from '../../database'; +import { toWhere } from '../../utils'; +import { getDatabase } from '..'; + +describe('utils.toWhere', () => { + let db: Database; + + beforeEach(async () => { + db = getDatabase(); + + db.table({ + name: 'users', + fields: [ + { + type: 'hasMany', + name: 'posts', + } + ], + }); + db.table({ + name: 'posts', + fields: [ + { + type: 'string', + name: 'title' + }, + { + type: 'belongsTo', + name: 'user', + } + ] + }); + + await db.sync({ force: true }); + + const Post = db.getModel('posts'); + await Post.bulkCreate(Array(5).fill(null).map((_, i) => ({ + title: `title${i}`, + created_at: new Date(2020, 11, 29 + i) + }))); + }); + + afterEach(async () => await db.close()); + + describe('date', () => { + it('$dateOn', async () => { + const Post = db.getModel('posts'); + const posts = await Post.findAll({ + where: toWhere({ + 'created_at.$dateOn': '2020-12-31' + }) + }); + expect(posts[0].created_at).toEqual(new Date(2020, 11,31)); + }); + + it('$dateNotOn', async () => { + const Post = db.getModel('posts'); + const posts = await Post.findAll({ + where: toWhere({ + 'created_at.$dateNotOn': '2020-12-31' + }) + }); + expect(posts.length).toBe(4); + }); + + it('Op.$dateBefore', async () => { + const Post = db.getModel('posts'); + const posts = await Post.findAll({ + where: toWhere({ + 'created_at.$dateBefore': '2020-12-29' + }) + }); + expect(posts.length).toBe(0); + }); + + it('Op.$dateBefore', async () => { + const Post = db.getModel('posts'); + const posts = await Post.findAll({ + where: toWhere({ + 'created_at.$dateBefore': '2021-01-02' + }) + }); + expect(posts.length).toBe(4); + }); + + it('Op.$dateBefore', async () => { + const Post = db.getModel('posts'); + const posts = await Post.findAll({ + where: toWhere({ + 'created_at.$dateBefore': '2021-01-03' + }) + }); + expect(posts.length).toBe(5); + }); + + it('Op.$dateAfter', async () => { + const Post = db.getModel('posts'); + const posts = await Post.findAll({ + where: toWhere({ + 'created_at.$dateAfter': '2021-01-03' + }) + }); + expect(posts.length).toBe(0); + }); + + it('Op.$dateAfter', async () => { + const Post = db.getModel('posts'); + const posts = await Post.findAll({ + where: toWhere({ + 'created_at.$dateAfter': '2021-01-03' + }) + }); + expect(posts.length).toBe(0); + }); + + it('Op.$dateAfter', async () => { + const Post = db.getModel('posts'); + const posts = await Post.findAll({ + where: toWhere({ + 'created_at.$dateAfter': '2020-12-29' + }) + }); + expect(posts.length).toBe(4); + }); + + it('Op.$dateNotBefore', async () => { + const Post = db.getModel('posts'); + const posts = await Post.findAll({ + where: toWhere({ + 'created_at.$dateNotBefore': '2020-12-29' + }) + }); + expect(posts.length).toBe(5); + }); + + it('Op.$dateNotAfter', async () => { + const Post = db.getModel('posts'); + const posts = await Post.findAll({ + where: toWhere({ + 'created_at.$dateNotAfter': '2020-12-29' + }) + }); + expect(posts.length).toBe(1); + }); + + it('Op.$dateBetween', async () => { + const Post = db.getModel('posts'); + const posts = await Post.findAll({ + where: toWhere({ + 'created_at.$dateBetween': ['2020-12-29', '2021-01-01'] + }) + }); + expect(posts.length).toBe(4); + }); + + it('Op.$dateBetween', async () => { + const Post = db.getModel('posts'); + const posts = await Post.findAll({ + where: toWhere({ + 'created_at.$dateBetween': ['2020-12-28', '2020-12-29'] + }) + }); + expect(posts.length).toBe(1); + }); + + it('Op.$dateBetween', async () => { + const Post = db.getModel('posts'); + const posts = await Post.findAll({ + where: toWhere({ + 'created_at.$dateBetween': ['2021-01-03', '2021-01-04'] + }) + }); + expect(posts.length).toBe(0); + }); + + it('Op.$dateNotBetween', async () => { + const Post = db.getModel('posts'); + const posts = await Post.findAll({ + where: toWhere({ + 'created_at.$dateNotBetween': ['2020-12-28', '2020-12-29'] + }) + }); + expect(posts.length).toBe(4); + }); + + it('Op.$dateNotBetween', async () => { + const Post = db.getModel('posts'); + const posts = await Post.findAll({ + where: toWhere({ + 'created_at.$dateNotBetween': ['2020-12-28', '2021-01-04'] + }) + }); + expect(posts.length).toBe(0); + }); + }); +}); diff --git a/packages/database/src/op.ts b/packages/database/src/op.ts index 13804372b..99a1a89f0 100644 --- a/packages/database/src/op.ts +++ b/packages/database/src/op.ts @@ -1,4 +1,5 @@ import { Op, Utils, Sequelize } from 'sequelize'; +import moment, { MomentInput } from 'moment'; function toArray(value: any): any[] { if (value == null) { @@ -7,6 +8,14 @@ function toArray(value: any): any[] { return Array.isArray(value) ? value : [value]; } +function stringToDate(value: string): Date { + return moment(value).toDate(); +} + +function getNextDay(value: MomentInput): Date { + return moment(value).add(1, 'd').toDate(); +} + const op = new Map(); // Sequelize 内置 @@ -56,6 +65,25 @@ op.set('$endsWith', (value: string) => ({ [Op.iLike]: `%${value}` })); // 不以之结束 op.set('$notEndsWith', (value: string) => ({ [Op.notILike]: `%${value}` })); +// 仅日期 + +// 在某日 +op.set('$dateOn', (value: string) => ({ [Op.and]: [{ [Op.gte]: stringToDate(value) }, { [Op.lt]: getNextDay(value) }] })); +// 不在某日 +op.set('$dateNotOn', (value: string) => ({ [Op.or]: [{ [Op.lt]: stringToDate(value) }, { [Op.gte]: getNextDay(value) }] })); +// 某日前 +op.set('$dateBefore', (value: string) => ({ [Op.lt]: stringToDate(value) })); +// 某日后 +op.set('$dateAfter', (value: string) => ({ [Op.gte]: getNextDay(value) })); +// 不早于(含当天) +op.set('$dateNotBefore', (value: string) => ({ [Op.gte]: stringToDate(value) })); +// 不晚于(含当天) +op.set('$dateNotAfter', (value: string) => ({ [Op.lt]: getNextDay(value) })); +// 在期间 +op.set('$dateBetween', ([from, to]: string[]) => ({ [Op.and]: [{ [Op.gte]: stringToDate(from) }, { [Op.lt]: getNextDay(to) }] })); +// 不在期间 +op.set('$dateNotBetween', ([from, to]: string[]) => ({ [Op.or]: [{ [Op.lt]: stringToDate(from) }, { [Op.gte]: getNextDay(to) }] })); + // 多选(JSON)类型 // 包含组中任意值(命名来源:`Array.prototype.some`) diff --git a/packages/plugin-collections/src/interfaces/types.ts b/packages/plugin-collections/src/interfaces/types.ts index 564c43225..ca8c95238 100644 --- a/packages/plugin-collections/src/interfaces/types.ts +++ b/packages/plugin-collections/src/interfaces/types.ts @@ -351,7 +351,7 @@ export const createdAt = { type: 'date', // name: 'created_at', field: 'created_at', - showTime: true, + showTime: false, dateFormat: 'YYYY-MM-DD', timeFormat: 'HH:mm:ss', required: true, @@ -370,7 +370,7 @@ export const updatedAt = { type: 'date', // name: 'updated_at', field: 'updated_at', - showTime: true, + showTime: false, dateFormat: 'YYYY-MM-DD', timeFormat: 'HH:mm:ss', required: true,