sqlite
This commit is contained in:
@@ -1,39 +1,44 @@
|
||||
import { DELETE_BY_COMPANY_AND_SI } from '../../providers/mssql/queries/unit.js';
|
||||
import { DELETE_BY_COMPANY_AND_SI as MSSQL_DELETE } from '../../providers/mssql/queries/unit.js';
|
||||
import { DELETE_BY_COMPANY_AND_SI as SQLITE_DELETE } from '../../providers/sqlite3/queries/unit.js';
|
||||
import { isForeignKeyConstraintError } from '../../providers/provider.js';
|
||||
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||
import makeRunner from '../runner.js';
|
||||
|
||||
export default function del(pool) {
|
||||
const access = resolveSelectedCompanyAccess(pool);
|
||||
export default function del(provider) {
|
||||
const access = resolveSelectedCompanyAccess(provider);
|
||||
const sql = provider?.dialect === 'sqlite3' ? SQLITE_DELETE : MSSQL_DELETE;
|
||||
|
||||
/**
|
||||
* Deletes a unit for the user's selected company by its SI code.
|
||||
*
|
||||
* @param {number} googleAuthId - The id of the Google auth user.
|
||||
* @param {string} si - The SI code of the unit to delete.
|
||||
* @param {object} [tx] - Optional transaction to run within.
|
||||
* @returns {Promise<void>}
|
||||
* @throws {Error} If the unit is not found.
|
||||
*
|
||||
* @example
|
||||
* await store.unit.delete(42, 'l');
|
||||
*/
|
||||
return async (googleAuthId, si) => {
|
||||
return async (googleAuthId, si, tx) => {
|
||||
if (!si?.trim()) {
|
||||
throw new Error('Unit not found');
|
||||
}
|
||||
|
||||
const { companyId } = await access(googleAuthId);
|
||||
const runner = makeRunner(provider, tx);
|
||||
const { companyId } = await access(googleAuthId, tx);
|
||||
|
||||
try {
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('companyId', companyId)
|
||||
.input('si', si.trim())
|
||||
.query(DELETE_BY_COMPANY_AND_SI);
|
||||
const result = await runner.query(sql, {
|
||||
companyId,
|
||||
si: si.trim(),
|
||||
});
|
||||
|
||||
if (!result.rowsAffected[0]) {
|
||||
if (!result.rowsAffected) {
|
||||
throw new Error('Unit not found');
|
||||
}
|
||||
} catch (err) {
|
||||
if (err.number === 547) {
|
||||
if (isForeignKeyConstraintError(err)) {
|
||||
throw new Error('Unit in use');
|
||||
}
|
||||
throw err;
|
||||
|
||||
@@ -1,46 +1,68 @@
|
||||
import { CREATE, GET_BY_SI } from '../../providers/mssql/queries/unit.js';
|
||||
import {
|
||||
CREATE as CREATE_UNITTEXT,
|
||||
GET_BY_UNIT_AND_LANGUAGE,
|
||||
CREATE as MSSQL_CREATE,
|
||||
GET_BY_SI as MSSQL_GET_BY_SI,
|
||||
} from '../../providers/mssql/queries/unit.js';
|
||||
import {
|
||||
CREATE as SQLITE_CREATE,
|
||||
GET_BY_SI as SQLITE_GET_BY_SI,
|
||||
} from '../../providers/sqlite3/queries/unit.js';
|
||||
import {
|
||||
CREATE as MSSQL_CREATE_UNITTEXT,
|
||||
GET_BY_UNIT_AND_LANGUAGE as MSSQL_GET_BY_UNIT_AND_LANGUAGE,
|
||||
} from '../../providers/mssql/queries/unittext.js';
|
||||
import request from '../request.js';
|
||||
import {
|
||||
CREATE as SQLITE_CREATE_UNITTEXT,
|
||||
GET_BY_UNIT_AND_LANGUAGE as SQLITE_GET_BY_UNIT_AND_LANGUAGE,
|
||||
} from '../../providers/sqlite3/queries/unittext.js';
|
||||
import makeRunner from '../runner.js';
|
||||
|
||||
const DEFAULT_SI = 'pc';
|
||||
const DEFAULT_SYMBOL = 'pc';
|
||||
const DEFAULT_NAME = 'Piece';
|
||||
|
||||
export default function ensureDefaultUnit(pool) {
|
||||
return async (tx, languageId, companyId) => {
|
||||
const existing = await request(pool, tx)
|
||||
.input('companyId', companyId)
|
||||
.input('si', DEFAULT_SI)
|
||||
.query(GET_BY_SI);
|
||||
export default function ensureDefaultUnit(provider) {
|
||||
const isSqlite = provider?.dialect === 'sqlite3';
|
||||
const getBySiSql = isSqlite ? SQLITE_GET_BY_SI : MSSQL_GET_BY_SI;
|
||||
const createSql = isSqlite ? SQLITE_CREATE : MSSQL_CREATE;
|
||||
const getUnitTextSql = isSqlite
|
||||
? SQLITE_GET_BY_UNIT_AND_LANGUAGE
|
||||
: MSSQL_GET_BY_UNIT_AND_LANGUAGE;
|
||||
const createUnitTextSql = isSqlite
|
||||
? SQLITE_CREATE_UNITTEXT
|
||||
: MSSQL_CREATE_UNITTEXT;
|
||||
|
||||
let unitId = existing.recordset[0]?.id;
|
||||
return async (tx, languageId, companyId) => {
|
||||
const runner = makeRunner(provider, tx);
|
||||
const existing = await runner.query(getBySiSql, {
|
||||
companyId,
|
||||
si: DEFAULT_SI,
|
||||
});
|
||||
|
||||
let unitId = existing.rows[0]?.id;
|
||||
|
||||
if (!unitId) {
|
||||
const created = await request(pool, tx)
|
||||
.input('companyId', companyId)
|
||||
.input('si', DEFAULT_SI)
|
||||
.input('basesi', DEFAULT_SI)
|
||||
.input('basesifactor', 1)
|
||||
.query(CREATE);
|
||||
unitId = created.recordset[0].id;
|
||||
const created = await runner.query(createSql, {
|
||||
companyId,
|
||||
si: DEFAULT_SI,
|
||||
basesi: DEFAULT_SI,
|
||||
basesifactor: 1,
|
||||
});
|
||||
unitId = created.rows[0]?.id ?? created.insertId;
|
||||
}
|
||||
|
||||
if (languageId != null) {
|
||||
const text = await request(pool, tx)
|
||||
.input('unitId', unitId)
|
||||
.input('languageId', languageId)
|
||||
.query(GET_BY_UNIT_AND_LANGUAGE);
|
||||
const text = await runner.query(getUnitTextSql, {
|
||||
unitId,
|
||||
languageId,
|
||||
});
|
||||
|
||||
if (!text.recordset[0]) {
|
||||
await request(pool, tx)
|
||||
.input('unitId', unitId)
|
||||
.input('languageId', languageId)
|
||||
.input('symbol', DEFAULT_SYMBOL)
|
||||
.input('name', DEFAULT_NAME)
|
||||
.query(CREATE_UNITTEXT);
|
||||
if (!text.rows[0]) {
|
||||
await runner.query(createUnitTextSql, {
|
||||
unitId,
|
||||
languageId,
|
||||
symbol: DEFAULT_SYMBOL,
|
||||
name: DEFAULT_NAME,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,29 +1,36 @@
|
||||
import { LIST_BY_COMPANY } from '../../providers/mssql/queries/unit.js';
|
||||
import { LIST_BY_COMPANY as MSSQL_LIST_BY_COMPANY } from '../../providers/mssql/queries/unit.js';
|
||||
import { LIST_BY_COMPANY as SQLITE_LIST_BY_COMPANY } from '../../providers/sqlite3/queries/unit.js';
|
||||
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||
import shapeUnit from './shapeUnit.js';
|
||||
import makeRunner from '../runner.js';
|
||||
|
||||
export default function list(pool) {
|
||||
const access = resolveSelectedCompanyAccess(pool);
|
||||
export default function list(provider) {
|
||||
const access = resolveSelectedCompanyAccess(provider);
|
||||
const sql =
|
||||
provider?.dialect === 'sqlite3'
|
||||
? SQLITE_LIST_BY_COMPANY
|
||||
: MSSQL_LIST_BY_COMPANY;
|
||||
|
||||
/**
|
||||
* Lists the units available for the user's selected company.
|
||||
*
|
||||
* @param {number} googleAuthId - The id of the Google auth user.
|
||||
* @param {object} [tx] - Optional transaction to run within.
|
||||
* @returns {Promise<Array<{id: number, si: string, basesi: string, basesifactor: number, symbol: string, name: string}>>} The units.
|
||||
*
|
||||
* @example
|
||||
* const units = await store.unit.list(42);
|
||||
* // => [{ id, si, basesi, basesifactor, symbol, name }]
|
||||
*/
|
||||
return async (googleAuthId) => {
|
||||
const { companyId, languageId } = await access(googleAuthId);
|
||||
return async (googleAuthId, tx) => {
|
||||
const runner = makeRunner(provider, tx);
|
||||
const { companyId, languageId } = await access(googleAuthId, tx);
|
||||
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('companyId', companyId)
|
||||
.input('languageId', languageId)
|
||||
.query(LIST_BY_COMPANY);
|
||||
const result = await runner.query(sql, {
|
||||
companyId,
|
||||
languageId,
|
||||
});
|
||||
|
||||
return result.recordset.map(shapeUnit);
|
||||
return result.rows.map(shapeUnit);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,17 +1,28 @@
|
||||
import {
|
||||
CREATE as CREATE_UNIT,
|
||||
GET_BY_SI,
|
||||
GET_FULL_BY_SI,
|
||||
UPDATE_BY_SI,
|
||||
CREATE as MSSQL_CREATE_UNIT,
|
||||
GET_BY_SI as MSSQL_GET_BY_SI,
|
||||
GET_FULL_BY_SI as MSSQL_GET_FULL_BY_SI,
|
||||
UPDATE_BY_SI as MSSQL_UPDATE_BY_SI,
|
||||
} from '../../providers/mssql/queries/unit.js';
|
||||
import {
|
||||
CREATE as CREATE_UNITTEXT,
|
||||
GET_BY_UNIT_AND_LANGUAGE,
|
||||
UPDATE_BY_UNIT_AND_LANGUAGE,
|
||||
CREATE as SQLITE_CREATE_UNIT,
|
||||
GET_BY_SI as SQLITE_GET_BY_SI,
|
||||
GET_FULL_BY_SI as SQLITE_GET_FULL_BY_SI,
|
||||
UPDATE_BY_SI as SQLITE_UPDATE_BY_SI,
|
||||
} from '../../providers/sqlite3/queries/unit.js';
|
||||
import {
|
||||
CREATE as MSSQL_CREATE_UNITTEXT,
|
||||
GET_BY_UNIT_AND_LANGUAGE as MSSQL_GET_BY_UNIT_AND_LANGUAGE,
|
||||
UPDATE_BY_UNIT_AND_LANGUAGE as MSSQL_UPDATE_BY_UNIT_AND_LANGUAGE,
|
||||
} from '../../providers/mssql/queries/unittext.js';
|
||||
import {
|
||||
CREATE as SQLITE_CREATE_UNITTEXT,
|
||||
GET_BY_UNIT_AND_LANGUAGE as SQLITE_GET_BY_UNIT_AND_LANGUAGE,
|
||||
UPDATE_BY_UNIT_AND_LANGUAGE as SQLITE_UPDATE_BY_UNIT_AND_LANGUAGE,
|
||||
} from '../../providers/sqlite3/queries/unittext.js';
|
||||
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||
import request from '../request.js';
|
||||
import shapeUnit from './shapeUnit.js';
|
||||
import makeRunner from '../runner.js';
|
||||
|
||||
function validateUnit({ si, basesi, basesifactor, symbol, name }) {
|
||||
if (!si?.trim() || !basesi?.trim() || !symbol?.trim() || !name?.trim()) {
|
||||
@@ -30,8 +41,23 @@ function validateUnit({ si, basesi, basesifactor, symbol, name }) {
|
||||
};
|
||||
}
|
||||
|
||||
export default function upsert(pool) {
|
||||
const access = resolveSelectedCompanyAccess(pool);
|
||||
export default function upsert(provider) {
|
||||
const access = resolveSelectedCompanyAccess(provider);
|
||||
const isSqlite = provider?.dialect === 'sqlite3';
|
||||
|
||||
const getBySiSql = isSqlite ? SQLITE_GET_BY_SI : MSSQL_GET_BY_SI;
|
||||
const getFullSql = isSqlite ? SQLITE_GET_FULL_BY_SI : MSSQL_GET_FULL_BY_SI;
|
||||
const createUnitSql = isSqlite ? SQLITE_CREATE_UNIT : MSSQL_CREATE_UNIT;
|
||||
const updateUnitSql = isSqlite ? SQLITE_UPDATE_BY_SI : MSSQL_UPDATE_BY_SI;
|
||||
const getUnitTextSql = isSqlite
|
||||
? SQLITE_GET_BY_UNIT_AND_LANGUAGE
|
||||
: MSSQL_GET_BY_UNIT_AND_LANGUAGE;
|
||||
const createUnitTextSql = isSqlite
|
||||
? SQLITE_CREATE_UNITTEXT
|
||||
: MSSQL_CREATE_UNITTEXT;
|
||||
const updateUnitTextSql = isSqlite
|
||||
? SQLITE_UPDATE_BY_UNIT_AND_LANGUAGE
|
||||
: MSSQL_UPDATE_BY_UNIT_AND_LANGUAGE;
|
||||
|
||||
/**
|
||||
* Creates or updates a unit for the user's selected company, keyed by its SI code.
|
||||
@@ -43,6 +69,7 @@ export default function upsert(pool) {
|
||||
* @param {number} input.basesifactor - The base SI factor (must be > 0).
|
||||
* @param {string} input.symbol - The unit symbol.
|
||||
* @param {string} input.name - The unit name.
|
||||
* @param {object} [tx] - Optional transaction to run within.
|
||||
* @returns {Promise<{id: number, si: string, basesi: string, basesifactor: number, symbol: string, name: string}>} The upserted unit.
|
||||
* @throws {Error} If the unit is invalid.
|
||||
*
|
||||
@@ -50,83 +77,79 @@ export default function upsert(pool) {
|
||||
* const unit = await store.unit.upsert(42, { si: 'l', basesi: 'm3', basesifactor: 0.001, symbol: 'L', name: 'Liter' });
|
||||
* // => { id, si, basesi, basesifactor, symbol, name }
|
||||
*/
|
||||
return async (googleAuthId, input) => {
|
||||
return async (googleAuthId, input, tx) => {
|
||||
const unit = validateUnit(input);
|
||||
const { companyId, languageId } = await access(googleAuthId);
|
||||
|
||||
const tx = pool.transaction();
|
||||
await tx.begin();
|
||||
const runUpsert = async (runner) => {
|
||||
const { companyId, languageId } = await access(googleAuthId, runner);
|
||||
|
||||
try {
|
||||
const existing = await request(pool, tx)
|
||||
.input('companyId', companyId)
|
||||
.input('si', unit.si)
|
||||
.query(GET_BY_SI);
|
||||
const existing = await runner.query(getBySiSql, {
|
||||
companyId,
|
||||
si: unit.si,
|
||||
});
|
||||
|
||||
let unitId = existing.recordset[0]?.id;
|
||||
let unitId = existing.rows[0]?.id;
|
||||
|
||||
if (!unitId) {
|
||||
const created = await request(pool, tx)
|
||||
.input('companyId', companyId)
|
||||
.input('si', unit.si)
|
||||
.input('basesi', unit.basesi)
|
||||
.input('basesifactor', unit.basesifactor)
|
||||
.query(CREATE_UNIT);
|
||||
unitId = created.recordset[0].id;
|
||||
const created = await runner.query(createUnitSql, {
|
||||
companyId,
|
||||
si: unit.si,
|
||||
basesi: unit.basesi,
|
||||
basesifactor: unit.basesifactor,
|
||||
});
|
||||
unitId = created.rows[0]?.id ?? created.insertId;
|
||||
|
||||
await request(pool, tx)
|
||||
.input('unitId', unitId)
|
||||
.input('languageId', languageId)
|
||||
.input('symbol', unit.symbol)
|
||||
.input('name', unit.name)
|
||||
.query(CREATE_UNITTEXT);
|
||||
await runner.query(createUnitTextSql, {
|
||||
unitId,
|
||||
languageId,
|
||||
symbol: unit.symbol,
|
||||
name: unit.name,
|
||||
});
|
||||
} else {
|
||||
await request(pool, tx)
|
||||
.input('companyId', companyId)
|
||||
.input('si', unit.si)
|
||||
.input('basesi', unit.basesi)
|
||||
.input('basesifactor', unit.basesifactor)
|
||||
.query(UPDATE_BY_SI);
|
||||
await runner.query(updateUnitSql, {
|
||||
companyId,
|
||||
si: unit.si,
|
||||
basesi: unit.basesi,
|
||||
basesifactor: unit.basesifactor,
|
||||
});
|
||||
|
||||
const text = await request(pool, tx)
|
||||
.input('unitId', unitId)
|
||||
.input('languageId', languageId)
|
||||
.query(GET_BY_UNIT_AND_LANGUAGE);
|
||||
const text = await runner.query(getUnitTextSql, {
|
||||
unitId,
|
||||
languageId,
|
||||
});
|
||||
|
||||
if (text.recordset[0]) {
|
||||
await request(pool, tx)
|
||||
.input('unitId', unitId)
|
||||
.input('languageId', languageId)
|
||||
.input('symbol', unit.symbol)
|
||||
.input('name', unit.name)
|
||||
.query(UPDATE_BY_UNIT_AND_LANGUAGE);
|
||||
if (text.rows[0]) {
|
||||
await runner.query(updateUnitTextSql, {
|
||||
unitId,
|
||||
languageId,
|
||||
symbol: unit.symbol,
|
||||
name: unit.name,
|
||||
});
|
||||
} else {
|
||||
await request(pool, tx)
|
||||
.input('unitId', unitId)
|
||||
.input('languageId', languageId)
|
||||
.input('symbol', unit.symbol)
|
||||
.input('name', unit.name)
|
||||
.query(CREATE_UNITTEXT);
|
||||
await runner.query(createUnitTextSql, {
|
||||
unitId,
|
||||
languageId,
|
||||
symbol: unit.symbol,
|
||||
name: unit.name,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await tx.commit();
|
||||
} catch (err) {
|
||||
try {
|
||||
await tx.rollback();
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
throw err;
|
||||
const full = await runner.query(getFullSql, {
|
||||
companyId,
|
||||
si: unit.si,
|
||||
languageId,
|
||||
});
|
||||
|
||||
return shapeUnit(full.rows[0]);
|
||||
};
|
||||
|
||||
if (tx) {
|
||||
return runUpsert(makeRunner(provider, tx));
|
||||
}
|
||||
|
||||
const result = await pool
|
||||
.request()
|
||||
.input('companyId', companyId)
|
||||
.input('si', unit.si)
|
||||
.input('languageId', languageId)
|
||||
.query(GET_FULL_BY_SI);
|
||||
|
||||
return shapeUnit(result.recordset[0]);
|
||||
if (typeof provider?.transaction === 'function') {
|
||||
return provider.transaction(runUpsert);
|
||||
}
|
||||
return runUpsert(makeRunner(provider));
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user