u
This commit is contained in:
78
src/store/brand/create.js
Normal file
78
src/store/brand/create.js
Normal file
@@ -0,0 +1,78 @@
|
||||
import {
|
||||
CREATE as MSSQL_CREATE,
|
||||
GET_BY_COMPANY_AND_NAME as MSSQL_GET_BY_COMPANY_AND_NAME,
|
||||
} from '../../providers/mssql/queries/brand.js';
|
||||
import {
|
||||
CREATE as SQLITE_CREATE,
|
||||
GET_BY_COMPANY_AND_NAME as SQLITE_GET_BY_COMPANY_AND_NAME,
|
||||
} from '../../providers/sqlite3/queries/brand.js';
|
||||
import { isUniqueConstraintError } from '../../providers/provider.js';
|
||||
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||
import makeRunner from '../runner.js';
|
||||
|
||||
export default function create(provider) {
|
||||
const access = resolveSelectedCompanyAccess(provider);
|
||||
const isSqlite = provider?.dialect === 'sqlite3';
|
||||
const createSql = isSqlite ? SQLITE_CREATE : MSSQL_CREATE;
|
||||
const getSql = isSqlite
|
||||
? SQLITE_GET_BY_COMPANY_AND_NAME
|
||||
: MSSQL_GET_BY_COMPANY_AND_NAME;
|
||||
|
||||
/**
|
||||
* Creates a brand for the user's selected company.
|
||||
*
|
||||
* @param {number} googleAuthId - The id of the Google auth user.
|
||||
* @param {object} input - The brand input.
|
||||
* @param {string} input.name - The brand name.
|
||||
* @param {string} [input.gsprpinfo] - Optional GSPRP info.
|
||||
* @param {object} [tx] - Optional transaction to run within.
|
||||
* @returns {Promise<{id: number, name: string, gsprpinfo: string|null, pics: Array<{id: number, sort: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>}>} The created brand.
|
||||
* @throws {Error} If the brand is invalid or already exists.
|
||||
*
|
||||
* @example
|
||||
* const brand = await store.brand.create(42, { name: 'Coca-Cola', gsprpinfo: 'x' });
|
||||
* // => { id, name, gsprpinfo, pics: [] }
|
||||
*/
|
||||
return async (googleAuthId, input = {}, tx) => {
|
||||
const name = input.name?.trim();
|
||||
if (!name) {
|
||||
throw new Error('Invalid brand');
|
||||
}
|
||||
const gsprpinfo = input.gsprpinfo ?? null;
|
||||
|
||||
const runner = makeRunner(provider, tx);
|
||||
const { companyId } = await access(googleAuthId, tx);
|
||||
|
||||
try {
|
||||
const created = await runner.query(createSql, {
|
||||
companyId,
|
||||
name,
|
||||
gsprpinfo,
|
||||
});
|
||||
|
||||
const id = created.rows[0]?.id ?? created.insertId;
|
||||
if (id == null) {
|
||||
const fetched = await runner.query(getSql, { companyId, name });
|
||||
const row = fetched.rows[0];
|
||||
return {
|
||||
id: row.id,
|
||||
name,
|
||||
gsprpinfo,
|
||||
pics: [],
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
gsprpinfo,
|
||||
pics: [],
|
||||
};
|
||||
} catch (err) {
|
||||
if (isUniqueConstraintError(err)) {
|
||||
throw new Error('Brand already exists');
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
}
|
||||
90
src/store/brand/update.js
Normal file
90
src/store/brand/update.js
Normal file
@@ -0,0 +1,90 @@
|
||||
import {
|
||||
GET_BY_ID_AND_COMPANY as MSSQL_GET,
|
||||
UPDATE_BY_ID as MSSQL_UPDATE,
|
||||
} from '../../providers/mssql/queries/brand.js';
|
||||
import {
|
||||
GET_BY_ID_AND_COMPANY as SQLITE_GET,
|
||||
UPDATE_BY_ID as SQLITE_UPDATE,
|
||||
} from '../../providers/sqlite3/queries/brand.js';
|
||||
import { isUniqueConstraintError } from '../../providers/provider.js';
|
||||
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||
import makeRunner from '../runner.js';
|
||||
|
||||
export default function update(provider) {
|
||||
const access = resolveSelectedCompanyAccess(provider);
|
||||
const isSqlite = provider?.dialect === 'sqlite3';
|
||||
const getSql = isSqlite ? SQLITE_GET : MSSQL_GET;
|
||||
const updateSql = isSqlite ? SQLITE_UPDATE : MSSQL_UPDATE;
|
||||
|
||||
/**
|
||||
* Renames/updates a brand for the user's selected company by id.
|
||||
* Touching `article.updated_at` for all articles linked via `brand_id`
|
||||
* when the name actually changes, so list caches invalidate.
|
||||
*
|
||||
* @param {number} googleAuthId - The id of the Google auth user.
|
||||
* @param {number} id - The id of the brand to update.
|
||||
* @param {object} input - The update input.
|
||||
* @param {string} [input.name] - The new brand name.
|
||||
* @param {string} [input.gsprpinfo] - The new GSPRP info.
|
||||
* @param {object} [tx] - Optional transaction to run within.
|
||||
* @returns {Promise<{id: number, name: string, gsprpinfo: string|null, touchedArticleCount: number}>} The updated brand plus the number of linked articles whose `updated_at` was bumped.
|
||||
* @throws {Error} If the brand is not found, invalid, or the name is already taken.
|
||||
*
|
||||
* @example
|
||||
* const brand = await store.brand.update(42, 3, { name: 'Coca-Cola GmbH' });
|
||||
* // => { id: 3, name, gsprpinfo, touchedArticleCount: 2 }
|
||||
*/
|
||||
return async (googleAuthId, id, input = {}, tx) => {
|
||||
const numericId = Number(id);
|
||||
if (!Number.isInteger(numericId) || numericId <= 0) {
|
||||
throw new Error('Brand not found');
|
||||
}
|
||||
|
||||
const runner = makeRunner(provider, tx);
|
||||
const { companyId } = await access(googleAuthId, tx);
|
||||
|
||||
const existing = await runner.query(getSql, { id: numericId, companyId });
|
||||
const current = existing.rows[0];
|
||||
if (!current) {
|
||||
throw new Error('Brand not found');
|
||||
}
|
||||
|
||||
const name = input.name !== undefined ? input.name?.trim() : current.name;
|
||||
if (!name) {
|
||||
throw new Error('Invalid brand');
|
||||
}
|
||||
const gsprpinfo = input.gsprpinfo !== undefined ? input.gsprpinfo : current.gsprpinfo;
|
||||
|
||||
try {
|
||||
await runner.query(updateSql, {
|
||||
id: numericId,
|
||||
companyId,
|
||||
name,
|
||||
gsprpinfo,
|
||||
});
|
||||
} catch (err) {
|
||||
if (isUniqueConstraintError(err)) {
|
||||
throw new Error('Brand already exists');
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
||||
let touchedArticleCount = 0;
|
||||
if (name !== current.name) {
|
||||
// Brand name is denormalized into article list views — bump
|
||||
// updated_at so caches/incremental syncs pick up the rename.
|
||||
const touchSql = isSqlite
|
||||
? "UPDATE article SET updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE brand_id = @brandId AND company_id = @companyId"
|
||||
: 'UPDATE article SET updated_at = SYSUTCDATETIME() WHERE brand_id = @brandId AND company_id = @companyId';
|
||||
const touched = await runner.query(touchSql, { brandId: numericId, companyId });
|
||||
touchedArticleCount = touched.rowsAffected ?? 0;
|
||||
}
|
||||
|
||||
return {
|
||||
id: numericId,
|
||||
name,
|
||||
gsprpinfo,
|
||||
touchedArticleCount,
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user