-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from vtex-apps/export-product
Export product
- Loading branch information
Showing
27 changed files
with
700 additions
and
128 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# Changelog | ||
|
||
All notable changes to this project will be documented in this file. | ||
|
||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) | ||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). | ||
|
||
## [Unreleased] | ||
|
||
### Added | ||
- Export all `Categories` translations in batch | ||
- Export `Products` for a given category in batch - Limit of 1.600 products |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
type Query { | ||
categoryTranslations(locale: String!, active: Boolean): [Category] | ||
getCategoriesName: [CategoryName] | ||
productTranslations(locale: String!, categoryId: String!): [Product] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
type Product { | ||
id: String! | ||
name: String | ||
description: String | ||
shortDescription: String | ||
title: String | ||
locale: String | ||
linkId: String | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,85 +1,89 @@ | ||
import { AppGraphQLClient, InstanceOptions, IOContext } from '@vtex/api' | ||
import { | ||
InstanceOptions, | ||
IOContext, | ||
JanusClient, | ||
RequestConfig, | ||
} from '@vtex/api' | ||
|
||
import { statusToError } from '../utils' | ||
import { | ||
statusToError, | ||
interations, | ||
getInterationPairs, | ||
extractProductId, | ||
MAX_PRODUCTS_PER_CATEGORY, | ||
} from '../utils' | ||
|
||
const CATALOG_GRAPHQL_APP = '[email protected]' | ||
export class Catalog extends JanusClient { | ||
constructor(ctx: IOContext, opts?: InstanceOptions) { | ||
super(ctx, { | ||
...opts, | ||
headers: { | ||
...opts?.headers, | ||
...(ctx.adminUserAuthToken | ||
? { VtexIdclientAutCookie: ctx.adminUserAuthToken } | ||
: null), | ||
}, | ||
}) | ||
} | ||
|
||
public getAllProducts = async (categoryId: string) => { | ||
const { range, ...products } = await this.getProductIdsByCategory( | ||
categoryId, | ||
1, | ||
MAX_PRODUCTS_PER_CATEGORY | ||
) | ||
const { total } = range | ||
const remainingInterations = interations(total) | ||
const productPerCategorypromises = [] | ||
|
||
const CATEGORIES_QUERY = ` | ||
query GetCategoriesId ($active: Boolean, $page: Int!) { | ||
categories(term:"*", page: $page, pageSize: 50, active: $active) { | ||
items { | ||
id | ||
} | ||
paging { | ||
pages | ||
} | ||
// /GetProductAndSkuIds returns max 50 responses. We loop over the remaining interations to get all products | ||
for (let i = 1; i <= remainingInterations; i++) { | ||
const [from, to] = getInterationPairs(i) | ||
const productPerIdPromise = this.getProductIdsByCategory( | ||
categoryId, | ||
from, | ||
to | ||
) | ||
productPerCategorypromises.push(productPerIdPromise) | ||
} | ||
} | ||
` | ||
|
||
const GET_TRANSLATION_QUERY = ` | ||
query getTranslation($id:ID!) { | ||
category(id: $id) { | ||
id | ||
name | ||
title | ||
description | ||
const productPerCategoryCollection = await Promise.all( | ||
productPerCategorypromises | ||
) | ||
|
||
const finalProducts = [] | ||
|
||
// we plug together the first response and all the others. Then we extract only the product ids from responses | ||
for (const product of [products, ...productPerCategoryCollection]) { | ||
const productIds = extractProductId(product.data) | ||
finalProducts.push(...productIds) | ||
} | ||
return finalProducts | ||
} | ||
` | ||
|
||
export class Catalog extends AppGraphQLClient { | ||
constructor(ctx: IOContext, opts?: InstanceOptions) { | ||
super(CATALOG_GRAPHQL_APP, ctx, opts) | ||
private getProductIdsByCategory = ( | ||
categoryId: string, | ||
_from: number, | ||
_to: number | ||
) => { | ||
return this.get<GetProductAndSkuIds>(this.routes.getProductAndSkuIds(), { | ||
params: { categoryId, _from, _to }, | ||
}) | ||
} | ||
|
||
public getCategoriesId = async (active = true) => { | ||
protected get = <T>(url: string, config: RequestConfig = {}) => { | ||
try { | ||
const response = await this.getCategoriesIdPerPage({ active, page: 1 }) | ||
const { | ||
items, | ||
paging: { pages }, | ||
} = (response.data as CategoryIdsResponse).categories | ||
const collectItems = items | ||
const responsePromises = [] | ||
|
||
for (let i = 2; i <= pages; i++) { | ||
const promise = this.getCategoriesIdPerPage({ active, page: i }) | ||
responsePromises.push(promise) | ||
} | ||
|
||
const resolvedPromises = await Promise.all(responsePromises) | ||
|
||
const flattenResponse = resolvedPromises.reduce((acc, curr) => { | ||
return [...acc, ...(curr.data as CategoryIdsResponse).categories.items] | ||
}, collectItems) | ||
|
||
return flattenResponse | ||
} catch (error) { | ||
return statusToError(error) | ||
return this.http.get<T>(url, config) | ||
} catch (e) { | ||
return statusToError(e) | ||
} | ||
} | ||
|
||
private getCategoriesIdPerPage = ({ | ||
active = true, | ||
page, | ||
}: { | ||
active: boolean | ||
page: number | ||
}) => | ||
this.graphql.query<CategoryIdsResponse, { active: boolean; page: number }>({ | ||
query: CATEGORIES_QUERY, | ||
variables: { | ||
active, | ||
page, | ||
}, | ||
}) | ||
private get routes() { | ||
const basePath = '/api/catalog_system' | ||
|
||
public getTranslation = (id: string) => | ||
this.graphql.query<TranslationResponse, { id: string }>({ | ||
query: GET_TRANSLATION_QUERY, | ||
variables: { | ||
id, | ||
}, | ||
}) | ||
return { | ||
getProductAndSkuIds: () => `${basePath}/pvt/products/GetProductAndSkuIds`, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
import { AppGraphQLClient, InstanceOptions, IOContext } from '@vtex/api' | ||
|
||
import { statusToError } from '../utils' | ||
|
||
const CATALOG_GRAPHQL_APP = '[email protected]' | ||
|
||
const CATEGORIES_QUERY = ` | ||
query GetCategories ($active: Boolean, $page: Int!) { | ||
categories(term:"*", page: $page, pageSize: 50, active: $active) { | ||
items { | ||
id | ||
name | ||
} | ||
paging { | ||
pages | ||
} | ||
} | ||
} | ||
` | ||
|
||
const GET_CATEGORY_TRANSLATION_QUERY = ` | ||
query getTranslation($id:ID!) { | ||
category(id: $id) { | ||
id | ||
name | ||
title | ||
description | ||
linkId | ||
} | ||
} | ||
` | ||
|
||
const GET_PRODUCT_TRANSLATION_QUERY = ` | ||
query getProductTranslation($identifier: ProductUniqueIdentifier) { | ||
product(identifier: $identifier) { | ||
id | ||
name | ||
description | ||
shortDescription | ||
title | ||
linkId | ||
} | ||
} | ||
` | ||
|
||
export class CatalogGQL extends AppGraphQLClient { | ||
constructor(ctx: IOContext, opts?: InstanceOptions) { | ||
super(CATALOG_GRAPHQL_APP, ctx, opts) | ||
} | ||
|
||
public getCategories = async (active = true) => { | ||
try { | ||
const response = await this.getCategoriesPerPage({ active, page: 1 }) | ||
const { | ||
items, | ||
paging: { pages }, | ||
} = (response.data as CategoryResponse).categories | ||
const collectItems = items | ||
const responsePromises = [] | ||
|
||
for (let i = 2; i <= pages; i++) { | ||
const promise = this.getCategoriesPerPage({ active, page: i }) | ||
responsePromises.push(promise) | ||
} | ||
|
||
const resolvedPromises = await Promise.all(responsePromises) | ||
|
||
const flattenResponse = resolvedPromises.reduce((acc, curr) => { | ||
return [...acc, ...(curr.data as CategoryResponse).categories.items] | ||
}, collectItems) | ||
|
||
return flattenResponse | ||
} catch (error) { | ||
return statusToError(error) | ||
} | ||
} | ||
|
||
private getCategoriesPerPage = ({ | ||
active = true, | ||
page, | ||
}: { | ||
active: boolean | ||
page: number | ||
}) => | ||
this.graphql.query<CategoryResponse, { active: boolean; page: number }>({ | ||
query: CATEGORIES_QUERY, | ||
variables: { | ||
active, | ||
page, | ||
}, | ||
}) | ||
|
||
public getCategoryTranslation = (id: string, locale: string) => { | ||
return this.graphql.query<CategoryTranslationResponse, { id: string }>( | ||
{ | ||
query: GET_CATEGORY_TRANSLATION_QUERY, | ||
variables: { | ||
id, | ||
}, | ||
}, | ||
{ | ||
headers: { | ||
'x-vtex-locale': `${locale}`, | ||
}, | ||
} | ||
) | ||
} | ||
|
||
public getProductTranslation = (id: string, locale: string) => | ||
this.graphql.query< | ||
ProductTranslationResponse, | ||
{ identifier: { value: string; field: 'id' } } | ||
>( | ||
{ | ||
query: GET_PRODUCT_TRANSLATION_QUERY, | ||
variables: { | ||
identifier: { | ||
field: 'id', | ||
value: id, | ||
}, | ||
}, | ||
}, | ||
{ | ||
headers: { | ||
'x-vtex-locale': `${locale}`, | ||
}, | ||
} | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,9 @@ | |
}, | ||
"devDependencies": { | ||
"@vtex/tsconfig": "^0.5.6", | ||
"typescript": "3.9.7" | ||
"typescript": "3.9.7", | ||
"vtex.catalog-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/[email protected]/public/@types/vtex.catalog-graphql", | ||
"vtex.styleguide": "http://vtex.vtexassets.com/_v/public/typings/v1/[email protected]/public/@types/vtex.styleguide", | ||
"vtex.tenant-graphql": "http://vtex.vtexassets.com/_v/public/typings/v1/[email protected]/public/@types/vtex.tenant-graphql" | ||
} | ||
} |
Oops, something went wrong.