u
This commit is contained in:
@@ -212,6 +212,8 @@ import attributevalueCreate from './store/attributevalue/create.js';
|
||||
import attributevalueUpdate from './store/attributevalue/update.js';
|
||||
import attributevalueOrder from './store/attributevalue/order.js';
|
||||
import attributevalueDelete from './store/attributevalue/delete.js';
|
||||
import attributevalueAddImage from './store/attributevalue/addImage.js';
|
||||
import attributevalueDeleteImage from './store/attributevalue/deleteImage.js';
|
||||
import articleattributevalueListByArticleSku from './store/articleattributevalue/listByArticleSku.js';
|
||||
import articleattributevalueSetByArticleSku from './store/articleattributevalue/setByArticleSku.js';
|
||||
import categorypropertyListByCategoryId from './store/categoryproperty/listByCategoryId.js';
|
||||
@@ -574,6 +576,8 @@ export default class LibDashStore {
|
||||
update: attributevalueUpdate(provider),
|
||||
order: attributevalueOrder(provider),
|
||||
delete: attributevalueDelete(provider),
|
||||
addImage: attributevalueAddImage(provider),
|
||||
deleteImage: attributevalueDeleteImage(provider),
|
||||
};
|
||||
|
||||
this.articleattributevalue = {
|
||||
|
||||
@@ -6,6 +6,7 @@ export const TABLES = [
|
||||
'account',
|
||||
'articleattributevalue',
|
||||
'articleproperty',
|
||||
'attributevaluepic',
|
||||
'attributevalue',
|
||||
'attributename',
|
||||
'propertyname',
|
||||
|
||||
23
src/providers/mssql/queries/attributevaluepic.js
Normal file
23
src/providers/mssql/queries/attributevaluepic.js
Normal file
@@ -0,0 +1,23 @@
|
||||
export const GET_NEXT_SORT = `
|
||||
SELECT ISNULL(MAX(sort), -1) + 1 AS sort
|
||||
FROM attributevaluepic
|
||||
WHERE attributevalue_id = @attributeValueId
|
||||
`;
|
||||
|
||||
export const ADD = `
|
||||
INSERT INTO attributevaluepic (attributevalue_id, pic_id, sort)
|
||||
VALUES (@attributeValueId, @picId, @sort)
|
||||
`;
|
||||
|
||||
export const DELETE_BY_ATTRIBUTE_VALUE = `
|
||||
DELETE FROM attributevaluepic
|
||||
WHERE attributevalue_id = @attributeValueId
|
||||
`;
|
||||
|
||||
export const GET_FIRST_PIC_BY_ATTRIBUTE_VALUE = `
|
||||
SELECT TOP 1 p.id AS picId, p.thumbw AS thumbW, p.thumbh AS thumbH, p.thumbhash AS thumbHash
|
||||
FROM attributevaluepic avp
|
||||
INNER JOIN pic p ON p.id = avp.pic_id
|
||||
WHERE avp.attributevalue_id = @attributeValueId
|
||||
ORDER BY avp.sort ASC, avp.id ASC
|
||||
`;
|
||||
@@ -45,6 +45,16 @@ FROM (
|
||||
INNER JOIN brand b ON b.id = bp.brand_id
|
||||
INNER JOIN company c ON c.id = b.company_id
|
||||
WHERE p.hash = @hash
|
||||
|
||||
UNION
|
||||
|
||||
SELECT c.root_category_id AS categoryId
|
||||
FROM pic p
|
||||
INNER JOIN attributevaluepic avp ON avp.pic_id = p.id
|
||||
INNER JOIN attributevalue av ON av.id = avp.attributevalue_id
|
||||
INNER JOIN attributename an ON an.id = av.attribute_id
|
||||
INNER JOIN company c ON c.id = an.company_id
|
||||
WHERE p.hash = @hash
|
||||
) AS combined
|
||||
WHERE categoryId IS NOT NULL
|
||||
`;
|
||||
|
||||
@@ -463,6 +463,22 @@ BEGIN
|
||||
END
|
||||
`;
|
||||
|
||||
export const INIT_ATTRIBUTEVALUEPIC = `
|
||||
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'attributevaluepic')
|
||||
BEGIN
|
||||
CREATE TABLE attributevaluepic (
|
||||
id INT IDENTITY(1,1) PRIMARY KEY,
|
||||
attributevalue_id INT NOT NULL,
|
||||
pic_id INT NOT NULL,
|
||||
sort INT NOT NULL CONSTRAINT DF_attributevaluepic_sort DEFAULT 0,
|
||||
CONSTRAINT FK_attributevaluepic_attributevalue FOREIGN KEY (attributevalue_id) REFERENCES attributevalue(id) ON DELETE CASCADE,
|
||||
CONSTRAINT FK_attributevaluepic_pic FOREIGN KEY (pic_id) REFERENCES pic(id) ON DELETE CASCADE,
|
||||
CONSTRAINT UQ_attributevaluepic_attributevalue_pic UNIQUE (attributevalue_id, pic_id),
|
||||
CONSTRAINT UQ_attributevaluepic_attributevalue_sort UNIQUE (attributevalue_id, sort)
|
||||
);
|
||||
END
|
||||
`;
|
||||
|
||||
export const INIT_ARTICLELISTARTICLE = `
|
||||
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'articlelistarticle')
|
||||
BEGIN
|
||||
@@ -1183,6 +1199,7 @@ export const SCHEMA_SCRIPTS = [
|
||||
INIT_ARTICLEEAN,
|
||||
INIT_ARTICLEPIC,
|
||||
INIT_BRANDPIC,
|
||||
INIT_ATTRIBUTEVALUEPIC,
|
||||
INIT_ARTICLELISTARTICLE,
|
||||
INIT_OPTIONSLISTARTICLE,
|
||||
INIT_CATEGORYARTICLE,
|
||||
|
||||
5
src/providers/sqlite3/queries/attributevaluepic.js
Normal file
5
src/providers/sqlite3/queries/attributevaluepic.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import * as source from '../../mssql/queries/attributevaluepic.js';
|
||||
import { translateQueries } from './translate.js';
|
||||
|
||||
const queries = translateQueries(source, 'attributevaluepic');
|
||||
export const { ADD, DELETE_BY_ATTRIBUTE_VALUE, GET_FIRST_PIC_BY_ATTRIBUTE_VALUE, GET_NEXT_SORT } = queries;
|
||||
@@ -284,6 +284,19 @@ CREATE TABLE IF NOT EXISTS brandpic (
|
||||
);
|
||||
`;
|
||||
|
||||
export const INIT_ATTRIBUTEVALUEPIC = `
|
||||
CREATE TABLE IF NOT EXISTS attributevaluepic (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
attributevalue_id INTEGER NOT NULL,
|
||||
pic_id INTEGER NOT NULL,
|
||||
sort INTEGER NOT NULL DEFAULT 0,
|
||||
UNIQUE (attributevalue_id, pic_id),
|
||||
UNIQUE (attributevalue_id, sort),
|
||||
FOREIGN KEY (attributevalue_id) REFERENCES attributevalue(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (pic_id) REFERENCES pic(id) ON DELETE CASCADE
|
||||
);
|
||||
`;
|
||||
|
||||
export const INIT_ARTICLELISTARTICLE = `
|
||||
CREATE TABLE IF NOT EXISTS articlelistarticle (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
@@ -853,6 +866,7 @@ export const SCHEMA_SCRIPTS = [
|
||||
INIT_ARTICLEEAN,
|
||||
INIT_ARTICLEPIC,
|
||||
INIT_BRANDPIC,
|
||||
INIT_ATTRIBUTEVALUEPIC,
|
||||
INIT_ARTICLELISTARTICLE,
|
||||
INIT_OPTIONSLISTARTICLE,
|
||||
INIT_CATEGORYARTICLE,
|
||||
|
||||
118
src/store/attributevalue/addImage.js
Normal file
118
src/store/attributevalue/addImage.js
Normal file
@@ -0,0 +1,118 @@
|
||||
import {
|
||||
ADD as MSSQL_ADD_AVPIC,
|
||||
DELETE_BY_ATTRIBUTE_VALUE as MSSQL_DELETE_AVPIC,
|
||||
} from '../../providers/mssql/queries/attributevaluepic.js';
|
||||
import {
|
||||
ADD as SQLITE_ADD_AVPIC,
|
||||
DELETE_BY_ATTRIBUTE_VALUE as SQLITE_DELETE_AVPIC,
|
||||
} from '../../providers/sqlite3/queries/attributevaluepic.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 resolveAttributeValueAccess from './resolveAttributeValueAccess.js';
|
||||
import makeRunner from '../runner.js';
|
||||
|
||||
export default function addImage(provider) {
|
||||
const access = resolveAttributeValueAccess(provider);
|
||||
const isSqlite = provider?.dialect === 'sqlite3';
|
||||
|
||||
const deleteAvPicSql = isSqlite ? SQLITE_DELETE_AVPIC : MSSQL_DELETE_AVPIC;
|
||||
const createPicSql = isSqlite ? SQLITE_CREATE_PIC : MSSQL_CREATE_PIC;
|
||||
const addAvPicSql = isSqlite ? SQLITE_ADD_AVPIC : MSSQL_ADD_AVPIC;
|
||||
|
||||
/**
|
||||
* Adds an image to an attribute value, processing full, thumb, and 32px-edge small-thumb AVIF variants.
|
||||
*
|
||||
* @param {number} googleAuthId - The id of the Google auth user.
|
||||
* @param {number} attributeValueId - The id of the attribute value.
|
||||
* @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, smallThumbW: number, smallThumbH: number, pics: Array<object>}>}
|
||||
*/
|
||||
return async (googleAuthId, attributeValueId, image, tx) => {
|
||||
const runAdd = async (runner) => {
|
||||
await access(googleAuthId, attributeValueId, runner);
|
||||
|
||||
const processed = await processAvifImage(image);
|
||||
|
||||
// Clean existing attributevaluepic so the attribute value has 1 primary image
|
||||
await runner.query(deleteAvPicSql, { attributeValueId });
|
||||
|
||||
const sort = 0;
|
||||
const fullHash = newFullHash(processed.full.buffer);
|
||||
|
||||
let picId;
|
||||
const existingPic = await runner.query(
|
||||
'SELECT id FROM pic WHERE hash = @fullHash',
|
||||
{ fullHash },
|
||||
);
|
||||
|
||||
if (existingPic.rows[0]) {
|
||||
picId = existingPic.rows[0].id;
|
||||
} else {
|
||||
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,
|
||||
smallthumbw: processed.smallThumb.w,
|
||||
smallthumbh: processed.smallThumb.h,
|
||||
smallthumbbinary: processed.smallThumb.buffer,
|
||||
source: '',
|
||||
fullbinary: processed.full.buffer,
|
||||
thumbbinary: processed.thumb.buffer,
|
||||
});
|
||||
|
||||
picId = picResult.rows[0]?.id ?? picResult.insertId;
|
||||
}
|
||||
|
||||
await runner.query(addAvPicSql, {
|
||||
attributeValueId,
|
||||
picId,
|
||||
sort,
|
||||
});
|
||||
|
||||
const picObj = {
|
||||
fullHash,
|
||||
thumbW: processed.thumb.w,
|
||||
thumbH: processed.thumb.h,
|
||||
thumbHash: processed.thumb.hash,
|
||||
smallThumbW: processed.smallThumb.w,
|
||||
smallThumbH: processed.smallThumb.h,
|
||||
};
|
||||
|
||||
return {
|
||||
id: attributeValueId,
|
||||
fullHash,
|
||||
thumbW: processed.thumb.w,
|
||||
thumbH: processed.thumb.h,
|
||||
thumbHash: processed.thumb.hash,
|
||||
smallThumbW: processed.smallThumb.w,
|
||||
smallThumbH: processed.smallThumb.h,
|
||||
pics: [picObj],
|
||||
};
|
||||
};
|
||||
|
||||
if (tx) {
|
||||
return runAdd(makeRunner(provider, tx));
|
||||
}
|
||||
if (typeof provider?.transaction === 'function') {
|
||||
return provider.transaction(runAdd);
|
||||
}
|
||||
return runAdd(makeRunner(provider));
|
||||
};
|
||||
}
|
||||
37
src/store/attributevalue/deleteImage.js
Normal file
37
src/store/attributevalue/deleteImage.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import { DELETE_BY_ATTRIBUTE_VALUE as MSSQL_DELETE } from '../../providers/mssql/queries/attributevaluepic.js';
|
||||
import { DELETE_BY_ATTRIBUTE_VALUE as SQLITE_DELETE } from '../../providers/sqlite3/queries/attributevaluepic.js';
|
||||
import resolveAttributeValueAccess from './resolveAttributeValueAccess.js';
|
||||
import makeRunner from '../runner.js';
|
||||
|
||||
export default function deleteImage(provider) {
|
||||
const access = resolveAttributeValueAccess(provider);
|
||||
const sql = provider?.dialect === 'sqlite3' ? SQLITE_DELETE : MSSQL_DELETE;
|
||||
|
||||
/**
|
||||
* Deletes the image of an attribute value.
|
||||
*
|
||||
* @param {number} googleAuthId - The id of the Google auth user.
|
||||
* @param {number} attributeValueId - The id of the attribute value.
|
||||
* @param {object} [tx] - Optional transaction.
|
||||
* @returns {Promise<{id: number, thumbW: null, thumbH: null, thumbHash: null, pics: Array}>}
|
||||
* @throws {Error} If attribute value not found or image not found.
|
||||
*/
|
||||
return async (googleAuthId, attributeValueId, tx) => {
|
||||
const runner = makeRunner(provider, tx);
|
||||
await access(googleAuthId, attributeValueId, runner);
|
||||
|
||||
const result = await runner.query(sql, { attributeValueId });
|
||||
|
||||
if (!result.rowsAffected) {
|
||||
throw new Error('Image not found');
|
||||
}
|
||||
|
||||
return {
|
||||
id: attributeValueId,
|
||||
thumbW: null,
|
||||
thumbH: null,
|
||||
thumbHash: null,
|
||||
pics: [],
|
||||
};
|
||||
};
|
||||
}
|
||||
22
src/store/attributevalue/resolveAttributeValueAccess.js
Normal file
22
src/store/attributevalue/resolveAttributeValueAccess.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { GET_BY_ID_AND_COMPANY as MSSQL_GET } from '../../providers/mssql/queries/attributevalue.js';
|
||||
import { GET_BY_ID_AND_COMPANY as SQLITE_GET } from '../../providers/sqlite3/queries/attributevalue.js';
|
||||
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||
import makeRunner from '../runner.js';
|
||||
|
||||
export default function resolveAttributeValueAccess(provider) {
|
||||
const access = resolveSelectedCompanyAccess(provider);
|
||||
const sql = provider?.dialect === 'sqlite3' ? SQLITE_GET : MSSQL_GET;
|
||||
|
||||
return async (googleAuthId, attributeValueId, tx) => {
|
||||
if (!Number.isFinite(attributeValueId) || attributeValueId <= 0) {
|
||||
throw new Error('Attribute value not found');
|
||||
}
|
||||
const { companyId } = await access(googleAuthId, tx);
|
||||
const runner = makeRunner(provider, tx);
|
||||
const result = await runner.query(sql, { id: attributeValueId, companyId });
|
||||
if (!result.rows[0]) {
|
||||
throw new Error('Attribute value not found');
|
||||
}
|
||||
return { companyId, attributeValue: result.rows[0] };
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user