Skip to content

Commit

Permalink
feat: fts params for units
Browse files Browse the repository at this point in the history
  • Loading branch information
mkeen committed Jan 12, 2022
1 parent 2b2ea18 commit 20e3236
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 22 deletions.
6 changes: 5 additions & 1 deletion migrations/20211212200953-fulltext-search.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,22 @@ module.exports = {
await queryInterface.sequelize.query(`
CREATE VIRTUAL TABLE units_fts USING fts5(
warehouseUnitId,
orgUid,
unitOwnerOrgUid,
countryJuridictionOfOwner,
inCountryJuridictionOfOwner,
serialNumberBlock,
unitIdentifier,
unitType,
intendedBuyerOrgUid,
marketplace,
tags,
inCountryJuridictionOfOwner,
unitStatus,
unitTransactionType,
unitStatusReason,
tokenIssuanceHash,
marketplaceIdentifier,
unitsIssuanceLocation,
unitRegistryLink,
unitMarketplaceLink,
cooresponingAdjustmentDeclaration,
Expand Down
32 changes: 26 additions & 6 deletions migrations/20211219184405-sqlite-triggers-units.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,44 @@ module.exports = {
CREATE TRIGGER unit_insert_fts AFTER INSERT ON units BEGIN
INSERT INTO units_fts(
warehouseUnitId,
orgUid,
unitOwnerOrgUid,
countryJuridictionOfOwner,
inCountryJuridictionOfOwner,
serialNumberBlock,
unitIdentifier,
unitType,
intendedBuyerOrgUid,
marketplace,
tags,
inCountryJuridictionOfOwner,
unitStatus,
unitTransactionType,
unitStatusReason,
tokenIssuanceHash,
marketplaceIdentifier,
unitsIssuanceLocation,
unitRegistryLink,
unitMarketplaceLink,
cooresponingAdjustmentDeclaration,
correspondingAdjustmentStatus
) VALUES (
new.warehouseUnitId,
new.orgUid,
new.unitOwnerOrgUid,
new.countryJuridictionOfOwner,
new.inCountryJuridictionOfOwner,
new.serialNumberBlock,
new.unitIdentifier,
new.unitType,
new.intendedBuyerOrgUid,
new.marketplace,
new.tags,
new.inCountryJuridictionOfOwner,
new.unitStatus,
new.unitTransactionType,
new.unitStatusReason,
new.tokenIssuanceHash,
new.marketplaceIdentifier,
new.unitsIssuanceLocation,
new.unitRegistryLink,
new.unitMarketplaceLink,
new.cooresponingAdjustmentDeclaration,
Expand All @@ -55,40 +63,52 @@ module.exports = {
DELETE FROM units_fts WHERE warehouseUnitId = old.warehouseUnitId;
INSERT INTO units_fts(
warehouseUnitId,
orgUid,
unitOwnerOrgUid,
countryJuridictionOfOwner,
inCountryJuridictionOfOwner,
serialNumberBlock,
unitIdentifier,
unitType,
intendedBuyerOrgUid,
marketplace,
tags,
inCountryJuridictionOfOwner,
unitStatus,
unitTransactionType,
unitStatusReason,
tokenIssuanceHash,
marketplaceIdentifier,
unitsIssuanceLocation,
unitRegistryLink,
unitMarketplaceLink,
cooresponingAdjustmentDeclaration,
correspondingAdjustmentStatus
correspondingAdjustmentStatus,
createdAt,
updatedAt
) VALUES (
new.warehouseUnitId,
new.orgUid,
new.unitOwnerOrgUid,
new.countryJuridictionOfOwner,
new.inCountryJuridictionOfOwner,
new.serialNumberBlock,
new.unitIdentifier,
new.unitType,
new.intendedBuyerOrgUid,
new.marketplace,
new.tags,
new.inCountryJuridictionOfOwner,
new.unitStatus,
new.unitTransactionType,
new.unitStatusReason,
new.tokenIssuanceHash,
new.marketplaceIdentifier,
new.unitsIssuanceLocation,
new.unitRegistryLink,
new.unitMarketplaceLink,
new.cooresponingAdjustmentDeclaration,
new.correspondingAdjustmentStatus
new.correspondingAdjustmentStatus,
new.createdAt,
new.updatedAt
);
END;
`);
Expand Down
37 changes: 23 additions & 14 deletions src/controllers/units.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export const create = async (req, res, next) => {
};

export const findAll = async (req, res) => {
let { page, limit, columns, orgUid } = req.query;
let { page, limit, columns, orgUid, search } = req.query;
let where = orgUid ? { orgUid } : undefined;

const includes = [Qualification];
Expand All @@ -76,19 +76,28 @@ export const findAll = async (req, res) => {
if (!columns.length) {
columns = ['warehouseUnitId'];
}

res.json(
optionallyPaginatedResponse(
await Unit.findAndCountAll({
where,
distinct: true,
...columnsToInclude(columns, includes),
...paginationParams(page, limit),
}),
page,
limit,
),
);

let results;

if (search) {
results = await Unit.fts(
search,
orgUid,
paginationParams(page, limit),
columns,
);
}

if (!results) {
results = await Unit.findAndCountAll({
where,
distinct: true,
...columnsToInclude(columns, includes),
...paginationParams(page, limit),
});
}

res.json(optionallyPaginatedResponse(results, page, limit));
};

export const findOne = async (req, res) => {
Expand Down
126 changes: 125 additions & 1 deletion src/models/units/units.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import Sequelize from 'sequelize';
import { sequelize } from '../database';
import { Qualification, Vintage } from '../../models';
import {CoBenefit, ProjectLocation, Qualification, RelatedProject, Vintage} from '../../models';
import ModelTypes from './units.modeltypes.cjs';
import rxjs from 'rxjs';

Expand Down Expand Up @@ -71,6 +71,130 @@ class Unit extends Model {

return super.destroy(values);
}

static async fts(searchStr, orgUid, pagination, columns = []) {
const dialect = sequelize.getDialect();

const handlerMap = {
sqlite: Unit.findAllSqliteFts,
mysql: Unit.findAllMySQLFts,
};

return handlerMap[dialect](
searchStr,
orgUid,
pagination,
columns
.filter((col) => ![
'createdAt',
'updatedAt',
'unitBlockStart',
'unitBlockEnd',
'unitCount'].includes(col))
);
}

static async findAllMySQLFts(searchStr, orgUid, pagination, columns = []) {
const { offset, limit } = pagination;

let fields = '*';
if (columns.length) {
fields = columns.join(', ');
}

let sql = `
SELECT ${fields} FROM units WHERE MATCH (
unitOwnerOrgUid,
countryJuridictionOfOwner,
inCountryJuridictionOfOwner,
serialNumberBlock,
unitIdentifier,
unitType,
intendedBuyerOrgUid,
marketplace,
tags,
unitStatus,
unitTransactionType,
unitStatusReason,
tokenIssuanceHash,
marketplaceIdentifier,
unitsIssuanceLocation,
unitRegistryLink,
unitMarketplaceLink,
cooresponingAdjustmentDeclaration,
correspondingAdjustmentStatus
) AGAINST ":search"
`;

if (orgUid) {
sql = `${sql} AND orgUid = :orgUid`;
}

const replacements = { search: searchStr, orgUid };

const count = (
await sequelize.query(sql, {
model: Unit,
mapToModel: true, // pass true here if you have any mapped fields
replacements,
})
).length;

if (limit && offset) {
sql = `${sql} ORDER BY relevance DESC LIMIT :limit OFFSET :offset`;
}

return {
count,
rows: await sequelize.query(sql, {
model: Unit,
replacements: { ...replacements, ...{ offset, limit } },
mapToModel: true, // pass true here if you have any mapped fields
offset,
limit,
}),
};
}

static async findAllSqliteFts(searchStr, orgUid, pagination, columns = []) {
const { offset, limit } = pagination;

let fields = '*';
if (columns.length) {
fields = columns.join(', ');
}

searchStr = searchStr = searchStr.replaceAll('-', '+');

let sql = `SELECT ${fields} FROM units_fts WHERE units_fts MATCH :search`;

if (orgUid) {
sql = `${sql} AND orgUid = :orgUid`;
}

const replacements = { search: `${searchStr}*`, orgUid };

const count = (
await sequelize.query(sql, {
model: Unit,
mapToModel: true, // pass true here if you have any mapped fields
replacements,
})
).length;

if (limit && offset) {
sql = `${sql} ORDER BY rank DESC LIMIT :limit OFFSET :offset`;
}

return {
count,
rows: await sequelize.query(sql, {
model: Unit,
mapToModel: true, // pass true here if you have any mapped fields
replacements: { ...replacements, ...{ offset, limit } },
}),
};
}
}

Unit.init(Object.assign({}, ModelTypes, virtualColumns), {
Expand Down

0 comments on commit 20e3236

Please sign in to comment.