u
This commit is contained in:
104
src/store/brand/addImage.js
Normal file
104
src/store/brand/addImage.js
Normal file
@@ -0,0 +1,104 @@
|
||||
import {
|
||||
ADD as MSSQL_ADD_BRANDPIC,
|
||||
DELETE_BY_BRAND as MSSQL_DELETE_BRANDPIC,
|
||||
} from '../../providers/mssql/queries/brandpic.js';
|
||||
import {
|
||||
ADD as SQLITE_ADD_BRANDPIC,
|
||||
DELETE_BY_BRAND as SQLITE_DELETE_BRANDPIC,
|
||||
} from '../../providers/sqlite3/queries/brandpic.js';
|
||||
import { CREATE as MSSQL_CREATE_PIC } from '../../providers/mssql/queries/pic.js';
|
||||
import { CREATE as SQLITE_CREATE_PIC } from '../../providers/sqlite3/queries/pic.js';
|
||||
import processAvifImage from '../../util/processAvifImage.js';
|
||||
import newFullHash from '../../util/newFullHash.js';
|
||||
import resolveBrandAccess from './resolveBrandAccess.js';
|
||||
import makeRunner from '../runner.js';
|
||||
|
||||
export default function addImage(provider) {
|
||||
const access = resolveBrandAccess(provider);
|
||||
const isSqlite = provider?.dialect === 'sqlite3';
|
||||
|
||||
const deleteBrandPicSql = isSqlite ? SQLITE_DELETE_BRANDPIC : MSSQL_DELETE_BRANDPIC;
|
||||
const createPicSql = isSqlite ? SQLITE_CREATE_PIC : MSSQL_CREATE_PIC;
|
||||
const addBrandPicSql = isSqlite ? SQLITE_ADD_BRANDPIC : MSSQL_ADD_BRANDPIC;
|
||||
|
||||
/**
|
||||
* Adds an image to a brand, processing it into AVIF full and thumb variants.
|
||||
*
|
||||
* @param {number} googleAuthId - The id of the Google auth user.
|
||||
* @param {number} brandId - The id of the brand.
|
||||
* @param {Buffer} image - The source image buffer.
|
||||
* @param {object} [tx] - Optional transaction to run within.
|
||||
* @returns {Promise<{id: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string, pics: Array<object>}>}
|
||||
*/
|
||||
return async (googleAuthId, brandId, image, tx) => {
|
||||
const runAdd = async (runner) => {
|
||||
await access(googleAuthId, brandId, runner);
|
||||
|
||||
const processed = await processAvifImage(image);
|
||||
|
||||
// Clean existing brandpic so the brand has 1 primary logo
|
||||
await runner.query(deleteBrandPicSql, { brandId });
|
||||
|
||||
const sort = 0;
|
||||
const fullHash = newFullHash();
|
||||
|
||||
if (isSqlite) {
|
||||
if (runner.writePicFull) {
|
||||
await runner.writePicFull(fullHash, processed.full.buffer);
|
||||
await runner.writePicThumb(fullHash, processed.thumb.buffer);
|
||||
} else if (provider?.writePicFull) {
|
||||
await provider.writePicFull(fullHash, processed.full.buffer);
|
||||
await provider.writePicThumb(fullHash, processed.thumb.buffer);
|
||||
}
|
||||
}
|
||||
|
||||
const picResult = await runner.query(createPicSql, {
|
||||
w: processed.full.w,
|
||||
h: processed.full.h,
|
||||
size: processed.full.size,
|
||||
hash: fullHash,
|
||||
thumbw: processed.thumb.w,
|
||||
thumbh: processed.thumb.h,
|
||||
thumbhash: processed.thumb.hash,
|
||||
source: '',
|
||||
fullbinary: processed.full.buffer,
|
||||
thumbbinary: processed.thumb.buffer,
|
||||
});
|
||||
|
||||
const picId = picResult.rows[0]?.id ?? picResult.insertId;
|
||||
|
||||
const brandPicResult = await runner.query(addBrandPicSql, {
|
||||
brandId,
|
||||
picId,
|
||||
sort,
|
||||
});
|
||||
const brandPicId = brandPicResult.rows[0]?.id ?? brandPicResult.insertId;
|
||||
|
||||
const picObj = {
|
||||
id: brandPicId,
|
||||
sort,
|
||||
fullHash,
|
||||
thumbW: processed.thumb.w,
|
||||
thumbH: processed.thumb.h,
|
||||
thumbHash: processed.thumb.hash,
|
||||
};
|
||||
|
||||
return {
|
||||
id: brandId,
|
||||
fullHash,
|
||||
thumbW: processed.thumb.w,
|
||||
thumbH: processed.thumb.h,
|
||||
thumbHash: processed.thumb.hash,
|
||||
pics: [picObj],
|
||||
};
|
||||
};
|
||||
|
||||
if (tx) {
|
||||
return runAdd(makeRunner(provider, tx));
|
||||
}
|
||||
if (typeof provider?.transaction === 'function') {
|
||||
return provider.transaction(runAdd);
|
||||
}
|
||||
return runAdd(makeRunner(provider));
|
||||
};
|
||||
}
|
||||
28
src/store/brand/deleteImage.js
Normal file
28
src/store/brand/deleteImage.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import { DELETE_BY_BRAND as MSSQL_DELETE } from '../../providers/mssql/queries/brandpic.js';
|
||||
import { DELETE_BY_BRAND as SQLITE_DELETE } from '../../providers/sqlite3/queries/brandpic.js';
|
||||
import resolveBrandAccess from './resolveBrandAccess.js';
|
||||
import makeRunner from '../runner.js';
|
||||
|
||||
export default function deleteImage(provider) {
|
||||
const access = resolveBrandAccess(provider);
|
||||
const sql = provider?.dialect === 'sqlite3' ? SQLITE_DELETE : MSSQL_DELETE;
|
||||
|
||||
return async (googleAuthId, brandId, tx) => {
|
||||
const runner = makeRunner(provider, tx);
|
||||
await access(googleAuthId, brandId, runner);
|
||||
|
||||
const result = await runner.query(sql, { brandId });
|
||||
|
||||
if (!result.rowsAffected) {
|
||||
throw new Error('Image not found');
|
||||
}
|
||||
|
||||
return {
|
||||
id: brandId,
|
||||
thumbW: null,
|
||||
thumbH: null,
|
||||
thumbHash: null,
|
||||
pics: [],
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -3,6 +3,12 @@ import { LIST_BY_COMPANY as SQLITE_LIST_BY_COMPANY } from '../../providers/sqlit
|
||||
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||
import makeRunner from '../runner.js';
|
||||
|
||||
function parsePics(raw) {
|
||||
if (!raw) return [];
|
||||
const parsed = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
||||
return Array.isArray(parsed) ? parsed : [];
|
||||
}
|
||||
|
||||
export default function list(provider) {
|
||||
const access = resolveSelectedCompanyAccess(provider);
|
||||
const sql =
|
||||
@@ -15,17 +21,22 @@ export default function list(provider) {
|
||||
*
|
||||
* @param {number} googleAuthId - The id of the Google auth user.
|
||||
* @param {object} [tx] - Optional transaction to run within.
|
||||
* @returns {Promise<Array<{id: number, name: string, gsprpinfo: string|null}>>} The brands.
|
||||
* @returns {Promise<Array<{id: number, name: string, gsprpinfo: string|null, pics: Array<{id: number, sort: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>}>>} The brands.
|
||||
*
|
||||
* @example
|
||||
* const brands = await store.brand.list(42);
|
||||
* // => [{ id, name, gsprpinfo }]
|
||||
* // => [{ id, name, gsprpinfo, pics: [{ sort, fullHash, thumbW, thumbH, thumbHash }] }]
|
||||
*/
|
||||
return async (googleAuthId, tx) => {
|
||||
const { companyId } = await access(googleAuthId, tx);
|
||||
|
||||
const result = await makeRunner(provider, tx).query(sql, { companyId });
|
||||
|
||||
return result.rows;
|
||||
return result.rows.map((row) => ({
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
gsprpinfo: row.gsprpinfo,
|
||||
pics: parsePics(row.picsJson),
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
22
src/store/brand/resolveBrandAccess.js
Normal file
22
src/store/brand/resolveBrandAccess.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { GET_BY_ID_AND_COMPANY as MSSQL_GET } from '../../providers/mssql/queries/brand.js';
|
||||
import { GET_BY_ID_AND_COMPANY as SQLITE_GET } from '../../providers/sqlite3/queries/brand.js';
|
||||
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||
import makeRunner from '../runner.js';
|
||||
|
||||
export default function resolveBrandAccess(provider) {
|
||||
const access = resolveSelectedCompanyAccess(provider);
|
||||
const sql = provider?.dialect === 'sqlite3' ? SQLITE_GET : MSSQL_GET;
|
||||
|
||||
return async (googleAuthId, brandId, tx) => {
|
||||
if (!Number.isFinite(brandId) || brandId <= 0) {
|
||||
throw new Error('Brand not found');
|
||||
}
|
||||
const { companyId } = await access(googleAuthId, tx);
|
||||
const runner = makeRunner(provider, tx);
|
||||
const result = await runner.query(sql, { id: brandId, companyId });
|
||||
if (!result.rows[0]) {
|
||||
throw new Error('Brand not found');
|
||||
}
|
||||
return { companyId, brand: result.rows[0] };
|
||||
};
|
||||
}
|
||||
@@ -11,6 +11,12 @@ import {
|
||||
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||
import makeRunner from '../runner.js';
|
||||
|
||||
function parsePics(raw) {
|
||||
if (!raw) return [];
|
||||
const parsed = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
||||
return Array.isArray(parsed) ? parsed : [];
|
||||
}
|
||||
|
||||
export default function upsert(provider) {
|
||||
const access = resolveSelectedCompanyAccess(provider);
|
||||
const isSqlite = provider?.dialect === 'sqlite3';
|
||||
@@ -28,12 +34,12 @@ export default function upsert(provider) {
|
||||
* @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}>} The upserted brand.
|
||||
* @returns {Promise<{id: number, name: string, gsprpinfo: string|null, pics: Array<{id: number, sort: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>}>} The upserted brand.
|
||||
* @throws {Error} If the brand is invalid.
|
||||
*
|
||||
* @example
|
||||
* const brand = await store.brand.upsert(42, { name: 'Coca-Cola', gsprpinfo: 'x' });
|
||||
* // => { id, name, gsprpinfo }
|
||||
* // => { id, name, gsprpinfo, pics: [] }
|
||||
*/
|
||||
return async (googleAuthId, input = {}, tx) => {
|
||||
const name = input.name?.trim();
|
||||
@@ -58,7 +64,12 @@ export default function upsert(provider) {
|
||||
name,
|
||||
gsprpinfo,
|
||||
});
|
||||
return { id, name, gsprpinfo };
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
gsprpinfo,
|
||||
pics: parsePics(existing.rows[0].picsJson),
|
||||
};
|
||||
}
|
||||
|
||||
const created = await runner.query(createSql, {
|
||||
@@ -73,6 +84,7 @@ export default function upsert(provider) {
|
||||
id,
|
||||
name,
|
||||
gsprpinfo,
|
||||
pics: [],
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user