UNPKG

larvitorder

Version:
441 lines 18.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Orders = void 0; const larvitutils_1 = require("larvitutils"); const helpers_1 = require("./helpers"); class Orders { constructor(options) { if (!options?.db) throw new Error('Missing required option "db"'); this.db = options.db; this.log = options.log ?? new larvitutils_1.Log(); this.lUtils = options.lUtils ?? new larvitutils_1.Utils(); this.helpers = options.helpers ?? new helpers_1.Helpers({ db: this.db, log: this.log, lUtils: this.lUtils, }); this.uuids = this.helpers.arrayify(options.uuids); this.matchDates = options.matchDates; this.matchFieldDates = options.matchFieldDates; this.createdAfter = options.createdAfter; this.updatedAfter = options.updatedAfter; this.matchFieldHasValue = options.matchFieldHasValue; this.matchFieldHasNoValue = options.matchFieldHasNoValue; this.q = options.q; this.matchAllFields = options.matchAllFields; this.fieldNotEqualTo = options.fieldNotEqualTo; this.fieldGreaterThanOrEqualTo = options.fieldGreaterThanOrEqualTo; this.fieldLessThanOrEqualTo = options.fieldLessThanOrEqualTo; this.matchAllRowFields = options.matchAllRowFields; this.limit = options.limit; this.offset = options.offset; this.returnFields = options.returnFields; this.returnRowFields = options.returnRowFields; } async get() { // Get basic orders and total hits const { orders, hits } = await this.getBasicOrders(); // Get fields await this.getAndPopulateOrderFields(orders); // Get rows await this.getAndPopulateOrderRows(orders); return { orders, hits }; } async getBasicOrders() { const orders = {}; // Create sql with filters let sql = ' FROM orders WHERE 1'; let dbFields = []; ({ sql, dbFields } = this.concatSqlUuidsFilter(sql, dbFields)); ({ sql, dbFields } = this.concatSqlCreatedAfterFilter(sql, dbFields)); ({ sql, dbFields } = this.concatSqlUpdatedAfterFilter(sql, dbFields)); ({ sql, dbFields } = await this.concatSqlDateFilter(sql, dbFields)); ({ sql, dbFields } = await this.concatSqlFieldDateFilter(sql, dbFields)); ({ sql, dbFields } = this.concatSqlQFilter(sql, dbFields)); ({ sql, dbFields } = this.concatSqlMatchAllFilter(sql, dbFields)); ({ sql, dbFields } = this.concatSqlFieldNotEqualToFilter(sql, dbFields)); ({ sql, dbFields } = this.concatSqlFieldGreaterThanOrEqualToFilter(sql, dbFields)); ({ sql, dbFields } = this.concatSqlFieldLessThanOrEqualToFilter(sql, dbFields)); ({ sql, dbFields } = this.concatSqlFieldHasValue(sql, dbFields)); ({ sql, dbFields } = this.concatSqlFieldHasNoValue(sql, dbFields)); ({ sql, dbFields } = this.concatSqlMatchAllRowsFieldsFilter(sql, dbFields)); sql += ' ORDER BY created DESC'; // Hits sql without limit and offset const hitsSql = 'SELECT COUNT(*) AS hits' + sql; // Finalize sql with limit, offset and select sql = this.concatSqlLimitAndOffset(sql); sql = 'SELECT *' + sql; // Query db let hits = 0; const queryOrders = async () => { const { rows } = await this.db.query(sql, dbFields); for (const row of rows) { const uuid = this.helpers.formatUuid(row.uuid); orders[uuid] = { uuid, created: row.created, updated: row.updated, fields: {}, rows: [], }; } }; const queryOrderCount = async () => { const { rows } = await this.db.query(hitsSql, dbFields); hits = rows[0].hits; }; await Promise.all([queryOrders(), queryOrderCount()]); return { orders, hits }; } concatSqlUuidsFilter(sql, dbFields) { if (!this.uuids) return { sql, dbFields }; // Match nothing if uuids is empty array if (!this.uuids.length) { sql += ' AND 0'; return { sql, dbFields }; } // Match against uuids sql += ' AND uuid IN ('; for (const uuid of this.uuids) { const buffer = this.helpers.uuidToBuffer(uuid); sql += '?,'; dbFields.push(buffer); } sql = sql.substring(0, sql.length - 1) + ')'; return { sql, dbFields }; } concatSqlCreatedAfterFilter(sql, dbFields) { if (!this.createdAfter) return { sql, dbFields }; if (!this.helpers.isDateIsh(this.createdAfter)) { sql += ' AND created IS NULL'; return { sql, dbFields }; } sql += ' AND created >= ?'; dbFields.push(this.createdAfter); return { sql, dbFields }; } concatSqlUpdatedAfterFilter(sql, dbFields) { if (!this.updatedAfter) return { sql, dbFields }; if (!this.helpers.isDateIsh(this.updatedAfter)) { sql += ' AND created IS NULL'; return { sql, dbFields }; } sql += ' AND updated >= ?'; dbFields.push(this.updatedAfter); return { sql, dbFields }; } async concatSqlDateFilter(sql, dbFields) { if (!this.matchDates || !this.matchDates.length) return { sql, dbFields }; const dbCon = await this.db.getConnection(); try { // Check headerDates for (const matchExistingDate of this.matchDates) { const operation = matchExistingDate.operation || 'eq'; const value = matchExistingDate.value; const field = matchExistingDate.field; if (!value) continue; if (!field) continue; if (['eq', 'gt', 'lt'].indexOf(operation) === -1) continue; sql += ' AND ' + dbCon.escapeId(field); if (operation === 'eq') sql += ' = CAST(? AS DATETIME)\n'; else if (operation === 'gt') sql += ' > CAST(? AS DATETIME)\n'; else if (operation === 'lt') sql += ' < CAST(? AS DATETIME)\n'; dbFields.push(value); } } finally { dbCon.release(); } return { sql, dbFields }; } async concatSqlFieldDateFilter(sql, dbFields) { if (!this.matchFieldDates || !this.matchFieldDates.length) return { sql, dbFields }; // Check field dates for (const matchExistingDate of this.matchFieldDates) { const operation = matchExistingDate.operation || 'eq'; const value = matchExistingDate.value; const field = matchExistingDate.field; if (!value) continue; if (!field) continue; if (['eq', 'gt', 'lt'].indexOf(operation) === -1) continue; dbFields.push(field); dbFields.push(value); sql += ' AND orders.uuid IN (\n'; sql += ' SELECT DISTINCT orderUuid\n'; sql += ' FROM orders_orders_fields\n'; sql += ' WHERE fieldUuid = (SELECT uuid FROM orders_orderFields WHERE name = ?)\n'; if (operation === 'eq') sql += ' AND CAST(fieldValue AS DATETIME) = CAST(? AS DATETIME)\n'; else if (operation === 'gt') sql += ' AND CAST(fieldValue AS DATETIME) > CAST(? AS DATETIME)\n'; else if (operation === 'lt') sql += ' AND CAST(fieldValue AS DATETIME) < CAST(? AS DATETIME)\n'; sql += ')'; } return { sql, dbFields }; } concatSqlQFilter(sql, dbFields) { if (this.q === undefined) { return { sql, dbFields }; } sql += ' AND (\n'; sql += ' (\n'; sql += ' uuid IN (SELECT DISTINCT orderUuid FROM orders_orders_fields WHERE MATCH (fieldValue) AGAINST (?))\n'; sql += ' )\n'; dbFields.push('"' + this.q + '"'); sql += ' OR uuid IN (\n'; sql += ' SELECT DISTINCT orderUuid\n'; sql += ' FROM orders_rows WHERE rowUuid IN (\n'; sql += ' SELECT rowUuid FROM orders_rows_fields WHERE MATCH (rowStrValue) AGAINST (?)\n'; sql += ' )\n'; sql += ' )\n'; dbFields.push('"' + this.q + '"'); sql += ' )\n'; return { sql, dbFields }; } concatSqlMatchAllFilter(sql, dbFields) { if (this.matchAllFields === undefined) { return { sql, dbFields }; } for (const fieldName in this.matchAllFields) { dbFields.push(fieldName); sql += ' AND orders.uuid IN (\n'; sql += ' SELECT DISTINCT orderUuid\n'; sql += ' FROM orders_orders_fields\n'; if (Array.isArray(this.matchAllFields[fieldName])) { sql += ' WHERE fieldUuid = (SELECT uuid FROM orders_orderFields WHERE name = ?) AND fieldValue IN ('; for (const fieldValue of this.matchAllFields[fieldName]) { dbFields.push(fieldValue); sql += '?,'; } sql = sql.substring(0, sql.length - 1); sql += ')\n'; } else { dbFields.push(this.matchAllFields[fieldName]); sql += ' WHERE fieldUuid = (SELECT uuid FROM orders_orderFields WHERE name = ?) AND fieldValue = ?\n'; } sql += ')'; } return { sql, dbFields }; } concatSqlFieldNotEqualToFilter(sql, dbFields) { if (this.fieldNotEqualTo === undefined) { return { sql, dbFields }; } for (const fieldName in this.fieldNotEqualTo) { sql += ' AND orders.uuid NOT IN (\n'; sql += ' SELECT DISTINCT orderUuid\n'; sql += ' FROM orders_orders_fields\n'; sql += ' WHERE fieldUuid = (SELECT uuid FROM orders_orderFields WHERE name = ?) AND fieldValue = ?\n'; sql += ')'; dbFields.push(fieldName); dbFields.push(this.fieldNotEqualTo[fieldName]); } return { sql, dbFields }; } concatSqlFieldGreaterThanOrEqualToFilter(sql, dbFields) { if (this.fieldGreaterThanOrEqualTo === undefined) { return { sql, dbFields }; } for (const fieldName in this.fieldGreaterThanOrEqualTo) { sql += ' AND orders.uuid IN (\n'; sql += ' SELECT DISTINCT orderUuid\n'; sql += ' FROM orders_orders_fields\n'; sql += ' WHERE fieldUuid = (SELECT uuid FROM orders_orderFields WHERE name = ?) AND fieldValue >= ?\n'; sql += ')'; dbFields.push(fieldName); dbFields.push(this.fieldGreaterThanOrEqualTo[fieldName]); } return { sql, dbFields }; } concatSqlFieldLessThanOrEqualToFilter(sql, dbFields) { if (this.fieldLessThanOrEqualTo === undefined) { return { sql, dbFields }; } for (const fieldName in this.fieldLessThanOrEqualTo) { sql += ' AND orders.uuid IN (\n'; sql += ' SELECT DISTINCT orderUuid\n'; sql += ' FROM orders_orders_fields\n'; sql += ' WHERE fieldUuid = (SELECT uuid FROM orders_orderFields WHERE name = ?) AND fieldValue <= ?\n'; sql += ')'; dbFields.push(fieldName); dbFields.push(this.fieldLessThanOrEqualTo[fieldName]); } return { sql, dbFields }; } concatSqlFieldHasValue(sql, dbFields) { if (!this.matchFieldHasValue || !this.matchFieldHasValue.length) return { sql, dbFields }; for (const matchFieldHasValue of this.matchFieldHasValue) { sql += ' AND orders.uuid IN (\n'; sql += ' SELECT orderUuid FROM orders_orders_fields WHERE fieldUuid IN (\n'; sql += ' SELECT uuid FROM orders_orderFields WHERE\n'; sql += ' name = ?\n'; sql += ' )\n'; sql += ' AND fieldValue IS NOT NULL AND fieldValue != ""\n'; sql += ' )\n'; dbFields.push(matchFieldHasValue); } return { sql, dbFields }; } concatSqlFieldHasNoValue(sql, dbFields) { if (!this.matchFieldHasNoValue || !this.matchFieldHasNoValue.length) return { sql, dbFields }; sql += ' AND (\n'; sql += ' orders.uuid IN (\n'; sql += ' SELECT orderUuid FROM orders_orders_fields WHERE fieldUuid IN (\n'; sql += ' SELECT uuid FROM orders_orderFields WHERE\n'; for (const matchFieldHasNoValue of this.matchFieldHasNoValue) { sql += 'name = ? OR '; dbFields.push(matchFieldHasNoValue); } sql = sql.substring(0, sql.length - 4); sql += ' )\n'; sql += ' AND (fieldValue IS NULL OR fieldValue = "")\n'; sql += ' )\n'; sql += ' OR (\n'; sql += ' orders.uuid NOT IN (\n'; sql += ' SELECT orderUuid FROM orders_orders_fields WHERE fieldUuid IN (\n'; sql += ' SELECT uuid FROM orders_orderFields WHERE\n'; for (const matchFieldHasNoValue of this.matchFieldHasNoValue) { sql += 'name = ? OR '; dbFields.push(matchFieldHasNoValue); } sql = sql.substring(0, sql.length - 4); sql += ' )\n'; sql += ' )\n'; sql += ' )\n'; sql += ')\n'; return { sql, dbFields }; } concatSqlMatchAllRowsFieldsFilter(sql, dbFields) { if (this.matchAllRowFields === undefined) { return { sql, dbFields }; } for (const rowFieldName in this.matchAllRowFields) { sql += ' AND orders.uuid IN (\n'; sql += ' SELECT DISTINCT orderUuid\n'; sql += ' FROM orders_rows\n'; sql += ' WHERE rowUuid IN (\n'; sql += ' SELECT rowUuid FROM orders_rows_fields WHERE rowFieldUuid = (SELECT uuid FROM orders_rowFields WHERE name = ?) AND '; if (this.helpers.isNumberIsh(this.matchAllRowFields[rowFieldName])) { sql += 'rowIntValue = ?\n'; } else { sql += 'rowStrValue = ?\n'; } sql += ' )'; sql += ')'; dbFields.push(rowFieldName); dbFields.push(this.matchAllRowFields[rowFieldName]); } return { sql, dbFields }; } concatSqlLimitAndOffset(sql) { if (this.limit) { sql += ` LIMIT ${Number(this.limit)}`; if (this.offset) { sql += ` OFFSET ${Number(this.offset)}`; } } return sql; } async getAndPopulateOrderFields(orders) { var _a, _b; if (!this.returnFields || !Object.keys(orders).length) return; const dbFields = []; let sql; sql = 'SELECT orderUuid, name AS fieldName, fieldValue\n'; sql += 'FROM orders_orders_fields JOIN orders_orderFields ON fieldUuid = uuid\n'; sql += 'WHERE\n'; sql += ' orderUuid IN ('; for (const orderUuid in orders) { const buffer = this.helpers.uuidToBuffer(orderUuid); sql += '?,'; dbFields.push(buffer); } sql = sql.substring(0, sql.length - 1) + ')\n'; sql += ' AND name IN ('; for (const returnField of this.returnFields) { sql += '?,'; dbFields.push(returnField); } sql = sql.substring(0, sql.length - 1) + ')\n'; const { rows: dbRows } = await this.db.query(sql, dbFields); for (const dbRow of dbRows) { const orderUuid = this.helpers.formatUuid(dbRow.orderUuid); const order = orders[orderUuid]; if (!order) throw new Error(`Order field mismatch, got unexpected field for order uuid: "${orderUuid}", sql: ${sql}, dbFields: ${JSON.stringify(dbFields)}`); order.fields ?? (order.fields = {}); (_a = order.fields)[_b = dbRow.fieldName] ?? (_a[_b] = []); order.fields[dbRow.fieldName].push(dbRow.fieldValue); } } async getAndPopulateOrderRows(orders) { var _a; const dbFields = []; if (!this.returnRowFields || !Object.keys(orders).length) return; let sql; sql = 'SELECT r.orderUuid, r.rowUuid, f.name AS fieldName, rf.rowIntValue, rf.rowStrValue\n'; sql += 'FROM orders_rows r\n'; sql += ' LEFT JOIN orders_rows_fields rf ON rf.rowUuid = r.rowUuid\n'; sql += ' LEFT JOIN orders_rowFields f ON f.uuid = rf.rowFieldUuid\n'; sql += 'WHERE r.orderUuid IN ('; for (const orderUuid in orders) { const buffer = this.helpers.uuidToBuffer(orderUuid); sql += '?,'; dbFields.push(buffer); } sql = sql.substring(0, sql.length - 1) + ')'; sql += ' AND f.name IN ('; for (const returnRowField of this.returnRowFields) { sql += '?,'; dbFields.push(returnRowField); } sql = sql.substring(0, sql.length - 1) + ')'; const { rows: dbRows } = await this.db.query(sql, dbFields); for (const dbRow of dbRows) { const orderUuid = this.helpers.formatUuid(dbRow.orderUuid); const rowUuid = this.helpers.formatUuid(dbRow.rowUuid); const order = orders[orderUuid]; if (!order) throw new Error(`Order field mismatch, got unexpected rows for order uuid: "${orderUuid}", sql: ${sql}, dbFields: ${JSON.stringify(dbFields)}`); order.rows ?? (order.rows = []); let row = order.rows.find(r => r.uuid === rowUuid); if (!row) { row = { uuid: rowUuid, }; order.rows.push(row); } row[_a = dbRow.fieldName] ?? (row[_a] = []); if (dbRow.rowIntValue !== null) { row[dbRow.fieldName].push(dbRow.rowIntValue); } else if (dbRow.rowStrValue !== null) { row[dbRow.fieldName].push(dbRow.rowStrValue); } } } } exports.Orders = Orders; //# sourceMappingURL=orders.js.map