u
This commit is contained in:
@@ -94,11 +94,12 @@ Lists the brands of the user's selected company, sorted by name.
|
|||||||
| `[opts]` | `object` | Optional pagination options. |
|
| `[opts]` | `object` | Optional pagination options. |
|
||||||
| `[opts.offset=0]` | `number` | Number of brands to skip. |
|
| `[opts.offset=0]` | `number` | Number of brands to skip. |
|
||||||
| `[opts.limit=10]` | `number` | Number of brands to return (max 100). |
|
| `[opts.limit=10]` | `number` | Number of brands to return (max 100). |
|
||||||
|
| `[opts.includeSmallThumbs=false]` | `boolean` | Include 40px-edge small thumbnail dimensions and base64 AVIF data. |
|
||||||
| `[tx]` | `object` | Optional transaction to run within. |
|
| `[tx]` | `object` | Optional transaction to run within. |
|
||||||
|
|
||||||
**Returns**
|
**Returns**
|
||||||
|
|
||||||
`Promise<{brands: Array<{id: number, name: string, gsprpinfo: string|null, pics: Array<{fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>}>, total: number, offset: number, limit: number}>` — The brands plus the total unpaged count.
|
`Promise<{brands: Array<{id: number, name: string, gsprpinfo: string|null, pics: Array<{fullHash: string, thumbW: number, thumbH: number, thumbHash: string, smallThumbW?: number|null, smallThumbH?: number|null, smallThumbBinary?: string|null}>}>, total: number, offset: number, limit: number}>` — The brands plus the total unpaged count. Small-thumbnail fields are present only when `includeSmallThumbs` is true; the binary is base64-encoded AVIF data.
|
||||||
|
|
||||||
**Example**
|
**Example**
|
||||||
|
|
||||||
|
|||||||
2
API.md
2
API.md
@@ -132,7 +132,7 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
|
|||||||
- `addImage(googleAuthId: number, brandId: number, image: Buffer, tx?: object): Promise<{id: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string, smallThumbW: number, smallThumbH: number, pics: Array<object>}>`
|
- `addImage(googleAuthId: number, brandId: number, image: Buffer, tx?: object): Promise<{id: number, fullHash: string, thumbW: number, thumbH: number, thumbHash: string, smallThumbW: number, smallThumbH: number, pics: Array<object>}>`
|
||||||
- `create(googleAuthId: number, input: {name: string, gsprpinfo?: string}, tx?: object): Promise<{id: number, name: string, gsprpinfo: string|null, pics: Array<{fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>}>`
|
- `create(googleAuthId: number, input: {name: string, gsprpinfo?: string}, tx?: object): Promise<{id: number, name: string, gsprpinfo: string|null, pics: Array<{fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>}>`
|
||||||
- `delete(googleAuthId: number, id: number, tx?: object): Promise<void>`
|
- `delete(googleAuthId: number, id: number, tx?: object): Promise<void>`
|
||||||
- `list(googleAuthId: number, opts?: {offset?: number, limit?: number}, tx?: object): Promise<{brands: Array<{id: number, name: string, gsprpinfo: string|null, pics: Array<{fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>}>, total: number, offset: number, limit: number}>`
|
- `list(googleAuthId: number, opts?: {offset?: number, limit?: number, includeSmallThumbs?: boolean}, tx?: object): Promise<{brands: Array<{id: number, name: string, gsprpinfo: string|null, pics: Array<{fullHash: string, thumbW: number, thumbH: number, thumbHash: string, smallThumbW?: number|null, smallThumbH?: number|null, smallThumbBinary?: string|null}>}>, total: number, offset: number, limit: number}>`
|
||||||
- `update(googleAuthId: number, id: number, input: {name?: string, gsprpinfo?: string}, tx?: object): Promise<{id: number, name: string, gsprpinfo: string|null, touchedArticleCount: number}>`
|
- `update(googleAuthId: number, id: number, input: {name?: string, gsprpinfo?: string}, tx?: object): Promise<{id: number, name: string, gsprpinfo: string|null, touchedArticleCount: number}>`
|
||||||
- `upsert(googleAuthId: number, input: {name: string, gsprpinfo?: string}, tx?: object): Promise<{id: number, name: string, gsprpinfo: string|null, pics: Array<{fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>}>`
|
- `upsert(googleAuthId: number, input: {name: string, gsprpinfo?: string}, tx?: object): Promise<{id: number, name: string, gsprpinfo: string|null, pics: Array<{fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>}>`
|
||||||
- [customergroup](API.customergroup.md)
|
- [customergroup](API.customergroup.md)
|
||||||
|
|||||||
@@ -214,6 +214,30 @@ async function runTests() {
|
|||||||
assert.equal(smallThumbMetadata.format, 'heif');
|
assert.equal(smallThumbMetadata.format, 'heif');
|
||||||
assert.equal(smallThumbMetadata.width, 40);
|
assert.equal(smallThumbMetadata.width, 40);
|
||||||
assert.equal(smallThumbMetadata.height, 27);
|
assert.equal(smallThumbMetadata.height, 27);
|
||||||
|
|
||||||
|
const brand = await store.brand.create(googleAuthId, { name: 'Small Thumb Test Brand' });
|
||||||
|
await store.brand.addImage(googleAuthId, brand.id, sampleImage);
|
||||||
|
const listedBrands = await store.brand.list(googleAuthId, { offset: 0, limit: 100 });
|
||||||
|
const listedBrand = listedBrands.brands.find((item) => item.id === brand.id);
|
||||||
|
assert(listedBrand, 'Brand list should include the created brand');
|
||||||
|
assert.equal(listedBrand.pics.length, 1);
|
||||||
|
assert(!('smallThumbW' in listedBrand.pics[0]), 'Small-thumb fields should be omitted by default');
|
||||||
|
|
||||||
|
const listedBrandsWithSmallThumbs = await store.brand.list(googleAuthId, {
|
||||||
|
offset: 0,
|
||||||
|
limit: 100,
|
||||||
|
includeSmallThumbs: true,
|
||||||
|
});
|
||||||
|
const listedBrandWithSmallThumbs = listedBrandsWithSmallThumbs.brands.find((item) => item.id === brand.id);
|
||||||
|
assert(listedBrandWithSmallThumbs, 'Brand list with thumbnails should include the created brand');
|
||||||
|
assert.equal(listedBrandWithSmallThumbs.pics.length, 1);
|
||||||
|
const listedPic = listedBrandWithSmallThumbs.pics[0];
|
||||||
|
assert.equal(listedPic.smallThumbW, 40);
|
||||||
|
assert.equal(listedPic.smallThumbH, 27);
|
||||||
|
assert.equal(typeof listedPic.smallThumbBinary, 'string');
|
||||||
|
const listedSmallThumb = Buffer.from(listedPic.smallThumbBinary, 'base64');
|
||||||
|
assert.deepEqual(listedSmallThumb, smallThumbRow.smallthumbbinary);
|
||||||
|
|
||||||
console.log('Article pic added with hash:', fullHash);
|
console.log('Article pic added with hash:', fullHash);
|
||||||
|
|
||||||
const fullPath = join(storageDir, 'fullbinary', fullHash + '.avif');
|
const fullPath = join(storageDir, 'fullbinary', fullHash + '.avif');
|
||||||
|
|||||||
@@ -49,6 +49,32 @@ ORDER BY b.name
|
|||||||
OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY
|
OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const LIST_BY_COMPANY_PAGED_WITH_SMALL_THUMBS = `
|
||||||
|
SELECT
|
||||||
|
b.id,
|
||||||
|
b.name,
|
||||||
|
b.gsprpinfo,
|
||||||
|
(
|
||||||
|
SELECT
|
||||||
|
p.hash AS fullHash,
|
||||||
|
p.thumbw AS thumbW,
|
||||||
|
p.thumbh AS thumbH,
|
||||||
|
p.thumbhash AS thumbHash,
|
||||||
|
p.smallthumbw AS smallThumbW,
|
||||||
|
p.smallthumbh AS smallThumbH,
|
||||||
|
p.smallthumbbinary AS smallThumbBinary
|
||||||
|
FROM brandpic bp
|
||||||
|
INNER JOIN pic p ON p.id = bp.pic_id
|
||||||
|
WHERE bp.brand_id = b.id
|
||||||
|
ORDER BY bp.sort ASC, bp.id ASC
|
||||||
|
FOR JSON PATH
|
||||||
|
) AS picsJson
|
||||||
|
FROM brand b
|
||||||
|
WHERE b.company_id = @companyId
|
||||||
|
ORDER BY b.name
|
||||||
|
OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY
|
||||||
|
`;
|
||||||
|
|
||||||
export const GET_BY_COMPANY_AND_NAME = `
|
export const GET_BY_COMPANY_AND_NAME = `
|
||||||
SELECT
|
SELECT
|
||||||
b.id,
|
b.id,
|
||||||
|
|||||||
@@ -58,6 +58,39 @@ ORDER BY b.name
|
|||||||
LIMIT @limit OFFSET @offset
|
LIMIT @limit OFFSET @offset
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const LIST_BY_COMPANY_PAGED_WITH_SMALL_THUMBS = `
|
||||||
|
SELECT
|
||||||
|
b.id,
|
||||||
|
b.name,
|
||||||
|
b.gsprpinfo,
|
||||||
|
(
|
||||||
|
SELECT COALESCE(json_group_array(json_object(
|
||||||
|
'fullHash', hash,
|
||||||
|
'thumbW', thumbw,
|
||||||
|
'thumbH', thumbh,
|
||||||
|
'thumbHash', thumbhash,
|
||||||
|
'smallThumbW', smallthumbw,
|
||||||
|
'smallThumbH', smallthumbh,
|
||||||
|
'smallThumbBinaryHex', CASE
|
||||||
|
WHEN smallthumbbinary IS NULL THEN NULL
|
||||||
|
ELSE hex(smallthumbbinary)
|
||||||
|
END
|
||||||
|
)), '[]')
|
||||||
|
FROM (
|
||||||
|
SELECT p.hash, p.thumbw, p.thumbh, p.thumbhash,
|
||||||
|
p.smallthumbw, p.smallthumbh, p.smallthumbbinary
|
||||||
|
FROM brandpic bp
|
||||||
|
INNER JOIN pic p ON p.id = bp.pic_id
|
||||||
|
WHERE bp.brand_id = b.id
|
||||||
|
ORDER BY bp.sort, bp.id
|
||||||
|
)
|
||||||
|
) AS picsJson
|
||||||
|
FROM brand b
|
||||||
|
WHERE b.company_id = @companyId
|
||||||
|
ORDER BY b.name
|
||||||
|
LIMIT @limit OFFSET @offset
|
||||||
|
`;
|
||||||
|
|
||||||
export const GET_BY_COMPANY_AND_NAME = `
|
export const GET_BY_COMPANY_AND_NAME = `
|
||||||
SELECT
|
SELECT
|
||||||
b.id,
|
b.id,
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ import {
|
|||||||
COUNT_BY_COMPANY as MSSQL_COUNT,
|
COUNT_BY_COMPANY as MSSQL_COUNT,
|
||||||
LIST_BY_COMPANY as MSSQL_LIST_BY_COMPANY,
|
LIST_BY_COMPANY as MSSQL_LIST_BY_COMPANY,
|
||||||
LIST_BY_COMPANY_PAGED as MSSQL_LIST_PAGED,
|
LIST_BY_COMPANY_PAGED as MSSQL_LIST_PAGED,
|
||||||
|
LIST_BY_COMPANY_PAGED_WITH_SMALL_THUMBS as MSSQL_LIST_PAGED_WITH_SMALL_THUMBS,
|
||||||
} from '../../providers/mssql/queries/brand.js';
|
} from '../../providers/mssql/queries/brand.js';
|
||||||
import {
|
import {
|
||||||
COUNT_BY_COMPANY as SQLITE_COUNT,
|
COUNT_BY_COMPANY as SQLITE_COUNT,
|
||||||
LIST_BY_COMPANY as SQLITE_LIST_BY_COMPANY,
|
LIST_BY_COMPANY as SQLITE_LIST_BY_COMPANY,
|
||||||
LIST_BY_COMPANY_PAGED as SQLITE_LIST_PAGED,
|
LIST_BY_COMPANY_PAGED as SQLITE_LIST_PAGED,
|
||||||
|
LIST_BY_COMPANY_PAGED_WITH_SMALL_THUMBS as SQLITE_LIST_PAGED_WITH_SMALL_THUMBS,
|
||||||
} from '../../providers/sqlite3/queries/brand.js';
|
} from '../../providers/sqlite3/queries/brand.js';
|
||||||
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import makeRunner from '../runner.js';
|
import makeRunner from '../runner.js';
|
||||||
@@ -14,7 +16,17 @@ import makeRunner from '../runner.js';
|
|||||||
function parsePics(raw) {
|
function parsePics(raw) {
|
||||||
if (!raw) return [];
|
if (!raw) return [];
|
||||||
const parsed = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
const parsed = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
||||||
return Array.isArray(parsed) ? parsed : [];
|
if (!Array.isArray(parsed)) return [];
|
||||||
|
return parsed.map((pic) => {
|
||||||
|
const { smallThumbBinaryHex, ...result } = pic;
|
||||||
|
if (smallThumbBinaryHex === undefined) return result;
|
||||||
|
return {
|
||||||
|
...result,
|
||||||
|
smallThumbBinary: smallThumbBinaryHex === null
|
||||||
|
? null
|
||||||
|
: Buffer.from(smallThumbBinaryHex, 'hex').toString('base64'),
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function list(provider) {
|
export default function list(provider) {
|
||||||
@@ -23,6 +35,9 @@ export default function list(provider) {
|
|||||||
const sql = isSqlite ? SQLITE_LIST_BY_COMPANY : MSSQL_LIST_BY_COMPANY;
|
const sql = isSqlite ? SQLITE_LIST_BY_COMPANY : MSSQL_LIST_BY_COMPANY;
|
||||||
const sqlCount = isSqlite ? SQLITE_COUNT : MSSQL_COUNT;
|
const sqlCount = isSqlite ? SQLITE_COUNT : MSSQL_COUNT;
|
||||||
const sqlPaged = isSqlite ? SQLITE_LIST_PAGED : MSSQL_LIST_PAGED;
|
const sqlPaged = isSqlite ? SQLITE_LIST_PAGED : MSSQL_LIST_PAGED;
|
||||||
|
const sqlPagedWithSmallThumbs = isSqlite
|
||||||
|
? SQLITE_LIST_PAGED_WITH_SMALL_THUMBS
|
||||||
|
: MSSQL_LIST_PAGED_WITH_SMALL_THUMBS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lists the brands of the user's selected company, sorted by name.
|
* Lists the brands of the user's selected company, sorted by name.
|
||||||
@@ -31,8 +46,9 @@ export default function list(provider) {
|
|||||||
* @param {object} [opts] - Optional pagination options.
|
* @param {object} [opts] - Optional pagination options.
|
||||||
* @param {number} [opts.offset=0] - Number of brands to skip.
|
* @param {number} [opts.offset=0] - Number of brands to skip.
|
||||||
* @param {number} [opts.limit=10] - Number of brands to return (max 100).
|
* @param {number} [opts.limit=10] - Number of brands to return (max 100).
|
||||||
|
* @param {boolean} [opts.includeSmallThumbs=false] - Include 40px-edge small thumbnail dimensions and base64 AVIF data.
|
||||||
* @param {object} [tx] - Optional transaction to run within.
|
* @param {object} [tx] - Optional transaction to run within.
|
||||||
* @returns {Promise<{brands: Array<{id: number, name: string, gsprpinfo: string|null, pics: Array<{fullHash: string, thumbW: number, thumbH: number, thumbHash: string}>}>, total: number, offset: number, limit: number}>} The brands plus the total unpaged count.
|
* @returns {Promise<{brands: Array<{id: number, name: string, gsprpinfo: string|null, pics: Array<{fullHash: string, thumbW: number, thumbH: number, thumbHash: string, smallThumbW?: number|null, smallThumbH?: number|null, smallThumbBinary?: string|null}>}>, total: number, offset: number, limit: number}>} The brands plus the total unpaged count. Small-thumbnail fields are present only when `includeSmallThumbs` is true; the binary is base64-encoded AVIF data.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const result = await store.brand.list(42, { offset: 0, limit: 10 });
|
* const result = await store.brand.list(42, { offset: 0, limit: 10 });
|
||||||
@@ -41,6 +57,7 @@ export default function list(provider) {
|
|||||||
return async (googleAuthId, opts, tx) => {
|
return async (googleAuthId, opts, tx) => {
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
let limit = 10;
|
let limit = 10;
|
||||||
|
let includeSmallThumbs = false;
|
||||||
let resolvedTx = tx;
|
let resolvedTx = tx;
|
||||||
|
|
||||||
if (opts != null && typeof opts === 'object' && !opts._isTx) {
|
if (opts != null && typeof opts === 'object' && !opts._isTx) {
|
||||||
@@ -54,6 +71,7 @@ export default function list(provider) {
|
|||||||
}
|
}
|
||||||
offset = parsedOffset;
|
offset = parsedOffset;
|
||||||
limit = parsedLimit;
|
limit = parsedLimit;
|
||||||
|
includeSmallThumbs = opts.includeSmallThumbs === true;
|
||||||
} else if (opts != null) {
|
} else if (opts != null) {
|
||||||
resolvedTx = opts;
|
resolvedTx = opts;
|
||||||
}
|
}
|
||||||
@@ -63,7 +81,10 @@ export default function list(provider) {
|
|||||||
|
|
||||||
const [countResult, listResult] = await Promise.all([
|
const [countResult, listResult] = await Promise.all([
|
||||||
runner.query(sqlCount, { companyId }),
|
runner.query(sqlCount, { companyId }),
|
||||||
runner.query(sqlPaged, { companyId, offset, limit }),
|
runner.query(
|
||||||
|
includeSmallThumbs ? sqlPagedWithSmallThumbs : sqlPaged,
|
||||||
|
{ companyId, offset, limit },
|
||||||
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user