feat: date-only operators (#50)
* feat: date-only operators * feat: add opposite operators * fix: use moment to parse date string * fix: remove additional moment dependency. * modify date filter operators Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
parent
d74eda3f23
commit
435cd9a7c9
@ -171,12 +171,12 @@ const OP_MAP = {
|
|||||||
{label: '为空', value: '$null'},
|
{label: '为空', value: '$null'},
|
||||||
],
|
],
|
||||||
datetime: [
|
datetime: [
|
||||||
{label: '等于', value: 'eq', selected: true},
|
{label: '等于', value: '$dateOn', selected: true},
|
||||||
{label: '不等于', value: 'neq'},
|
{label: '不等于', value: '$dateNotOn'},
|
||||||
{label: '大于', value: 'gt'},
|
{label: '早于', value: '$dateBefore'},
|
||||||
{label: '大于等于', value: 'gte'},
|
{label: '晚于', value: '$dateAfter'},
|
||||||
{label: '小于', value: 'lt'},
|
{label: '不早于', value: '$dateNotBefore'},
|
||||||
{label: '小于等于', value: 'lte'},
|
{label: '不晚于', value: '$dateNotAfter'},
|
||||||
// {label: '介于', value: 'between'},
|
// {label: '介于', value: 'between'},
|
||||||
{label: '非空', value: '$notNull'},
|
{label: '非空', value: '$notNull'},
|
||||||
{label: '为空', value: '$null'},
|
{label: '为空', value: '$null'},
|
||||||
@ -257,15 +257,20 @@ const controls = {
|
|||||||
function DateControl(props: any) {
|
function DateControl(props: any) {
|
||||||
const { field, value, onChange, ...restProps } = props;
|
const { field, value, onChange, ...restProps } = props;
|
||||||
let format = field.dateFormat;
|
let format = field.dateFormat;
|
||||||
if (field.showTime) {
|
// if (field.showTime) {
|
||||||
format += ` ${field.timeFormat}`;
|
// format += ` ${field.timeFormat}`;
|
||||||
}
|
// }
|
||||||
const m = moment(value, format);
|
const m = moment(value, format);
|
||||||
return (
|
return (
|
||||||
<DatePicker format={format} showTime={field.showTime} value={m.isValid() ? m : null} onChange={(value) => {
|
<DatePicker format={format} value={m.isValid() ? m : null} onChange={(value) => {
|
||||||
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 (
|
||||||
|
// <DatePicker format={format} showTime={field.showTime} value={m.isValid() ? m : null} onChange={(value) => {
|
||||||
|
// onChange(value ? value.format(field.showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD') : null)
|
||||||
|
// }}/>
|
||||||
|
// );
|
||||||
}
|
}
|
||||||
|
|
||||||
function TimeControl(props: any) {
|
function TimeControl(props: any) {
|
||||||
|
@ -4,8 +4,7 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"types": "./lib/index.d.ts",
|
"types": "./lib/index.d.ts",
|
||||||
"scripts": {
|
"scripts": {},
|
||||||
},
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bcrypt": "^5.0.0",
|
"bcrypt": "^5.0.0",
|
||||||
|
@ -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() {
|
export function getDatabase() {
|
||||||
|
197
packages/database/src/__tests__/utils/op.test.ts
Normal file
197
packages/database/src/__tests__/utils/op.test.ts
Normal file
@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -1,4 +1,5 @@
|
|||||||
import { Op, Utils, Sequelize } from 'sequelize';
|
import { Op, Utils, Sequelize } from 'sequelize';
|
||||||
|
import moment, { MomentInput } from 'moment';
|
||||||
|
|
||||||
function toArray(value: any): any[] {
|
function toArray(value: any): any[] {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
@ -7,6 +8,14 @@ function toArray(value: any): any[] {
|
|||||||
return Array.isArray(value) ? value : [value];
|
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<string, typeof Op | Function>();
|
const op = new Map<string, typeof Op | Function>();
|
||||||
|
|
||||||
// Sequelize 内置
|
// Sequelize 内置
|
||||||
@ -56,6 +65,25 @@ op.set('$endsWith', (value: string) => ({ [Op.iLike]: `%${value}` }));
|
|||||||
// 不以之结束
|
// 不以之结束
|
||||||
op.set('$notEndsWith', (value: string) => ({ [Op.notILike]: `%${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)类型
|
// 多选(JSON)类型
|
||||||
|
|
||||||
// 包含组中任意值(命名来源:`Array.prototype.some`)
|
// 包含组中任意值(命名来源:`Array.prototype.some`)
|
||||||
|
@ -351,7 +351,7 @@ export const createdAt = {
|
|||||||
type: 'date',
|
type: 'date',
|
||||||
// name: 'created_at',
|
// name: 'created_at',
|
||||||
field: 'created_at',
|
field: 'created_at',
|
||||||
showTime: true,
|
showTime: false,
|
||||||
dateFormat: 'YYYY-MM-DD',
|
dateFormat: 'YYYY-MM-DD',
|
||||||
timeFormat: 'HH:mm:ss',
|
timeFormat: 'HH:mm:ss',
|
||||||
required: true,
|
required: true,
|
||||||
@ -370,7 +370,7 @@ export const updatedAt = {
|
|||||||
type: 'date',
|
type: 'date',
|
||||||
// name: 'updated_at',
|
// name: 'updated_at',
|
||||||
field: 'updated_at',
|
field: 'updated_at',
|
||||||
showTime: true,
|
showTime: false,
|
||||||
dateFormat: 'YYYY-MM-DD',
|
dateFormat: 'YYYY-MM-DD',
|
||||||
timeFormat: 'HH:mm:ss',
|
timeFormat: 'HH:mm:ss',
|
||||||
required: true,
|
required: true,
|
||||||
|
Loading…
Reference in New Issue
Block a user