Add collections (#172)
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
import { BaseSQLDataSource } from './BaseSQLDataSource';
|
||||
import { DataSourceOptions, Maybe } from '../types/types';
|
||||
import { ScopeAccess, Scopes } from '../cognito/access-control';
|
||||
import { Collection } from '../types/collection-types';
|
||||
import DataLoader from 'dataloader';
|
||||
|
||||
export class CollectionAPI extends BaseSQLDataSource {
|
||||
productCollectionsLoader: DataLoader<number, Collection[]>;
|
||||
|
||||
constructor(options: DataSourceOptions, config) {
|
||||
super(options, config);
|
||||
|
||||
// DataLoader for batching product-to-collections lookups
|
||||
this.productCollectionsLoader = new DataLoader(
|
||||
async (productIds: readonly number[]) => {
|
||||
return this.batchGetProductCollections(productIds);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
async getCollections(): Promise<Array<Collection>> {
|
||||
ScopeAccess.validate(this.user).some([
|
||||
Scopes.PRODUCTS_READ,
|
||||
Scopes.PRODUCTS_PUBLIC_READ,
|
||||
]);
|
||||
const query = `
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
metadata
|
||||
FROM editorial_pages
|
||||
WHERE type = 'collection' AND deleted IS NULL
|
||||
ORDER BY name
|
||||
`;
|
||||
const collections = await this.knex.raw(query).then((data) => {
|
||||
return data.rows.map((row) => this.createCollectionFromRow(row));
|
||||
});
|
||||
return collections;
|
||||
}
|
||||
|
||||
async getCollection(id: number): Promise<Maybe<Collection>> {
|
||||
ScopeAccess.validate(this.user).some([
|
||||
Scopes.PRODUCTS_READ,
|
||||
Scopes.PRODUCTS_PUBLIC_READ,
|
||||
]);
|
||||
const query = `
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
metadata
|
||||
FROM editorial_pages
|
||||
WHERE id = ? AND type = 'collection' AND deleted IS NULL
|
||||
`;
|
||||
const collection = await this.knex.raw(query, [id]).then((data) => {
|
||||
if (data.rows.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return this.createCollectionFromRow(data.rows[0]);
|
||||
});
|
||||
return collection;
|
||||
}
|
||||
|
||||
createCollectionFromRow(row: any): Collection {
|
||||
let productIds: number[] = [];
|
||||
if (row.metadata && Array.isArray(row.metadata.collection_products)) {
|
||||
productIds = row.metadata.collection_products.map((id: string | number) =>
|
||||
Number(id),
|
||||
);
|
||||
}
|
||||
return {
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
productIds,
|
||||
};
|
||||
}
|
||||
|
||||
async getProductCollections(productId: number): Promise<Collection[]> {
|
||||
ScopeAccess.validate(this.user).some([
|
||||
Scopes.PRODUCTS_READ,
|
||||
Scopes.PRODUCTS_PUBLIC_READ,
|
||||
]);
|
||||
return this.productCollectionsLoader.load(productId);
|
||||
}
|
||||
|
||||
private async batchGetProductCollections(
|
||||
productIds: readonly number[],
|
||||
): Promise<Collection[][]> {
|
||||
const productIdsStr = productIds.map(String);
|
||||
const query = `
|
||||
WITH collection_products AS (
|
||||
SELECT
|
||||
e.id,
|
||||
e.name,
|
||||
e.metadata,
|
||||
jsonb_array_elements_text(e.metadata->'collection_products') AS product_id
|
||||
FROM editorial_pages e
|
||||
WHERE e.type = 'collection'
|
||||
AND e.deleted IS NULL
|
||||
AND e.metadata->'collection_products' IS NOT NULL
|
||||
)
|
||||
SELECT * FROM collection_products
|
||||
WHERE product_id = ANY (?)
|
||||
`;
|
||||
const results = await this.knex.raw(query, [productIdsStr]);
|
||||
// Group collections by product ID
|
||||
const collectionsByProduct: { [key: string]: Collection[] } = {};
|
||||
productIdsStr.forEach((id) => {
|
||||
collectionsByProduct[id] = [];
|
||||
});
|
||||
results.rows.forEach((row) => {
|
||||
const productId = row.product_id;
|
||||
if (!collectionsByProduct[productId])
|
||||
collectionsByProduct[productId] = [];
|
||||
collectionsByProduct[productId].push(this.createCollectionFromRow(row));
|
||||
});
|
||||
// Return collections in the same order as the input productIds
|
||||
return productIdsStr.map((id) => collectionsByProduct[id] || []);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user