Add keywords and product types

This commit is contained in:
Niklas Fondberg
2021-07-07 16:16:58 +02:00
parent 512ebf89f5
commit 267bc4f1c9
11 changed files with 262 additions and 53 deletions
+46 -1
View File
@@ -156,13 +156,17 @@
{
product(id: 73803) {
id
keywords {
id
value
type
}
fields_json
inserted
path
updated
visible
browsable
api1json
categories {
id
name
@@ -191,3 +195,44 @@
}
}
}
# Categories
{
category(id: 1653) {
id
name
path
isLeaf
depth
childCount
lft
rgt
products {
id
fields_json
}
}
}
# Keywords
{
keywords {
id
value
type
products {
id
}
}
}
{
keyword(id: 618) {
id
value
type
products {
id
}
}
}
+75
View File
@@ -0,0 +1,75 @@
import { SQLDataSource } from 'datasource-sql';
import { Keyword, KeywordType } from '../types/keyword-types';
const MINUTE = 60;
export class KeywordAPI extends SQLDataSource {
constructor(config) {
super(config);
}
getType(data: any) {
// raw queries doesn't camelCase...
const typeObject = data.type_id ?? data.typeId;
const typeId = typeObject ?? 0;
return {
...data,
type: KeywordType[typeId],
};
}
async getProductKeywords(productId: number): Promise<Array<Keyword>> {
const query = /* sql */ `
SELECT keywords.*, keyword_type.type_id FROM keywords
LEFT JOIN keyword_type ON keyword_type.keyword_id = keywords.id
JOIN product_keyword ON product_keyword.keyword_id = keywords.id
WHERE product_keyword.product_id = ?
ORDER BY keywords.value
`;
const res = await this.knex
.raw(query, productId)
.then((data) => data.rows.map((row) => this.getType(row)));
return res;
}
async getKeywords(): Promise<Array<Keyword>> {
const query = /* sql */ `
SELECT keywords.*, keyword_type.type_id FROM keywords
LEFT JOIN keyword_type ON keyword_type.keyword_id = keywords.id
ORDER BY keywords.value
`;
const res = await this.knex
.raw(query)
.then((data) => data.rows.map((row) => this.getType(row)));
return res;
}
async getKeywordById(id: number): Promise<Keyword> {
const res = await this.knex
.select('*')
.from('keywords')
.leftJoin('keyword_type', 'keyword_type.keyword_id', 'keywords.id')
.where('id', id)
.first()
.cache(MINUTE)
.then((row) => this.getType(row));
return res;
}
/**
* category keywords
*
SELECT category_keyword.category_id, keywords.value
FROM category_keyword
JOIN keywords ON category_keyword.keyword_id = keywords.id;
FROM categorydata cd
JOIN categorydatakeys cdk ON cd.datakey_id = cdk.id
*
*/
}
+25 -28
View File
@@ -4,6 +4,7 @@ import {
Product,
ProductGroup,
PrintProduct,
ProductType,
ProductBlacklist,
} from '../types/product-types';
import { Maybe } from '../types/types';
@@ -40,9 +41,25 @@ export class ProductAPI extends SQLDataSource {
});
}
getProductTypes(row: any): Array<ProductType> {
if (!row.types) {
return [];
}
return row.types.map((type: any) => {
if (type === 'typeillustration') {
return ProductType[ProductType.ILLUSTRATION];
}
if (type === 'typephotography') {
return ProductType[ProductType.PHOTO];
}
return ProductType[ProductType.UNKNOWN];
});
}
createProductFromRow(row: any) {
row.blacklisting = this.getBlacklisting(row);
row.printProducts = this.getPrintProducts(row);
row.type = this.getProductTypes(row);
row.designerId = row.designerid;
row.fields_json = row.fields;
return row;
@@ -80,32 +97,12 @@ export class ProductAPI extends SQLDataSource {
.raw(query)
.then((data) => data.rows.map((row) => this.createProductFromRow(row)));
}
async getKeywordProducts(keywordId: number): Promise<Array<Product>> {
const query = sql.keywordProducts(keywordId);
return await this.knex
.raw(query)
.then((data) => data.rows.map((row) => this.createProductFromRow(row)));
}
}
/**
*
* SELECT product_keyword.product_id, keywords.value
FROM product_keyword
JOIN keywords ON product_keyword.keyword_id = keywords.id;
*
keywords
id, value
keyword_type:
keyword_id, type_id
keywordstypes
id, name (color)
keywords_i18n NOT used it seems and misses some languages
*/
+15 -1
View File
@@ -48,7 +48,12 @@ SELECT products.productid as id,
FROM "product-products_fields" pf
JOIN "product-fields" fields ON fields.fieldid = pf.fieldid
WHERE pf.productid = products.productid
) AS fields
) AS fields,
( SELECT json_agg(keywords.value)
FROM product_keyword pk
JOIN keywords ON keywords.id = pk.keyword_id
WHERE keywords.id IN (1103,1104)AND pk.product_id = products.productid
) AS types
FROM "product-products" products
`;
@@ -89,3 +94,12 @@ export function categoryProducts(categoryId: number) {
`
);
}
export function keywordProducts(keywordId: number) {
return (
baseQuery +
/* sql */ `
WHERE products.productid IN (SELECT product_id FROM product_keyword WHERE keyword_id = ${keywordId});
`
);
}
+3
View File
@@ -14,6 +14,7 @@ import { Api1DataSource } from './datasources/api1-datasource';
import { verifyToken } from './cognito/cognito-client';
import { CategoryAPI } from './datasources/category-api';
import { KeywordAPI } from './datasources/keyword-api';
console.log(`dbConfig`, dbConfig);
@@ -26,6 +27,7 @@ const api2 = new Api2DataSource();
const orderApi = new OrderAPI(knexConfig);
const productApi = new ProductAPI(knexConfig);
const categoryApi = new CategoryAPI(knexConfig);
const keywordApi = new KeywordAPI(knexConfig);
const designerApi = new DesignerAPI(knexConfig);
const dataSources = () => ({
@@ -33,6 +35,7 @@ const dataSources = () => ({
api2,
categoryApi,
designerApi,
keywordApi,
orderApi,
productApi,
});
+3
View File
@@ -3,17 +3,20 @@ import { productQueryTypeDefs, productTypeDefs } from './products-resolver';
import { designerQueryTypeDefs, designerTypeDefs } from './designers-resolver';
import { categoryQueryTypeDefs, categoryTypeDefs } from './categories-resolver';
import { DateTimeResolver, DateResolver, JSONResolver } from 'graphql-scalars';
import { keywordsQueryTypeDefs, keywordTypeDefs } from './keywords-resolver';
const resolvers = {
Query: {
...orderQueryTypeDefs,
...productQueryTypeDefs,
...designerQueryTypeDefs,
...categoryQueryTypeDefs,
...keywordsQueryTypeDefs,
},
...orderTypeDefs,
...productTypeDefs,
...designerTypeDefs,
...categoryTypeDefs,
...keywordTypeDefs,
DateTime: DateTimeResolver,
Date: DateResolver,
JSON: JSONResolver,
+24
View File
@@ -0,0 +1,24 @@
import { IResolverObject } from 'graphql-tools';
import { KeywordAPI } from '../datasources/keyword-api';
import { ProductAPI } from '../datasources/product-api';
const Keyword: IResolverObject = {
async products({ id }, _args, { dataSources }) {
return (<ProductAPI>dataSources.productApi).getKeywordProducts(id);
},
};
async function getKeywords(_, _args, { dataSources }) {
return (<KeywordAPI>dataSources.keywordApi).getKeywords();
}
async function getKeyword(_, { id }, { dataSources }) {
return (<KeywordAPI>dataSources.keywordApi).getKeywordById(id);
}
export const keywordTypeDefs = { Keyword };
export const keywordsQueryTypeDefs = {
keywords: getKeywords,
keyword: getKeyword,
};
+5
View File
@@ -5,6 +5,8 @@ import { ProductAPI } from '../datasources/product-api';
import { Product } from '../types/product-types';
import { CategoryAPI } from '../datasources/category-api';
import { Category } from '../types/category-types';
import { KeywordAPI } from '../datasources/keyword-api';
import { Keyword } from '../types/keyword-types';
const ProductBlacklist: IResolverObject = {
async market(parent, _args, { dataSources }) {
@@ -20,6 +22,9 @@ const Product: IResolverObject = {
async designer({ designerId }, args, { dataSources }) {
return dataSources.designerApi.getDesignerById(designerId);
},
async keywords({ id }, _args, { dataSources }): Promise<Array<Keyword>> {
return (<KeywordAPI>dataSources.keywordApi).getProductKeywords(id);
},
async api1json({ id }, _args, { dataSources }): Promise<JSON> {
return dataSources.api1.getProduct(id);
},
+26
View File
@@ -12,6 +12,8 @@ const typeDefs = gql`
product(id: Int!): Product
categories: [Category]
category(id: Int!): Category
keywords: [Keyword]
keyword(id: Int!): Keyword
designers(limit: Int): [Designer]
designer(id: Int!): Designer
}
@@ -190,6 +192,12 @@ const typeDefs = gql`
categories: [Category]
designerId: Int
designer: Designer
keywords: [Keyword]
"""
Will be single value return in later release
"""
type: [ProductType]
# Below are for debug
api1json: JSON
fields_json: JSON
}
@@ -206,6 +214,12 @@ const typeDefs = gql`
UNKNOWN
}
enum ProductType {
UNKNOWN
PHOTO
ILLUSTRATION
}
type ProductBlacklist {
id: ID!
groupId: Int!
@@ -231,6 +245,18 @@ const typeDefs = gql`
path: String
orderRows(filter: FilterInput): [OrderRow]
}
enum KeywordType {
NOT_SET
COLOR
}
type Keyword {
id: Int!
value: String!
type: KeywordType
products: [Product]
}
`;
export { typeDefs };
+10
View File
@@ -0,0 +1,10 @@
export enum KeywordType {
NOT_SET = 0,
COLOR = 1,
}
export interface Keyword {
id: number;
value: string;
type: KeywordType;
}
+30 -23
View File
@@ -10,29 +10,10 @@ export enum ProductGroup {
UNKNOWN = 9,
}
export function getProductGroupStringFromString(group: string): string {
return ProductGroup[getProductGroupFromString(group)];
}
export function getProductGroupFromString(group: string): ProductGroup {
switch (group) {
case 'canvas':
return ProductGroup.CANVAS;
case 'framed-print':
return ProductGroup.FRAMED_PRINT;
case 'photo-wallpaper':
return ProductGroup.PHOTO_WALLPAPER;
case 'poster':
return ProductGroup.POSTER;
case 'wallpaper':
return ProductGroup.WALLPAPER;
case 'design-wallpaper':
return ProductGroup.DESIGNER_WALLPAPER;
case 'doityourselfframe':
return ProductGroup.DO_IT_YOURSELF_FRAME;
default:
return ProductGroup.UNKNOWN;
}
export enum ProductType {
UNKNOWN = 0,
PHOTO = 1,
ILLUSTRATION = 2,
}
export interface ProductBlacklist {
id: number;
@@ -60,6 +41,32 @@ export interface Product {
updated?: Date;
printProducts: [PrintProduct];
blacklisting: [ProductBlacklist];
type: [ProductType];
api1json: JSON;
fields_json: JSON;
}
export function getProductGroupStringFromString(group: string): string {
return ProductGroup[getProductGroupFromString(group)];
}
export function getProductGroupFromString(group: string): ProductGroup {
switch (group) {
case 'canvas':
return ProductGroup.CANVAS;
case 'framed-print':
return ProductGroup.FRAMED_PRINT;
case 'photo-wallpaper':
return ProductGroup.PHOTO_WALLPAPER;
case 'poster':
return ProductGroup.POSTER;
case 'wallpaper':
return ProductGroup.WALLPAPER;
case 'design-wallpaper':
return ProductGroup.DESIGNER_WALLPAPER;
case 'doityourselfframe':
return ProductGroup.DO_IT_YOURSELF_FRAME;
default:
return ProductGroup.UNKNOWN;
}
}