fix: array $noneOf with null (#220)

* fix: array $noneOf with null

* fix: mysql test
This commit is contained in:
ChengLei Shao 2022-03-04 18:13:48 +08:00 committed by GitHub
parent 5233d00373
commit 534a6e43ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 55 additions and 17 deletions

View File

@ -26,14 +26,14 @@ describe('array field operator', function () {
t1 = await Test.repository.create({ t1 = await Test.repository.create({
values: { values: {
selected: [1, 2, 'a', 'b'], selected: ['1', '2', 'a', 'b'],
name: 't1', name: 't1',
}, },
}); });
t2 = await Test.repository.create({ t2 = await Test.repository.create({
values: { values: {
selected: [11, 22, 'aa', 'bb', 'cc'], selected: ['11', '22', 'aa', 'bb', 'cc'],
name: 't2', name: 't2',
}, },
}); });
@ -133,7 +133,7 @@ describe('array field operator', function () {
test('$match', async () => { test('$match', async () => {
const filter1 = await Test.repository.find({ const filter1 = await Test.repository.find({
filter: { filter: {
'selected.$match': [2, 1, 'a', 'b'], 'selected.$match': ['2', '1', 'a', 'b'],
}, },
}); });
@ -146,7 +146,7 @@ describe('array field operator', function () {
filter: { filter: {
$and: [ $and: [
{ {
selected: { $match: [2, 1, 'a', 'b'] }, selected: { $match: ['2', '1', 'a', 'b'] },
}, },
], ],
}, },
@ -159,7 +159,7 @@ describe('array field operator', function () {
test('$notMatch', async () => { test('$notMatch', async () => {
const filter2 = await Test.repository.find({ const filter2 = await Test.repository.find({
filter: { filter: {
'selected.$notMatch': [1, 2, 'a', 'b'], 'selected.$notMatch': ['1', '2', 'a', 'b'],
}, },
}); });
@ -193,6 +193,16 @@ describe('array field operator', function () {
expect(filter3[0].get('name')).toEqual(t2.get('name')); expect(filter3[0].get('name')).toEqual(t2.get('name'));
}); });
test('$anyOf with multiple items', async () => {
const filter3 = await Test.repository.find({
filter: {
'selected.$anyOf': ['aa', 'a', '1'],
},
});
expect(filter3.length).toEqual(2);
});
test('$noneOf', async () => { test('$noneOf', async () => {
const filter = await Test.repository.find({ const filter = await Test.repository.find({
filter: { filter: {
@ -204,6 +214,24 @@ describe('array field operator', function () {
expect(filter[0].get('name')).toEqual(t1.get('name')); expect(filter[0].get('name')).toEqual(t1.get('name'));
}); });
test('$noneOf with null', async () => {
const t3 = await Test.repository.create({
values: {
name: 't3',
selected: null,
},
});
const filter = await Test.repository.find({
filter: {
'selected.$noneOf': ['a', 'aa', '1'],
},
});
expect(filter.length).toEqual(1);
expect(filter[0].get('name')).toEqual(t3.get('name'));
});
test('$empty', async () => { test('$empty', async () => {
const t3 = await Test.repository.create({ const t3 = await Test.repository.create({
values: { values: {

View File

@ -12,6 +12,7 @@ export class ArrayField extends Field {
sortValue(model) { sortValue(model) {
const oldValue = model.get(this.options.name); const oldValue = model.get(this.options.name);
if (oldValue) { if (oldValue) {
const newValue = oldValue.sort(); const newValue = oldValue.sort();
model.set(this.options.name, newValue); model.set(this.options.name, newValue);

View File

@ -81,9 +81,12 @@ export default {
const fieldName = getFieldName(ctx); const fieldName = getFieldName(ctx);
if (isPg(ctx)) { if (isPg(ctx)) {
const queryValue = JSON.stringify(value).replace("'", "''"); return Sequelize.literal(
`${fieldName} ?| ${escape(
return Sequelize.literal(`${fieldName} @> ${escape(queryValue, ctx)}::JSONB`); value.map((i) => `${i}`),
ctx,
)}`,
);
} }
if (isMySQL(ctx)) { if (isMySQL(ctx)) {
@ -98,23 +101,29 @@ export default {
}, },
$noneOf(value, ctx) { $noneOf(value, ctx) {
let where;
if (isPg(ctx)) { if (isPg(ctx)) {
const fieldName = getFieldName(ctx); const fieldName = getFieldName(ctx);
// pg single quote // pg single quote
const queryValue = JSON.stringify(value).replace("'", "''"); where = Sequelize.literal(
return Sequelize.literal(`not (${fieldName} @> ${escape(queryValue, ctx)}::JSONB)`); `not (${fieldName} ?| ${escape(
} value.map((i) => `${i}`),
ctx,
if (isMySQL(ctx)) { )})`,
);
} else if (isMySQL(ctx)) {
const fieldName = getFieldName(ctx); const fieldName = getFieldName(ctx);
value = escape(JSON.stringify(value), ctx); value = escape(JSON.stringify(value), ctx);
return Sequelize.literal(`NOT JSON_OVERLAPS(${fieldName}, ${value})`); where = Sequelize.literal(`NOT JSON_OVERLAPS(${fieldName}, ${value})`);
} else {
const subQuery = sqliteExistQuery(value, ctx);
where = Sequelize.literal(`not ${subQuery}`);
} }
const subQuery = sqliteExistQuery(value, ctx);
return { return {
[Op.and]: [Sequelize.literal(`not ${subQuery}`)], [Op.or]: [where, { [Op.is]: null }],
}; };
}, },