larvitorder
Version:
Generic order system
242 lines • 10.8 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Helpers = void 0;
const uuidLib = __importStar(require("uuid"));
const topLogPrefix = 'larvitorder: helpers.ts:';
class Helpers {
constructor(options) {
this.cachedOrderFields = [];
this.cachedRowFields = [];
if (!options.db)
throw new Error('Missing required option "db"');
if (!options.log)
throw new Error('Missing required option "log"');
if (!options.lUtils)
throw new Error('Missing required option "lUtils"');
this.db = options.db;
this.log = options.log;
this.lUtils = options.lUtils;
}
async getFieldValues(options) {
if (typeof options === 'string') {
options = { fieldName: options };
}
const dbFields = [];
let sql = 'SELECT DISTINCT fieldValue\n';
sql += 'FROM orders_orders_fields\n';
sql += 'WHERE fieldUuid = (SELECT uuid FROM orders_orderFields WHERE name = ?)\n';
dbFields.push(options.fieldName);
if (options.matchAllFields) {
for (const fieldName in options.matchAllFields) {
dbFields.push(fieldName);
sql += 'AND orderUuid IN (\n';
sql += 'SELECT orderUuid\n';
sql += 'FROM orders_orders_fields\n';
if (Array.isArray(options.matchAllFields[fieldName])) {
sql += 'WHERE fieldUuid = (SELECT uuid FROM orders_orderFields WHERE name = ?) AND fieldValue IN (';
for (let i = 0; i < options.matchAllFields[fieldName].length; i++) {
dbFields.push(options.matchAllFields[fieldName][i]);
sql += '?,';
}
sql = sql.substring(0, sql.length - 1);
sql += ')\n';
}
else {
dbFields.push(options.matchAllFields[fieldName]);
sql += 'WHERE fieldUuid = (SELECT uuid FROM orders_orderFields WHERE name = ?) AND fieldValue = ?\n';
}
sql += ')';
}
}
sql += 'ORDER BY fieldValue;';
const { rows } = await this.db.query(sql, dbFields);
const names = rows.map((r) => r.fieldValue);
return names;
}
async getOrderFieldUuid(fieldName) {
const cachedOrderField = this.cachedOrderFields.find(field => field.name === fieldName);
if (cachedOrderField)
return cachedOrderField.uuid;
// If we get down here, the field does not exist, create it and rerun
const uuid = uuidLib.v1();
// NOTE: uuid is inserted as string here, it will be trunkated. Keep it as is for now to not break existing stuff.
await this.db.query('INSERT IGNORE INTO orders_orderFields (uuid, name) VALUES(?,?)', [uuid, fieldName]);
await this.loadOrderFieldsToCache();
return await this.getOrderFieldUuid(fieldName);
}
async getOrderFieldUuids(fieldNames) {
const fieldUuidsByName = {};
for (const fieldName of fieldNames) {
fieldUuidsByName[fieldName] = await this.getOrderFieldUuid(fieldName);
}
return fieldUuidsByName;
}
async getRowFieldUuid(rowFieldName) {
const logPrefix = `${topLogPrefix} getRowFieldUuid() -`;
if (rowFieldName === 'uuid') {
const err = new Error('Row field "uuid" is reserved and have no uuid');
this.log.warn(`${logPrefix} ${err.message}`);
throw err;
}
const cachedField = this.cachedRowFields.find(field => field.name === rowFieldName);
if (cachedField)
return cachedField.uuid;
// If we get down here, the field does not exist, create it and rerun
const uuid = uuidLib.v1();
// NOTE: uuid is inserted as string here, it will be trunkated. Keep it as is for now to not break existing stuff.
await this.db.query('INSERT IGNORE INTO orders_rowFields (uuid, name) VALUES(?,?)', [uuid, rowFieldName]);
await this.loadRowFieldsToCache();
return await this.getRowFieldUuid(rowFieldName);
}
async getRowFieldUuids(rowFieldNames) {
const rowFieldUuidsByName = {};
for (const rowFieldName of rowFieldNames) {
if (rowFieldName === 'uuid')
continue; // Ignore uuid
const fieldUuid = await this.getRowFieldUuid(rowFieldName);
rowFieldUuidsByName[rowFieldName] = fieldUuid;
}
return rowFieldUuidsByName;
}
async loadOrderFieldsToCache() {
const { rows } = await this.db.query('SELECT * FROM orders_orderFields ORDER BY name;');
this.cachedOrderFields = rows;
}
async loadRowFieldsToCache() {
const { rows } = await this.db.query('SELECT * FROM orders_rowFields ORDER BY name;');
this.cachedRowFields = rows;
}
isBufferEqual(b1, b2) {
if (b1.length !== b2.length)
return false;
for (let i = 0; i < b1.length; i++) {
if (b1[i] !== b2[i])
return false;
}
return true;
}
formatUuid(uuid) {
const uuidStr = this.lUtils.formatUuid(uuid);
if (typeof uuidStr === 'boolean')
throw new Error(`Failed to format uuid: "${uuid.toString()}"`);
return uuidStr;
}
uuidToBuffer(uuid) {
const uuidBuf = this.lUtils.uuidToBuffer(uuid);
if (typeof uuidBuf === 'boolean')
throw new Error(`Failed to convert uuid to buffer, uuid: "${uuid}"`);
return uuidBuf;
}
arrayify(value) {
if (value === undefined)
return undefined;
return Array.isArray(value) ? value : [value];
}
// This is only giving true for positive (including 0) integers, keps this way for backwards compatibility
isNumberIsh(value) {
return typeof value === 'number' && (value % 1) === 0;
}
isDateIsh(value) {
// value is a string representation of a date and time (e.g. "2021-01-01 00:00:00")
// This function checks if the string is a valid date and time
return !isNaN(Date.parse(value));
}
async getChangedRows(dbCon, orderUuidBuf, orderRows, rowFieldUuidsByName) {
// Get order rows
const { rows: dbRows } = await dbCon.query('SELECT rowUuid FROM orders_rows WHERE orderUuid = ?', [orderUuidBuf]);
// Get order row data
const orderRowDataQuery = 'SELECT \n' +
'rowUuid, \n' +
'rowFieldUuid, \n' +
'rowIntValue, \n' +
'rowStrValue\n' +
'FROM orders_rows_fields \n' +
'WHERE rowUuid IN ( \n' +
'SELECT rowUuid FROM orders_rows WHERE orderUuid = ? \n' +
')';
const { rows: dbOrderRowData } = await dbCon.query(orderRowDataQuery, [orderUuidBuf]);
// Compare data and remove untouched rows
const changedRows = [];
const removeRows = [];
for (const dbRowUuidBuff of dbRows.map((x) => x.rowUuid)) {
const dbRowUuid = this.formatUuid(dbRowUuidBuff);
if (!orderRows.map(x => x.uuid).includes(dbRowUuid)) {
removeRows.push({ rowUuid: dbRowUuid, rowUuidBuff: dbRowUuidBuff });
}
}
let rowAdded = false;
for (const row of orderRows) {
if (!row.uuid) {
throw new Error('Row is missing uuid, make sure it has been set before calling getChangedRows()');
}
const rowUuidBuff = this.uuidToBuffer(row.uuid);
const foundDbRows = dbOrderRowData.filter((x) => this.isBufferEqual(x.rowUuid, rowUuidBuff));
if (!foundDbRows.length) {
// New row.
changedRows.push({ rowUuid: row.uuid, rowUuidBuff: rowUuidBuff, row: row });
rowAdded = true;
continue;
}
rowAdded = false;
for (const rowFieldName of Object.keys(row)) {
if (rowAdded)
break;
if (rowFieldName === 'uuid')
continue;
const foundRowsByField = foundDbRows.filter((x) => this.isBufferEqual(x.rowFieldUuid, rowFieldUuidsByName[rowFieldName]));
if (!foundRowsByField.length) {
// New row.
changedRows.push({ rowUuid: row.uuid, rowUuidBuff: rowUuidBuff, row: row });
rowAdded = true;
break;
}
row[rowFieldName] = this.arrayify(row[rowFieldName]) ?? [];
for (const rowFieldValue of row[rowFieldName]) {
if (rowAdded)
break;
let intValue;
let strValue;
if (this.isNumberIsh(rowFieldValue)) {
intValue = rowFieldValue;
}
else {
strValue = String(rowFieldValue);
}
if (!foundRowsByField.find((x) => x.rowIntValue === (intValue !== undefined ? intValue : null)
&& x.rowStrValue === (strValue !== undefined ? strValue : null))) {
// Changed row.
changedRows.push({ rowUuid: row.uuid, rowUuidBuff: rowUuidBuff, row: row });
rowAdded = true;
break;
}
}
}
}
return { changedRows, removeRows };
}
}
exports.Helpers = Helpers;
//# sourceMappingURL=helpers.js.map