Skip to content

Commit

Permalink
Merge pull request #132 from UN-OCHA/HPC-8569-flow-list
Browse files Browse the repository at this point in the history
HPC-8569: Add `legacy` model
  • Loading branch information
Pl217 authored Mar 20, 2024
2 parents 509f4e5 + 9c158ee commit c119045
Show file tree
Hide file tree
Showing 3 changed files with 264 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/db/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import iatiRecipientCountry from './models/iatiRecipientCountry';
import iatiTransaction from './models/iatiTransaction';
import job from './models/job';
import jobAssociation from './models/jobAssociation';
import legacy from './models/legacy';
import location from './models/location';
import lookup from './models/lookup';
import measurement from './models/measurement';
Expand Down Expand Up @@ -164,6 +165,7 @@ const initializeTables = (conn: Knex) => ({
iatiTransaction: iatiTransaction(conn),
job: job(conn),
jobAssociation: jobAssociation(conn),
legacy: legacy(conn),
location: location(conn),
lookup: lookup(conn),
measurement: measurement(conn),
Expand Down
16 changes: 16 additions & 0 deletions src/db/models/legacy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as t from 'io-ts';

import { defineSequelizeModel } from '../util/sequelize-model';
import { FLOW_OBJECT_TYPE_TYPE } from './flowObjectType';

export default defineSequelizeModel({
tableName: 'legacy',
fields: {
required: {
objectType: { kind: 'checked', type: FLOW_OBJECT_TYPE_TYPE },
objectID: { kind: 'checked', type: t.number },
legacyID: { kind: 'checked', type: t.number },
},
},
softDeletionEnabled: false,
});
246 changes: 246 additions & 0 deletions tests/db/conditions.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
import ContextProvider from '../testContext';

import { Cond, Op, prepareCondition } from '../../src/db/util/conditions';

const context = ContextProvider.Instance;

describe('prepareCondition', () => {
type ExampleType = {
id: number;
name: string;
};

it('empty where clause', () => {
const q = context.conn.queryBuilder();
q.where(prepareCondition<ExampleType>({}));
expect(q.toQuery()).toEqual('select *');
});

it('undefined property equality', () => {
const q = context.conn.queryBuilder();
q.where(
prepareCondition<ExampleType>({
id: undefined,
})
);
expect(() => q.toQuery()).toThrowError('Unexpected undefined value for id');
});

it('single property equality', () => {
const q = context.conn.queryBuilder();
q.where(
prepareCondition<ExampleType>({
id: 123,
})
);
expect(q.toQuery()).toEqual('select * where ("id" = 123)');
});

it('single property in list', () => {
const q = context.conn.queryBuilder();
q.where(
prepareCondition<ExampleType>({
id: {
[Op.IN]: [123, 456],
},
})
);
expect(q.toQuery()).toEqual('select * where ("id" in (123, 456))');
});

it('single property not in list', () => {
const q = context.conn.queryBuilder();
q.where(
prepareCondition<ExampleType>({
id: {
[Op.NOT_IN]: [123, 456],
},
})
);
expect(q.toQuery()).toEqual('select * where ("id" not in (123, 456))');
});

it('single property is null', () => {
const q = context.conn.queryBuilder();
q.where(
prepareCondition<ExampleType>({
name: {
[Op.IS_NULL]: true,
},
})
);
expect(q.toQuery()).toEqual('select * where ("name" is null)');
});

it('single property is not null', () => {
const q = context.conn.queryBuilder();
q.where(
prepareCondition<ExampleType>({
name: {
[Op.IS_NULL]: false,
},
})
);
expect(q.toQuery()).toEqual('select * where ("name" is not null)');
});

it('single property between', () => {
const q = context.conn.queryBuilder();
q.where(
prepareCondition<ExampleType>({
id: {
[Op.BETWEEN]: [123, 456],
},
})
);
expect(q.toQuery()).toEqual('select * where ("id" between 123 and 456)');
});

it('single property like', () => {
const q = context.conn.queryBuilder();
q.where(
prepareCondition<ExampleType>({
name: {
[Op.LIKE]: '%abc%',
},
})
);
expect(q.toQuery()).toEqual('select * where ("name" like \'%abc%\')');
});

it('single property ilike', () => {
const q = context.conn.queryBuilder();
q.where(
prepareCondition<ExampleType>({
name: {
[Op.ILIKE]: '%abc%',
},
})
);
expect(q.toQuery()).toEqual('select * where ("name" ilike \'%abc%\')');
});

it('single property <', () => {
const q = context.conn.queryBuilder();
q.where(
prepareCondition<ExampleType>({
id: {
[Op.LT]: 123,
},
})
);
expect(q.toQuery()).toEqual('select * where ("id" < 123)');
});

it('single property <=', () => {
const q = context.conn.queryBuilder();
q.where(
prepareCondition<ExampleType>({
id: {
[Op.LTE]: 123,
},
})
);
expect(q.toQuery()).toEqual('select * where ("id" <= 123)');
});

it('single property >', () => {
const q = context.conn.queryBuilder();
q.where(
prepareCondition<ExampleType>({
id: {
[Op.GT]: 123,
},
})
);
expect(q.toQuery()).toEqual('select * where ("id" > 123)');
});

it('single property >', () => {
const q = context.conn.queryBuilder();
q.where(
prepareCondition<ExampleType>({
id: {
[Op.GTE]: 123,
},
})
);
expect(q.toQuery()).toEqual('select * where ("id" >= 123)');
});

it('multiple properties', () => {
const q = context.conn.queryBuilder();
q.where(
prepareCondition<ExampleType>({
name: 'foo',
id: {
[Op.NOT_IN]: [123, 456],
},
})
);
expect(q.toQuery()).toEqual(
'select * where ("name" = \'foo\' and "id" not in (123, 456))'
);
});

it('with builder', () => {
const q = context.conn.queryBuilder();
q.where(
prepareCondition<ExampleType>({
[Cond.BUILDER]: (qb) => qb.whereNull('name'),
})
);
expect(q.toQuery()).toEqual('select * where (("name" is null))');
});

it('disjunction with multiple properties and builder', () => {
const q = context.conn.queryBuilder();
q.where(
prepareCondition<ExampleType>({
[Cond.OR]: [
{
name: 'foo',
id: {
[Op.NOT_IN]: [123, 456, 123],
},
},
{
[Cond.BUILDER]: (qb) => qb.whereNull('name'),
},
],
})
);
expect(q.toQuery()).toEqual(
'select * where (("name" = \'foo\' and "id" not in (123, 456, 123)) or (("name" is null)))'
);
});

it('disjunction with conjunction and multiple properties and builder', () => {
const q = context.conn.queryBuilder();
q.where(
prepareCondition<ExampleType>({
[Cond.OR]: [
{
name: 'foo',
id: {
[Op.NOT_IN]: [123, 456],
},
},
{
[Cond.AND]: [
{
[Cond.BUILDER]: (qb) => qb.whereNull('name'),
},
{
[Cond.BUILDER]: (qb) => qb.whereNotNull('id'),
},
],
},
],
})
);
expect(q.toQuery()).toEqual(
'select * where (("name" = \'foo\' and "id" not in (123, 456)) or ((("name" is null)) and (("id" is not null))))'
);
});
});

0 comments on commit c119045

Please sign in to comment.