From d699018bfb99100da4f67f6e8e360ef616ba2220 Mon Sep 17 00:00:00 2001 From: Sofia Leon Date: Tue, 12 Jan 2021 01:39:17 +0000 Subject: [PATCH 01/54] feat!: initial stub of library --- retail/package.json | 23 ++++++++++++++++++ retail/quickstart.js | 51 +++++++++++++++++++++++++++++++++++++++ retail/test/quickstart.js | 50 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 retail/package.json create mode 100644 retail/quickstart.js create mode 100644 retail/test/quickstart.js diff --git a/retail/package.json b/retail/package.json new file mode 100644 index 0000000000..e01267ae6c --- /dev/null +++ b/retail/package.json @@ -0,0 +1,23 @@ +{ + "name": "nodejs-retail", + "private": true, + "license": "Apache-2.0", + "author": "Google LLC", + "engines": { + "node": ">=10" + }, + "files": [ + "*.js" + ], + "scripts": { + "test": "c8 mocha --timeout 600000 test/*.js" + }, + "dependencies": { + "@google-cloud/retail": "^0.1.0" + }, + "devDependencies": { + "c8": "^7.1.0", + "chai": "^4.2.0", + "mocha": "^8.0.0" + } +} diff --git a/retail/quickstart.js b/retail/quickstart.js new file mode 100644 index 0000000000..04cce91ff8 --- /dev/null +++ b/retail/quickstart.js @@ -0,0 +1,51 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +'use strict'; + +async function main() { + // [START nodejs_retail_quickstart] + // Imports the Google Cloud client library + + // remove this line after package is released + // eslint-disable-next-line node/no-missing-require + const {UserEventServiceClient} = require('@google-cloud/retail'); + + // TODO(developer): replace with your prefered project ID. + // const projectId = 'my-project' + + // Creates a client + // eslint-disable-next-line no-unused-vars + const client = new {UserEventServiceClient}(); + + //TODO(library generator): write the actual function you will be testing + async function doSomething() { + console.log( + 'Developer! Change this code so that it shows how to use the library! See comments below on structure.' + ); + // const [thing] = await client.methodName({ + // }); + // console.info(thing); + } + doSomething(); + // [END nodejs_retail_quickstart] +} + +main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; +}); +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); diff --git a/retail/test/quickstart.js b/retail/test/quickstart.js new file mode 100644 index 0000000000..2d076f85c7 --- /dev/null +++ b/retail/test/quickstart.js @@ -0,0 +1,50 @@ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ** This file is automatically generated by gapic-generator-typescript. ** +// ** https://github.com/googleapis/gapic-generator-typescript ** +// ** All changes to this file may be overwritten. ** + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it} = require('mocha'); +// eslint-disable-next-line node/no-missing-require +const {UserEventServiceClient} = require('@google-cloud/retail'); +// eslint-disable-next-line no-unused-vars, node/no-missing-require +const {assert} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cwd = path.join(__dirname, '..'); + +const client = new {UserEventServiceClient}(); + +describe('Quickstart', () => { + //TODO: remove this if not using the projectId + // eslint-disable-next-line no-unused-vars + let projectId; + + before(async () => { + // eslint-disable-next-line no-unused-vars + projectId = await client.getProjectId(); + }); + + it('should run quickstart', async () => { + //TODO: remove this disability + // eslint-disable-next-line no-unused-vars + const stdout = execSync('node ./quickstart.js', {cwd}); + //assert(stdout, stdout !== null); + }); +}); From 11ec98864c61c0a5c908a7f9d2987a12eca33326 Mon Sep 17 00:00:00 2001 From: sofisl <55454395+sofisl@users.noreply.github.com> Date: Wed, 13 Jan 2021 10:49:15 -0800 Subject: [PATCH 02/54] feat: add initial samples (#2) * feat: add samples and tests --- retail/quickstart.js | 29 ++++++++++++----------------- retail/test/quickstart.js | 15 ++++----------- 2 files changed, 16 insertions(+), 28 deletions(-) diff --git a/retail/quickstart.js b/retail/quickstart.js index 04cce91ff8..e8b65192f3 100644 --- a/retail/quickstart.js +++ b/retail/quickstart.js @@ -13,31 +13,26 @@ 'use strict'; -async function main() { +async function main(projectId, location) { // [START nodejs_retail_quickstart] - // Imports the Google Cloud client library - // remove this line after package is released - // eslint-disable-next-line node/no-missing-require - const {UserEventServiceClient} = require('@google-cloud/retail'); + // Imports the Google Cloud client library + const {CatalogServiceClient} = require('@google-cloud/retail'); - // TODO(developer): replace with your prefered project ID. + // TODO(developer): uncomment these variables with your information // const projectId = 'my-project' + // const location = 'global' // Creates a client - // eslint-disable-next-line no-unused-vars - const client = new {UserEventServiceClient}(); + const client = new CatalogServiceClient(); - //TODO(library generator): write the actual function you will be testing - async function doSomething() { - console.log( - 'Developer! Change this code so that it shows how to use the library! See comments below on structure.' - ); - // const [thing] = await client.methodName({ - // }); - // console.info(thing); + async function listCatalogs() { + const catalogs = await client.listCatalogs({ + parent: `projects/${projectId}/locations/${location}`, + }); + console.info(catalogs); } - doSomething(); + listCatalogs(); // [END nodejs_retail_quickstart] } diff --git a/retail/test/quickstart.js b/retail/test/quickstart.js index 2d076f85c7..5f93004506 100644 --- a/retail/test/quickstart.js +++ b/retail/test/quickstart.js @@ -20,31 +20,24 @@ const path = require('path'); const cp = require('child_process'); const {before, describe, it} = require('mocha'); -// eslint-disable-next-line node/no-missing-require -const {UserEventServiceClient} = require('@google-cloud/retail'); -// eslint-disable-next-line no-unused-vars, node/no-missing-require +const {CatalogServiceClient} = require('@google-cloud/retail'); const {assert} = require('chai'); const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); const cwd = path.join(__dirname, '..'); -const client = new {UserEventServiceClient}(); +const client = new CatalogServiceClient(); describe('Quickstart', () => { - //TODO: remove this if not using the projectId - // eslint-disable-next-line no-unused-vars let projectId; before(async () => { - // eslint-disable-next-line no-unused-vars projectId = await client.getProjectId(); }); it('should run quickstart', async () => { - //TODO: remove this disability - // eslint-disable-next-line no-unused-vars - const stdout = execSync('node ./quickstart.js', {cwd}); - //assert(stdout, stdout !== null); + const stdout = execSync(`node ./quickstart.js ${projectId} global`, {cwd}); + assert.match(stdout, /default_catalog/); }); }); From 984e0c9b8209438cf35f0efcdc7dd03cf4c86fc3 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Wed, 13 Jan 2021 15:02:12 -0800 Subject: [PATCH 03/54] chore: release 1.0.0 (#1) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index e01267ae6c..bbee8126c6 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha --timeout 600000 test/*.js" }, "dependencies": { - "@google-cloud/retail": "^0.1.0" + "@google-cloud/retail": "^1.0.0" }, "devDependencies": { "c8": "^7.1.0", From e09d5880bf066166cf74dc0ae3a9f27c4a241811 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Mon, 1 Mar 2021 16:42:47 -0800 Subject: [PATCH 04/54] chore: release 1.1.0 (#19) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index bbee8126c6..18be1c5089 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha --timeout 600000 test/*.js" }, "dependencies": { - "@google-cloud/retail": "^1.0.0" + "@google-cloud/retail": "^1.1.0" }, "devDependencies": { "c8": "^7.1.0", From 4808c1251de6acaad99ca189b0309440d47344b7 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 13 May 2021 10:30:02 -0700 Subject: [PATCH 05/54] chore: release 1.1.1 (#48) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index 18be1c5089..cc7675fdb2 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha --timeout 600000 test/*.js" }, "dependencies": { - "@google-cloud/retail": "^1.1.0" + "@google-cloud/retail": "^1.1.1" }, "devDependencies": { "c8": "^7.1.0", From 082d3193eade00e7b0e9b774675c8ce97a23bb13 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 25 May 2021 18:17:52 -0400 Subject: [PATCH 06/54] chore: release 1.1.2 (#56) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index cc7675fdb2..c0f971fb5a 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha --timeout 600000 test/*.js" }, "dependencies": { - "@google-cloud/retail": "^1.1.1" + "@google-cloud/retail": "^1.1.2" }, "devDependencies": { "c8": "^7.1.0", From 7bebc1addab7c75af29d6696b9bcc69c3aa1653f Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Fri, 25 Jun 2021 10:01:18 -0700 Subject: [PATCH 07/54] chore: release 1.1.3 (#63) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index c0f971fb5a..49864f6dcb 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha --timeout 600000 test/*.js" }, "dependencies": { - "@google-cloud/retail": "^1.1.2" + "@google-cloud/retail": "^1.1.3" }, "devDependencies": { "c8": "^7.1.0", From edae10bd6a02e98da9f27c4697f7f9b553fe6fb6 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 16:06:09 +0000 Subject: [PATCH 08/54] chore: release 1.1.4 (#68) :robot: I have created a release \*beep\* \*boop\* --- ### [1.1.4](https://www.github.com/googleapis/nodejs-retail/compare/v1.1.3...v1.1.4) (2021-07-01) ### Bug Fixes * **deps:** require google-gax v2.17.0 ([#66](https://www.github.com/googleapis/nodejs-retail/issues/66)) ([94fd8a8](https://www.github.com/googleapis/nodejs-retail/commit/94fd8a842f4fc7cfb480e72d4b3375ec0293cc09)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index 49864f6dcb..0863d97188 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha --timeout 600000 test/*.js" }, "dependencies": { - "@google-cloud/retail": "^1.1.3" + "@google-cloud/retail": "^1.1.4" }, "devDependencies": { "c8": "^7.1.0", From 0e177ccc9537832148c57faef8f0a0f251e990af Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 13 Jul 2021 15:36:06 -0700 Subject: [PATCH 09/54] chore: release 1.1.5 (#70) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index 0863d97188..983de279fb 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha --timeout 600000 test/*.js" }, "dependencies": { - "@google-cloud/retail": "^1.1.4" + "@google-cloud/retail": "^1.1.5" }, "devDependencies": { "c8": "^7.1.0", From cf66bc7292485f0182f58d26d120d1de56158583 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Fri, 16 Jul 2021 13:00:08 -0700 Subject: [PATCH 10/54] chore: release 1.1.6 (#74) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index 983de279fb..7ed2ee30fa 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha --timeout 600000 test/*.js" }, "dependencies": { - "@google-cloud/retail": "^1.1.5" + "@google-cloud/retail": "^1.1.6" }, "devDependencies": { "c8": "^7.1.0", From c7c8192c1a2bba317d4c47c0c6e6001f6944f8e9 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Mon, 2 Aug 2021 20:34:26 +0000 Subject: [PATCH 11/54] chore: release 1.2.0 (#80) :robot: I have created a release \*beep\* \*boop\* --- ## [1.2.0](https://www.github.com/googleapis/nodejs-retail/compare/v1.1.6...v1.2.0) (2021-08-02) ### Features * Add restricted Retail Search features for Retail API v2 ([b8279f4](https://www.github.com/googleapis/nodejs-retail/commit/b8279f4b3e90150d349ddd2071d8e25c51c07ec4)) * Add restricted Retail Search features for Retail API v2alpha ([b8279f4](https://www.github.com/googleapis/nodejs-retail/commit/b8279f4b3e90150d349ddd2071d8e25c51c07ec4)) * Add restricted Retail Search features for Retail API v2beta. ([#79](https://www.github.com/googleapis/nodejs-retail/issues/79)) ([b8279f4](https://www.github.com/googleapis/nodejs-retail/commit/b8279f4b3e90150d349ddd2071d8e25c51c07ec4)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index 7ed2ee30fa..da44249b2e 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha --timeout 600000 test/*.js" }, "dependencies": { - "@google-cloud/retail": "^1.1.6" + "@google-cloud/retail": "^1.2.0" }, "devDependencies": { "c8": "^7.1.0", From acc003d6a6f7af72aff829c27b4a574058b3b704 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 17 Aug 2021 03:12:40 +0000 Subject: [PATCH 12/54] chore: release 1.2.1 (#92) :robot: I have created a release \*beep\* \*boop\* --- ### [1.2.1](https://www.github.com/googleapis/nodejs-retail/compare/v1.2.0...v1.2.1) (2021-08-17) ### Bug Fixes * **deps:** google-gax v2.24.1 ([#91](https://www.github.com/googleapis/nodejs-retail/issues/91)) ([893845a](https://www.github.com/googleapis/nodejs-retail/commit/893845aae9f43a41ad21f97000bc73da3fb985c0)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index da44249b2e..035c06dbea 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha --timeout 600000 test/*.js" }, "dependencies": { - "@google-cloud/retail": "^1.2.0" + "@google-cloud/retail": "^1.2.1" }, "devDependencies": { "c8": "^7.1.0", From 9f8d53f9c191d1e546d8ad7e52418f01a43d4985 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Fri, 10 Sep 2021 10:53:07 -0700 Subject: [PATCH 13/54] chore: release 1.2.2 (#99) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index 035c06dbea..3643454006 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha --timeout 600000 test/*.js" }, "dependencies": { - "@google-cloud/retail": "^1.2.1" + "@google-cloud/retail": "^1.2.2" }, "devDependencies": { "c8": "^7.1.0", From 3a85df71501813437bd546497c4d98462a130a3f Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 19 Oct 2021 22:58:29 +0000 Subject: [PATCH 14/54] chore: release 1.3.0 (#108) :robot: I have created a release \*beep\* \*boop\* --- ## [1.3.0](https://www.github.com/googleapis/nodejs-retail/compare/v1.2.2...v1.3.0) (2021-10-19) ### Features * add search mode to search request. If not specified, a single search request triggers both product search and faceted search. ([49b9b8e](https://www.github.com/googleapis/nodejs-retail/commit/49b9b8e22eba6318f54e44025df4e3c1900cb73e)) * update grpc service config settings to reflect correct API deadlines ([49b9b8e](https://www.github.com/googleapis/nodejs-retail/commit/49b9b8e22eba6318f54e44025df4e3c1900cb73e)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index 3643454006..33a2d71bad 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha --timeout 600000 test/*.js" }, "dependencies": { - "@google-cloud/retail": "^1.2.2" + "@google-cloud/retail": "^1.3.0" }, "devDependencies": { "c8": "^7.1.0", From b1f9455af2c7bfec43823c01307d0b6e36f9aa74 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 4 Nov 2021 16:02:20 +0000 Subject: [PATCH 15/54] chore: release 1.4.0 (#113) :robot: I have created a release \*beep\* \*boop\* --- ## [1.4.0](https://www.github.com/googleapis/nodejs-retail/compare/v1.3.0...v1.4.0) (2021-11-04) ### Features * Add local inventory ingestion APIs to product service in alpha channel ([#112](https://www.github.com/googleapis/nodejs-retail/issues/112)) ([8387781](https://www.github.com/googleapis/nodejs-retail/commit/8387781135ddb02b43af222bbbd3d5852e0147d3)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index 33a2d71bad..5ba6636e98 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha --timeout 600000 test/*.js" }, "dependencies": { - "@google-cloud/retail": "^1.3.0" + "@google-cloud/retail": "^1.4.0" }, "devDependencies": { "c8": "^7.1.0", From c3e2574da6f729e7154dff5b7b5bbd0926fb5550 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Mon, 29 Nov 2021 10:07:18 -0800 Subject: [PATCH 16/54] chore: release 1.5.0 (#118) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index 5ba6636e98..55e3f26cd8 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha --timeout 600000 test/*.js" }, "dependencies": { - "@google-cloud/retail": "^1.4.0" + "@google-cloud/retail": "^1.5.0" }, "devDependencies": { "c8": "^7.1.0", From 86aca25299167f6156d17df0819daffb21f4f649 Mon Sep 17 00:00:00 2001 From: nmykhailets <94851929+nmykhailets@users.noreply.github.com> Date: Tue, 15 Feb 2022 17:40:48 +0200 Subject: [PATCH 17/54] test: create/delete test resources scripts (#145) --- retail/.mocharc.json | 5 + .../resources/events_schema.json | 73 ++++ .../resources/product_schema.json | 317 ++++++++++++++++ .../resources/products.json | 316 ++++++++++++++++ .../resources/products_some_invalid.json | 3 + .../resources/user_events.json | 4 + .../resources/user_events_some_invalid.json | 4 + .../setup/setup-cleanup.js | 347 ++++++++++++++++++ .../TEST_RESOURCES_SETUP_CLEANUP.md | 53 +++ .../create-test-resources.js | 128 +++++++ .../remove-test-resources.js | 44 +++ retail/package.json | 6 +- 12 files changed, 1298 insertions(+), 2 deletions(-) create mode 100644 retail/.mocharc.json create mode 100644 retail/interactive-tutorials/resources/events_schema.json create mode 100644 retail/interactive-tutorials/resources/product_schema.json create mode 100644 retail/interactive-tutorials/resources/products.json create mode 100644 retail/interactive-tutorials/resources/products_some_invalid.json create mode 100644 retail/interactive-tutorials/resources/user_events.json create mode 100644 retail/interactive-tutorials/resources/user_events_some_invalid.json create mode 100644 retail/interactive-tutorials/setup/setup-cleanup.js create mode 100644 retail/interactive-tutorials/test-resources-setup/TEST_RESOURCES_SETUP_CLEANUP.md create mode 100644 retail/interactive-tutorials/test-resources-setup/create-test-resources.js create mode 100644 retail/interactive-tutorials/test-resources-setup/remove-test-resources.js diff --git a/retail/.mocharc.json b/retail/.mocharc.json new file mode 100644 index 0000000000..33a4e2f7e0 --- /dev/null +++ b/retail/.mocharc.json @@ -0,0 +1,5 @@ +{ + "timeout": "600000", + "recursive": true, + "spec": ["test/*.js", "interactive-tutorials/test/*.js"] +} \ No newline at end of file diff --git a/retail/interactive-tutorials/resources/events_schema.json b/retail/interactive-tutorials/resources/events_schema.json new file mode 100644 index 0000000000..a52c0e56f3 --- /dev/null +++ b/retail/interactive-tutorials/resources/events_schema.json @@ -0,0 +1,73 @@ +[ + { + "fields":[ + { + "mode": "NULLABLE", + "name": "currencyCode", + "type": "STRING" + }, + { + "mode": "NULLABLE", + "name": "revenue", + "type": "FLOAT" + } + ], + "mode": "NULLABLE", + "name": "purchaseTransaction", + "type": "RECORD" + }, + { + "fields":[ + { + "mode": "NULLABLE", + "name": "quantity", + "type": "INTEGER" + }, + { + "fields":[ + { + "mode": "NULLABLE", + "name": "id", + "type": "STRING" + } + ], + "mode": "NULLABLE", + "name": "product", + "type": "RECORD" + } + ], + "mode": "REPEATED", + "name": "productDetails", + "type": "RECORD" + }, + { + "mode": "REQUIRED", + "name": "eventTime", + "type": "STRING" + }, + { + "mode": "REQUIRED", + "name": "visitorId", + "type": "STRING" + }, + { + "mode": "REQUIRED", + "name": "eventType", + "type": "STRING" + }, + { + "mode": "NULLABLE", + "name": "searchQuery", + "type": "STRING" + }, + { + "mode": "NULLABLE", + "name": "cartId", + "type": "STRING" + }, + { + "mode": "REPEATED", + "name": "pageCategories", + "type": "STRING" + } + ] \ No newline at end of file diff --git a/retail/interactive-tutorials/resources/product_schema.json b/retail/interactive-tutorials/resources/product_schema.json new file mode 100644 index 0000000000..2dcc79f7fe --- /dev/null +++ b/retail/interactive-tutorials/resources/product_schema.json @@ -0,0 +1,317 @@ +[ + { + "name": "name", + "type": "STRING", + "mode": "NULLABLE" + }, + { + "name": "id", + "type": "STRING", + "mode": "REQUIRED" + }, + { + "name": "type", + "type": "STRING", + "mode": "NULLABLE" + }, + { + "name": "primaryProductId", + "type": "STRING", + "mode": "NULLABLE" + }, + { + "name": "collectionMemberIds", + "type": "STRING", + "mode": "REPEATED" + }, + { + "name": "gtin", + "type": "STRING", + "mode": "NULLABLE" + }, + { + "name": "categories", + "type": "STRING", + "mode": "REPEATED" + }, + { + "name": "title", + "type": "STRING", + "mode": "REQUIRED" + }, + { + "name": "brands", + "type": "STRING", + "mode": "REPEATED" + }, + { + "name": "description", + "type": "STRING", + "mode": "NULLABLE" + }, + { + "name": "languageCode", + "type": "STRING", + "mode": "NULLABLE" + }, + { + "name": "attributes", + "type": "RECORD", + "mode": "REPEATED", + "fields": [ + { + "name": "key", + "type": "STRING", + "mode": "NULLABLE" + }, + { + "name": "value", + "type": "RECORD", + "mode": "NULLABLE", + "fields": [ + { + "name": "text", + "type": "STRING", + "mode": "REPEATED" + }, + { + "name": "numbers", + "type": "FLOAT", + "mode": "REPEATED" + }, + { + "name": "searchable", + "type": "BOOLEAN", + "mode": "NULLABLE" + }, + { + "name": "indexable", + "type": "BOOLEAN", + "mode": "NULLABLE" + } + ] + } + ] + }, + { + "name": "tags", + "type": "STRING", + "mode": "REPEATED" + }, + { + "name": "priceInfo", + "type": "RECORD", + "mode": "NULLABLE", + "fields": [ + { + "name": "currencyCode", + "type": "STRING", + "mode": "NULLABLE" + }, + { + "name": "price", + "type": "FLOAT", + "mode": "NULLABLE" + }, + { + "name": "originalPrice", + "type": "FLOAT", + "mode": "NULLABLE" + }, + { + "name": "cost", + "type": "FLOAT", + "mode": "NULLABLE" + }, + { + "name": "priceEffectiveTime", + "type": "STRING", + "mode": "NULLABLE" + }, + { + "name": "priceExpireTime", + "type": "STRING", + "mode": "NULLABLE" + } + ] + }, + { + "name": "rating", + "type": "RECORD", + "mode": "NULLABLE", + "fields": [ + { + "name": "ratingCount", + "type": "INTEGER", + "mode": "NULLABLE" + }, + { + "name": "averageRating", + "type": "FLOAT", + "mode": "NULLABLE" + }, + { + "name": "ratingHistogram", + "type": "INTEGER", + "mode": "REPEATED" + } + ] + }, + { + "name": "expireTime", + "type": "STRING", + "mode": "NULLABLE" + }, + { + "name": "ttl", + "type": "RECORD", + "mode": "NULLABLE", + "fields": [ + { + "name": "seconds", + "type": "INTEGER", + "mode": "NULLABLE" + }, + { + "name": "nanos", + "type": "INTEGER", + "mode": "NULLABLE" + } + ] + }, + { + "name": "availableTime", + "type": "STRING", + "mode": "NULLABLE" + }, + { + "name": "availability", + "type": "STRING", + "mode": "NULLABLE" + }, + { + "name": "availableQuantity", + "type": "INTEGER", + "mode": "NULLABLE" + }, + { + "name": "fulfillmentInfo", + "type": "RECORD", + "mode": "REPEATED", + "fields": [ + { + "name": "type", + "type": "STRING", + "mode": "NULLABLE" + }, + { + "name": "placeIds", + "type": "STRING", + "mode": "REPEATED" + } + ] + }, + { + "name": "uri", + "type": "STRING", + "mode": "NULLABLE" + }, + { + "name": "images", + "type": "RECORD", + "mode": "REPEATED", + "fields": [ + { + "name": "uri", + "type": "STRING", + "mode": "REQUIRED" + }, + { + "name": "height", + "type": "INTEGER", + "mode": "NULLABLE" + }, + { + "name": "width", + "type": "INTEGER", + "mode": "NULLABLE" + } + ] + }, + { + "name": "audience", + "type": "RECORD", + "mode": "NULLABLE", + "fields": [ + { + "name": "genders", + "type": "STRING", + "mode": "REPEATED" + }, + { + "name": "ageGroups", + "type": "STRING", + "mode": "REPEATED" + } + ] + }, + { + "name": "colorInfo", + "type": "RECORD", + "mode": "NULLABLE", + "fields": [ + { + "name": "colorFamilies", + "type": "STRING", + "mode": "REPEATED" + }, + { + "name": "colors", + "type": "STRING", + "mode": "REPEATED" + } + ] + }, + { + "name": "sizes", + "type": "STRING", + "mode": "REPEATED" + }, + { + "name": "materials", + "type": "STRING", + "mode": "REPEATED" + }, + { + "name": "patterns", + "type": "STRING", + "mode": "REPEATED" + }, + { + "name": "conditions", + "type": "STRING", + "mode": "REPEATED" + }, + { + "name": "retrievableFields", + "type": "STRING", + "mode": "NULLABLE" + }, + { + "name": "publishTime", + "type": "STRING", + "mode": "NULLABLE" + }, + { + "name": "promotions", + "type": "RECORD", + "mode": "REPEATED", + "fields": [ + { + "name": "promotionId", + "type": "STRING", + "mode": "NULLABLE" + } + ] + } +] \ No newline at end of file diff --git a/retail/interactive-tutorials/resources/products.json b/retail/interactive-tutorials/resources/products.json new file mode 100644 index 0000000000..17de0ec4c5 --- /dev/null +++ b/retail/interactive-tutorials/resources/products.json @@ -0,0 +1,316 @@ +{"id": "GGCOGOAC101259","name": "GGCOGOAC101259","title": "#IamRemarkable Pen","brands": ["#IamRemarkable"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "16"},"colorInfo": {"colorFamilies": ["Blue"],"colors": ["Light blue","Blue","Dark blue"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGCOGOAC101259.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Metal","Recycled Plastic"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Office/IamRemarkable+Pen"} +{"id": "GGOEAAEC172013","name": "GGOEAAEC172013","title": "Android Embroidered Crewneck Sweater","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Android+Embroidered+Crewneck+Sweater"} +{"id": "GGPRAHPL107110","name": "GGPRAHPL107110","title": "Android Iconic Hat Green","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "16"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive","Grass green","Light green"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAHPL130910.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Android+Iconic+Hat+Green"} +{"id": "GGOEAAKQ137410","name": "GGOEAAKQ137410","title": "Android Iconic Sock","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "17"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAAKQ137410.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Membrane"]}},{"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Android+Iconic+Sock"} +{"id": "GGOEAAWL130147","name": "GGOEAAWL130147","title": "Android Pocket Onesie Navy","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAXXX1301.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Membrane"]}},{"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Android+Pocket+Onesie+Navy"} +{"id": "GGOEGAED142617","name": "GGOEGAED142617","title": "Google Austin Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1426.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Austin+Campus+Unisex+Tee"} +{"id": "GGOEGAEJ163316","name": "GGOEGAEJ163316","title": "Google Charcoal Unisex Badge Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "21"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1633.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Charcoal+Unisex+Badge+Tee"} +{"id": "GGOEGDWC140899","name": "GGOEGDWC140899","title": "Google Chicago Campus Mug","brands": ["Google"],"categories": ["Drinkware"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "12"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGDWC140899.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Drinkware/Google+Chicago+Campus+Mug"} +{"id": "GGOEGCBD142299","name": "GGOEGCBD142299","title": "Google Cork Tablet Case","brands": ["Google"],"categories": ["Bags"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGCBD142299.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Accessories/Google+Cork+Tablet+Case"} +{"id": "GGOEGAEB119414","name": "GGOEGAEB119414","title": "Google Dino Game Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1194.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Dino+Game+Tee"} +{"id": "GGOEGAAH134316","name": "GGOEGAAH134316","title": "Google Heather Green Speckled Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive","Grass green","Light green"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1343.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Heather+Green+Speckled+Tee"} +{"id": "GGPRGBRC104499","name": "GGPRGBRC104499","title": "Google Incognito Zippack V2","brands": ["Google"],"categories": ["Bags"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "36"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGBRC128099.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Incognito+Zippack+V2"} +{"id": "GGOEGAEH146017","name": "GGOEGAEH146017","title": "Google LA Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1460.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+LA+Campus+Unisex+Tee"} +{"id": "GGOEGAED161612","name": "GGOEGAED161612","title": "Google LA Campus Women Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGCOGXXX1569.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Land+and+Sea+Unisex+Tee+LS"} +{"id": "GGOEGCBA150799","name": "GGOEGCBA150799","title": "Google Large Pet Leash (Red/Yellow)","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGCBA150799.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Accessories/Google+Large+Pet+Leash+Red+Yellow"} +{"id": "GGOEGADJ137115","name": "GGOEGADJ137115","title": "Google Men's Tech Fleece Vest Charcoal","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "39"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1371.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Mens+Tech+Fleece+Vest+Charcoal"} +{"id": "GGOEGAER119515","name": "GGOEGAER119515","title": "Google Mountain View Tee Red","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"colorInfo": {"colorFamilies": ["Red"],"colors": ["Red","Neon red"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1195.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Mountain+View+Tee+Red"} +{"id": "GGOEGAEB140413","name": "GGOEGAEB140413","title": "Google NYC Campus Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1404.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+NYC+Campus+Zip+Hoodie"} +{"id": "GGOEGAEC165215","name": "GGOEGAEC165215","title": "Google Navy French Terry Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1652.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Navy+French+Terry+Zip+Hoodie"} +{"id": "GGOEGALJ148813","name": "GGOEGALJ148813","title": "Google Seattle Campus Ladies Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1488.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Seattle+Campus+Ladies+Tee"} +{"id": "GGOEGALJ148816","name": "GGOEGALJ148816","title": "Google Seattle Campus Ladies Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1488.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Seattle+Campus+Ladies+Tee"} +{"id": "GGOEGAAQ117715","name": "GGOEGAAQ117715","title": "Google Striped Tank","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "29"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1177.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Google+Striped+Tank"} +{"id": "GGOEGAAQ117716","name": "GGOEGAAQ117716","title": "Google Striped Tank","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "29"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1177.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Google+Striped+Tank"} +{"id": "GGCOGAEJ153718","name": "GGCOGAEJ153718","title": "Google TYCTWD Gray Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1537.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/TYCTWD/Google+TYCTWD+Charcoal+Tee"} +{"id": "GGOEGAER090417","name": "GGOEGAER090417","title": "Google Tee Red","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Red"],"colors": ["Red","Flame red"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX0904.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Membrane"]}},{"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Tee+Red"} +{"id": "GGOEGAXB135628","name": "GGOEGAXB135628","title": "Google Toddler Hero Tee Charcoal Black","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "24"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Ebony","Outer Space","Jet"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1356.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Toddler+Hero+Tee+Black"} +{"id": "GGOEGHBJ101899","name": "GGOEGHBJ101899","title": "Google Twill Cap Charcoal","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "13"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGHBJ101899.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Twill+Cap+Charcoal"} +{"id": "GGOEGAEB125316","name": "GGOEGAEB125316","title": "Google Unisex Pride Eco-Tee Black","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Ebony","Outer Space","Jet"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1253.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Unisex+Pride+Eco-Tee+Black"} +{"id": "GGOEGAEB170917","name": "GGOEGAEB170917","title": "Google Unisex V-neck Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "27"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1709.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Unisex+V+neck+Tee"} +{"id": "GGOEGAPC167099","name": "GGOEGAPC167099","title": "Google Vintage Cap Navy","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "3"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGAPC167099.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Vintage+Cap+Navy"} +{"id": "GGOEGAEH174914","name": "GGOEGAEH174914","title": "Google Vintage Olive Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "28"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1749.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Vintage+Olive+Tee"} +{"id": "GGOEGAPJ108213","name": "GGOEGAPJ108213","title": "Google Women's Discovery Lt. Rain Shell","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1082.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Womens+Discovery"} +{"id": "GGOEGALB119017","name": "GGOEGALB119017","title": "Google Women's Eco Tee Black","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Ebony","Outer Space","Jet"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1190.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Womens+Eco+Tee+Black"} +{"id": "GGOEGAWH126845","name": "GGOEGAWH126845","title": "Stan and Friends 2019 Onesie","brands": ["Stan and Friends"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive","Grass green","Light green"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1268.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Stan+and+Friends+Onesie+Green"} +{"id": "GGOEYOCR125599","name": "GGOEYOCR125599","title": "YouTube Transmission Journal Red","brands": ["YouTube"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "16"},"colorInfo": {"colorFamilies": ["Red"],"colors": ["Red","Neon red","Flame red"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEYOCR125599.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/YouTube+Transmission+Journal+Red"} +{"id": "GGCOGADC100815","name": "GGCOGADC100815","title": "#IamRemarkable Hoodie","brands": ["#IamRemarkable"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "32"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGCOGXXX1008.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/IamRemarkable+Hoodie"} +{"id": "GGCOGALC100713","name": "GGCOGALC100713","title": "#IamRemarkable Ladies T-Shirt","brands": ["#IamRemarkable"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "12"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGCOGXXX1007.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/IamRemarkable+Ladies+T-Shirt"} +{"id": "GGOEAAYH130212","name": "GGOEAAYH130212","title": "Android Pocket Youth Tee Green","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive","Grass green","Light green"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAXXX1302.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Android+Pocket+Youth+Tee+Green"} +{"id": "GGPRGCBA104199","name": "GGPRGCBA104199","title": "Google ApPeel Journal Red","brands": ["Google"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "3.67"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20210405858/assets/items/images/GGPRGCBA104199.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Sustainable+Kit"} +{"id": "GGOEGAFB134012","name": "GGOEGAFB134012","title": "Google Badge Heavyweight Pullover Black","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Ebony","Outer Space","Jet"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1340.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Badge+Heavyweight+Pullover+Black"} +{"id": "GGOEGAFB134018","name": "GGOEGAFB134018","title": "Google Badge Heavyweight Pullover Black","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Outer Space","Jet"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1340.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Badge+Heavyweight+Pullover+Black"} +{"id": "GGOEGALL144015","name": "GGOEGALL144015","title": "Google Boulder Campus Ladies Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1440.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Boulder+Campus+Ladies+Tee"} +{"id": "GGOEGADH120418","name": "GGOEGADH120418","title": "Google Campus Raincoat Green","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "44"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive","Grass green","Light green"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Campus+Raincoat+Green"} +{"id": "GGOEGBJD141499","name": "GGOEGBJD141499","title": "Google Chicago Campus Tote","brands": ["Google"],"categories": ["Bags"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "11"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGBJD141499.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Bags/Google+Chicago+Campus+Tote"} +{"id": "GGPRGDHB106099","name": "GGPRGDHB106099","title": "Google Chrome Dino Light Up Water Bottle","brands": ["Google"],"categories": ["Drinkware"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "24"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGDHB163199.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Chrome+Dino+Light+Up+Water+Bottle"} +{"id": "GGOEGAEB173714","name": "GGOEGAEB173714","title": "Google Crewneck Sweatshirt Black","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "37"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Outer Space","Jet"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Crewneck+Sweatshirt+Black"} +{"id": "GGOEGADH134214","name": "GGOEGADH134214","title": "Google Crewneck Sweatshirt Green","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive","Grass green","Light green"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1342.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Crewneck+Sweatshirt+Green"} +{"id": "GGOEGAER149217","name": "GGOEGAER149217","title": "Google Kirkland Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1492.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Kirkland+Campus+Unisex+Tee"} +{"id": "GGOEGOAA172399","name": "GGOEGOAA172399","title": "Google Ombre Pen","brands": ["Google"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "1.75"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGOAA172399.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Ombre+Pen+Yellow"} +{"id": "GGOEGAEJ148013","name": "GGOEGAEJ148013","title": "Google PNW Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1480.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+PNW+Campus+Zip+Hoodie"} +{"id": "GGOEGAEJ148214","name": "GGOEGAEJ148214","title": "Google PNW Campus Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1482.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+PNW+Campus+Unisex+Tee"} +{"id": "GGPRGAAB100712","name": "GGPRGAAB100712","title": "Google Unisex Eco Tee Black","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Ebony","Outer Space","Jet"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20210405858/assets/items/images/GGPRGXXX1007.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Unisex+Eco+Tee+Black"} +{"id": "GGOEGAQB107813","name": "GGOEGAQB107813","title": "Google Women's Grid Zip-Up","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "33"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1078.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Womens+Grid+Zip+Up"} +{"id": "GGOEGAPB176914","name": "GGOEGAPB176914","title": "Google Women's Puffer Jacket","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "36"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Womens+Puffer+Jacket"} +{"id": "GGOEGATB176713","name": "GGOEGATB176713","title": "Google Women's Puffer Vest","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "34"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Womens+Puffer+Vest"} +{"id": "GGOEGAPJ138615","name": "GGOEGAPJ138615","title": "Google Women's Tech Fleece Grey","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "39"},"colorInfo": {"colorFamilies": ["Gray"],"colors": ["Light gray","Silver"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1386.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Womens+Tech+Fleece+Grey"} +{"id": "GGOEGAYH135914","name": "GGOEGAYH135914","title": "Google Youth Badge Tee Olive","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "24"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1359.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Youth+Badge+Tee+Olive"} +{"id": "GGOEGAYB113113","name": "GGOEGAYB113113","title": "Google Youth FC Longsleeve Charcoal","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1131.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Youth+FC+Longsleeve+Charcoal"} +{"id": "GGOEGAEH126718","name": "GGOEGAEH126718","title": "Stan and Friends 2019 Tee","brands": ["Stan and Friends"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive","Grass green"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1267.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Stan+and+Friends+Tee+Green"} +{"id": "GGOEYAEB093815","name": "GGOEYAEB093815","title": "YouTube Icon Pullover Black","brands": ["YouTube"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Ebony","Outer Space","Jet"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEYXXX0938.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/YouTube+Icon+Hoodie+Black"} +{"id": "GGOEYAEJ120318","name": "GGOEYAEJ120318","title": "YouTube Icon Tee Grey","brands": ["YouTube"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Gray"],"colors": ["Light gray","Silver"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEYXXX1203.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/YouTube+Icon+Tee+Grey"} +{"id": "GGPRAOAL107699","name": "GGPRAOAL107699","title": "Android Iconic Pen","brands": ["Android"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "1.75"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAOAL129199.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Android+Iconic+Pen"} +{"id": "GGOEAAEH129617","name": "GGOEAAEH129617","title": "Android Pocket Tee Green","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "29"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive","Grass green"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAXXX1296.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Android+Pocket+Tee+Green"} +{"id": "GGPRAAEH107217","name": "GGPRAAEH107217","title": "Android Pocket Tee Green","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "29"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive","Grass green"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAXXX1296.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Android+Pocket+Tee+Green"} +{"id": "GGOEAAXL129928","name": "GGOEAAXL129928","title": "Android Pocket Toddler Tee Navy","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "23"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAXXX1299.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Android+Pocket+Toddler+Tee+Navy"} +{"id": "GGOEGAEC171813","name": "GGOEGAEC171813","title": "Google Bike Eco Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1718.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Bike+Eco+Tee"} +{"id": "GGOEGALL144016","name": "GGOEGALL144016","title": "Google Boulder Campus Ladies Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1440.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Boulder+Campus+Ladies+Tee"} +{"id": "GGOEGAEC176213","name": "GGOEGAEC176213","title": "Google Camp Fleece Snap Pullover","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "32"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Camp+Fleece+Snap+Pullover"} +{"id": "GGOEGAER141014","name": "GGOEGAER141014","title": "Google Chicago Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1410.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Chicago+Campus+Unisex+Tee"} +{"id": "GGOEGAEJ096415","name": "GGOEGAEJ096415","title": "Google Crewneck Sweatshirt Grey","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"colorInfo": {"colorFamilies": ["Gray"],"colors": ["Light gray","Silver"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX0964.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Crew+Grey"} +{"id": "GGOEGCBA139099","name": "GGOEGCBA139099","title": "Google Emoji Magnet Set","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "10"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGCBA139099.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Accessories/Google+Emoji+Magnet+Set"} +{"id": "GGOEGBRC127999","name": "GGOEGBRC127999","title": "Google Incognito Techpack V2","brands": ["Google"],"categories": ["Bags"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGBRC127999.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Bags/Google+Incognito+Techpack+V2"} +{"id": "GGPRGCBA105199","name": "GGPRGCBA105199","title": "Google Medium Pet Collar (Blue/Green)","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"colorInfo": {"colorFamilies": ["Blue"],"colors": ["Light blue","Blue","Green blue"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGCBA139599.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Medium+Pet+Collar+Blue+Green"} +{"id": "GGOEGAER119516","name": "GGOEGAER119516","title": "Google Mountain View Tee Red","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"colorInfo": {"colorFamilies": ["Red"],"colors": ["Red","Flame red","Dark red"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1195.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Mountain+View+Tee+Red"} +{"id": "GGOEGAEJ148014","name": "GGOEGAEJ148014","title": "Google PNW Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1480.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+PNW+Campus+Zip+Hoodie"} +{"id": "GGPRGOAH102499","name": "GGPRGOAH102499","title": "Google Pen Citron","brands": ["Google"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "1.75"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20210405858/assets/items/images/GGPRGOAH102499.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Pen+Citron"} +{"id": "GGOEGAEL146914","name": "GGOEGAEL146914","title": "Google SF Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1469.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+SF+Campus+Unisex+Tee"} +{"id": "GGCOGALB153913","name": "GGCOGALB153913","title": "Google TYCTWD Black Women's Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1539.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/TYCTWD/Google+TYCTWD+Womens+Tee"} +{"id": "GGCOGAEJ153715","name": "GGCOGAEJ153715","title": "Google TYCTWD Gray Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1537.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/TYCTWD/Google+TYCTWD+Charcoal+Tee"} +{"id": "GGOEGAEC173816","name": "GGOEGAEC173816","title": "Google Tonal Shirt Marine Blue","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "27"},"colorInfo": {"colorFamilies": ["Blue"],"colors": ["Light blue","Blue","Dark blue"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Tonal+Shirt+Marine+Blue"} +{"id": "GGOEGAEJ104015","name": "GGOEGAEJ104015","title": "Google Tudes Recycled Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1040.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Tudes+Recycled+Tee"} +{"id": "GGPRGAAB100718","name": "GGPRGAAB100718","title": "Google Unisex Eco Tee Black","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Ebony","Outer Space"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20210405858/assets/items/images/GGPRGXXX1007.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Unisex+Eco+Tee+Black"} +{"id": "GGOEGAPH138213","name": "GGOEGAPH138213","title": "Google Women's Softshell Moss","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "39"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1382.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Womens+Softshell+Moss"} +{"id": "GGOEGAYB113713","name": "GGOEGAYB113713","title": "Google Youth FC Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1137.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Youth+FC+Zip+Hoodie"} +{"id": "GGOEGAEB110915","name": "GGOEGAEB110915","title": "Google Zip Hoodie F/C","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1109.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Zip+Hoodie+FC"} +{"id": "GGPRACBA107016","name": "GGPRACBA107016","title": "I \u003c3 Android Kit","brands": ["Android"],"categories": ["Kit"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "44.75"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20210405858/assets/items/images/GGPRAXXX1070.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/I+Love+Android+Kit"} +{"id": "GGOEYAEJ120313","name": "GGOEYAEJ120313","title": "YouTube Icon Tee Grey","brands": ["YouTube"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Gray"],"colors": ["Light gray","Silver"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEYXXX1203.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/YouTube+Icon+Tee+Grey"} +{"id": "GGOEYADJ173418","name": "GGOEYADJ173418","title": "YouTube Ultralight Embroidered Sweatshirt","brands": ["YouTube"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "33"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/YouTube+Ultralight+Embroidered+Sweatshirt"} +{"id": "GGOEAFDH105799","name": "GGOEAFDH105799","title": "Android Cardboard Sculpture","brands": ["Android"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "17"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAFDH105799.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Accessories/Android+Cardboard+Sculpture"} +{"id": "GGOEGAEM126414","name": "GGOEGAEM126414","title": "Android Garden 2019 Tee","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "29"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1264.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Android+Garden+Tee+Orange"} +{"id": "GGOEAFBA115599","name": "GGOEAFBA115599","title": "Google Android Super Hero 3D Framed Art","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAFBA115599.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Accessories/Android+Super+Hero+3D+Framed+Art"} +{"id": "GGOECAEB163614","name": "GGOECAEB163614","title": "Google Black Cloud Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "28"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Ebony","Jet"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOECXXX1636.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Black+Cloud+Tee"} +{"id": "GGOEGAEH143916","name": "GGOEGAEH143916","title": "Google Boulder Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1439.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Boulder+Campus+Unisex+Tee"} +{"id": "GGOEGAEJ133717","name": "GGOEGAEJ133717","title": "Google Cambridge Campus Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1337.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Cambridge+Campus+Zip+Hoodie"} +{"id": "GGOEGAEJ168612","name": "GGOEGAEJ168612","title": "Google Campus Unisex Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1686.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Campus+Unisex+Zip+Hoodie"} +{"id": "GGOEGAEJ168613","name": "GGOEGAEJ168613","title": "Google Campus Unisex Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1686.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Campus+Unisex+Zip+Hoodie"} +{"id": "GGPRGCBD102699","name": "GGPRGCBD102699","title": "Google Cork Tablet Case","brands": ["Google"],"categories": ["Bags"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20210405858/assets/items/images/GGPRGCBD102699.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Cork+Tablet+Case"} +{"id": "GGOEGAER149212","name": "GGOEGAER149212","title": "Google Kirkland Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1492.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Kirkland+Campus+Unisex+Tee"} +{"id": "GGOEGCBA162099","name": "GGOEGCBA162099","title": "Google Land Sea Tech Taco","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "3"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGCOGCBA161199.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Land+and+Sea+Tech+Taco+LS"} +{"id": "GGOEGALC153213","name": "GGOEGALC153213","title": "Google Mountain View Campus Ladies Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1532.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Campus+Collection/Google+Mountain+View+Campus+Ladies+Tee"} +{"id": "GGOEGAEH153016","name": "GGOEGAEH153016","title": "Google Mountain View Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1530.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Campus+Collection/Google+Mountain+View+Campus+Unisex+Tee"} +{"id": "GGOEGAEJ153416","name": "GGOEGAEJ153416","title": "Google Mountain View Campus Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1534.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Campus+Collection/Google+Mountain+View+Campus+Zip+Hoodie"} +{"id": "GGOEGAEJ140215","name": "GGOEGAEJ140215","title": "Google NYC Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1402.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+NYC+Campus+Unisex+Tee"} +{"id": "GGOEGBBA175499","name": "GGOEGBBA175499","title": "Google Recycled Drawstring Bag","brands": ["Google"],"categories": ["Bags"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "3"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Recycled+Drawstring+Bag"} +{"id": "GGOEGALL147017","name": "GGOEGALL147017","title": "Google SF Campus Ladies Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1470.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+SF+Campus+Ladies+Tee"} +{"id": "GGOEGALJ148814","name": "GGOEGALJ148814","title": "Google Seattle Campus Ladies Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1488.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Seattle+Campus+Ladies+Tee"} +{"id": "GGOEGAEH148718","name": "GGOEGAEH148718","title": "Google Seattle Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1487.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Seattle+Campus+Unisex+Tee"} +{"id": "GGOEGAEJ153514","name": "GGOEGAEJ153514","title": "Google Sunnyvale Campus Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1535.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Campus+Collection/Google+Sunnyvale+Campus+Zip+Hoodie"} +{"id": "GGOEGAED176313","name": "GGOEGAED176313","title": "Google Sweatshirt Brick Red","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"colorInfo": {"colorFamilies": ["Red"],"colors": ["Red","Flame red","Dark red"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Sweatshirt+Brick+Red"} +{"id": "GGOEGAEC090714","name": "GGOEGAEC090714","title": "Google Tee Blue","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Blue"],"colors": ["Light blue","Blue","Dark blue"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX0907.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Tee+Blue"} +{"id": "GGOEGAAB118913","name": "GGOEGAAB118913","title": "Google Unisex Eco Tee Black","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Ebony","Jet"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1189.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Unisex+Eco+Tee+Black"} +{"id": "GGOEGAPB176915","name": "GGOEGAPB176915","title": "Google Women's Puffer Jacket","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "36"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Womens+Puffer+Jacket"} +{"id": "GGOEGAEB110912","name": "GGOEGAEB110912","title": "Google Zip Hoodie F/C","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1109.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Zip+Hoodie+FC"} +{"id": "GGPRACBA107018","name": "GGPRACBA107018","title": "I \u003c3 Android Kit","brands": ["Android"],"categories": ["Kit"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "44.75"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20210405858/assets/items/images/GGPRAXXX1070.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/I+Love+Android+Kit"} +{"id": "GGOEYAEA105610","name": "GGOEYAEA105610","title": "YouTube Crew Socks","brands": ["YouTube"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "16"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEYAEA105610.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/YouTube+Crew+Socks"} +{"id": "GGCOGADC100817","name": "GGCOGADC100817","title": "#IamRemarkable Hoodie","brands": ["#IamRemarkable"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "32"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGCOGXXX1008.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/IamRemarkable+Hoodie"} +{"id": "GGCOGAEC100613","name": "GGCOGAEC100613","title": "#IamRemarkable T-Shirt","brands": ["#IamRemarkable"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "12"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGCOGXXX1006.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/IamRemarkable+Unisex+T-Shirt"} +{"id": "GGOEGCKR133899","name": "GGOEGCKR133899","title": "Google Cambridge Campus Sticker","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "2"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGCKR133899.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Accessories/Google+Cambridge+Campus+Sticker"} +{"id": "GGOEGAEJ168615","name": "GGOEGAEJ168615","title": "Google Campus Unisex Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1686.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Campus+Unisex+Zip+Hoodie"} +{"id": "GGOEGAER141013","name": "GGOEGAER141013","title": "Google Chicago Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1410.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Chicago+Campus+Unisex+Tee"} +{"id": "GGOECOLJ164299","name": "GGOECOLJ164299","title": "Google Cloud Journal","brands": ["Google Cloud"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "18"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOECOLJ164299.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Stationery/Google+Cloud+Journal"} +{"id": "GGOEGHPB178810","name": "GGOEGHPB178810","title": "Google Corduroy Black Cap","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "19"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Ebony","Outer Space","Jet"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Corduroy+Black+Cap"} +{"id": "GGOEGAXA123610","name": "GGOEGAXA123610","title": "Google Crew Combed Cotton Sock","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "17"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGAXA123610.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Google+Crew+Combed+Cotton+Sock"} +{"id": "GGOEGAXA123510","name": "GGOEGAXA123510","title": "Google Crew Striped Athletic Sock","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "17"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGAXA123510.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Google+Crew+Striped+Athletic+Sock"} +{"id": "GGOEGAEJ103915","name": "GGOEGAEJ103915","title": "Google F/C Longsleeve Ash","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1039.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+FC+Longsleeve+Ash"} +{"id": "GGOEGAEJ165013","name": "GGOEGAEJ165013","title": "Google Gray French Terry Sweatshirt","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"colorInfo": {"colorFamilies": ["Gray"],"colors": ["Light gray","Silver"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1650.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Gray+French+Terry+Sweatshirt"} +{"id": "GGOEGAXJ164914","name": "GGOEGAXJ164914","title": "Google Gray Toddler Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"colorInfo": {"colorFamilies": ["Gray"],"colors": ["Light gray","Silver","Stone gray","Cool gray"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1649.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Gray+Toddler+Zip+Hoodie"} +{"id": "GGOEGCBA169499","name": "GGOEGCBA169499","title": "Google Kirkland Campus Patch Set","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "16"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGCBA169499.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Campus+Collection/Google+Kirkland+Campus+Patch+Set"} +{"id": "GGOEGCBA150599","name": "GGOEGCBA150599","title": "Google Large Pet Collar (Red/Yellow)","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGCBA150599.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Accessories/Google+Large+Pet+Collar+Red+Yellow"} +{"id": "GGOEGOAH090199","name": "GGOEGOAH090199","title": "Google Light Pen Green","brands": ["Google"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "3"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive","Grass green"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGOAH090199.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Metal","Recycled Plastic"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Office/Google+Light+Up+Pen+Green"} +{"id": "GGOEGCBA169399","name": "GGOEGCBA169399","title": "Google Los Angeles Campus Patch Set","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "16"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGCBA169399.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Campus+Collection/Google+Los+Angeles+Campus+Patch+Set"} +{"id": "GGOEGOAB177399","name": "GGOEGOAB177399","title": "Google Maps Wheat Pen","brands": ["Google"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "1.75"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGOAB177399.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Maps+Wheat+Pen"} +{"id": "GGOEGAEH153018","name": "GGOEGAEH153018","title": "Google Mountain View Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1530.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Campus+Collection/Google+Mountain+View+Campus+Unisex+Tee"} +{"id": "GGOEGALJ140315","name": "GGOEGALJ140315","title": "Google NYC Campus Ladies Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1403.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+NYC+Campus+Ladies+Tee"} +{"id": "GGOEGAEC165218","name": "GGOEGAEC165218","title": "Google Navy French Terry Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1652.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Navy+French+Terry+Zip+Hoodie"} +{"id": "GGPRGADC107914","name": "GGPRGADC107914","title": "Google Raincoat Navy","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "44"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1350.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Raincoat+Navy"} +{"id": "GGOEGALJ148815","name": "GGOEGALJ148815","title": "Google Seattle Campus Ladies Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1488.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Seattle+Campus+Ladies+Tee"} +{"id": "GGOEGADJ135212","name": "GGOEGADJ135212","title": "Google Sherpa Zip Hoodie Charcoal","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "39"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1352.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Sherpa+Zip+Hoodie+Charcoal"} +{"id": "GGCOGAYC154115","name": "GGCOGAYC154115","title": "Google TYCTWD Blue Youth Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "24"},"colorInfo": {"colorFamilies": ["Blue"],"colors": ["Light blue","Blue","Dark blue"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1541.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/TYCTWD/Google+TYCTWD+Blue+Youth+Tee"} +{"id": "GGOEGAEC164713","name": "GGOEGAEC164713","title": "Google Tonal Blue Eco Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "27"},"colorInfo": {"colorFamilies": ["Blue"],"colors": ["Light blue","Blue","Dark blue"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1647.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Tonal+Blue+Eco+Tee"} +{"id": "GGOEGHPL107710","name": "GGOEGHPL107710","title": "Google Twill Cap Navy","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "13"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy","Dark blue"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGHPL107710.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Dad+Hat+Navy"} +{"id": "GGPRGAAB100714","name": "GGPRGAAB100714","title": "Google Unisex Eco Tee Black","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Ebony","Outer Space","Jet"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20210405858/assets/items/images/GGPRGXXX1007.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Unisex+Eco+Tee+Black"} +{"id": "GGOEGAEH174912","name": "GGOEGAEH174912","title": "Google Vintage Olive Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "28"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1749.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Vintage+Olive+Tee"} +{"id": "GGOEGAEH175114","name": "GGOEGAEH175114","title": "Google Vintage Pullover Olive","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Vintage+Pullover+Olive"} +{"id": "GGOEAAXQ129830","name": "GGOEAAXQ129830","title": "Android Pocket Toddler Tee White","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "23"},"colorInfo": {"colorFamilies": ["White"],"colors": ["White"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAXXX1298.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Android+Pocket+Toddler+Tee+White"} +{"id": "GGOEGBJC122399","name": "GGOEGBJC122399","title": "Google Campus Bike Tote Navy","brands": ["Google"],"categories": ["Bags"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "11"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy","Dark blue"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGBJC122399.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Bags/Google+Google+Campus+Bike+Tote+Navy"} +{"id": "GGOEGAEC141216","name": "GGOEGAEC141216","title": "Google Chicago Campus Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1412.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Chicago+Campus+Zip+Hoodie"} +{"id": "GGOEGAEA137817","name": "GGOEGAEA137817","title": "Google Cotopaxi Shell","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1378.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Cotopaxi+Shell"} +{"id": "GGOEGAED168116","name": "GGOEGAED168116","title": "Google Earth Day Eco Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1681.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Earth+Day+Eco+Tee"} +{"id": "GGOEGAEJ165116","name": "GGOEGAEJ165116","title": "Google Gray French Terry Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"colorInfo": {"colorFamilies": ["Gray"],"colors": ["Light gray","Silver","Stone gray","Cool gray"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1651.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Gray+French+Terry+Zip+Hoodie"} +{"id": "GGPRGBRC101599","name": "GGPRGBRC101599","title": "Google Incognito Laptop Organizer V2","brands": ["Google"],"categories": ["Bags"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "36"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20210405858/assets/items/images/GGPRGBRC101599.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Incognito+Laptop+Organizer"} +{"id": "GGOEGALJ149314","name": "GGOEGALJ149314","title": "Google Kirkland Campus Ladies Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1493.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Kirkland+Campus+Ladies+Tee"} +{"id": "GGOEGACH161516","name": "GGOEGACH161516","title": "Google Land Sea French Terry Sweatshirt","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGCOGXXX1609.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Land+and+Sea+French+Terry+Sweatshirt+LS"} +{"id": "GGOEGACH161517","name": "GGOEGACH161517","title": "Google Land Sea French Terry Sweatshirt","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGCOGXXX1609.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Land+and+Sea+French+Terry+Sweatshirt+LS"} +{"id": "GGCOGAED156912","name": "GGCOGAED156912","title": "Google Land Sea Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGCOGXXX1569.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Land+and+Sea+Unisex+Tee"} +{"id": "GGOEGOAR090099","name": "GGOEGOAR090099","title": "Google Light Pen Red","brands": ["Google"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "3"},"colorInfo": {"colorFamilies": ["Red"],"colors": ["Red","Flame red","Dark red"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGOAR090099.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Metal","Recycled Plastic"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Office/Google+Light+Up+Pen+Red"} +{"id": "GGOEGCBA168999","name": "GGOEGCBA168999","title": "Google Patch","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "3.5"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGCBA168999.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Lifestyle/Google+Patch"} +{"id": "GGOEGOAC123799","name": "GGOEGOAC123799","title": "Google Pen Bright Blue","brands": ["Google"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "1.75"},"colorInfo": {"colorFamilies": ["Blue"],"colors": ["Light blue","Blue","Dark blue"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGOAC123799.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Metal","Recycled Plastic"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Office/Google+Pen+Bright+Blue"} +{"id": "GGOEGAEL146912","name": "GGOEGAEL146912","title": "Google SF Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1469.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+SF+Campus+Unisex+Tee"} +{"id": "GGOEGAEJ118215","name": "GGOEGAEJ118215","title": "Google Summer19 Crew Grey","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "32"},"colorInfo": {"colorFamilies": ["Gray"],"colors": ["Light gray","Silver"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1182.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2020.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Google+Summer19+Crew+Grey"} +{"id": "GGOEGAEJ153515","name": "GGOEGAEJ153515","title": "Google Sunnyvale Campus Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1535.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Campus+Collection/Google+Sunnyvale+Campus+Zip+Hoodie"} +{"id": "GGCOGAEJ153717","name": "GGCOGAEJ153717","title": "Google TYCTWD Gray Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1537.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/TYCTWD/Google+TYCTWD+Charcoal+Tee"} +{"id": "GGCOGAXT154229","name": "GGCOGAXT154229","title": "Google TYCTWD Yellow Toddler Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "23"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1542.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/TYCTWD/Google+TYCTWD+Yellow+Toddler+Tee"} +{"id": "GGOEGAEC090718","name": "GGOEGAEC090718","title": "Google Tee Blue","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Blue"],"colors": ["Light blue","Blue","Dark blue"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX0907.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Tee+Blue"} +{"id": "GGOEGAXQ134629","name": "GGOEGAXQ134629","title": "Google Toddler Tee White V2","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "24"},"colorInfo": {"colorFamilies": ["White"],"colors": ["White"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1346.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Toddler+Tee+White"} +{"id": "GGOEGAED175017","name": "GGOEGAED175017","title": "Google Tonal Brick Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "28"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Tonal+Brick+Tee"} +{"id": "GGOEGAEC173818","name": "GGOEGAEC173818","title": "Google Tonal Shirt Marine Blue","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "27"},"colorInfo": {"colorFamilies": ["Blue"],"colors": ["Light blue","Blue","Dark blue"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Tonal+Shirt+Marine+Blue"} +{"id": "GGOEGAEB125312","name": "GGOEGAEB125312","title": "Google Unisex Pride Eco-Tee Black","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Ebony","Outer Space"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1253.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino","Membrane"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Unisex+Pride+Eco-Tee+Black"} +{"id": "GGOEGAEC164612","name": "GGOEGAEC164612","title": "Google Vintage Navy Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "27"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy","Dark blue"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1646.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Vintage+Navy+Tee"} +{"id": "GGOEGABB099199","name": "GGOEGABB099199","title": "Google Wallet Stand Black","brands": ["Google"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "3"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Ebony","Outer Space"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGABB099199.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Accessories/Google+Wallet+Stand+Black"} +{"id": "GGOEGAPJ108216","name": "GGOEGAPJ108216","title": "Google Women's Discovery Lt. Rain Shell","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1082.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Womens+Discovery"} +{"id": "GGOEGALB109913","name": "GGOEGALB109913","title": "Google Women's Tee F/C Black","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Ebony","Outer Space"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1099.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Womens+Tee+FC+Black"} +{"id": "GGOEGAYB116714","name": "GGOEGAYB116714","title": "Google Youth F/C Pullover Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1167.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual","Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Youth+FC+Pullover+Hoodie"} +{"id": "GGOEYCBR138999","name": "GGOEYCBR138999","title": "YouTube Iconic Play Pin","brands": ["YouTube"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "3"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEYCBR138999.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Accessories/YouTube+Iconic+Play+Pin"} +{"id": "GGCOGADC100814","name": "GGCOGADC100814","title": "#IamRemarkable Hoodie","brands": ["#IamRemarkable"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "32"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGCOGXXX1008.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/IamRemarkable+Hoodie"} +{"id": "GGOEAFKQ130599","name": "GGOEAFKQ130599","title": "Android Iconic 4in Decal","brands": ["Android"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "1.5"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAFKQ130599.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Accessories/Android+Iconic+4in+Decal"} +{"id": "GGOEAAEL130815","name": "GGOEAAEL130815","title": "Android Iconic Crew","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "32"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAXXX1308.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Android+Iconic+Crew"} +{"id": "GGOEGCOA173158","name": "GGOEGCOA173158","title": "Google Bike Paper Clip Set","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "3.5"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Bike+Paper+Clip+Set"} +{"id": "GGOEGALJ141117","name": "GGOEGALJ141117","title": "Google Chicago Campus Ladies Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1411.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Chicago+Campus+Ladies+Tee"} +{"id": "GGOEGCBA169599","name": "GGOEGCBA169599","title": "Google Chicago Campus Patch Set","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "16"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGCBA169599.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Campus+Collection/Google+Chicago+Campus+Patch+Set"} +{"id": "GGOECAEB165513","name": "GGOECAEB165513","title": "Google Cloud Tri-Blend Crew Tee","brands": ["Google Cloud"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOECXXX1655.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Cloud+Unisex+Tri-Blend+Crew+Tee"} +{"id": "GGOEGDNQ138099","name": "GGOEGDNQ138099","title": "Google Cork Base Tumbler","categories": ["Drinkware"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "28"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGDNQ138099.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Drinkware/Google+Cork+Base+Tumbler"} +{"id": "GGOEGAEL091315","name": "GGOEGAEL091315","title": "Google Crewneck Sweatshirt Navy","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy","Dark blue"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX0913.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Crew+Sweater+Navy"} +{"id": "GGPRGAEL101415","name": "GGPRGAEL101415","title": "Google Crewneck Sweatshirt Navy","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "32"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy","Dark blue"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20210405858/assets/items/images/GGPRGXXX1014.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Crewneck+Sweatshirt+Navy"} +{"id": "GGOEGAWH144552","name": "GGOEGAWH144552","title": "Google Infant Hero Tee Olive","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1445.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Infant+Hero+Tee+Olive"} +{"id": "GGOEGAEH146018","name": "GGOEGAEH146018","title": "Google LA Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1460.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+LA+Campus+Unisex+Tee"} +{"id": "GGOEGAEJ146218","name": "GGOEGAEJ146218","title": "Google LA Campus Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1462.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+LA+Campus+Zip+Hoodie"} +{"id": "GGOEGADB138314","name": "GGOEGADB138314","title": "Google Men's Puff Jacket Black","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "44"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Ebony","Outer Space"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1383.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Mens+Puff+Jacket+Black"} +{"id": "GGOEGDHH177299","name": "GGOEGDHH177299","title": "Google Olive Tundra Bottle","brands": ["Google"],"categories": ["Drinkware"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "31"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Olive+Tundra+Bottle"} +{"id": "GGOEGAEC153118","name": "GGOEGAEC153118","title": "Google Sunnyvale Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1531.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Campus+Collection/Google+Sunnyvale+Campus+Unisex+Tee"} +{"id": "GGOEGAEC090713","name": "GGOEGAEC090713","title": "Google Tee Blue","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Blue"],"colors": ["Light blue","Blue","Dark blue"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX0907.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Tee+Blue"} +{"id": "GGOEGAXC171928","name": "GGOEGAXC171928","title": "Google Tricyle Toddler Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "23"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1719.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Tricyle+Toddler+Tee"} +{"id": "GGOEGAEJ173613","name": "GGOEGAEJ173613","title": "Google Ultralight Gray Sweatshirt","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"colorInfo": {"colorFamilies": ["Gray"],"colors": ["Light gray","Silver"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Ultralight+Gray+Sweatshirt"} +{"id": "GGOEGAEJ173615","name": "GGOEGAEJ173615","title": "Google Ultralight Gray Sweatshirt","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"colorInfo": {"colorFamilies": ["Gray"],"colors": ["Stone gray","Cool gray"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Ultralight+Gray+Sweatshirt"} +{"id": "GGOEGAEQ120116","name": "GGOEGAEQ120116","title": "Google Unisex 3/4 Raglan Red","categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"colorInfo": {"colorFamilies": ["Red"],"colors": ["Red","Flame red","Dark red"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1201.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Unisex+3+4+Raglan+Red"} +{"id": "GGOEGADB176812","name": "GGOEGADB176812","title": "Google Unisex Puffer Jacket","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "36"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Unisex+Puffer+Jacket"} +{"id": "GGOEGAEC164617","name": "GGOEGAEC164617","title": "Google Vintage Navy Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "27"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy","Dark blue"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1646.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Vintage+Navy+Tee"} +{"id": "GGOEACBA116699","name": "GGOEACBA116699","title": "Noogler Android Figure 2019","brands": ["Android"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "16"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEACBA116699.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Accessories/Noogler+Android+Figure+2019"} +{"id": "GGOEYAXB089629","name": "GGOEYAXB089629","title": "YouTube Kids Tee Black","brands": ["YouTube"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "20"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Ebony","Outer Space","Jet"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEYXXX0896.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Kids/Youtube+Kids+Tee+Black"} +{"id": "GGOEYALQ091917","name": "GGOEYALQ091917","title": "YouTube Women's Favorite Tee White","brands": ["YouTube"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["White"],"colors": ["White"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX0919.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Youtube+Favorite+Tee+White"} +{"id": "GGOEAAYL130315","name": "GGOEAAYL130315","title": "Android Pocket Youth Tee Navy","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy","Dark blue"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAXXX1303.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Android+Pocket+Youth+Tee+Navy"} +{"id": "GGOEGPJC019099","name": "GGOEGPJC019099","title": "Google 7-inch Dog Flying Disc Blue","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "1.5"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGPJC019099.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Lifestyle/Google-Frisbee"} +{"id": "GGOEGAED142612","name": "GGOEGAED142612","title": "Google Austin Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1426.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Austin+Campus+Unisex+Tee"} +{"id": "GGOEGAEJ144113","name": "GGOEGAEJ144113","title": "Google Boulder Campus Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1441.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Boulder+Campus+Zip+Hoodie"} +{"id": "GGOEGAEJ133712","name": "GGOEGAEJ133712","title": "Google Cambridge Campus Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1337.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Cambridge+Campus+Zip+Hoodie"} +{"id": "GGOEGCBA096099","name": "GGOEGCBA096099","title": "Google Campus Bike","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGCBA096099.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Accessories/Google+Campus+Bike"} +{"id": "GGOECAEB165413","name": "GGOECAEB165413","title": "Google Cloud Carhartt Crew Sweatshirt","brands": ["Google Cloud"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOECXXX1654.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Cloud+Unisex+Carhartt+Crew+Sweatshirt"} +{"id": "GGOEGAEL091312","name": "GGOEGAEL091312","title": "Google Crewneck Sweatshirt Navy","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy","Dark blue"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX0913.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Crew+Sweater+Navy"} +{"id": "GGOEGAEL091318","name": "GGOEGAEL091318","title": "Google Crewneck Sweatshirt Navy","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy","Dark blue"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX0913.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Crew+Sweater+Navy"} +{"id": "GGOEGBMH177899","name": "GGOEGBMH177899","title": "Google ecofriendly Green Duffel","brands": ["Google"],"categories": ["Bags"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "31"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive","Grass green"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+ecofriendly+Green+Duffel"} +{"id": "GGOEGBMR177799","name": "GGOEGBMR177799","title": "Google ecofriendly Red Duffel","brands": ["Google"],"categories": ["Bags"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "31"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+ecofriendly+Red+Duffel"} +{"id": "GGOEGAEB103815","name": "GGOEGAEB103815","title": "Google F/C Longsleeve Charcoal","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1038.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+FC+Longsleeve+Charcoal"} +{"id": "GGPRGBRC103299","name": "GGPRGBRC103299","title": "Google Incognito Dopp Kit V2","brands": ["Google"],"categories": ["Bags"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20210405858/assets/items/images/GGPRGBRC103299.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Incognito+Dopp+Kit+V2"} +{"id": "GGPRGCBA100399","name": "GGPRGCBA100399","title": "Google Journal Set","brands": ["Google"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "10.75"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20210405858/assets/items/images/GGPRGCBA100399.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Journal+Set"} +{"id": "GGOEGAYC118315","name": "GGOEGAYC118315","title": "Google Kids Playful Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1183.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Google+Kids+Playful+Tee"} +{"id": "GGOEGDHJ145999","name": "GGOEGDHJ145999","title": "Google LA Campus Bottle","brands": ["Google"],"categories": ["Drinkware"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "20"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGDHJ145999.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Drinkware/Google+LA+Campus+Bottle"} +{"id": "GGOEMAEB164115","name": "GGOEMAEB164115","title": "Google F/C Charcoal","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "21"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEMXXX1641.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Maps+Pin+Tee"} +{"id": "GGOEGAEB165317","name": "GGOEGAEB165317","title": "Google Marine Layer Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1653.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Marine+Layer+Tee"} +{"id": "GGOEGADH138114","name": "GGOEGADH138114","title": "Google Men's Softshell Moss","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "39"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1381.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Mens+Softshell+Moss"} +{"id": "GGOEGAEC119613","name": "GGOEGAEC119613","title": "Google Mountain View Tee Blue","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"colorInfo": {"colorFamilies": ["Blue"],"colors": ["Light blue","Blue","Dark blue"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1196.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Mountain+View+Tee+Blue"} +{"id": "GGOEGAEC165212","name": "GGOEGAEC165212","title": "Google Navy French Terry Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy","Dark blue"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1652.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Navy+French+Terry+Zip+Hoodie"} +{"id": "GGOEGCBA169999","name": "GGOEGCBA169999","title": "Google New York Campus Patch Set","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "16"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGCBA169999.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Campus+Collection/Google+New+York+Campus+Patch+Set"} +{"id": "GGOEGBJD148499","name": "GGOEGBJD148499","title": "Google PNW Campus Tote","brands": ["Google"],"categories": ["Bags"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "11"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGBJD148499.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Bags/Google+PNW+Campus+Tote"} +{"id": "GGOEGAAR134513","name": "GGOEGAAR134513","title": "Google Red Speckled Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1345.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Red+Speckled+Tee"} +{"id": "GGOEGAEH148715","name": "GGOEGAEH148715","title": "Google Seattle Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1487.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Seattle+Campus+Unisex+Tee"} +{"id": "GGOEGADC134712","name": "GGOEGADC134712","title": "Google Sherpa Zip Hoodie Navy","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "39"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy","Dark blue"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1347.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Sherpa+Zip+Hoodie+Navy"} +{"id": "GGOEGAEC134910","name": "GGOEGAEC134910","title": "Google Speckled Beanie Navy","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "20"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy","Dark blue"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGAEC134910.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Speckled+Beanie+Navy"} +{"id": "GGOEGOCB178199","name": "GGOEGOCB178199","title": "Google Stitched Journal Set","brands": ["Google"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Stitched+Journal+Set"} +{"id": "GGOEGAXB113351","name": "GGOEGAXB113351","title": "Google Toddler FC Tee Charcoal","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1133.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Toddler+FC+Tee+Charcoal"} +{"id": "GGOEGAED175014","name": "GGOEGAED175014","title": "Google Tonal Brick Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "28"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Tonal+Brick+Tee"} +{"id": "GGOEGADB176613","name": "GGOEGADB176613","title": "Google Unisex Puffer Vest","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "34"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Unisex+Puffer+Vest"} +{"id": "GGOEGAPJ178414","name": "GGOEGAPJ178414","title": "Google Women's Essential Jacket","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1784.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Womens+Essential+Jacket"} +{"id": "GGOEGAPB096315","name": "GGOEGAPB096315","title": "Google Womens Microfleece Jacket Black","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Ebony"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX0963.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Womens+Microfleece+Jacket+Black"} +{"id": "GGOEYAXB089655","name": "GGOEYAXB089655","title": "YouTube Kids Tee Black","brands": ["YouTube"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "20"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Outer Space","Jet"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEYXXX0896.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Kids/Youtube+Kids+Tee+Black"} +{"id": "GGOEYAEJ092115","name": "GGOEYAEJ092115","title": "Youtube 3 lines Tee Grey","brands": ["YouTube"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Gray"],"colors": ["Light gray","Silver"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX0921.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Youtube+3+lines+tee+grey"} +{"id": "GGCOGADC100813","name": "GGCOGADC100813","title": "#IamRemarkable Hoodie","brands": ["#IamRemarkable"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "32"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGCOGXXX1008.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/IamRemarkable+Hoodie"} +{"id": "GGCOGAEC100616","name": "GGCOGAEC100616","title": "#IamRemarkable T-Shirt","brands": ["#IamRemarkable"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "12"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGCOGXXX1006.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/IamRemarkable+Unisex+T-Shirt"} +{"id": "GGOEAAEL130813","name": "GGOEAAEL130813","title": "Android Iconic Crew","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "32"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAXXX1308.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Android+Iconic+Crew"} +{"id": "GGOEAAEL130818","name": "GGOEAAEL130818","title": "Android Iconic Crew","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "32"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAXXX1308.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Android+Iconic+Crew"} +{"id": "GGOEAAWL130145","name": "GGOEAAWL130145","title": "Android Pocket Onesie Navy","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy","Dark blue"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAXXX1301.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Android+Pocket+Onesie+Navy"} +{"id": "GGPRAAEH107214","name": "GGPRAAEH107214","title": "Android Pocket Tee Green","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "29"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive","Grass green"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAXXX1296.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Android+Pocket+Tee+Green"} +{"id": "GGOEGAEC171816","name": "GGOEGAEC171816","title": "Google Bike Eco Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1718.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Bike+Eco+Tee"} +{"id": "GGOECAEB163513","name": "GGOECAEB163513","title": "Google Black Cloud Polo","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "36"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Ebony","Outer Space","Jet"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOECXXX1635.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Black+Cloud+Polo"} +{"id": "GGOEGALC133617","name": "GGOEGALC133617","title": "Google Cambridge Campus Ladies Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1336.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Cambridge+Campus+Ladies+Tee"} +{"id": "GGOEGAEC176217","name": "GGOEGAEC176217","title": "Google Camp Fleece Snap Pullover","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "32"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Camp+Fleece+Snap+Pullover"} +{"id": "GGPRGBJC103999","name": "GGPRGBJC103999","title": "Google Campus Bike Tote Navy","brands": ["Google"],"categories": ["Bags"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "3.4"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy","Dark blue"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20210405858/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Campus+Bike+Tote+Navy"} +{"id": "GGOEGAEJ168513","name": "GGOEGAEJ168513","title": "Google Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1685.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Campus+Unisex+Tee"} +{"id": "GGOEGDWH175999","name": "GGOEGDWH175999","title": "Google Ceramic Glazed Mug","brands": ["Google"],"categories": ["Drinkware"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "12"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Ceramic+Glazed+Mug"} +{"id": "GGOEGAEJ163317","name": "GGOEGAEJ163317","title": "Google Charcoal Unisex Badge Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "21"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1633.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Charcoal+Unisex+Badge+Tee"} +{"id": "GGPRGCBA100499","name": "GGPRGCBA100499","title": "Google Confetti Task Pad","brands": ["Google"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "3.75"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20210405858/assets/items/images/GGPRGCBA100499.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Confetti+Combo"} +{"id": "GGPRGOCA102299","name": "GGPRGOCA102299","title": "Google Confetti Slim Task Pad","brands": ["Google"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "3"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20210405858/assets/items/images/GGPRGOCA102299.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Confetti+Slim+Task+Pad"} +{"id": "GGPRGOCD102099","name": "GGPRGOCD102099","title": "Google Cork Journal","brands": ["Google"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "3"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20210405858/assets/items/images/GGPRGOCD102099.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Cork+Journal"} +{"id": "GGOEGAEJ096412","name": "GGOEGAEJ096412","title": "Google Crewneck Sweatshirt Grey","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"colorInfo": {"colorFamilies": ["Gray"],"colors": ["Light gray","Silver"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX0964.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Crew+Grey"} +{"id": "GGOEGAEL091316","name": "GGOEGAEL091316","title": "Google Crewneck Sweatshirt Navy","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy","Dark blue"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX0913.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Crew+Sweater+Navy"} +{"id": "GGOEGHGA174599","name": "GGOEGHGA174599","title": "Google Gradient Green Sunglasses","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "3"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive","Grass green"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Gradient+Green+Sunglasses"} +{"id": "GGOEGAER149216","name": "GGOEGAER149216","title": "Google Kirkland Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1492.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Kirkland+Campus+Unisex+Tee"} +{"id": "GGOEGCBA139899","name": "GGOEGCBA139899","title": "Google Large Pet Leash (Blue/Green)","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"colorInfo": {"colorFamilies": ["Blue"],"colors": ["Light blue","Blue","Dark blue"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGCBA139899.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Accessories/Google+Large+Pet+Leash+Blue+Green"} +{"id": "GGOEGAEB165316","name": "GGOEGAEB165316","title": "Google Marine Layer Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1653.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Cotton"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Marine+Layer+Tee"} +{"id": "GGOEGBJA127699","name": "GGOEGBJA127699","title": "Google Mural Tote","brands": ["Google"],"categories": ["Bags"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "18"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGBJA127699.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Bags/Google+Mural+Tote"} +{"id": "GGOEGAEC165217","name": "GGOEGAEC165217","title": "Google Navy French Terry Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1652.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Navy+French+Terry+Zip+Hoodie"} +{"id": "GGOEGOAQ101299","name": "GGOEGOAQ101299","title": "Google Pen White","brands": ["Google"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "1.75"},"colorInfo": {"colorFamilies": ["White"],"colors": ["White"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGOAQ101299.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Metal","Recycled Plastic"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Office/Google+Pen+White"} +{"id": "GGOEGADC135016","name": "GGOEGADC135016","title": "Google Raincoat Navy","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "44"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1350.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Raincoat+Navy"} +{"id": "GGCOAAPR155410","name": "GGCOAAPR155410","title": "Google TYCTWD Red Cap","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "13"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGAPR155410.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/TYCTWD/Google+TYCTWD+Red+Cap"} +{"id": "GGOEGAEH090616","name": "GGOEGAEH090616","title": "Google Tee Green","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive","Grass green"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX0906.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Greenesign/Apparel/Google+Tee+Green"} +{"id": "GGOEGAXB113330","name": "GGOEGAXB113330","title": "Google Toddler FC Tee Charcoal","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1133.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Toddler+FC+Tee+Charcoal"} +{"id": "GGOEGAXB113617","name": "GGOEGAXB113617","title": "Google Toddler FC Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1136.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Toddler+FC+Zip+Hoodie"} +{"id": "GGOEGAEC164718","name": "GGOEGAEC164718","title": "Google Tonal Blue Eco Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"colorInfo": {"colorFamilies": ["Blue"],"colors": ["Light blue","Blue","Dark blue"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1647.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Tonal+Blue+Eco+Tee"} +{"id": "GGOEGAED175018","name": "GGOEGAED175018","title": "Google Tonal Brick Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "28"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Tonal+Brick+Tee"} +{"id": "GGPRGALB100815","name": "GGPRGALB100815","title": "Google Women's Eco Tee Black","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Ebony","Jet"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20210405858/assets/items/images/GGPRGXXX1008.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Womens+Eco+Tee+Black"} +{"id": "GGOEGATJ137214","name": "GGOEGATJ137214","title": "Google Women's Tech Fleece Vest Charcoal","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "39"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1372.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Womens+Tech+Fleece+Vest+Charcoal"} +{"id": "GGPRACBA107014","name": "GGPRACBA107014","title": "I \u003c3 Android Kit","brands": ["Android"],"categories": ["Kit"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "44.75"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20210405858/assets/items/images/GGPRAXXX1070.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/I+Love+Android+Kit"} +{"id": "GGOEGAWH126846","name": "GGOEGAWH126846","title": "Stan and Friends 2019 Onesie","brands": ["Stan and Friends"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive","Grass green"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1268.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Stan+and+Friends+Onesie+Green"} +{"id": "GGOEGAYH126913","name": "GGOEGAYH126913","title": "Stan and Friends 2019 Youth Tee","brands": ["Stan and Friends"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive","Grass green"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1269.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Stan+and+Friends+Youth+Tee+Green"} +{"id": "GGCOGADC100816","name": "GGCOGADC100816","title": "#IamRemarkable Hoodie","brands": ["#IamRemarkable"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "32"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGCOGXXX1008.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/IamRemarkable+Hoodie"} +{"id": "GGOEAAEC172017","name": "GGOEAAEC172017","title": "Android Embroidered Crewneck Sweater","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Android+Embroidered+Crewneck+Sweater"} +{"id": "GGOEAHPL130910","name": "GGOEAHPL130910","title": "Android Iconic Hat Green","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "16"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive","Grass green"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAHPL130910.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Android+Iconic+Hat+Green"} +{"id": "GGOEAAEH129616","name": "GGOEAAEH129616","title": "Android Pocket Tee Green","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "29"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive","Grass green","Light green"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAXXX1296.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Android+Pocket+Tee+Green"} +{"id": "GGOEAAYL130313","name": "GGOEAAYL130313","title": "Android Pocket Youth Tee Navy","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAXXX1303.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Android+Pocket+Youth+Tee+Navy"} +{"id": "GGOEGCBA169899","name": "GGOEGCBA169899","title": "Google Austin Campus Patch Set","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "16"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGCBA169899.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Campus+Collection/Google+Austin+Campus+Patch+Set"} +{"id": "GGOEGAXN127229","name": "GGOEGAXN127229","title": "Google Beekeepers 2019 Toddler Tee, Pink","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1272.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/ApparelGoogle+Beekeepers+Toddler+Tee+Pink"} +{"id": "GGOEGDWJ141799","name": "GGOEGDWJ141799","title": "Google Camp Mug Gray","brands": ["Google"],"categories": ["Drinkware"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "13"},"colorInfo": {"colorFamilies": ["Gray"],"colors": ["Light gray","Cool gray"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGDWJ141799.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Lifestyle/Google+Camp+Mug+Gray"} +{"id": "GGPRGCBA101299","name": "GGPRGCBA101299","title": "Google Cork Set","brands": ["Google"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "39"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20210405858/assets/items/images/GGPRGCBA101299.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Cork+Set"} +{"id": "GGOEGAED168115","name": "GGOEGAED168115","title": "Google Earth Day Eco Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1681.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Earth+Day+Eco+Tee"} +{"id": "GGOEGAEJ103917","name": "GGOEGAEJ103917","title": "Google F/C Longsleeve Ash","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1039.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+FC+Longsleeve+Ash"} +{"id": "GGOEGFSR022099","name": "GGOEGFSR022099","title": "Google Kick Ball","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "2"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGFSR022099.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Lifestyle/Fun/Google+Kick+Ball.axd"} +{"id": "GGCOGCBA164499","name": "GGCOGCBA164499","title": "Google Knit Blanket","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "0"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGCOGCBA164499.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Lifestyle/Google+Knit+Blanket"} +{"id": "GGOEGAEJ146213","name": "GGOEGAEJ146213","title": "Google LA Campus Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1462.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+LA+Campus+Zip+Hoodie"} +{"id": "GGOEGACH161518","name": "GGOEGACH161518","title": "Google Land Sea French Terry Sweatshirt","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGCOGXXX1609.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Land+and+Sea+French+Terry+Sweatshirt+LS"} +{"id": "GGCOGCBA161199","name": "GGCOGCBA161199","title": "Google Land Sea Tech Taco","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "3"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGCOGCBA161199.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Land+and+Sea+Tech+Taco"} +{"id": "GGOEGAED161615","name": "GGOEGAED161615","title": "Google Land Sea Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGCOGXXX1569.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Land+and+Sea+Unisex+Tee+LS"} +{"id": "GGOEMAEB164113","name": "GGOEMAEB164113","title": "Google Maps Pin Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "21"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEMXXX1641.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Maps+Pin+Tee"} +{"id": "GGOEGADH138118","name": "GGOEGADH138118","title": "Google Men's Softshell Moss","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "39"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1381.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Mens+Softshell+Moss"} +{"id": "GGOEGDHJ147999","name": "GGOEGDHJ147999","title": "Google PNW Campus Bottle","brands": ["Google"],"categories": ["Drinkware"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "20"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGDHJ147999.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Drinkware/Google+PNW+Campus+Bottle"} +{"id": "GGOEGOAJ101399","name": "GGOEGOAJ101399","title": "Google Pen Grey","brands": ["Google"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "1.75"},"colorInfo": {"colorFamilies": ["Gray"],"colors": ["Light gray","Silver"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGOAJ101399.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Metal","Recycled Plastic"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Office/Google+pen+grey"} +{"id": "GGPRGADC107915","name": "GGPRGADC107915","title": "Google Raincoat Navy","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "44"},"colorInfo": {"colorFamilies": ["Navy"],"colors": ["Navy"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1350.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Raincoat+Navy"} +{"id": "GGOEGAAH136915","name": "GGOEGAAH136915","title": "Google Split Seam Tee Olive","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "26"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1369.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Split+Seam+Tee+Olive"} +{"id": "GGCOGAEC153813","name": "GGCOGAEC153813","title": "Google TYCTWD Blue Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"colorInfo": {"colorFamilies": ["Blue"],"colors": ["Light blue","Blue","Dark blue"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1538.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/TYCTWD/Google+TYCTWD+Blue+Tee"} +{"id": "GGOEGAEB110018","name": "GGOEGAEB110018","title": "Google Tee F/C Black","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Ebony"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1100.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Tee+FC+Black"} +{"id": "GGOEGAAB118914","name": "GGOEGAAB118914","title": "Google Unisex Eco Tee Black","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Jet"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1189.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Unisex+Eco+Tee+Black"} +{"id": "GGOEGAAB118916","name": "GGOEGAAB118916","title": "Google Unisex Eco Tee Black","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Outer Space","Jet"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1189.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Unisex+Eco+Tee+Black"} +{"id": "GGOEGAEJ178314","name": "GGOEGAEJ178314","title": "Google Unisex Essential Jacket","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1783.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Unisex+Essential+Jacket"} +{"id": "GGOEGAPJ178416","name": "GGOEGAPJ178416","title": "Google Women's Essential Jacket","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1784.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Womens+Essential+Jacket"} +{"id": "GGOEGCBD165799","name": "GGOEGCBD165799","title": "Google Wooden Yo-Yo","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "3"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGCBD165799.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Wooden+Yo+Yo"} +{"id": "GGOEGAYJ136014","name": "GGOEGAYJ136014","title": "Google Youth Hero Tee Grey","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "24"},"colorInfo": {"colorFamilies": ["Gray"],"colors": ["Light gray","Silver"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1360.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Youth+Hero+Tee+Grey"} +{"id": "GGOEYAEB120713","name": "GGOEYAEB120713","title": "YouTube Standards Zip Hoodie Black","brands": ["YouTube"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Jet"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEYXXX1207.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/YouTube+Standards+Zip+Hoodie+Black"} +{"id": "GGOEYAEB120715","name": "GGOEYAEB120715","title": "YouTube Standards Zip Hoodie Black","brands": ["YouTube"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"colorInfo": {"colorFamilies": ["Black"],"colors": ["Onyx","Outer Space","Jet"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEYXXX1207.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/YouTube+Standards+Zip+Hoodie+Black"} +{"id": "GGOEYALQ091914","name": "GGOEYALQ091914","title": "YouTube Women's Favorite Tee White","brands": ["YouTube"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"colorInfo": {"colorFamilies": ["White"],"colors": ["White"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX0919.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Youtube+Favorite+Tee+White"} +{"id": "GGOEGCKA151899","name": "GGOEGCKA151899","title": "Google 4in Decal","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "2"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGCKA151899.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Stationery/Google+4in+Decal"} +{"id": "GGOEGAEQ162514","name": "GGOEGAEQ162514","title": "Google 5k Run 2020 Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "22"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1625.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/5k+run/Google+5K+Run+2020+Unisex+Tee"} +{"id": "GGOEGEBK094499","name": "GGOEGEBK094499","title": "Google Bot Natural","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "10"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGEBK094499.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Accessories/Google+Bot"} +{"id": "GGPRGCBA106399","name": "GGPRGCBA106399","title": "Google Campus Bike","brands": ["Google"],"categories": ["Accessories"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGCBA096099.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Google+Campus+Bike"} +{"id": "GGOEGAER141015","name": "GGOEGAER141015","title": "Google Chicago Campus Unisex Tee","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "25"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1410.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Chicago+Campus+Unisex+Tee"} +{"id": "GGOEGAEC141218","name": "GGOEGAEC141218","title": "Google Chicago Campus Zip Hoodie","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "38"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1412.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Chicago+Campus+Zip+Hoodie"} +{"id": "GGOECAEB165414","name": "GGOECAEB165414","title": "Google Cloud Carhartt Crew Sweatshirt","brands": ["Google Cloud"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "30"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOECXXX1654.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Cloud+Unisex+Carhartt+Crew+Sweatshirt"} +{"id": "GGOEGAEJ178516","name": "GGOEGAEJ178516","title": "Google Cloud Packable Lightweight Jacket","brands": ["Google Cloud"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "32"},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/noimage.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Google+Cloud+Packable+Lightweight+Jacket"} +{"id": "GGOEGADH134212","name": "GGOEGADH134212","title": "Google Crewneck Sweatshirt Green","brands": ["Google"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "35"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive","Grass green","Light green"]},"availability": "OUT_OF_STOCK","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEGXXX1342.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2021.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Merino"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Casual"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Google+Crewneck+Sweatshirt+Green"} diff --git a/retail/interactive-tutorials/resources/products_some_invalid.json b/retail/interactive-tutorials/resources/products_some_invalid.json new file mode 100644 index 0000000000..1c560905dd --- /dev/null +++ b/retail/interactive-tutorials/resources/products_some_invalid.json @@ -0,0 +1,3 @@ +{"id": "GGCOGOAC101259","name": "GGCOGOAC101259","title": "#IamRemarkable Pen","brands": ["#IamRemarkable"],"categories": ["Office"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "16"},"colorInfo": {"colorFamilies": ["Blue"],"colors": ["Light blue","Blue","Dark blue"]},"availability": "INVALID_VALUE","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGCOGOAC101259.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Metal","Recycled Plastic"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Office/IamRemarkable+Pen"} +{"id": "GGPRAHPL107110","name": "GGPRAHPL107110","title": "Android Iconic Hat Green","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "16"},"colorInfo": {"colorFamilies": ["Green"],"colors": ["Olive","Grass green","Light green"]},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAHPL130910.jpg"}],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","uri": "https://shop.googlemerchandisestore.com/Google+Prize+Portal/Android+Iconic+Hat+Green"} +{"id": "GGOEAAKQ137410","name": "GGOEAAKQ137410","title": "Android Iconic Sock","brands": ["Android"],"categories": ["Apparel"],"priceInfo": {"cost": "12.0","currencyCode": "USD","originalPrice": "45.0","priceEffectiveTime": "2020-08-01T12:00:00+00:00","priceExpireTime": "2120-08-01T12:00:00+00:00","price": "17"},"availability": "IN_STOCK","availableQuantity": 50,"availableTime": "2021-10-11T12:00:00+00:00","images": [{"height": "300","width": "400","uri": "https://shop.googlemerchandisestore.com/store/20160512512/assets/items/images/GGOEAAKQ137410.jpg"}],"sizes": ["XS","S","M","L","XL"],"retrievableFields": "name,title,brands,categories,price_info,color_info,availability,images,attributes.material,attributes.ecofriendly,attributes.style,attributes.collection,uri","attributes":[ {"key":"collection", "value": {"indexable": "true","numbers": [2022.0]}},{"key":"material", "value": {"indexable": "true","searchable": "true","text": ["Polyester","Membrane"]}},{"key":"ecofriendly", "value": {"indexable": "false","searchable": "false","text": ["Low-impact fabrics","recycled fabrics","recycled packaging","plastic-free packaging","ethically made"]}},{"key":"style", "value": {"indexable": "true","searchable": "true","text": ["Sport","Functional"]}}],"uri": "https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Android+Iconic+Sock"} \ No newline at end of file diff --git a/retail/interactive-tutorials/resources/user_events.json b/retail/interactive-tutorials/resources/user_events.json new file mode 100644 index 0000000000..5360c30970 --- /dev/null +++ b/retail/interactive-tutorials/resources/user_events.json @@ -0,0 +1,4 @@ +{"eventType":"home-page-view","visitorId":"bjbs_group1_visitor1","eventTime":"2021-12-12T10:27:42+00:00"} +{"eventType":"search","visitorId":"bjbs_group1_visitor1","eventTime":"2021-12-12T10:27:42+00:00","searchQuery":"RockerJeans teenagers blue jeans"} +{"eventType":"search","visitorId":"bjbs_group1_visitor1","eventTime":"2021-12-12T10:27:42+00:00","searchQuery":"SocksUnlimited teenagers black socks"} +{"eventType":"detail-page-view","visitorId":"bjbs_group1_visitor1","eventTime":"2021-12-12T10:27:42+00:00","productDetails":{"product":{"id":"GGCOGAEC100616"},"quantity":3}} diff --git a/retail/interactive-tutorials/resources/user_events_some_invalid.json b/retail/interactive-tutorials/resources/user_events_some_invalid.json new file mode 100644 index 0000000000..c98b169964 --- /dev/null +++ b/retail/interactive-tutorials/resources/user_events_some_invalid.json @@ -0,0 +1,4 @@ +{"eventType":"home-page-view","visitorId":"bjbs_group1_visitor1","eventTime":"2021-12-12T10:27:42+00:00"} +{"eventType":"invalid","visitorId":"bjbs_group1_visitor1","eventTime":"2021-12-12T10:27:42+00:00","searchQuery":"RockerJeans teenagers blue jeans"} +{"eventType":"search","visitorId":"bjbs_group1_visitor1","eventTime":"2021-12-12T10:27:42+00:00","searchQuery":"SocksUnlimited teenagers black socks"} +{"eventType":"detail-page-view","visitorId":"bjbs_group1_visitor1","eventTime":"2021-12-12T10:27:42+00:00","productDetails":{"product":{"id":"GGCOGAEC100616"},"quantity":3}} diff --git a/retail/interactive-tutorials/setup/setup-cleanup.js b/retail/interactive-tutorials/setup/setup-cleanup.js new file mode 100644 index 0000000000..a0561c3256 --- /dev/null +++ b/retail/interactive-tutorials/setup/setup-cleanup.js @@ -0,0 +1,347 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; +// Imports the Google Cloud client library. +const {ProductServiceClient} = require('@google-cloud/retail').v2; +const {UserEventServiceClient} = require('@google-cloud/retail').v2; +const {Storage} = require('@google-cloud/storage'); +const {BigQuery} = require('@google-cloud/bigquery'); +const fs = require('fs'); + +const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); + +const createProduct = async ( + projectNumber, + generatedProductId, + isFullfillment = false +) => { + // The parent catalog resource name + const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch`; + + // The ID to use for the product + const productId = generatedProductId + ? generatedProductId + : Math.random().toString(36).slice(2).toUpperCase(); + + const fulfillmentInfo = isFullfillment + ? [ + { + type: 'same-day-delivery', + placeIds: ['store1', 'store2', 'store3'], + }, + ] + : []; + + // The product to create. + const product = { + title: 'Nest Mini', + type: 'PRIMARY', + categories: ['Speakers and displays'], + brands: ['Google'], + fulfillmentInfo, + priceInfo: { + price: 30.0, + originalPrice: 35.5, + currency_code: 'USD', + }, + availability: 'IN_STOCK', + }; + + const retailClient = new ProductServiceClient(); + + // Construct request + const request = { + parent, + product, + productId, + }; + + // Run request + const response = await retailClient.createProduct(request); + console.log(`Product ${response[0].id} created`); + return response[0]; +}; + +const getProduct = async name => { + const retailClient = new ProductServiceClient(); + + // Construct request + const request = { + name, + }; + + // Run request + const response = await retailClient.getProduct(request); + return response; +}; + +const deleteProduct = async name => { + const retailClient = new ProductServiceClient(); + + // Construct request + const request = { + name, + }; + + // Run request + const response = await retailClient.deleteProduct(request); + return response; +}; + +const deleteProductsByIds = async (projectNumber, ids) => { + const retailClient = new ProductServiceClient(); + + for (const id of ids) { + const name = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${id}`; + await retailClient.deleteProduct({name}); + } + return true; +}; + +const deleteProductsAll = async parent => { + const retailClient = new ProductServiceClient(); + const listProductsRequest = { + parent, + }; + const iterable = await retailClient.listProductsAsync(listProductsRequest); + let counter = 0; + for await (const product of iterable) { + await retailClient.deleteProduct({name: product.name}); + counter++; + } + console.log(`${counter} deleted products`); +}; + +const getBucketsList = async () => { + const storage = new Storage(); + const [buckets] = await storage.getBuckets(); + const bucketNames = buckets.map(item => item.name); + console.log(bucketNames); + return buckets; +}; + +const isBucketExist = async name => { + const storage = new Storage(); + const [buckets] = await storage.getBuckets(); + const bucketNames = buckets.map(item => item.name); + return bucketNames.indexOf(name) !== -1 ? true : false; +}; + +const createBucket = async name => { + if (await isBucketExist(name)) { + console.log(`Bucket ${name} alreaty exists`); + return false; + } else { + const storage = new Storage(); + const location = 'us'; + const storageClass = 'STANDARD'; + const createdBucket = await storage.createBucket(name, { + location, + [storageClass]: true, + }); + console.log(`Bucket ${createdBucket[0].name} created.`); + return createdBucket; + } +}; + +const deleteBucket = async bucketName => { + if (await isBucketExist(bucketName)) { + const storage = new Storage(); + await storage.bucket(bucketName).deleteFiles({force: true}); + await storage.bucket(bucketName).delete(); + console.log(`Bucket ${bucketName} deleted`); + } else { + console.log(`Bucket ${bucketName} doesn't exist`); + return false; + } +}; + +const uploadFile = async (bucketName, filePath, destFileName) => { + const storage = new Storage(); + await storage.bucket(bucketName).upload(filePath, { + destination: destFileName, + }); + console.log(`File ${destFileName} uploaded to ${bucketName}`); +}; + +const listFiles = async bucketName => { + const storage = new Storage(); + const [files] = await storage.bucket(bucketName).getFiles(); + + console.log('Files:'); + files.forEach(file => { + console.log(file.name); + }); +}; + +const isDatasetExist = async datasetId => { + const bigquery = new BigQuery(); + const [datasets] = await bigquery.getDatasets(); + const datasetIds = datasets.map(dataset => dataset.id); + return datasetIds.indexOf(datasetId) !== -1 ? true : false; +}; + +const createBqDataset = async datasetId => { + if (await isDatasetExist(datasetId)) { + console.log(`Dataset ${datasetId} already exists`); + return false; + } else { + const bigquery = new BigQuery(); + // Specify the geographic location where the dataset should reside + const options = { + location: 'US', + }; + + // Create a new dataset + const [dataset] = await bigquery.createDataset(datasetId, options); + console.log(`Dataset ${dataset.id} created.`); + return true; + } +}; + +const deleteBqDataset = async datasetId => { + if (await isDatasetExist(datasetId)) { + const bigquery = new BigQuery(); + await bigquery.dataset(datasetId).delete({force: true}); + console.log(`Dataset ${datasetId} deleted.`); + } else { + console.log(`Dataset ${datasetId} doesn't exist`); + return false; + } +}; + +const isTableExist = async (datasetId, tableId) => { + const bigquery = new BigQuery(); + const [tables] = await bigquery.dataset(datasetId).getTables(); + const tableIds = tables.map(table => table.id); + return tableIds.indexOf(tableId) !== -1 ? true : false; +}; + +const createBqTable = async (datasetId, tableId, schemaFile) => { + if (await isTableExist(datasetId, tableId)) { + console.log(`Table ${tableId} already exists`); + return false; + } else { + const schemaFileData = fs.readFileSync(schemaFile); + const schema = JSON.parse(schemaFileData); + + const bigquery = new BigQuery(); + const options = { + schema: schema, + location: 'US', + }; + + //Create a new table in the dataset + const [table] = await bigquery + .dataset(datasetId) + .createTable(tableId, options); + + console.log(`Table ${table.id} created.`); + return true; + } +}; + +const deleteBqTable = async (datasetId, tableId) => { + const bigquery = new BigQuery(); + await bigquery.dataset(datasetId).table(tableId).delete({force: true}); + console.log(`Table ${tableId} deleted.`); +}; + +const uploadDataToBqTable = async (datasetId, tableId, source, schemaFile) => { + const schemaFileData = fs.readFileSync(schemaFile); + const schema = { + fields: JSON.parse(schemaFileData), + }; + + const bigquery = new BigQuery(); + const options = { + sourceFormat: 'NEWLINE_DELIMITED_JSON', + schema, + location: 'US', + }; + const [job] = await bigquery + .dataset(datasetId) + .table(tableId) + .load(source, options); + // load() waits for the job to finish + console.log(`Job ${job.id} completed.`); +}; + +const writeUserEvent = async visitorId => { + const projectNumber = process.env['GCLOUD_PROJECT']; + const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog`; + const retailClient = new UserEventServiceClient(); + + const userEvent = { + eventType: 'detail-page-view', + visitorId, + eventTime: { + seconds: Math.round(Date.now() / 1000), + }, + productDetails: [ + { + product: { + id: 'test_id', + }, + quantity: { + value: 3, + }, + }, + ], + }; + + const request = { + parent, + userEvent, + }; + + const response = await retailClient.writeUserEvent(request); + return response[0]; +}; + +const purgeUserEvents = async (parent, visitorId) => { + const retailClient = new UserEventServiceClient(); + const request = { + parent, + filter: `visitorId="${visitorId}"`, + force: true, + }; + + const [operation] = await retailClient.purgeUserEvents(request); + console.log( + `Purge operation in progress.. Operation name: ${operation.name}` + ); +}; + +module.exports = { + createProduct, + getProduct, + deleteProduct, + deleteProductsByIds, + deleteProductsAll, + createBucket, + deleteBucket, + getBucketsList, + uploadFile, + listFiles, + createBqDataset, + deleteBqDataset, + createBqTable, + deleteBqTable, + uploadDataToBqTable, + writeUserEvent, + purgeUserEvents, + delay, +}; diff --git a/retail/interactive-tutorials/test-resources-setup/TEST_RESOURCES_SETUP_CLEANUP.md b/retail/interactive-tutorials/test-resources-setup/TEST_RESOURCES_SETUP_CLEANUP.md new file mode 100644 index 0000000000..688250c67c --- /dev/null +++ b/retail/interactive-tutorials/test-resources-setup/TEST_RESOURCES_SETUP_CLEANUP.md @@ -0,0 +1,53 @@ + +# How to set up/ tear down the test resources + +## Required environment variables + +To successfully import the catalog data for tests, the following environment variables should be set: + - GCLOUD_PROJECT + - BUCKET_NAME + - EVENTS_BUCKET_NAME + +These values are stored in the Secret Manager and will be submitted as + docker environment variables before the test run. + +The Secret Manager name is set in .kokoro/presubmit/common.cfg file, SECRET_MANAGER_KEYS variable. + +## Import catalog data + +There are a JSON files with valid products and user events prepared in `resources` directory: +`samples/interactive-tutorials/resources/products.json` and `samples/interactive-tutorials/resources/user_events.json` respectively. + +Run the `create_test_resources.js` to perform the following actions: + - create the GCS bucket , + - upload the product data from `resources/products.json` file to products bucket, + - import products to the default branch of the Retail catalog, + - create the GCS bucket , + - upload the product data from `resources/user_events.json` file to events bucket, + - create a BigQuery dataset and table `products`, + - insert products from resources/products.json to the created products table, + - create a BigQuery dataset and table `events`, + - insert user events from resources/user_events.json to the created events table + + +``` +$ node create-test-resources.js +``` + +In the result 316 products should be created in the test project catalog. + + +## Remove catalog data + +Run the `remove_test_resources.js` to perform the following actions: + - remove all objects from the GCS bucket , + - remove the bucket, + - delete all products from the Retail catalog. + - remove all objects from the GCS bucket , + - remove the bucket, + - remove dataset `products` along with tables + - remove dataset `user_events` along with tables + +``` +$ node remove-test-resources.js +``` \ No newline at end of file diff --git a/retail/interactive-tutorials/test-resources-setup/create-test-resources.js b/retail/interactive-tutorials/test-resources-setup/create-test-resources.js new file mode 100644 index 0000000000..dc7e47b5e3 --- /dev/null +++ b/retail/interactive-tutorials/test-resources-setup/create-test-resources.js @@ -0,0 +1,128 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main() { + const {ProductServiceClient} = require('@google-cloud/retail').v2; + const utils = require('../setup/setup-cleanup'); + + const projectNumber = process.env['GCLOUD_PROJECT']; + + const productsBucketName = process.env['BUCKET_NAME']; + const eventsBucketName = process.env['EVENTS_BUCKET_NAME']; + + const gcsBucket = `gs://${productsBucketName}`; + const gcsErrorsBucket = `gs://${productsBucketName}/error`; + const gcsProductsObject = 'products.json'; + + const productsDataset = 'products'; + const productTable = 'products'; + const productSchema = 'interactive-tutorials/resources/product_schema.json'; + const eventsDataset = 'user_events'; + const eventsTable = 'events'; + const eventsSchema = 'interactive-tutorials/resources/events_schema.json'; + + const productsSourceFile = 'interactive-tutorials/resources/products.json'; + const eventsSourceFile = 'interactive-tutorials/resources/user_events.json'; + + const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch`; + + const inputConfig = { + gcsSource: { + inputUris: [gcsBucket + '/' + gcsProductsObject], + dataSchema: 'product', + }, + }; + + const errorsConfig = { + gcsPrefix: gcsErrorsBucket, + }; + + const IResponseParams = { + IImportProductsResponse: 0, + IImportMetadata: 1, + IOperation: 2, + }; + + const retailClient = new ProductServiceClient(); + + const importProducts = async () => { + // Construct request + const request = { + parent, + inputConfig, + errorsConfig, + }; + console.log('Import products request:', request); + + // Run request + const [operation] = await retailClient.importProducts(request); + const response = await operation.promise(); + const result = response[IResponseParams.IImportMetadata]; + console.log( + `Number of successfully imported products: ${result.successCount | 0}` + ); + console.log( + `Number of failures during the importing: ${result.failureCount | 0}` + ); + console.log(`Operation result: ${JSON.stringify(response)}`); + }; + + // Create a GCS bucket with products.json file + await utils.createBucket(productsBucketName); + await utils.uploadFile( + productsBucketName, + productsSourceFile, + 'products.json' + ); + + // Create a GCS bucket with user_events.json file + await utils.createBucket(eventsBucketName); + await utils.uploadFile( + eventsBucketName, + eventsSourceFile, + 'user_events.json' + ); + + // Import prodcuts from the GCS bucket to the Retail catalog + await importProducts(); + + // Create a BigQuery table with products + await utils.createBqDataset(productsDataset); + await utils.createBqTable(productsDataset, productTable, productSchema); + await utils.uploadDataToBqTable( + productsDataset, + productTable, + productsSourceFile, + productSchema + ); + + // Create a BigQuery table with user events + await utils.createBqDataset(eventsDataset); + await utils.createBqTable(eventsDataset, eventsTable, eventsSchema); + await utils.uploadDataToBqTable( + eventsDataset, + eventsTable, + eventsSourceFile, + eventsSchema + ); +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(); diff --git a/retail/interactive-tutorials/test-resources-setup/remove-test-resources.js b/retail/interactive-tutorials/test-resources-setup/remove-test-resources.js new file mode 100644 index 0000000000..614add7017 --- /dev/null +++ b/retail/interactive-tutorials/test-resources-setup/remove-test-resources.js @@ -0,0 +1,44 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main() { + const utils = require('../setup/setup-cleanup'); + + const projectNumber = process.env['GCLOUD_PROJECT']; + + const productsBucketName = process.env['BUCKET_NAME']; + const eventsBucketName = process.env['EVENTS_BUCKET_NAME']; + + const productsDataset = 'products'; + const eventsDataset = 'user_events'; + + const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch`; + + await utils.deleteBucket(productsBucketName); + await utils.deleteBucket(eventsBucketName); + + await utils.deleteProductsAll(parent); + + await utils.deleteBqDataset(productsDataset); + await utils.deleteBqDataset(eventsDataset); +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(); diff --git a/retail/package.json b/retail/package.json index 55e3f26cd8..c7fe454126 100644 --- a/retail/package.json +++ b/retail/package.json @@ -10,10 +10,12 @@ "*.js" ], "scripts": { - "test": "c8 mocha --timeout 600000 test/*.js" + "test": "c8 mocha" }, "dependencies": { - "@google-cloud/retail": "^1.5.0" + "@google-cloud/retail": "^1.5.0", + "@google-cloud/bigquery": "^5.9.2", + "@google-cloud/storage": "^5.16.1" }, "devDependencies": { "c8": "^7.1.0", From 432c6f0cbd8acd30259bd661a98f4fedb5eb0569 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 15 Feb 2022 17:36:50 +0000 Subject: [PATCH 18/54] chore(main): release 1.6.0 (#141) :robot: I have created a release *beep* *boop* --- ## [1.6.0](https://github.com/googleapis/nodejs-retail/compare/v1.5.0...v1.6.0) (2022-02-15) ### Features * add ControlService ([92d4d84](https://github.com/googleapis/nodejs-retail/commit/92d4d849b9c4093778cf81bd56e8ebc2d6afd98b)) * add ServingConfigService ([92d4d84](https://github.com/googleapis/nodejs-retail/commit/92d4d849b9c4093778cf81bd56e8ebc2d6afd98b)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index c7fe454126..77ebaa7428 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha" }, "dependencies": { - "@google-cloud/retail": "^1.5.0", + "@google-cloud/retail": "^1.6.0", "@google-cloud/bigquery": "^5.9.2", "@google-cloud/storage": "^5.16.1" }, From 1173bb0d3154246556060a592cfa8104f67ed82a Mon Sep 17 00:00:00 2001 From: nmykhailets <94851929+nmykhailets@users.noreply.github.com> Date: Fri, 25 Feb 2022 17:05:52 +0200 Subject: [PATCH 19/54] samples: interactive tutorials code samples for search service (#146) --- retail/interactive-tutorials/README.md | 64 +++++++++ .../search/search-simple-query.js | 76 ++++++++++ .../search/search-with-boost-spec.js | 89 ++++++++++++ .../search/search-with-facet-spec.js | 80 +++++++++++ .../search/search-with-filtering.js | 82 +++++++++++ .../search/search-with-ordering.js | 81 +++++++++++ .../search/search-with-pagination.js | 91 ++++++++++++ .../search-with-query-expansion-spec.js | 83 +++++++++++ .../test/search-simple-query.test.js | 92 +++++++++++++ .../test/search-with-boost-spec.test.js | 96 +++++++++++++ .../test/search-with-facet-spec.test.js | 103 ++++++++++++++ .../test/search-with-filtering.test.js | 116 ++++++++++++++++ .../test/search-with-ordering.test.js | 110 +++++++++++++++ .../test/search-with-pagination.test.js | 130 ++++++++++++++++++ .../search-with-query-expansion-spec.test.js | 107 ++++++++++++++ 15 files changed, 1400 insertions(+) create mode 100644 retail/interactive-tutorials/README.md create mode 100644 retail/interactive-tutorials/search/search-simple-query.js create mode 100644 retail/interactive-tutorials/search/search-with-boost-spec.js create mode 100644 retail/interactive-tutorials/search/search-with-facet-spec.js create mode 100644 retail/interactive-tutorials/search/search-with-filtering.js create mode 100644 retail/interactive-tutorials/search/search-with-ordering.js create mode 100644 retail/interactive-tutorials/search/search-with-pagination.js create mode 100644 retail/interactive-tutorials/search/search-with-query-expansion-spec.js create mode 100644 retail/interactive-tutorials/test/search-simple-query.test.js create mode 100644 retail/interactive-tutorials/test/search-with-boost-spec.test.js create mode 100644 retail/interactive-tutorials/test/search-with-facet-spec.test.js create mode 100644 retail/interactive-tutorials/test/search-with-filtering.test.js create mode 100644 retail/interactive-tutorials/test/search-with-ordering.test.js create mode 100644 retail/interactive-tutorials/test/search-with-pagination.test.js create mode 100644 retail/interactive-tutorials/test/search-with-query-expansion-spec.test.js diff --git a/retail/interactive-tutorials/README.md b/retail/interactive-tutorials/README.md new file mode 100644 index 0000000000..bb5332f61b --- /dev/null +++ b/retail/interactive-tutorials/README.md @@ -0,0 +1,64 @@ + +## Get started with Google Cloud Retail + +### Select your project and enable the Retail API + +Google Cloud organizes resources into projects. This lets you +collect all the related resources for a single application in one place. + +If you don't have a Google Cloud project yet or you're not the Owner of an existing one, you can +[create a new project](https://console.cloud.google.com/projectcreate). + +After the project is created, set your PROJECT_ID to a ```project``` variable. +1. Run the following command in Terminal: + ```bash + gcloud config set project + ``` + +1. Check that the Retail API is enabled for your Project in the [Admin Console](https://console.cloud.google.com/ai/retail/). + +### Set up authentication + +To run a code sample from the Cloud Shell, you need to authenticate. To do this, use the Application Default Credentials. + +1. Set your user credentials to authenticate your requests to the Retail API + + ```bash + gcloud auth application-default login + ``` + +1. Type `Y` and press **Enter**. Click the link in Terminal. A browser window should appear asking you to log in using your Google account. + +1. Provide the Google Auth Library with access to your credentials and paste the code from the browser to the Terminal. + +1. Run the code sample and check the Retail API in action. + +**Note**: Click the copy button on the side of the code box to paste the command in the Cloud Shell terminal and run it. + +### Set the GCLOUD_PROJECT environment variable + +Because you are going to run the code samples in your own Google Cloud project, you should specify the **project_number** as an environment variable. It will be used in every request to the Retail API. + +1. You can find the ```project_number``` in the **Home/Dashboard/Project Info card**. + +1. Set the environment variable with the following command: + ```bash + export GCLOUD_PROJECT= + ``` + +### Install Google Cloud Retail libraries + +To install all the dependencies, run + +``` +cd cloudshell_open/retail-search-nodejs-samples +npm install +``` + +### Running the code samples +Samples are in the `search/`, `products/`, `events/` directories. +To execute an individual code sample, invoke `node` with a file as a parameter at the command line prompt, e.g.: + +``` +node search/search-simple-query.js +``` \ No newline at end of file diff --git a/retail/interactive-tutorials/search/search-simple-query.js b/retail/interactive-tutorials/search/search-simple-query.js new file mode 100644 index 0000000000..7a5bd03669 --- /dev/null +++ b/retail/interactive-tutorials/search/search-simple-query.js @@ -0,0 +1,76 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main() { + // [START retail_search_for_products_with_query_parameter] + // Call Retail API to search for a products in a catalog using only search query. + + // Imports the Google Cloud client library. + const {SearchServiceClient} = require('@google-cloud/retail'); + + const projectNumber = process.env['GCLOUD_PROJECT']; + + // Placement is used to identify the Serving Config name. + const placement = `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`; + + // Raw search query. + const query = 'Hoodie'; //TRY DIFFERENT QUERY PHRASES + + // A unique identifier for tracking visitors. + const visitorId = '12345'; + + // Maximum number of Products to return. + const pageSize = 10; + + // Instantiates a client. + const retailClient = new SearchServiceClient(); + + const IResponseParams = { + ISearchResult: 0, + ISearchRequest: 1, + ISearchResponse: 2, + }; + + const callSearch = async () => { + console.log('Search start'); + // Construct request + const request = { + placement, + query, + visitorId, + pageSize, + }; + console.log('Search request: ', request); + + // Run request + const response = await retailClient.search(request, { + autoPaginate: false, + }); + const searchResponse = response[IResponseParams.ISearchResponse]; + console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); + console.log('Search end'); + }; + + callSearch(); + // [END retail_search_for_products_with_query_parameter] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(); diff --git a/retail/interactive-tutorials/search/search-with-boost-spec.js b/retail/interactive-tutorials/search/search-with-boost-spec.js new file mode 100644 index 0000000000..52db62db08 --- /dev/null +++ b/retail/interactive-tutorials/search/search-with-boost-spec.js @@ -0,0 +1,89 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main() { + // [START retail_search_product_with_boost_spec] + // Call Retail API to search for a products in a catalog, rerank the + // results boosting or burying the products that match defined condition. + + // Imports the Google Cloud client library. + const {SearchServiceClient} = require('@google-cloud/retail'); + + const projectNumber = process.env['GCLOUD_PROJECT']; + + // Placement is used to identify the Serving Config name. + const placement = `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`; + + // Raw search query. + const query = 'Hoodie'; + + // A unique identifier for tracking visitors. + const visitorId = '12345'; + + //Boost specification to boost certain products. + const boostSpec = { + conditionBoostSpecs: [ + { + condition: '(colorFamilies: ANY("Blue"))', // TRY OTHER CONDITIONS + boost: 0.0, // TRY DIFFERENT SCORES + }, + ], + }; + + // Maximum number of Products to return. + const pageSize = 10; + + // Instantiates a client + const retailClient = new SearchServiceClient(); + + const IResponseParams = { + ISearchResult: 0, + ISearchRequest: 1, + ISearchResponse: 2, + }; + + const callSearch = async () => { + console.log('Search start'); + // Construct request + const request = { + placement, + query, + visitorId, + boostSpec, + pageSize, + }; + + console.log('Search request: ', request); + + // Run request + const response = await retailClient.search(request, { + autoPaginate: false, + }); + const searchResponse = response[IResponseParams.ISearchResponse]; + console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); + console.log('Search end'); + }; + + callSearch(); + // [END retail_search_product_with_boost_spec] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(); diff --git a/retail/interactive-tutorials/search/search-with-facet-spec.js b/retail/interactive-tutorials/search/search-with-facet-spec.js new file mode 100644 index 0000000000..7205c874bc --- /dev/null +++ b/retail/interactive-tutorials/search/search-with-facet-spec.js @@ -0,0 +1,80 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main() { + // [START retail_search_products_with_facet_spec] + // Call Retail API to search for a products in a catalog using only search query. + + // Imports the Google Cloud client library. + const {SearchServiceClient} = require('@google-cloud/retail'); + + const projectNumber = process.env['GCLOUD_PROJECT']; + + // Placement is used to identify the Serving Config name. + const placement = `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`; + + // Raw search query. + const query = 'Tee'; + + // A unique identifier for tracking visitors. + const visitorId = '12345'; + + //Facet specifications for faceted search. + const facetSpecs = [{facetKey: {key: 'colorFamilies'}}]; //PUT THE INTERVALS HERE + + // Maximum number of Products to return. + const pageSize = 10; + + // Instantiates a client. + const retailClient = new SearchServiceClient(); + + const IResponseParams = { + ISearchResult: 0, + ISearchRequest: 1, + ISearchResponse: 2, + }; + + const callSearch = async () => { + console.log('Search start'); + // Construct request + const request = { + placement, + query, + visitorId, + facetSpecs, + pageSize, + }; + console.log('Search request: ', request); + + // Run request + const response = await retailClient.search(request, { + autoPaginate: false, + }); + const searchResponse = response[IResponseParams.ISearchResponse]; + console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); + console.log('Search end'); + }; + + callSearch(); + // [END retail_search_products_with_facet_spec] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(); diff --git a/retail/interactive-tutorials/search/search-with-filtering.js b/retail/interactive-tutorials/search/search-with-filtering.js new file mode 100644 index 0000000000..3147809df4 --- /dev/null +++ b/retail/interactive-tutorials/search/search-with-filtering.js @@ -0,0 +1,82 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main() { + // [START retail_search_for_products_with_filter] + // Call Retail API to search for a products in a catalog, filter the results by different product fields. + + // Imports the Google Cloud client library. + const {SearchServiceClient} = require('@google-cloud/retail'); + + const projectNumber = process.env['GCLOUD_PROJECT']; + + // Placement is used to identify the Serving Config name. + const placement = `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`; + + // Raw search query. + const query = 'Tee'; + + // A unique identifier for tracking visitors. + const visitorId = '12345'; + + // The filter syntax consists of an expression language for constructing a + // predicate from one or more fields of the products being filtered. + const filter = '(colorFamilies: ANY("Black"))'; // TRY DIFFERENT FILTER EXPRESSIONS + + // Maximum number of Products to return. + const pageSize = 10; + + // Instantiates a client. + const retailClient = new SearchServiceClient(); + + const IResponseParams = { + ISearchResult: 0, + ISearchRequest: 1, + ISearchResponse: 2, + }; + + const callSearch = async () => { + console.log('Search start'); + // Construct request + const request = { + placement, + query, + visitorId, + filter, + pageSize, + }; + + console.log('Search request: ', request); + + // Run request + const response = await retailClient.search(request, { + autoPaginate: false, + }); + const searchResponse = response[IResponseParams.ISearchResponse]; + console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); + console.log('Search end'); + }; + + callSearch(); + // [END retail_search_for_products_with_filter] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(); diff --git a/retail/interactive-tutorials/search/search-with-ordering.js b/retail/interactive-tutorials/search/search-with-ordering.js new file mode 100644 index 0000000000..af99188f29 --- /dev/null +++ b/retail/interactive-tutorials/search/search-with-ordering.js @@ -0,0 +1,81 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main() { + // [START retail_search_for_products_with_ordering] + // Call Retail API to search for a products in a catalog, order the results by different product fields. + + // Imports the Google Cloud client library. + const {SearchServiceClient} = require('@google-cloud/retail'); + + const projectNumber = process.env['GCLOUD_PROJECT']; + + // Placement is used to identify the Serving Config name. + const placement = `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`; + + // Raw search query. + const query = 'Hoodie'; + + // A unique identifier for tracking visitors. + const visitorId = '12345'; + + // The order in which products are returned. + const orderBy = 'price desc'; // TRY DIFFERENT ORDER + + // Maximum number of Products to return. + const pageSize = 10; + + // Instantiates a client + const retailClient = new SearchServiceClient(); + + const IResponseParams = { + ISearchResult: 0, + ISearchRequest: 1, + ISearchResponse: 2, + }; + + const callSearch = async () => { + console.log('Search start'); + // Construct request + const request = { + placement, + query, + visitorId, + orderBy, + pageSize, + }; + + console.log('Search request: ', request); + + // Run request + const response = await retailClient.search(request, { + autoPaginate: false, + }); + const searchResponse = response[IResponseParams.ISearchResponse]; + console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); + console.log('Search end'); + }; + + callSearch(); + // [END retail_search_for_products_with_ordering] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(); diff --git a/retail/interactive-tutorials/search/search-with-pagination.js b/retail/interactive-tutorials/search/search-with-pagination.js new file mode 100644 index 0000000000..3158f3565a --- /dev/null +++ b/retail/interactive-tutorials/search/search-with-pagination.js @@ -0,0 +1,91 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main() { + // [START retail_search_for_products_with_pagination] + + // Imports the Google Cloud client library. + const {SearchServiceClient} = require('@google-cloud/retail'); + + const projectNumber = process.env['GCLOUD_PROJECT']; + + // Placement is used to identify the Serving Config name. + const placement = `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`; + + // Raw search query. + const query = 'Hoodie'; + + // A unique identifier for tracking visitors. + const visitorId = '12345'; + + // Maximum number of Products to return. + const pageSize = 6; // TRY DIFFERENT PAGE SIZES, INCLUDING THOSE OVER 100 + + // A 0-indexed integer that specifies the current offset in search results. + const offset = 0; // TRY DIFFERENT OFFSETS TO SEE DIFFERENT PRODUCTS + + //A page token received from a previous search call. + let pageToken = ''; + + // Instantiates a client. + const retailClient = new SearchServiceClient(); + + const IResponseParams = { + ISearchResult: 0, + ISearchRequest: 1, + ISearchResponse: 2, + }; + + const callSearch = async () => { + console.log('Search start'); + // Construct request + const request = { + placement, + query, + visitorId, + pageSize, + offset, + pageToken, + }; + + // Run request + const response = await retailClient.search(request, { + autoPaginate: false, + }); + const searchResponse = response[IResponseParams.ISearchResponse]; + console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); + pageToken = response[IResponseParams.ISearchResponse].nextPageToken; + console.log( + 'Next page token:', + response[IResponseParams.ISearchResponse].nextPageToken + ); + console.log('Search end'); + }; + + // Call search + await callSearch(); + + //PASTE CALL WITH NEXT PAGE TOKEN HERE: + + // [END retail_search_for_products_with_pagination] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(); diff --git a/retail/interactive-tutorials/search/search-with-query-expansion-spec.js b/retail/interactive-tutorials/search/search-with-query-expansion-spec.js new file mode 100644 index 0000000000..e70387f9e1 --- /dev/null +++ b/retail/interactive-tutorials/search/search-with-query-expansion-spec.js @@ -0,0 +1,83 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main() { + // [START retail_search_for_products_with_query_expansion_specification] + + // Imports the Google Cloud client library. + const {SearchServiceClient} = require('@google-cloud/retail'); + + const projectNumber = process.env['GCLOUD_PROJECT']; + + // Placement is used to identify the Serving Config name. + const placement = `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`; + + // Raw search query. + const query = 'Google Youth Hero Tee Grey'; + + // A unique identifier for tracking visitors. + const visitorId = '12345'; + + // The query expansion specification that specifies the conditions under which + // query expansion will occur. + const queryExpansionSpec = { + condition: 'AUTO', // TRY OTHER QUERY EXPANSION CONDITIONS HERE + }; + + //Maximum number of products to return + const pageSize = 10; + + // Instantiates a client. + const retailClient = new SearchServiceClient(); + + const IResponseParams = { + ISearchResult: 0, + ISearchRequest: 1, + ISearchResponse: 2, + }; + + const callSearch = async () => { + console.log('Search start'); + // Construct request + const request = { + placement, + query, + visitorId, + queryExpansionSpec, + pageSize, + }; + + console.log('Search request: ', request); + + // Run request + const response = await retailClient.search(request, { + autoPaginate: false, + }); + const searchResponse = response[IResponseParams.ISearchResponse]; + console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); + console.log('Search end'); + }; + + callSearch(); + // [END retail_search_for_products_with_query_expansion_specification] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(); diff --git a/retail/interactive-tutorials/test/search-simple-query.test.js b/retail/interactive-tutorials/test/search-simple-query.test.js new file mode 100644 index 0000000000..ff74a29d24 --- /dev/null +++ b/retail/interactive-tutorials/test/search-simple-query.test.js @@ -0,0 +1,92 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it} = require('mocha'); +const {SearchServiceClient} = require('@google-cloud/retail'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); +const cwd = path.join(__dirname, '..'); + +describe('Search simple query', () => { + describe('Search simple query run', () => { + let stdout; + + before(async () => { + stdout = execSync( + 'node interactive-tutorials/search/search-simple-query.js', + {cwd} + ); + }); + + it('should show that search successfully started', () => { + assert.match(stdout, /Search start/); + }); + + it('should show that search successfully finished', () => { + assert.match(stdout, /Search end/); + }); + }); + + describe('Search simple query sample result', () => { + const retailClient = new SearchServiceClient(); + + const projectNumber = process.env['GCLOUD_PROJECT']; + const request = { + placement: `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`, + query: 'Hoodie', + visitorId: '12345', + }; + const IResponseParams = { + ISearchResult: 0, + ISearchRequest: 1, + ISearchResponse: 2, + }; + let response = []; + + before(async () => { + response = await retailClient.search(request, {autoPaginate: false}); + }); + + it('should be a valid response', () => { + expect(response).to.be.an('array'); + expect(response.length).to.equal(3); + const searchResult = response[IResponseParams.ISearchResult]; + const searchResponse = response[IResponseParams.ISearchResponse]; + if (searchResult.length) { + expect(searchResponse.totalSize).to.be.above(0); + searchResult.forEach(resultItem => { + expect(resultItem, 'It should be an object').to.be.an('object'); + expect( + resultItem, + 'The object has no valid properties' + ).to.have.all.keys( + 'matchingVariantFields', + 'variantRollupValues', + 'id', + 'product', + 'matchingVariantCount' + ); + }); + } else { + expect(searchResult).to.be.an('array').that.is.empty; + expect(searchResponse.totalSize).to.equal(0); + } + }); + }); +}); diff --git a/retail/interactive-tutorials/test/search-with-boost-spec.test.js b/retail/interactive-tutorials/test/search-with-boost-spec.test.js new file mode 100644 index 0000000000..54d07dfd4d --- /dev/null +++ b/retail/interactive-tutorials/test/search-with-boost-spec.test.js @@ -0,0 +1,96 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it} = require('mocha'); +const {SearchServiceClient} = require('@google-cloud/retail'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); +const cwd = path.join(__dirname, '..'); + +describe('Search with boost spec', () => { + describe('Search with boost spec run sample', () => { + let stdout; + + before(async () => { + stdout = execSync( + 'node interactive-tutorials/search/search-with-boost-spec.js', + {cwd} + ); + }); + + it('should show that search successfully started', () => { + assert.match(stdout, /Search start/); + }); + + it('should show that search successfully finished', () => { + assert.match(stdout, /Search end/); + }); + }); + + describe('Search with boost spec sample result', () => { + const retailClient = new SearchServiceClient(); + + const projectNumber = process.env['GCLOUD_PROJECT']; + const request = { + placement: `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`, + query: 'Hoodie', + visitorId: '12345', + boostSpec: { + condition: '(colorFamilies: ANY("Blue"))', + boost: 0.0, + }, + }; + const IResponseParams = { + ISearchResult: 0, + ISearchRequest: 1, + ISearchResponse: 2, + }; + let response = []; + + before(async () => { + response = await retailClient.search(request, {autoPaginate: false}); + }); + + it('should be a valid response', () => { + expect(response).to.be.an('array'); + expect(response.length).to.equal(3); + const searchResult = response[IResponseParams.ISearchResult]; + const searchResponse = response[IResponseParams.ISearchResponse]; + if (searchResult.length) { + expect(searchResponse.totalSize).to.be.above(0); + searchResult.forEach(resultItem => { + expect(resultItem, 'It should be an object').to.be.an('object'); + expect( + resultItem, + 'The object has no valid properties' + ).to.have.all.keys( + 'matchingVariantFields', + 'variantRollupValues', + 'id', + 'product', + 'matchingVariantCount' + ); + }); + } else { + expect(searchResult).to.be.an('array').that.is.empty; + expect(searchResponse.totalSize).to.equal(0); + } + }); + }); +}); diff --git a/retail/interactive-tutorials/test/search-with-facet-spec.test.js b/retail/interactive-tutorials/test/search-with-facet-spec.test.js new file mode 100644 index 0000000000..6f79d3fc5b --- /dev/null +++ b/retail/interactive-tutorials/test/search-with-facet-spec.test.js @@ -0,0 +1,103 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it} = require('mocha'); +const {SearchServiceClient} = require('@google-cloud/retail'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); +const cwd = path.join(__dirname, '..'); + +describe('Search with facet spec', () => { + describe('Search with facet spec run sample', () => { + let stdout; + + before(async () => { + stdout = execSync( + 'node interactive-tutorials/search/search-with-facet-spec.js', + {cwd} + ); + }); + + it('should show that search successfully started', () => { + assert.match(stdout, /Search start/); + }); + + it('should show that search successfully finished', () => { + assert.match(stdout, /Search end/); + }); + }); + + describe('Search with facet spec result', () => { + const retailClient = new SearchServiceClient(); + const projectNumber = process.env['GCLOUD_PROJECT']; + const request = { + placement: `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`, + query: 'Tee', + visitorId: '12345', + facetSpecs: [{facetKey: {key: 'colorFamilies'}}], + pageSize: 10, + }; + const IResponseParams = { + ISearchResult: 0, + ISearchRequest: 1, + ISearchResponse: 2, + }; + let response = []; + + before(async () => { + response = await retailClient.search(request, {autoPaginate: false}); + }); + + it('should be a valid response', () => { + expect(response).to.be.an('array'); + expect(response.length).to.equal(3); + const searchResult = response[IResponseParams.ISearchResult]; + const searchResponse = response[IResponseParams.ISearchResponse]; + if (searchResult.length) { + expect(searchResponse.totalSize).to.be.above(0); + searchResult.forEach(resultItem => { + expect(resultItem, 'It should be an object').to.be.an('object'); + expect( + resultItem, + 'The object has no valid properties' + ).to.have.all.keys( + 'matchingVariantFields', + 'variantRollupValues', + 'id', + 'product', + 'matchingVariantCount' + ); + }); + } else { + expect(searchResult).to.be.an('array').that.is.empty; + expect(searchResponse.totalSize).to.equal(0); + } + }); + + it('should contain correct facets array', () => { + const searchResponse = response[IResponseParams.ISearchResponse]; + expect(searchResponse).to.be.an('object').that.is.not.empty; + expect(searchResponse.facets).to.be.an('array').that.is.not.empty; + + const facet = searchResponse.facets[0]; + expect(facet).to.be.an('object').that.is.not.empty; + expect(facet.key).to.equal('colorFamilies'); + }); + }); +}); diff --git a/retail/interactive-tutorials/test/search-with-filtering.test.js b/retail/interactive-tutorials/test/search-with-filtering.test.js new file mode 100644 index 0000000000..0aaa1b10ae --- /dev/null +++ b/retail/interactive-tutorials/test/search-with-filtering.test.js @@ -0,0 +1,116 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it} = require('mocha'); +const {SearchServiceClient} = require('@google-cloud/retail'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); +const cwd = path.join(__dirname, '..'); + +describe('Search with filtering', () => { + describe('Search with filtering run sample', () => { + let stdout; + + before(async () => { + stdout = execSync( + 'node interactive-tutorials/search/search-with-filtering.js', + {cwd} + ); + }); + + it('should show that search successfully started', () => { + assert.match(stdout, /Search start/); + }); + + it('should show that search successfully finished', () => { + assert.match(stdout, /Search end/); + }); + }); + + describe('Search with filtering sample result', () => { + const retailClient = new SearchServiceClient(); + const projectNumber = process.env['GCLOUD_PROJECT']; + const request = { + placement: `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`, + query: 'Tee', + visitorId: '12345', + filter: '(colorFamilies: ANY("Black"))', + }; + const IResponseParams = { + ISearchResult: 0, + ISearchRequest: 1, + ISearchResponse: 2, + }; + let response = []; + + before(async () => { + response = await retailClient.search(request, {autoPaginate: false}); + }); + + it('should be a valid response', () => { + expect(response).to.be.an('array'); + expect(response.length).to.equal(3); + const searchResult = response[IResponseParams.ISearchResult]; + const searchResponse = response[IResponseParams.ISearchResponse]; + if (searchResult.length) { + expect(searchResponse.totalSize).to.be.above(0); + searchResult.forEach(resultItem => { + expect(resultItem, 'It should be an object').to.be.an('object'); + expect( + resultItem, + 'The object has no valid properties' + ).to.have.all.keys( + 'matchingVariantFields', + 'variantRollupValues', + 'id', + 'product', + 'matchingVariantCount' + ); + }); + } else { + expect(searchResult).to.be.an('array').that.is.empty; + expect(searchResponse.totalSize).to.equal(0); + } + }); + + it('should contain filtered values', () => { + const searchResult = response[IResponseParams.ISearchResult]; + if (searchResult.length) { + searchResult.forEach(item => { + expect( + item.product, + 'Object has no "colorInfo" property' + ).to.have.property('colorInfo'); + expect( + item.product.colorInfo, + 'Object has no "colorFamilies" array' + ).to.have.property('colorFamilies'); + expect( + item.product.colorInfo.colorFamilies, + '"colorFamilies" field does not containt filter condition value' + ) + .to.be.an('array') + .that.includes('Black'); + }); + } else { + expect(searchResult).to.be.an('array').that.is.empty; + } + }); + }); +}); diff --git a/retail/interactive-tutorials/test/search-with-ordering.test.js b/retail/interactive-tutorials/test/search-with-ordering.test.js new file mode 100644 index 0000000000..4ddd6f0c0a --- /dev/null +++ b/retail/interactive-tutorials/test/search-with-ordering.test.js @@ -0,0 +1,110 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it} = require('mocha'); +const {SearchServiceClient} = require('@google-cloud/retail'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); +const cwd = path.join(__dirname, '..'); + +describe('Search with ordering', () => { + describe('Search with ordering run sample', () => { + let stdout; + + before(async () => { + stdout = execSync( + 'node interactive-tutorials/search/search-with-ordering.js', + {cwd} + ); + }); + + it('should show that search successfully started', () => { + assert.match(stdout, /Search start/); + }); + + it('should show that search successfully finished', () => { + assert.match(stdout, /Search end/); + }); + }); + + describe('Search with ordering sample result', () => { + const retailClient = new SearchServiceClient(); + const projectNumber = process.env['GCLOUD_PROJECT']; + const request = { + placement: `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`, + query: 'Hoodie', + visitorId: '12345', + orderBy: 'price desc', + }; + const IResponseParams = { + ISearchResult: 0, + ISearchRequest: 1, + ISearchResponse: 2, + }; + let response = []; + + before(async () => { + response = await retailClient.search(request, {autoPaginate: false}); + }); + + it('should be a valid response', () => { + expect(response).to.be.an('array'); + expect(response.length).to.equal(3); + const searchResult = response[IResponseParams.ISearchResult]; + const searchResponse = response[IResponseParams.ISearchResponse]; + if (searchResult.length) { + expect(searchResponse.totalSize).to.be.above(0); + searchResult.forEach(resultItem => { + expect(resultItem, 'It should be an object').to.be.an('object'); + expect( + resultItem, + 'The object has no valid properties' + ).to.have.all.keys( + 'matchingVariantFields', + 'variantRollupValues', + 'id', + 'product', + 'matchingVariantCount' + ); + }); + } else { + expect(searchResult).to.be.an('array').that.is.empty; + expect(searchResponse.totalSize).to.equal(0); + } + }); + + it('should be ordered', () => { + const searchResult = response[IResponseParams.ISearchResult]; + if (searchResult.length) { + const prices = []; + searchResult.forEach(item => { + prices.push(item.product.priceInfo.price); + }); + const sortedArrayDesc = [...prices].sort((a, b) => b - a); + expect( + prices, + 'It should be an ordered array' + ).to.include.ordered.members(sortedArrayDesc); + } else { + expect(searchResult, 'It should be an empty array').to.be.an('array') + .that.is.empty; + } + }); + }); +}); diff --git a/retail/interactive-tutorials/test/search-with-pagination.test.js b/retail/interactive-tutorials/test/search-with-pagination.test.js new file mode 100644 index 0000000000..59c1c24277 --- /dev/null +++ b/retail/interactive-tutorials/test/search-with-pagination.test.js @@ -0,0 +1,130 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it} = require('mocha'); +const {SearchServiceClient} = require('@google-cloud/retail'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); +const cwd = path.join(__dirname, '..'); + +describe('Search with pagination', () => { + describe('Search with pagination run sample', () => { + let stdout; + + before(async () => { + stdout = execSync( + 'node interactive-tutorials/search/search-with-pagination.js', + {cwd} + ); + }); + + it('should show that search successfully started', () => { + assert.match(stdout, /Search start/); + }); + + it('should contain next page token', () => { + assert.match(stdout, /Next page token/); + }); + + it('should show that search successfully finished', () => { + assert.match(stdout, /Search end/); + }); + }); + + describe('Search with pagination sample result', () => { + const retailClient = new SearchServiceClient(); + const projectNumber = process.env['GCLOUD_PROJECT']; + const pageSize = 2; + const offset = 0; + const pageToken = ''; + const request = { + placement: `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`, + query: 'Hoodie', + visitorId: '12345', + pageSize, + offset, + pageToken, + }; + let response; + + const IResponseParams = { + ISearchResult: 0, + ISearchRequest: 1, + ISearchResponse: 2, + }; + + before(async () => { + response = await retailClient.search(request, {autoPaginate: false}); + }); + + it('should be a valid response', () => { + expect(response).to.be.an('array'); + expect(response.length).to.equal(3); + const searchResult = response[IResponseParams.ISearchResult]; + const searchResponse = response[IResponseParams.ISearchResponse]; + if (searchResult.length) { + expect(searchResponse.totalSize).to.be.above(0); + searchResult.forEach(resultItem => { + expect(resultItem, 'It should be an object').to.be.an('object'); + expect( + resultItem, + 'The object has no valid properties' + ).to.have.all.keys( + 'matchingVariantFields', + 'variantRollupValues', + 'id', + 'product', + 'matchingVariantCount' + ); + }); + } else { + expect(searchResult).to.be.an('array').that.is.empty; + expect(searchResponse.totalSize).to.equal(0); + } + }); + + it('should contain a fixed number of products', () => { + const searchResult = response[IResponseParams.ISearchResult]; + if (searchResult.length) { + expect(searchResult.length).to.equal(pageSize); + } else { + expect(searchResult, 'It should be an empty array').to.be.an('array') + .that.is.empty; + } + }); + + it('should be a valid search response object', () => { + const searchResponse = response[IResponseParams.ISearchResponse]; + expect(searchResponse, 'It should be an object').to.be.an('object'); + expect( + searchResponse, + 'The object has no valid properties' + ).to.include.all.keys( + 'results', + 'facets', + 'totalSize', + 'correctedQuery', + 'attributionToken', + 'nextPageToken', + 'queryExpansionInfo', + 'redirectUri' + ); + }); + }); +}); diff --git a/retail/interactive-tutorials/test/search-with-query-expansion-spec.test.js b/retail/interactive-tutorials/test/search-with-query-expansion-spec.test.js new file mode 100644 index 0000000000..246cc1df65 --- /dev/null +++ b/retail/interactive-tutorials/test/search-with-query-expansion-spec.test.js @@ -0,0 +1,107 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it} = require('mocha'); +const {SearchServiceClient} = require('@google-cloud/retail'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); +const cwd = path.join(__dirname, '..'); + +describe('Search with query expansion spec', () => { + describe('Search with query expansion spec run sample', () => { + let stdout; + + before(async () => { + stdout = execSync( + 'node interactive-tutorials/search/search-with-query-expansion-spec.js', + { + cwd, + } + ); + }); + + it('should show that search successfully started', () => { + assert.match(stdout, /Search start/); + }); + + it('should show that search successfully finished', () => { + assert.match(stdout, /Search end/); + }); + }); + + describe('Search with query expansion spec sample result', () => { + const retailClient = new SearchServiceClient(); + const projectNumber = process.env['GCLOUD_PROJECT']; + const request = { + placement: `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`, + query: 'Google Youth Hero Tee Grey', + visitorId: '12345', + queryExpansionSpec: { + condition: 'AUTO', + }, + pageSize: 10, + }; + const IResponseParams = { + ISearchResult: 0, + ISearchRequest: 1, + ISearchResponse: 2, + }; + let response = []; + + before(async () => { + response = await retailClient.search(request, {autoPaginate: false}); + }); + + it('should be a valid response', () => { + expect(response).to.be.an('array'); + expect(response.length).to.equal(3); + const searchResult = response[IResponseParams.ISearchResult]; + const searchResponse = response[IResponseParams.ISearchResponse]; + if (searchResult.length) { + expect(searchResponse.totalSize).to.be.above(0); + searchResult.forEach(resultItem => { + expect(resultItem, 'It should be an object').to.be.an('object'); + expect( + resultItem, + 'The object has no valid properties' + ).to.have.all.keys( + 'matchingVariantFields', + 'variantRollupValues', + 'id', + 'product', + 'matchingVariantCount' + ); + }); + } else { + expect(searchResult).to.be.an('array').that.is.empty; + expect(searchResponse.totalSize).to.equal(0); + } + }); + + it('should contain expanded query', () => { + const searchResponse = response[IResponseParams.ISearchResponse]; + console.log(response); + expect( + searchResponse.queryExpansionInfo, + 'Search response does not contain query expansion info' + ).to.be.an('object'); + expect(searchResponse.queryExpansionInfo.expandedQuery).to.be.true; + }); + }); +}); From 27428adfadde3f2b9022a82828be9617a4599774 Mon Sep 17 00:00:00 2001 From: nmykhailets <94851929+nmykhailets@users.noreply.github.com> Date: Tue, 8 Mar 2022 04:34:07 +0200 Subject: [PATCH 20/54] chore(samples): interactive tutorials code samples for import products (#147) --- .../import-products-big-query-table.js | 94 +++++++++++++ .../product/import-products-gcs.js | 91 ++++++++++++ .../product/import-products-inline-source.js | 131 ++++++++++++++++++ .../setup/create-bigquery-table.js | 46 ++++++ .../setup/create-gcs-bucket.js | 49 +++++++ .../setup/delete-bigquery-table.js | 31 +++++ .../setup/delete-gcs-bucket.js | 34 +++++ .../test/import-products-gcs.test.js | 83 +++++++++++ .../import-products-inline-source.test.js | 102 ++++++++++++++ 9 files changed, 661 insertions(+) create mode 100644 retail/interactive-tutorials/product/import-products-big-query-table.js create mode 100644 retail/interactive-tutorials/product/import-products-gcs.js create mode 100644 retail/interactive-tutorials/product/import-products-inline-source.js create mode 100644 retail/interactive-tutorials/setup/create-bigquery-table.js create mode 100644 retail/interactive-tutorials/setup/create-gcs-bucket.js create mode 100644 retail/interactive-tutorials/setup/delete-bigquery-table.js create mode 100644 retail/interactive-tutorials/setup/delete-gcs-bucket.js create mode 100644 retail/interactive-tutorials/test/import-products-gcs.test.js create mode 100644 retail/interactive-tutorials/test/import-products-inline-source.test.js diff --git a/retail/interactive-tutorials/product/import-products-big-query-table.js b/retail/interactive-tutorials/product/import-products-big-query-table.js new file mode 100644 index 0000000000..2b9c3c842a --- /dev/null +++ b/retail/interactive-tutorials/product/import-products-big-query-table.js @@ -0,0 +1,94 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main() { + // [START retail_import_products_from_big_query] + + // Imports the Google Cloud client library. + const {ProductServiceClient} = require('@google-cloud/retail').v2; + + const projectNumber = process.env['GCLOUD_PROJECT']; + const projectId = process.env['PROJECT_ID']; + + const datasetId = 'products'; + const tableId = 'products'; // TO CHECK ERROR HANDLING USE THE TABLE WITH INVALID PRODUCTS + const dataSchema = 'product'; + + // Placement + const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch`; // TO CHECK ERROR HANDLING PASTE THE INVALID CATALOG NAME HERE + + // The desired input location of the data. + const inputConfig = { + bigQuerySource: { + projectId, + datasetId, + tableId, + dataSchema, + }, + }; + + const reconciliationModes = { + RECONCILIATION_MODE_UNSPECIFIED: 0, + INCREMENTAL: 1, + FULL: 2, + }; + + const IResponseParams = { + IImportProductsResponse: 0, + IImportMetadata: 1, + IOperation: 2, + }; + + // The mode of reconciliation between existing products and the products to be imported. + const reconciliationMode = reconciliationModes.INCREMENTAL; + + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const callImportProducts = async () => { + // Construct request + const request = { + parent, + inputConfig, + reconciliationMode, + }; + console.log('Import product request:', request); + + // Run request + const [operation] = await retailClient.importProducts(request); + const response = await operation.promise(); + const result = response[IResponseParams.IImportMetadata]; + console.log( + `Number of successfully imported products: ${result.successCount | 0}` + ); + console.log( + `Number of failures during the importing: ${result.failureCount | 0}` + ); + console.log(`Operation result: ${JSON.stringify(response)}`); + }; + + console.log('Start import products'); + await callImportProducts(); + console.log('Import products finished'); + // [END retail_import_products_from_big_query] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(); diff --git a/retail/interactive-tutorials/product/import-products-gcs.js b/retail/interactive-tutorials/product/import-products-gcs.js new file mode 100644 index 0000000000..d5ddaa4282 --- /dev/null +++ b/retail/interactive-tutorials/product/import-products-gcs.js @@ -0,0 +1,91 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(bucketName) { + // [START retail_import_products_from_gcs] + + // Imports the Google Cloud client library. + const {ProductServiceClient} = require('@google-cloud/retail').v2; + + const projectNumber = process.env['GCLOUD_PROJECT']; + + const gcsBucket = `gs://${bucketName}`; + const gcsErrorsBucket = `gs://${bucketName}/error`; + const gcsProductsObject = 'products.json'; // TO CHECK ERROR HANDLING USE THE JSON WITH INVALID PRODUCT + + // Placement + const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch`; //TO CHECK ERROR HANDLING PASTE THE INVALID CATALOG NAME HERE + + // The desired input location of the data. + const inputConfig = { + gcsSource: { + inputUris: [gcsBucket + '/' + gcsProductsObject], + dataSchema: 'product', + }, + }; + + // The desired location of errors incurred during the Import. + const errorsConfig = { + gcsPrefix: gcsErrorsBucket, + }; + + const IResponseParams = { + IImportProductsResponse: 0, + IImportMetadata: 1, + IOperation: 2, + }; + + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const callImportProducts = async () => { + // Construct request + const request = { + parent, + inputConfig, + errorsConfig, + }; + console.log('Import products request:', request); + + // Run request + const [operation] = await retailClient.importProducts(request); + const response = await operation.promise(); + const result = response[IResponseParams.IImportMetadata]; + console.log( + `Number of successfully imported products: ${result.successCount | 0}` + ); + console.log( + `Number of failures during the importing: ${result.failureCount | 0}` + ); + console.log(`Operation result: ${JSON.stringify(response)}`); + }; + console.log('Start import products'); + await callImportProducts(); + console.log('Import products finished'); + // [END retail_import_products_from_gcs] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main( + ...(() => { + const argv = process.argv.slice(2); + return argv.length ? argv : [process.env['BUCKET_NAME']]; + })() +); diff --git a/retail/interactive-tutorials/product/import-products-inline-source.js b/retail/interactive-tutorials/product/import-products-inline-source.js new file mode 100644 index 0000000000..396646b2d2 --- /dev/null +++ b/retail/interactive-tutorials/product/import-products-inline-source.js @@ -0,0 +1,131 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(id1, id2) { + // [START retail_import_products_from_inline_source] + + // Imports the Google Cloud client library. + const {ProductServiceClient} = require('@google-cloud/retail').v2; + const utils = require('../setup/setup-cleanup'); + + const projectNumber = process.env['GCLOUD_PROJECT']; + + // Placement + const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch`; + + const product1 = { + id: id1 ? id1 : Math.random().toString(36).slice(2).toUpperCase(), + title: '#IamRemarkable Pen', //TO CHECK ERROR HANDLING COMMENT OUT THE PRODUCT TITLE HERE + uri: 'https://shop.googlemerchandisestore.com/Google+Redesign/Office/IamRemarkable+Pen', + brands: ['#IamRemarkable'], + categories: ['Apparel'], + priceInfo: { + price: 16.0, + originalPrice: 45.0, + cost: 12.0, + currencyCode: 'USD', + }, + colorInfo: { + colorFamilies: ['Blue'], + colors: ['Light blue', 'Blue', 'Dark blue'], + }, + fulFillmentInfo: { + type: 'pickup-in-store', + placeIds: ['store1', 'store2'], + }, + retrievable_fields: { + paths: ['title', 'categories', 'price_info', 'color_info'], + }, + }; + + const product2 = { + id: id2 ? id2 : Math.random().toString(36).slice(2).toUpperCase(), + title: 'Android Embroidered Crewneck Sweater', + uri: 'https://shop.googlemerchandisestore.com/Google+Redesign/Apparel/Android+Embroidered+Crewneck+Sweater', + brands: ['Android'], + categories: ['Apparel'], + priceInfo: { + price: 35.0, + originalPrice: 45.0, + cost: 12.0, + currencyCode: 'USD', + }, + colorInfo: { + colorFamilies: ['Blue'], + colors: ['Sky blue'], + }, + fulFillmentInfo: { + type: 'pickup-in-store', + placeIds: ['store2', 'store3'], + }, + retrievable_fields: { + paths: ['title', 'categories', 'price_info', 'color_info'], + }, + }; + + // The desired input location of the data. + const inputConfig = { + productInlineSource: { + products: [product1, product2], + }, + }; + + const IResponseParams = { + IImportProductsResponse: 0, + IImportMetadata: 1, + IOperation: 2, + }; + + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const callImportProducts = async () => { + // Construct request + const request = { + parent, + inputConfig, + }; + console.log('Import products request:', request); + + // Run request + const [operation] = await retailClient.importProducts(request); + const response = await operation.promise(); + const result = response[IResponseParams.IImportMetadata]; + console.log( + `Number of successfully imported products: ${result.successCount | 0}` + ); + console.log( + `Number of failures during the importing: ${result.failureCount | 0}` + ); + console.log(`Operation result: ${JSON.stringify(response)}`); + }; + // Start import products + console.log('Start import products'); + await callImportProducts(); + console.log('Import products finished'); + + // Delete imported products + await utils.deleteProductsByIds(projectNumber, [product1.id, product2.id]); + console.log('Products deleted'); + // [END retail_import_products_from_inline_source] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(...process.argv.slice(2)); diff --git a/retail/interactive-tutorials/setup/create-bigquery-table.js b/retail/interactive-tutorials/setup/create-bigquery-table.js new file mode 100644 index 0000000000..77990b35cf --- /dev/null +++ b/retail/interactive-tutorials/setup/create-bigquery-table.js @@ -0,0 +1,46 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main() { + const utils = require('./setup-cleanup'); + + const dataset = 'products'; + const validTable = 'products'; + const invalidTable = 'products_some_invalid'; + const schema = 'interactive-tutorials/resources/product_schema.json'; + const validSourceFile = 'interactive-tutorials/resources/products.json'; + const invalidSourceFile = + 'interactive-tutorials/resources/products_some_invalid.json'; + + await utils.createBqDataset(dataset); + await utils.createBqTable(dataset, validTable, schema); + await utils.uploadDataToBqTable(dataset, validTable, validSourceFile, schema); + + await utils.createBqTable(dataset, invalidTable, schema); + await utils.uploadDataToBqTable( + dataset, + validTable, + invalidSourceFile, + schema + ); +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(); diff --git a/retail/interactive-tutorials/setup/create-gcs-bucket.js b/retail/interactive-tutorials/setup/create-gcs-bucket.js new file mode 100644 index 0000000000..6d5172ea79 --- /dev/null +++ b/retail/interactive-tutorials/setup/create-gcs-bucket.js @@ -0,0 +1,49 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(generatedBucketName) { + const utils = require('./setup-cleanup'); + + //Get your project ID + const projectId = process.env['PROJECT_ID']; + + // The ID of your GCS bucket + const bucketName = generatedBucketName + ? generatedBucketName + : `${projectId}_${Math.round(Date.now() / 1000)}`; + + //Creates the new bucket + await utils.createBucket(bucketName); + + //Upload files + await utils.uploadFile( + bucketName, + 'interactive-tutorials/resources/products.json', + 'products.json' + ); + await utils.uploadFile( + bucketName, + 'interactive-tutorials/resources/products_some_invalid.json', + 'products_some_invalid.json' + ); +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(...process.argv.slice(2)); diff --git a/retail/interactive-tutorials/setup/delete-bigquery-table.js b/retail/interactive-tutorials/setup/delete-bigquery-table.js new file mode 100644 index 0000000000..344a81a4e7 --- /dev/null +++ b/retail/interactive-tutorials/setup/delete-bigquery-table.js @@ -0,0 +1,31 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main() { + const utils = require('./setup-cleanup'); + + const dataset = 'products'; + + //Delete created bigquery dataset + await utils.deleteBqDataset(dataset); +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(); diff --git a/retail/interactive-tutorials/setup/delete-gcs-bucket.js b/retail/interactive-tutorials/setup/delete-gcs-bucket.js new file mode 100644 index 0000000000..6034ed390d --- /dev/null +++ b/retail/interactive-tutorials/setup/delete-gcs-bucket.js @@ -0,0 +1,34 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(generatedBucketName) { + const utils = require('./setup-cleanup'); + + // The ID of your GCS bucket + const bucketName = generatedBucketName + ? generatedBucketName + : process.env['BUCKET_NAME']; + + //Delete created bucket + await utils.deleteBucket(bucketName); +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(...process.argv.slice(2)); diff --git a/retail/interactive-tutorials/test/import-products-gcs.test.js b/retail/interactive-tutorials/test/import-products-gcs.test.js new file mode 100644 index 0000000000..b9e7e497b2 --- /dev/null +++ b/retail/interactive-tutorials/test/import-products-gcs.test.js @@ -0,0 +1,83 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, after, describe, it} = require('mocha'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cwd = path.join(__dirname, '..'); +const utils = require('../setup/setup-cleanup'); + +describe('Import product from gcs', () => { + let stdout; + const bucketName = `product_bucket_${Math.round(Date.now() / 1000)}`; + + before(async () => { + await utils.createBucket(bucketName); + await utils.uploadFile( + bucketName, + 'interactive-tutorials/resources/products.json', + 'products.json' + ); + await utils.uploadFile( + bucketName, + 'interactive-tutorials/resources/products_some_invalid.json', + 'products_some_invalid.json' + ); + + stdout = execSync( + `node interactive-tutorials/product/import-products-gcs.js ${bucketName}`, + {cwd} + ); + }); + + it('should check that import started', () => { + assert.match(stdout, /Start import products/); + }); + + it('should check that products imported correctly', async () => { + const regex = new RegExp('Operation result: .*\\n', 'g'); + assert.match(stdout, regex); + const string = stdout + .match(regex) + .toString() + .replace('Operation result: ', ''); + const importOperation = JSON.parse(string); + + expect(importOperation).to.be.an('array'); + expect(importOperation.length).to.equal(3); + + const response = importOperation[1]; + const metadata = importOperation[2]; + + expect(metadata).to.be.an('object'); + expect(metadata.done).to.be.true; + + expect(response).to.be.an('object'); + expect(response.successCount).to.equal('316'); + }); + + it('should check that import finished', () => { + assert.match(stdout, /Import products finished/); + }); + + after(async () => { + await utils.deleteBucket(bucketName); + }); +}); diff --git a/retail/interactive-tutorials/test/import-products-inline-source.test.js b/retail/interactive-tutorials/test/import-products-inline-source.test.js new file mode 100644 index 0000000000..319bca5e1e --- /dev/null +++ b/retail/interactive-tutorials/test/import-products-inline-source.test.js @@ -0,0 +1,102 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it, after} = require('mocha'); +const {ProductServiceClient} = require('@google-cloud/retail'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cwd = path.join(__dirname, '..'); + +describe('Import product from inline source', () => { + const retailClient = new ProductServiceClient(); + const projectNumber = process.env['GCLOUD_PROJECT']; + + const id1 = Math.random().toString(36).slice(2).toUpperCase(); + const id2 = Math.random().toString(36).slice(2).toUpperCase(); + + const product1 = { + id: id1, + name: `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${id1}`, + }; + + const product2 = { + id: id2, + name: `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${id2}`, + }; + + let stdout; + + before(async () => { + stdout = execSync( + `node interactive-tutorials/product/import-products-inline-source.js ${product1.id} ${product2.id}`, + {cwd} + ); + }); + + it('should check that import started', () => { + assert.match(stdout, /Start import products/); + }); + + it('should check that products imported correctly', async () => { + const regex = new RegExp('Operation result: .*\\n', 'g'); + assert.match(stdout, regex); + const string = stdout + .match(regex) + .toString() + .replace('Operation result: ', ''); + const importOperation = JSON.parse(string); + + expect(importOperation).to.be.an('array'); + expect(importOperation.length).to.equal(3); + + const response = importOperation[1]; + const metadata = importOperation[2]; + + expect(metadata).to.be.an('object'); + expect(metadata.done).to.be.true; + + expect(response).to.be.an('object'); + expect(response.successCount).to.equal('2'); + }); + + it('should check that import finished', () => { + assert.match(stdout, /Import products finished/); + }); + + it('should check that product deleted', async () => { + const regex = new RegExp('Products deleted', 'g'); + assert.match(stdout, regex); + }); + + after(async () => { + try { + const importedProduct1 = await retailClient.getProduct({ + name: product1.name, + }); + const importedProduct2 = await retailClient.getProduct({ + name: product2.name, + }); + expect(importedProduct1, 'The product not deleted').to.be.undefined; + expect(importedProduct2, 'The product not deleted').to.be.undefined; + } catch (err) { + expect(err, 'Bad error code').to.include({code: 5}); + } + }); +}); From eca0809d0cd6cdfb7cf14b71f7a2185129e8ac57 Mon Sep 17 00:00:00 2001 From: nmykhailets <94851929+nmykhailets@users.noreply.github.com> Date: Tue, 8 Mar 2022 05:01:32 +0200 Subject: [PATCH 21/54] chore(samples): interactive tutorials code samples for write/rejoin/purge user events (#150) Co-authored-by: tetiana-karasova Co-authored-by: Karl Weinmeister <11586922+kweinmeister@users.noreply.github.com> Co-authored-by: Benjamin E. Coe --- .../events/purge-user-events.js | 73 ++++++++++++++++++ .../events/rejoin-user-events.js | 77 +++++++++++++++++++ .../events/write-user-event.js | 71 +++++++++++++++++ .../test/purge-user-events.test.js | 50 ++++++++++++ .../test/rejoin-user-events.test.js | 55 +++++++++++++ .../test/write-user-event.test.js | 63 +++++++++++++++ 6 files changed, 389 insertions(+) create mode 100644 retail/interactive-tutorials/events/purge-user-events.js create mode 100644 retail/interactive-tutorials/events/rejoin-user-events.js create mode 100644 retail/interactive-tutorials/events/write-user-event.js create mode 100644 retail/interactive-tutorials/test/purge-user-events.test.js create mode 100644 retail/interactive-tutorials/test/rejoin-user-events.test.js create mode 100644 retail/interactive-tutorials/test/write-user-event.test.js diff --git a/retail/interactive-tutorials/events/purge-user-events.js b/retail/interactive-tutorials/events/purge-user-events.js new file mode 100644 index 0000000000..e63c9f2c1a --- /dev/null +++ b/retail/interactive-tutorials/events/purge-user-events.js @@ -0,0 +1,73 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main() { + // [START retail_purge_user_events] + + // Imports the Google Cloud client library. + const {UserEventServiceClient} = require('@google-cloud/retail').v2; + const utils = require('../setup/setup-cleanup'); + + const projectNumber = process.env['GCLOUD_PROJECT']; + const visitorId = 'test_visitor_id'; + + // Placement + const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog`; + + // The filter string to specify the events to be deleted with a + // length limit of 5,000 characters. + const filter = `visitorId="${visitorId}"`; // TO CHECK ERROR HANDLING SET INVALID FILTER HERE + + // Actually perform the purge. + const force = true; + + // Instantiates a client. + const retailClient = new UserEventServiceClient(); + + const callPurgeUserEvents = async () => { + // Construct request + const request = { + parent, + filter, + force, + }; + + console.log('Purge request: ', request); + + // Run request + const [operation] = await retailClient.purgeUserEvents(request); + console.log( + `Purge operation in progress.. Operation name: ${operation.name}` + ); + }; + + // Create new event + const event = await utils.writeUserEvent(visitorId); + console.log( + `Created event ${event.eventType} with visitor id ${event.visitorId}` + ); + + // Purge events + await callPurgeUserEvents(); + // [END retail_purge_user_events] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(); diff --git a/retail/interactive-tutorials/events/rejoin-user-events.js b/retail/interactive-tutorials/events/rejoin-user-events.js new file mode 100644 index 0000000000..82e73a54b5 --- /dev/null +++ b/retail/interactive-tutorials/events/rejoin-user-events.js @@ -0,0 +1,77 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main() { + // [START retail_rejoin_user_event] + + // Imports the Google Cloud client library. + const {UserEventServiceClient} = require('@google-cloud/retail').v2; + const utils = require('../setup/setup-cleanup'); + + const projectNumber = process.env['GCLOUD_PROJECT']; + const visitorId = 'test_visitor_id'; + + // Placement + const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog`; // TO CHECK ERROR HANDLING PASTE THE INVALID CATALOG NAME HERE + + const UserEventRejoinScope = { + USER_EVENT_REJOIN_SCOPE_UNSPECIFIED: 0, + JOINED_EVENTS: 1, + UNJOINED_EVENTS: 2, + }; + // The type of the user event rejoin to define the scope and range of the user + // events to be rejoined with the latest product catalog + const userEventRejoinScope = UserEventRejoinScope.UNJOINED_EVENTS; + + // Instantiates a client. + const retailClient = new UserEventServiceClient(); + + const callRejoinUserEvents = async () => { + // Construct request + const request = { + parent, + userEventRejoinScope, + }; + + console.log('Rejoin request: ', request); + + // Run request + const [operation] = await retailClient.rejoinUserEvents(request); + console.log( + `Rejoin operation in progress.. Operation name: ${operation.name}` + ); + }; + + // Create new event + const event = await utils.writeUserEvent(visitorId); + console.log( + `Created event ${event.eventType} with visitor id ${event.visitorId}` + ); + + // Rejoin events + await callRejoinUserEvents(); + + // Purge events + utils.purgeUserEvents(parent, visitorId); + // [END retail_rejoin_user_event] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(); diff --git a/retail/interactive-tutorials/events/write-user-event.js b/retail/interactive-tutorials/events/write-user-event.js new file mode 100644 index 0000000000..6763abbde8 --- /dev/null +++ b/retail/interactive-tutorials/events/write-user-event.js @@ -0,0 +1,71 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main() { + // [START retail_write_user_event] + + // Imports the Google Cloud client library. + const {UserEventServiceClient} = require('@google-cloud/retail').v2; + const utils = require('../setup/setup-cleanup'); + + const projectNumber = process.env['GCLOUD_PROJECT']; + const visitorId = 'test_visitor_id'; + + // Placement + const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog`; // TO CHECK ERROR HANDLING PASTE THE INVALID CATALOG NAME HERE + + // User event to write + const userEvent = { + eventType: 'home-page-view', + visitorId, + eventTime: { + seconds: Math.round(Date.now() / 1000), + }, + }; + + // Instantiates a client. + const retailClient = new UserEventServiceClient(); + + const callWriteUserEvent = async () => { + // Construct request + const request = { + userEvent, + parent, + }; + + console.log('Write request: ', request); + + // Run request + const response = await retailClient.writeUserEvent(request); + console.log(`Operation result: ${JSON.stringify(response[0])}`); + }; + + // Create new user event + console.log('Start to write user event'); + await callWriteUserEvent(); + console.log('Write operation finished'); + + // Purge user events by visitor id + await utils.purgeUserEvents(parent, visitorId); + // [END retail_write_user_event] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(); diff --git a/retail/interactive-tutorials/test/purge-user-events.test.js b/retail/interactive-tutorials/test/purge-user-events.test.js new file mode 100644 index 0000000000..71ba59fea4 --- /dev/null +++ b/retail/interactive-tutorials/test/purge-user-events.test.js @@ -0,0 +1,50 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it} = require('mocha'); +const {assert} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cwd = path.join(__dirname, '..'); + +describe('Purge user events', () => { + const eventType = 'detail-page-view'; + const visitorId = 'test_visitor_id'; + let stdout; + + before(async () => { + stdout = execSync( + 'node interactive-tutorials/events/purge-user-events.js', + {cwd} + ); + }); + + it('should check that new event already created', () => { + const regex = new RegExp( + `Created event ${eventType} with visitor id ${visitorId}`, + 'g' + ); + assert.match(stdout, regex); + }); + + it('should check that purge operation started', () => { + const regex = new RegExp('Purge operation in progress', 'g'); + assert.match(stdout, regex); + }); +}); diff --git a/retail/interactive-tutorials/test/rejoin-user-events.test.js b/retail/interactive-tutorials/test/rejoin-user-events.test.js new file mode 100644 index 0000000000..2a8e701836 --- /dev/null +++ b/retail/interactive-tutorials/test/rejoin-user-events.test.js @@ -0,0 +1,55 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it} = require('mocha'); +const {assert} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cwd = path.join(__dirname, '..'); + +describe('Rejoin user events', () => { + const eventType = 'detail-page-view'; + const visitorId = 'test_visitor_id'; + let stdout; + + before(async () => { + stdout = execSync( + 'node interactive-tutorials/events/rejoin-user-events.js', + {cwd} + ); + }); + + it('should check that new event already created', () => { + const regex = new RegExp( + `Created event ${eventType} with visitor id ${visitorId}`, + 'g' + ); + assert.match(stdout, regex); + }); + + it('should check that rejoin operation started', () => { + const regex = new RegExp('Rejoin operation in progress', 'g'); + assert.match(stdout, regex); + }); + + it('should check that purge operation started', () => { + const regex = new RegExp('Purge operation in progress', 'g'); + assert.match(stdout, regex); + }); +}); diff --git a/retail/interactive-tutorials/test/write-user-event.test.js b/retail/interactive-tutorials/test/write-user-event.test.js new file mode 100644 index 0000000000..ac982ba75e --- /dev/null +++ b/retail/interactive-tutorials/test/write-user-event.test.js @@ -0,0 +1,63 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it} = require('mocha'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cwd = path.join(__dirname, '..'); + +describe('Write user event', () => { + const eventType = 'home-page-view'; + const visitorId = 'test_visitor_id'; + let stdout; + + before(async () => { + stdout = execSync('node interactive-tutorials/events/write-user-event.js', { + cwd, + }); + }); + + it('should check that write operation started', () => { + const regex = new RegExp('Start to write user event', 'g'); + assert.match(stdout, regex); + }); + + it('should check that new event created correctly', () => { + const regex = new RegExp('Operation result: .*\\n', 'g'); + assert.match(stdout, regex); + const string = stdout + .match(regex) + .toString() + .replace('Operation result: ', ''); + const event = JSON.parse(string); + expect(event.eventType).to.be.equal(eventType); + expect(event.visitorId).to.be.equal(visitorId); + }); + + it('should check that write operation finished', () => { + const regex = new RegExp('Write operation finished', 'g'); + assert.match(stdout, regex); + }); + + it('should check that purge operation started', () => { + const regex = new RegExp('Purge operation in progress', 'g'); + assert.match(stdout, regex); + }); +}); From c70edc65bcf0d9a02b67d15cfe43318459e2685a Mon Sep 17 00:00:00 2001 From: nmykhailets <94851929+nmykhailets@users.noreply.github.com> Date: Tue, 8 Mar 2022 17:54:57 +0200 Subject: [PATCH 22/54] chore(samples): interactive tutorials code samples for CRUD products (#149) --- .../product/add-fulfillment-places.js | 98 +++++++++++ .../product/create-product.js | 83 ++++++++++ .../product/crud-product.js | 155 ++++++++++++++++++ .../product/delete-product.js | 58 +++++++ .../product/get-product.js | 65 ++++++++ .../product/get-products-list.js | 56 +++++++ .../product/remove-fulfillment-places.js | 93 +++++++++++ .../product/set-inventory.js | 118 +++++++++++++ .../product/update-product.js | 91 ++++++++++ .../test/add-fulfillment.test.js | 95 +++++++++++ .../test/create-product.test.js | 63 +++++++ .../test/crud-product.test.js | 116 +++++++++++++ .../test/delete-product.test.js | 63 +++++++ .../test/get-product.test.js | 70 ++++++++ .../test/get-products-list.test.js | 43 +++++ .../test/remove-fulfillment.test.js | 98 +++++++++++ .../test/set-inventory.test.js | 151 +++++++++++++++++ .../test/update-product.test.js | 105 ++++++++++++ 18 files changed, 1621 insertions(+) create mode 100644 retail/interactive-tutorials/product/add-fulfillment-places.js create mode 100644 retail/interactive-tutorials/product/create-product.js create mode 100644 retail/interactive-tutorials/product/crud-product.js create mode 100644 retail/interactive-tutorials/product/delete-product.js create mode 100644 retail/interactive-tutorials/product/get-product.js create mode 100644 retail/interactive-tutorials/product/get-products-list.js create mode 100644 retail/interactive-tutorials/product/remove-fulfillment-places.js create mode 100644 retail/interactive-tutorials/product/set-inventory.js create mode 100644 retail/interactive-tutorials/product/update-product.js create mode 100644 retail/interactive-tutorials/test/add-fulfillment.test.js create mode 100644 retail/interactive-tutorials/test/create-product.test.js create mode 100644 retail/interactive-tutorials/test/crud-product.test.js create mode 100644 retail/interactive-tutorials/test/delete-product.test.js create mode 100644 retail/interactive-tutorials/test/get-product.test.js create mode 100644 retail/interactive-tutorials/test/get-products-list.test.js create mode 100644 retail/interactive-tutorials/test/remove-fulfillment.test.js create mode 100644 retail/interactive-tutorials/test/set-inventory.test.js create mode 100644 retail/interactive-tutorials/test/update-product.test.js diff --git a/retail/interactive-tutorials/product/add-fulfillment-places.js b/retail/interactive-tutorials/product/add-fulfillment-places.js new file mode 100644 index 0000000000..9612d1c829 --- /dev/null +++ b/retail/interactive-tutorials/product/add-fulfillment-places.js @@ -0,0 +1,98 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(generatedProductId) { + // [START retail_add_remove_fulfillment_places] + + // Imports the Google Cloud client library. + const {ProductServiceClient} = require('@google-cloud/retail').v2; + const utils = require('../setup/setup-cleanup'); + + const projectNumber = process.env['GCLOUD_PROJECT']; + + // Create product + const createdProduct = await utils.createProduct( + projectNumber, + generatedProductId + ); + + // Full resource name of Product + const product = createdProduct.name; + + // The fulfillment type, including commonly used types (such as + // pickup in store and same day delivery), and custom types. + const type = 'same-day-delivery'; + + // The IDs for this type, such as the store IDs for "pickup-in-store" or the region IDs for + // "same-day-delivery" to be added for this type. + const placeIds = ['store1', 'store2', 'store3']; + + // The time when the fulfillment updates are issued, used to prevent + // out-of-order updates on fulfillment information. + const addTime = { + seconds: Math.round(Date.now() / 1000), + }; + + //If set to true, and the product is not found, the fulfillment information will still be processed and retained for + // at most 1 day and processed once the product is created + const allowMissing = true; + + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const calladdFulfillmentPlaces = async () => { + // Construct request + const request = { + product, + type, + placeIds, + addTime, + allowMissing, + }; + + console.log('Add fulfillment request:', request); + + // Run request + await retailClient.addFulfillmentPlaces(request); + + console.log('Waiting to complete add operation..'); + }; + + // Add fulfillment places with current time + console.log('Start add fulfillment'); + await calladdFulfillmentPlaces(); + await utils.delay(180000); + + //Get product + const response = await utils.getProduct(product); + console.log( + 'Updated product with current time: ', + JSON.stringify(response[0]) + ); + console.log('Add fulfillment finished'); + + // Delete product + await utils.deleteProduct(product); + console.log(`Product ${createdProduct.id} deleted`); + // [END retail_add_remove_fulfillment_places] +} + +process.on('unhandledRejection', err => { + console.error('ERROR', err.message); + process.exitCode = 1; +}); + +main(...process.argv.slice(2)); diff --git a/retail/interactive-tutorials/product/create-product.js b/retail/interactive-tutorials/product/create-product.js new file mode 100644 index 0000000000..a385af3c18 --- /dev/null +++ b/retail/interactive-tutorials/product/create-product.js @@ -0,0 +1,83 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(generatedProductId) { + // [START retail_create_product] + + // Imports the Google Cloud client library. + const {ProductServiceClient} = require('@google-cloud/retail').v2; + const utils = require('../setup/setup-cleanup'); + + const projectNumber = process.env['GCLOUD_PROJECT']; + + // The parent catalog resource name + const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch`; + + // The ID to use for the product + const productId = generatedProductId + ? generatedProductId + : Math.random().toString(36).slice(2).toUpperCase(); + + // The product to create. + const product = { + title: 'Nest Mini', + type: 'PRIMARY', + categories: ['Speakers and displays'], + brands: ['Google'], + priceInfo: { + price: 30.0, + originalPrice: 35.5, + currencyCode: 'USD', + }, + availability: 'IN_STOCK', + }; + + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const callCreateProduct = async () => { + // Construct request + const request = { + parent, + product, + productId, + }; + console.log('Create product request:', request); + + // Run request + const response = await retailClient.createProduct(request); + console.log('Created product:', response); + return response[0]; + }; + + // Create product + console.log('Start to create the product'); + const createdProduct = await callCreateProduct(); + console.log(`Product ${createdProduct.id} creation ended`); + + // Delete product + await utils.deleteProduct(createdProduct.name); + console.log(`Product ${createdProduct.id} deleted`); + + // [END retail_create_product] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(...process.argv.slice(2)); diff --git a/retail/interactive-tutorials/product/crud-product.js b/retail/interactive-tutorials/product/crud-product.js new file mode 100644 index 0000000000..a4c3ea1ee8 --- /dev/null +++ b/retail/interactive-tutorials/product/crud-product.js @@ -0,0 +1,155 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(generatedProductId) { + // [START retail_crud_product] + + // Imports the Google Cloud client library. + const {ProductServiceClient} = require('@google-cloud/retail').v2; + + const projectNumber = process.env['GCLOUD_PROJECT']; + + // The parent catalog resource name + const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch`; + + // The ID to use for the product + const productId = generatedProductId + ? generatedProductId + : Math.random().toString(36).slice(2).toUpperCase(); + + // Full resource name of Product + const name = `${parent}/products/${productId}`; + + // The product to create. + const productForCreate = { + title: 'Nest Mini', + type: 'PRIMARY', + categories: ['Speakers and displays'], + brands: ['Google'], + priceInfo: { + price: 30.0, + originalPrice: 35.5, + currencyCode: 'USD', + }, + availability: 'IN_STOCK', + }; + + // The product to update. + const productForUpdate = { + productId, + name, + title: 'Updated Nest Mini', + type: 'PRIMARY', + categories: ['Updated Speakers and displays'], + brands: ['Updated Google'], + priceInfo: { + price: 20.0, + originalPrice: 25.5, + currencyCode: 'EUR', + }, + availability: 'OUT_OF_STOCK', + }; + + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const callCreateProduct = async () => { + // Construct request + const request = { + parent, + product: productForCreate, + productId, + }; + console.log('Create product request:', request); + + // Run request + const response = await retailClient.createProduct(request); + console.log('Created product:', response); + return response[0]; + }; + + const callGetProduct = async () => { + // Construct request + const request = { + name, + }; + console.log('Get product request:', request); + + // Run request + const response = await retailClient.getProduct(request); + console.log('Get product response:', response); + + return response[0]; + }; + + const callUpdateProduct = async () => { + // Construct request + const request = { + product: productForUpdate, + }; + console.log('Update product request:', request); + + // Run request + const response = await retailClient.updateProduct(request); + console.log('Updated product:', response); + + return response[0]; + }; + + const callDeleteProduct = async () => { + // Construct request + const request = { + name, + }; + console.log('Delete product request:', request); + + // Run request + await retailClient.deleteProduct(request); + }; + + console.log('Start CRUD product'); + // Create product + console.log('Start to create the product'); + const createdProduct = await callCreateProduct(); + console.log(`Product ${createdProduct.id} creation finished`); + + // Get product + console.log('Start product get operation'); + const foundProduct = await callGetProduct(); + console.log(`Product ${foundProduct.id} get operation finished`); + + // Update product + console.log('Start product update'); + const updatedProduct = await callUpdateProduct(); + console.log( + `Product ${updatedProduct.id} update finished: `, + JSON.stringify(updatedProduct) + ); + + // Delete product + console.log('Start deleting the product'); + await callDeleteProduct(); + console.log(`Product ${createdProduct.id} deleted`); + console.log('CRUD product finished'); + // [END retail_crud_product] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(...process.argv.slice(2)); diff --git a/retail/interactive-tutorials/product/delete-product.js b/retail/interactive-tutorials/product/delete-product.js new file mode 100644 index 0000000000..daee6c17ef --- /dev/null +++ b/retail/interactive-tutorials/product/delete-product.js @@ -0,0 +1,58 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(generatedProductId) { + // [START retail_delete_product] + + // Imports the Google Cloud client library. + const {ProductServiceClient} = require('@google-cloud/retail').v2; + const utils = require('../setup/setup-cleanup'); + + const projectNumber = process.env['GCLOUD_PROJECT']; + + // Create product + const product = await utils.createProduct(projectNumber, generatedProductId); + + // Full resource name of Product + const name = product.name; + + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const callDeleteProduct = async () => { + // Construct request + const request = { + name, + }; + console.log('Delete product request:', request); + + // Run request + await retailClient.deleteProduct(request); + }; + + // Delete product + console.log('Start deleting the product'); + await callDeleteProduct(); + console.log(`Product ${product.id} deleted`); + // [END retail_delete_product] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(...process.argv.slice(2)); diff --git a/retail/interactive-tutorials/product/get-product.js b/retail/interactive-tutorials/product/get-product.js new file mode 100644 index 0000000000..ef015d8ece --- /dev/null +++ b/retail/interactive-tutorials/product/get-product.js @@ -0,0 +1,65 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(generatedProductId) { + // [START retail_get_product] + + // Imports the Google Cloud client library. + const {ProductServiceClient} = require('@google-cloud/retail').v2; + const utils = require('../setup/setup-cleanup'); + + const projectNumber = process.env['GCLOUD_PROJECT']; + + // Create product + const product = await utils.createProduct(projectNumber, generatedProductId); + + // Full resource name of Product + const name = product.name; + + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const callGetProduct = async () => { + // Construct request + const request = { + name, + }; + console.log('Get product request:', request); + + // Run request + const response = await retailClient.getProduct(request); + console.log('Get product response:', response); + + return response[0]; + }; + + // Get product + console.log('Start product get operation'); + const foundProduct = await callGetProduct(); + console.log(`Product ${foundProduct.id} get operation finished`); + + // Delete product + await utils.deleteProduct(name); + console.log(`Product ${foundProduct.id} deleted`); + // [END retail_get_product] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(...process.argv.slice(2)); diff --git a/retail/interactive-tutorials/product/get-products-list.js b/retail/interactive-tutorials/product/get-products-list.js new file mode 100644 index 0000000000..cffc146512 --- /dev/null +++ b/retail/interactive-tutorials/product/get-products-list.js @@ -0,0 +1,56 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main() { + // [START retail_get_products_list] + + // Imports the Google Cloud client library. + const {ProductServiceClient} = require('@google-cloud/retail').v2; + + const projectNumber = process.env['GCLOUD_PROJECT']; + + // Placement + const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch`; + + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + async function callListProducts() { + console.log('Start get products list'); + // Construct request + const request = { + parent, + }; + console.log('List of products request:', request); + + // Run request + const iterable = await retailClient.listProductsAsync(request); + for await (const response of iterable) { + console.log(response); + } + console.log('Get products list finished'); + } + + callListProducts(); + // [END retail_get_products_list] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(); diff --git a/retail/interactive-tutorials/product/remove-fulfillment-places.js b/retail/interactive-tutorials/product/remove-fulfillment-places.js new file mode 100644 index 0000000000..3e5ce00df4 --- /dev/null +++ b/retail/interactive-tutorials/product/remove-fulfillment-places.js @@ -0,0 +1,93 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(generatedProductId) { + // [START retail_remove_fulfillment_places] + + // Imports the Google Cloud client library. + const {ProductServiceClient} = require('@google-cloud/retail').v2; + const utils = require('../setup/setup-cleanup'); + + const projectNumber = process.env['GCLOUD_PROJECT']; + + // Create product + const createdProduct = await utils.createProduct( + projectNumber, + generatedProductId, + true + ); + + // Full resource name of Product + const product = createdProduct.name; + + // The fulfillment type, including commonly used types (such as + // pickup in store and same day delivery), and custom types. + const type = 'same-day-delivery'; + + // The IDs for this type, such as the store IDs for "pickup-in-store" or the region IDs for + // "same-day-delivery" to be added for this type. + const placeIds = ['store1']; + + // The time when the fulfillment updates are issued, used to prevent + // out-of-order updates on fulfillment information. + const removeTime = { + seconds: Math.round(Date.now() / 1000), + }; + + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const callRemoveFulfillmentPlaces = async () => { + // Construct request + const request = { + product, + type, + placeIds, + removeTime, + }; + + console.log('Remove fulfillment request:', request); + // Run request + await retailClient.removeFulfillmentPlaces(request); + + console.log('Waiting to complete remove operation..'); + }; + + // Remove fulfillment places with current time + console.log('Start remove fulfillment'); + await callRemoveFulfillmentPlaces(); + await utils.delay(180000); + + //Get product + const response = await utils.getProduct(product); + console.log( + 'Updated product with current time: ', + JSON.stringify(response[0]) + ); + console.log('Remove fulfillment finished'); + + // Delete product + await utils.deleteProduct(product); + console.log(`Product ${createdProduct.id} deleted`); + // [END retail_remove_fulfillment_places] +} + +process.on('unhandledRejection', err => { + console.error('ERROR', err.message); + process.exitCode = 1; +}); + +main(...process.argv.slice(2)); diff --git a/retail/interactive-tutorials/product/set-inventory.js b/retail/interactive-tutorials/product/set-inventory.js new file mode 100644 index 0000000000..6d8586c592 --- /dev/null +++ b/retail/interactive-tutorials/product/set-inventory.js @@ -0,0 +1,118 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(generatedProductId) { + // [START retail_set_inventory] + + // Imports the Google Cloud client library. + const {ProductServiceClient} = require('@google-cloud/retail').v2; + const utils = require('../setup/setup-cleanup'); + + const projectNumber = process.env['GCLOUD_PROJECT']; + + // Create product + const createdProduct = await utils.createProduct( + projectNumber, + generatedProductId + ); + + // The inventory information to update + const product = { + id: createdProduct.id, + name: createdProduct.name, + priceInfo: { + price: 15.0, + originalPrice: 20.0, + cost: 8.0, + currencyCode: 'USD', + }, + fulfillmentInfo: [ + { + type: 'same-day-delivery', + placeIds: ['store3', 'store4'], + }, + ], + availableQuantity: { + value: 2, + }, + availability: 'IN_STOCK', + }; + + // The time when the request is issued, used to prevent + // out-of-order updates on inventory fields with the last update time recorded. + let setTime = { + seconds: Math.round(Date.now() / 1000), + }; + + // If set to true, and the product with name is not found, the + // inventory update will still be processed and retained for at most 1 day until the product is created + const allowMissing = true; + + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const callSetInventory = async () => { + // Construct request + const request = { + inventory: product, + setTime, + allowMissing, + }; + console.log('Set inventory request:', request); + + // Run request + await retailClient.setInventory(request); + console.log('Waiting to complete set inventory operation..'); + }; + + // Set inventory with current time + console.log('Start set inventory'); + await callSetInventory(); + await utils.delay(180000); + + // Get product + let changedProduct = await utils.getProduct(createdProduct.name); + console.log( + `Updated product ${createdProduct.id} with current time: `, + JSON.stringify(changedProduct[0]) + ); + + // Set inventory with outdated time + product.priceInfo.price = 20.0; + setTime = {seconds: Math.round(Date.now() / 1000) - 86400}; + await callSetInventory(); + await utils.delay(180000); + + // Get product + changedProduct = await utils.getProduct(createdProduct.name); + console.log( + `Updated product ${createdProduct.id} with outdated time: `, + JSON.stringify(changedProduct[0]) + ); + console.log('Set inventory finished'); + + // Delete product + await utils.deleteProduct(createdProduct.name); + console.log(`Product ${createdProduct.id} deleted`); + // [END retail_set_inventory] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(...process.argv.slice(2)); diff --git a/retail/interactive-tutorials/product/update-product.js b/retail/interactive-tutorials/product/update-product.js new file mode 100644 index 0000000000..30a2da2a1c --- /dev/null +++ b/retail/interactive-tutorials/product/update-product.js @@ -0,0 +1,91 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(generatedProductId) { + // [START retail_update_product] + + // Imports the Google Cloud client library. + const {ProductServiceClient} = require('@google-cloud/retail').v2; + const utils = require('../setup/setup-cleanup'); + + const projectNumber = process.env['GCLOUD_PROJECT']; + + // Create product + const createdProduct = await utils.createProduct( + projectNumber, + generatedProductId + ); + + // The ID to use for the product + const productId = createdProduct.id; + + // The parent catalog resource name + const name = createdProduct.name; + + // The product to update. + const product = { + productId, + name, + title: 'Updated Nest Mini', + type: 'PRIMARY', + categories: ['Updated Speakers and displays'], + brands: ['Updated Google'], + priceInfo: { + price: 20.0, + originalPrice: 25.5, + currencyCode: 'EUR', + }, + availability: 'OUT_OF_STOCK', + }; + + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const callUpdateProduct = async () => { + // Construct request + const request = { + product, + }; + console.log('Update product request:', request); + + // Run request + const response = await retailClient.updateProduct(request); + console.log('Updated product:', response); + + return response[0]; + }; + + // Update product + console.log('Start product update'); + const updatedProduct = await callUpdateProduct(); + console.log( + `Product ${updatedProduct.id} update finished: `, + JSON.stringify(updatedProduct) + ); + + // Delete product + await utils.deleteProduct(updatedProduct.name); + console.log(`Product ${updatedProduct.id} deleted`); + + // [END retail_update_product] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(...process.argv.slice(2)); diff --git a/retail/interactive-tutorials/test/add-fulfillment.test.js b/retail/interactive-tutorials/test/add-fulfillment.test.js new file mode 100644 index 0000000000..080c922d8f --- /dev/null +++ b/retail/interactive-tutorials/test/add-fulfillment.test.js @@ -0,0 +1,95 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it, after} = require('mocha'); +const {ProductServiceClient} = require('@google-cloud/retail'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cwd = path.join(__dirname, '..'); + +describe('Add fulfillment', () => { + const retailClient = new ProductServiceClient(); + const productId = Math.random().toString(36).slice(2).toUpperCase(); + const projectNumber = process.env['GCLOUD_PROJECT']; + const name = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; + + let stdout; + + before(async () => { + stdout = execSync( + `node interactive-tutorials/product/add-fulfillment-places.js ${productId}`, + { + cwd, + } + ); + }); + + it('should check that product created', () => { + const regex = new RegExp(`Product ${productId} created`, 'g'); + assert.match(stdout, regex); + }); + + it('should check that add fulfillment started', () => { + assert.match(stdout, /Start add fulfillment/); + }); + + it('should check that add fulfillment finished', () => { + assert.match(stdout, /Add fulfillment finished/); + }); + + it('should check that product updated correctly', async () => { + const regex = new RegExp('Updated product with current time: .*\\n', 'g'); + assert.match(stdout, regex); + const string = stdout + .match(regex) + .toString() + .replace('Updated product with current time: ', ''); + const updatedProduct = JSON.parse(string); + + expect(updatedProduct).to.be.an('object'); + expect(updatedProduct.fulfillmentInfo).to.be.an('array'); + expect( + updatedProduct.fulfillmentInfo.length, + 'Fulfillment array is empty' + ).to.equal(1); + + const item = updatedProduct.fulfillmentInfo[0]; + expect(item).to.be.an('object'); + expect(item).to.have.all.keys('type', 'placeIds'); + expect(item.type).to.equal('same-day-delivery'); + expect(item.placeIds) + .to.be.an('array') + .that.includes('store1', 'store2', 'store3'); + }); + + it('should check that product deleted', async () => { + const regex = new RegExp(`Product ${productId} deleted`, 'g'); + assert.match(stdout, regex); + }); + + after(async () => { + try { + const product = await retailClient.getProduct({name: name}); + expect(product, 'The product not deleted').to.be.undefined; + } catch (err) { + expect(err, 'Bad error code').to.include({code: 5}); + } + }); +}); diff --git a/retail/interactive-tutorials/test/create-product.test.js b/retail/interactive-tutorials/test/create-product.test.js new file mode 100644 index 0000000000..060cdc07af --- /dev/null +++ b/retail/interactive-tutorials/test/create-product.test.js @@ -0,0 +1,63 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it, after} = require('mocha'); +const {ProductServiceClient} = require('@google-cloud/retail'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cwd = path.join(__dirname, '..'); + +describe('Create product', () => { + const retailClient = new ProductServiceClient(); + const productId = Math.random().toString(36).slice(2).toUpperCase(); + const projectNumber = process.env['GCLOUD_PROJECT']; + const name = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; + let stdout; + + before(async () => { + stdout = execSync( + `node interactive-tutorials/product/create-product.js ${productId}`, + {cwd} + ); + }); + + it('should check that product creation started', () => { + assert.match(stdout, /Start to create the product/); + }); + + it('should check that product created', () => { + const regex = new RegExp(`Product ${productId} creation ended`, 'g'); + assert.match(stdout, regex); + }); + + it('should check that product deleted', async () => { + const regex = new RegExp(`Product ${productId} deleted`, 'g'); + assert.match(stdout, regex); + }); + + after(async () => { + try { + const product = await retailClient.getProduct({name: name}); + expect(product, 'The product not deleted').to.be.undefined; + } catch (err) { + expect(err, 'Bad error code').to.include({code: 5}); + } + }); +}); diff --git a/retail/interactive-tutorials/test/crud-product.test.js b/retail/interactive-tutorials/test/crud-product.test.js new file mode 100644 index 0000000000..b7f83bf8ae --- /dev/null +++ b/retail/interactive-tutorials/test/crud-product.test.js @@ -0,0 +1,116 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it, after} = require('mocha'); +const {ProductServiceClient} = require('@google-cloud/retail'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); +const cwd = path.join(__dirname, '..'); + +describe('CRUD product', () => { + const retailClient = new ProductServiceClient(); + const productId = Math.random().toString(36).slice(2).toUpperCase(); + const projectNumber = process.env['GCLOUD_PROJECT']; + const name = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; + const product = { + productId, + name, + title: 'Updated Nest Mini', + type: 'PRIMARY', + categories: ['Updated Speakers and displays'], + brands: ['Updated Google'], + priceInfo: { + price: 20.0, + originalPrice: 25.5, + currencyCode: 'EUR', + }, + availability: 'OUT_OF_STOCK', + }; + let stdout; + + before(async () => { + stdout = execSync( + `node interactive-tutorials/product/crud-product.js ${productId}`, + {cwd} + ); + }); + + it('should check that product CRUD operation started', () => { + assert.match(stdout, /Start CRUD product/); + }); + + it('should check that product created', () => { + const regex = new RegExp(`Product ${productId} creation finished`, 'g'); + assert.match(stdout, regex); + }); + + it('should check that product get operation finished', () => { + const regex = new RegExp( + `Product ${productId} get operation finished`, + 'g' + ); + assert.match(stdout, regex); + }); + + it('should check that product update finished', async () => { + const regex = new RegExp( + `Product ${productId} update finished: .*\\n`, + 'g' + ); + assert.match(stdout, regex); + const string = stdout + .match(regex) + .toString() + .replace(`Product ${productId} update finished: `, ''); + const updatedProduct = JSON.parse(string); + expect(updatedProduct).to.be.an('object'); + expect(updatedProduct).to.have.deep.property( + 'title', + product.title, + 'type', + product.type, + 'categories', + product.categories, + 'brands', + product.brands, + 'priceInfo', + product.priceInfo, + 'availability', + product.availability + ); + }); + + it('should check that product deleted', async () => { + const regex = new RegExp(`Product ${productId} deleted`, 'g'); + assert.match(stdout, regex); + }); + + it('should check that product CRUD operation finished', () => { + assert.match(stdout, /CRUD product finished/); + }); + + after(async () => { + try { + const product = await retailClient.getProduct({name: name}); + expect(product, 'The product not deleted').to.be.undefined; + } catch (err) { + expect(err, 'Bad error code').to.include({code: 5}); + } + }); +}); diff --git a/retail/interactive-tutorials/test/delete-product.test.js b/retail/interactive-tutorials/test/delete-product.test.js new file mode 100644 index 0000000000..18b8d9dbda --- /dev/null +++ b/retail/interactive-tutorials/test/delete-product.test.js @@ -0,0 +1,63 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it, after} = require('mocha'); +const {ProductServiceClient} = require('@google-cloud/retail'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cwd = path.join(__dirname, '..'); + +describe('Delete product', () => { + const retailClient = new ProductServiceClient(); + const productId = Math.random().toString(36).slice(2).toUpperCase(); + const projectNumber = process.env['GCLOUD_PROJECT']; + const name = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; + let stdout; + + before(async () => { + stdout = execSync( + `node interactive-tutorials/product/delete-product.js ${productId}`, + {cwd} + ); + }); + + it('should check that product created', () => { + const regex = new RegExp(`Product ${productId} created`, 'g'); + assert.match(stdout, regex); + }); + + it('should check that product deletion started', () => { + assert.match(stdout, /Start deleting the product/); + }); + + it('should check that product deleted', async () => { + const regex = new RegExp(`Product ${productId} deleted`, 'g'); + assert.match(stdout, regex); + }); + + after(async () => { + try { + const product = await retailClient.getProduct({name: name}); + expect(product, 'The product not deleted').to.be.undefined; + } catch (err) { + expect(err, 'Bad error code').to.include({code: 5}); + } + }); +}); diff --git a/retail/interactive-tutorials/test/get-product.test.js b/retail/interactive-tutorials/test/get-product.test.js new file mode 100644 index 0000000000..7898314b6c --- /dev/null +++ b/retail/interactive-tutorials/test/get-product.test.js @@ -0,0 +1,70 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it, after} = require('mocha'); +const {ProductServiceClient} = require('@google-cloud/retail'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); +const cwd = path.join(__dirname, '..'); + +describe('Get product', () => { + const retailClient = new ProductServiceClient(); + const productId = Math.random().toString(36).slice(2).toUpperCase(); + const projectNumber = process.env['GCLOUD_PROJECT']; + const name = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; + let stdout; + + before(async () => { + stdout = execSync( + `node interactive-tutorials/product/get-product.js ${productId}`, + {cwd} + ); + }); + + it('should check that product created', () => { + const regex = new RegExp(`Product ${productId} created`, 'g'); + assert.match(stdout, regex); + }); + + it('should check that get product started', () => { + assert.match(stdout, /Start product get operation/); + }); + + it('should check that get product finished', async () => { + const regex = new RegExp( + `Product ${productId} get operation finished`, + 'g' + ); + assert.match(stdout, regex); + }); + + it('should check that product deleted', async () => { + const regex = new RegExp(`Product ${productId} deleted`, 'g'); + assert.match(stdout, regex); + }); + + after(async () => { + try { + const product = await retailClient.getProduct({name: name}); + expect(product, 'The product not deleted').to.be.undefined; + } catch (err) { + expect(err, 'Bad error code').to.include({code: 5}); + } + }); +}); diff --git a/retail/interactive-tutorials/test/get-products-list.test.js b/retail/interactive-tutorials/test/get-products-list.test.js new file mode 100644 index 0000000000..d2a8350322 --- /dev/null +++ b/retail/interactive-tutorials/test/get-products-list.test.js @@ -0,0 +1,43 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it} = require('mocha'); +const {assert} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cwd = path.join(__dirname, '..'); + +describe('Get products list', () => { + let stdout; + + before(async () => { + stdout = execSync( + 'node interactive-tutorials/product/get-products-list.js', + {cwd} + ); + }); + + it('should check that get products list started', () => { + assert.match(stdout, /Start get products list/); + }); + + it('should check that get product list finished', async () => { + assert.match(stdout, /Get products list finished/); + }); +}); diff --git a/retail/interactive-tutorials/test/remove-fulfillment.test.js b/retail/interactive-tutorials/test/remove-fulfillment.test.js new file mode 100644 index 0000000000..b3d7773344 --- /dev/null +++ b/retail/interactive-tutorials/test/remove-fulfillment.test.js @@ -0,0 +1,98 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it, after} = require('mocha'); +const {ProductServiceClient} = require('@google-cloud/retail'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cwd = path.join(__dirname, '..'); + +describe('Remove fulfillment', () => { + const retailClient = new ProductServiceClient(); + const productId = Math.random().toString(36).slice(2).toUpperCase(); + const projectNumber = process.env['GCLOUD_PROJECT']; + const name = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; + + let stdout; + + before(async () => { + stdout = execSync( + `node interactive-tutorials/product/remove-fulfillment-places.js ${productId}`, + {cwd} + ); + }); + + it('should check that product created', () => { + const regex = new RegExp(`Product ${productId} created`, 'g'); + assert.match(stdout, regex); + }); + + it('should check that remove fulfillment started', () => { + assert.match(stdout, /Start remove fulfillment/); + }); + + it('should check that add fulfillment finished', () => { + assert.match(stdout, /Remove fulfillment finished/); + }); + + const checkUpdatedProduct = updatedProduct => { + expect(updatedProduct).to.be.an('object'); + expect(updatedProduct.fulfillmentInfo).to.be.an('array'); + expect( + updatedProduct.fulfillmentInfo.length, + 'Fulfillment array is empty' + ).to.equal(1); + + const item = updatedProduct.fulfillmentInfo[0]; + expect(item).to.be.an('object'); + expect(item).to.have.all.keys('type', 'placeIds'); + expect(item.type).to.equal('same-day-delivery'); + expect(item.placeIds) + .to.be.an('array') + .that.includes('store3', 'store2') + .but.not.include('store1'); + }; + + it('should check that fulfillment removed correctly', async () => { + const regex = new RegExp('Updated product with current time: .*\\n', 'g'); + assert.match(stdout, regex); + const string = stdout + .match(regex) + .toString() + .replace('Updated product with current time: ', ''); + const updatedProduct = JSON.parse(string); + + checkUpdatedProduct(updatedProduct); + }); + + it('should check that product deleted', async () => { + const regex = new RegExp(`Product ${productId} deleted`, 'g'); + assert.match(stdout, regex); + }); + + after(async () => { + try { + const product = await retailClient.getProduct({name: name}); + expect(product, 'The product not deleted').to.be.undefined; + } catch (err) { + expect(err, 'Bad error code').to.include({code: 5}); + } + }); +}); diff --git a/retail/interactive-tutorials/test/set-inventory.test.js b/retail/interactive-tutorials/test/set-inventory.test.js new file mode 100644 index 0000000000..180051166b --- /dev/null +++ b/retail/interactive-tutorials/test/set-inventory.test.js @@ -0,0 +1,151 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it, after} = require('mocha'); +const {ProductServiceClient} = require('@google-cloud/retail'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cwd = path.join(__dirname, '..'); + +describe('Set inventory', () => { + const retailClient = new ProductServiceClient(); + const productId = Math.random().toString(36).slice(2).toUpperCase(); + const projectNumber = process.env['GCLOUD_PROJECT']; + const name = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; + const product = { + priceInfo: { + price: 15.0, + originalPrice: 20.0, + cost: 8.0, + currencyCode: 'USD', + }, + fulfillmentInfo: [ + { + type: 'same-day-delivery', + placeIds: ['store3', 'store4'], + }, + ], + availableQuantity: { + value: 2, + }, + availability: 'IN_STOCK', + }; + let stdout; + + before(async () => { + stdout = execSync( + `node interactive-tutorials/product/set-inventory.js ${productId}`, + {cwd} + ); + }); + + it('should check that product created', () => { + const regex = new RegExp(`Product ${productId} created`, 'g'); + assert.match(stdout, regex); + }); + + it('should check that set inventory started', () => { + assert.match(stdout, /Start set inventory/); + }); + + it('should check that set inventory finished', () => { + assert.match(stdout, /Set inventory finished/); + }); + + const checkUpdatedProduct = updatedProduct => { + expect(updatedProduct).to.be.an('object'); + assert.containsAllDeepKeys(updatedProduct, product); + expect(updatedProduct.priceInfo.price, 'Price not equal').to.equal(15.0); + expect( + updatedProduct.priceInfo.originalPrice, + 'Original price not equal' + ).to.equal(20.0); + expect(updatedProduct.priceInfo.cost, 'Cost not equal').to.equal(8.0); + expect( + updatedProduct.priceInfo.currencyCode, + 'Currency code not equal' + ).to.equal('USD'); + expect(updatedProduct.fulfillmentInfo).to.be.an('array'); + expect( + updatedProduct.fulfillmentInfo.length, + 'Fulfillment array is empty' + ).to.equal(1); + + const fulfillmentItem = updatedProduct.fulfillmentInfo[0]; + expect(fulfillmentItem).to.be.an('object'); + expect(fulfillmentItem).to.have.all.keys('type', 'placeIds'); + expect(fulfillmentItem.type).to.equal('same-day-delivery'); + expect(fulfillmentItem.placeIds) + .to.be.an('array') + .that.includes('store3', 'store4'); + + expect( + updatedProduct.availableQuantity, + 'Available quantity not equal' + ).to.deep.equal({value: 2}); + expect(updatedProduct.availability, 'Availability not equal').to.equal( + 'IN_STOCK' + ); + }; + + it('should check that product updated correctly', async () => { + const regex = new RegExp( + `Updated product ${productId} with current time: .*\\n`, + 'g' + ); + assert.match(stdout, regex); + const string = stdout + .match(regex) + .toString() + .replace(`Updated product ${productId} with current time: `, ''); + const updatedProduct = JSON.parse(string); + + checkUpdatedProduct(updatedProduct); + }); + + it('should check that product has not been updated with outdated time', async () => { + const regex = new RegExp( + `Updated product ${productId} with outdated time: .*\\n`, + 'g' + ); + assert.match(stdout, regex); + const string = stdout + .match(regex) + .toString() + .replace(`Updated product ${productId} with outdated time: `, ''); + const updatedProduct = JSON.parse(string); + + checkUpdatedProduct(updatedProduct); + }); + + it('should check that product deleted', async () => { + const regex = new RegExp(`Product ${productId} deleted`, 'g'); + assert.match(stdout, regex); + }); + + after(async () => { + try { + const product = await retailClient.getProduct({name: name}); + expect(product, 'The product not deleted').to.be.undefined; + } catch (err) { + expect(err, 'Bad error code').to.include({code: 5}); + } + }); +}); diff --git a/retail/interactive-tutorials/test/update-product.test.js b/retail/interactive-tutorials/test/update-product.test.js new file mode 100644 index 0000000000..0f50ff290a --- /dev/null +++ b/retail/interactive-tutorials/test/update-product.test.js @@ -0,0 +1,105 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it, after} = require('mocha'); +const {ProductServiceClient} = require('@google-cloud/retail'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cwd = path.join(__dirname, '..'); + +describe('Update product', () => { + const retailClient = new ProductServiceClient(); + const productId = Math.random().toString(36).slice(2).toUpperCase(); + const projectNumber = process.env['GCLOUD_PROJECT']; + const name = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; + const product = { + productId, + name, + title: 'Updated Nest Mini', + type: 'PRIMARY', + categories: ['Updated Speakers and displays'], + brands: ['Updated Google'], + priceInfo: { + price: 20.0, + originalPrice: 25.5, + currencyCode: 'EUR', + }, + availability: 'OUT_OF_STOCK', + }; + let stdout; + + before(async () => { + stdout = execSync( + `node interactive-tutorials/product/update-product.js ${productId}`, + {cwd} + ); + }); + + it('should check that product created', () => { + const regex = new RegExp(`Product ${productId} created`, 'g'); + assert.match(stdout, regex); + }); + + it('should check that product update started', () => { + assert.match(stdout, /Start product update/); + }); + + it('should check that product update finished', async () => { + const regex = new RegExp( + `Product ${productId} update finished: .*\\n`, + 'g' + ); + assert.match(stdout, regex); + const string = stdout + .match(regex) + .toString() + .replace(`Product ${productId} update finished: `, ''); + const updatedProduct = JSON.parse(string); + expect(updatedProduct).to.be.an('object'); + expect(updatedProduct).to.have.deep.property( + 'title', + product.title, + 'type', + product.type, + 'categories', + product.categories, + 'brands', + product.brands, + 'priceInfo', + product.priceInfo, + 'availability', + product.availability + ); + }); + + it('should check that product deleted', async () => { + const regex = new RegExp(`Product ${productId} deleted`, 'g'); + assert.match(stdout, regex); + }); + + after(async () => { + try { + const product = await retailClient.getProduct({name: name}); + expect(product, 'The product not deleted').to.be.undefined; + } catch (err) { + expect(err, 'Bad error code').to.include({code: 5}); + } + }); +}); From d34d524465989925bc84039617b29c5615b1e6fc Mon Sep 17 00:00:00 2001 From: nmykhailets <94851929+nmykhailets@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:54:59 +0200 Subject: [PATCH 23/54] chore(samples): interactive tutorials code samples for import user events (#152) * chore: import user events interactive samples --- .../events/import-user-events-big-query.js | 87 ++++++++++ .../events/import-user-events-gcs.js | 94 +++++++++++ .../events/import-user-events-inline.js | 92 +++++++++++ .../product/set-inventory.js | 4 +- .../setup/delete-events-bigquery-table.js | 31 ++++ .../setup/delete-events-gcs-bucket.js | 32 ++++ .../setup/events-create-bigquery-table.js | 45 ++++++ .../setup/events-create-gcs-bucket.js | 52 ++++++ .../setup/update-user-events-json.js | 51 ++++++ .../test/add-fulfillment.test.js | 95 ----------- .../test/import-user-events-big-query.test.js | 78 +++++++++ .../test/import-user-events-gcs.test.js | 78 +++++++++ .../test/import-user-events-inline.test.js | 67 ++++++++ .../test/remove-fulfillment.test.js | 98 ------------ .../search-with-query-expansion-spec.test.js | 1 - .../test/set-inventory.test.js | 151 ------------------ 16 files changed, 709 insertions(+), 347 deletions(-) create mode 100644 retail/interactive-tutorials/events/import-user-events-big-query.js create mode 100644 retail/interactive-tutorials/events/import-user-events-gcs.js create mode 100644 retail/interactive-tutorials/events/import-user-events-inline.js create mode 100644 retail/interactive-tutorials/setup/delete-events-bigquery-table.js create mode 100644 retail/interactive-tutorials/setup/delete-events-gcs-bucket.js create mode 100644 retail/interactive-tutorials/setup/events-create-bigquery-table.js create mode 100644 retail/interactive-tutorials/setup/events-create-gcs-bucket.js create mode 100644 retail/interactive-tutorials/setup/update-user-events-json.js delete mode 100644 retail/interactive-tutorials/test/add-fulfillment.test.js create mode 100644 retail/interactive-tutorials/test/import-user-events-big-query.test.js create mode 100644 retail/interactive-tutorials/test/import-user-events-gcs.test.js create mode 100644 retail/interactive-tutorials/test/import-user-events-inline.test.js delete mode 100644 retail/interactive-tutorials/test/remove-fulfillment.test.js delete mode 100644 retail/interactive-tutorials/test/set-inventory.test.js diff --git a/retail/interactive-tutorials/events/import-user-events-big-query.js b/retail/interactive-tutorials/events/import-user-events-big-query.js new file mode 100644 index 0000000000..2c49490084 --- /dev/null +++ b/retail/interactive-tutorials/events/import-user-events-big-query.js @@ -0,0 +1,87 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(datasetId) { + // [START retail_import_user_events_big_query] + + // Imports the Google Cloud client library. + const {UserEventServiceClient} = require('@google-cloud/retail').v2; + + // Instantiates a client. + const retailClient = new UserEventServiceClient(); + + const projectId = await retailClient.getProjectId(); + const dataSchema = 'user_event'; + const tableId = 'events'; // TO CHECK ERROR HANDLING USE THE TABLE OF INVALID USER EVENTS + + // Placement + const parent = `projects/${projectId}/locations/global/catalogs/default_catalog`; // TO CHECK ERROR HANDLING PASTE THE INVALID CATALOG NAME HERE + + // The desired input location of the data. + const inputConfig = { + bigQuerySource: { + projectId, + datasetId, + tableId, + dataSchema, + }, + }; + + const IResponseParams = { + IImportUserEventsResponse: 0, + IImportMetadata: 1, + IOperation: 2, + }; + + const callImportUserEvents = async () => { + // Construct request + const request = { + parent, + inputConfig, + }; + + console.log('Import request: ', request); + + // Run request + const [operation] = await retailClient.importUserEvents(request); + const response = await operation.promise(); + const result = response[IResponseParams.IImportMetadata]; + console.log( + `Number of successfully imported events: ${result.successCount | 0}` + ); + console.log( + `Number of failures during the importing: ${result.failureCount | 0}` + ); + console.log(`Operation result: ${JSON.stringify(response)}`); + }; + + console.log('Start events import'); + await callImportUserEvents(); + console.log('Events import finished'); + // [END retail_import_user_events_big_query] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main( + ...(() => { + const argv = process.argv.slice(2); + return argv.length ? argv : ['user_events']; + })() +); diff --git a/retail/interactive-tutorials/events/import-user-events-gcs.js b/retail/interactive-tutorials/events/import-user-events-gcs.js new file mode 100644 index 0000000000..e42a908acc --- /dev/null +++ b/retail/interactive-tutorials/events/import-user-events-gcs.js @@ -0,0 +1,94 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(bucketName) { + // [START retail_import_user_events_gcs] + + // Imports the Google Cloud client library. + const {UserEventServiceClient} = require('@google-cloud/retail').v2; + + // Instantiates a client. + const retailClient = new UserEventServiceClient(); + + const projectId = await retailClient.getProjectId(); + + //TODO(developer) set the environment variable value which will be used as the bucket name + const gcsBucket = `gs://${bucketName}`; + const gcsErrorsBucket = `gs://${bucketName}/error`; + const gcsEventsObject = 'user_events.json'; // TO CHECK ERROR HANDLING USE THE JSON WITH INVALID USER EVENTS + + // Placement + const parent = `projects/${projectId}/locations/global/catalogs/default_catalog`; // TO CHECK ERROR HANDLING PASTE THE INVALID CATALOG NAME HERE + + // The desired input location of the data. + const inputConfig = { + gcsSource: { + inputUris: [gcsBucket + '/' + gcsEventsObject], + dataSchema: 'user_event', + }, + }; + + // The desired location of errors incurred during the Import. + const errorsConfig = { + gcsPrefix: gcsErrorsBucket, + }; + + const IResponseParams = { + IImportUserEventsResponse: 0, + IImportMetadata: 1, + IOperation: 2, + }; + + const callImportUserEvents = async () => { + // Construct request + const request = { + parent, + inputConfig, + errorsConfig, + }; + + console.log('Import request: ', request); + + // Run request + const [operation] = await retailClient.importUserEvents(request); + const response = await operation.promise(); + const result = response[IResponseParams.IImportMetadata]; + console.log( + `Number of successfully imported events: ${result.successCount | 0}` + ); + console.log( + `Number of failures during the importing: ${result.failureCount | 0}` + ); + console.log(`Operation result: ${JSON.stringify(response)}`); + }; + + console.log('Start events import'); + await callImportUserEvents(); + console.log('Events import finished'); + // [END retail_import_user_events_gcs] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main( + ...(() => { + const argv = process.argv.slice(2); + return argv.length ? argv : [process.env['EVENTS_BUCKET_NAME']]; + })() +); diff --git a/retail/interactive-tutorials/events/import-user-events-inline.js b/retail/interactive-tutorials/events/import-user-events-inline.js new file mode 100644 index 0000000000..99a628e1a5 --- /dev/null +++ b/retail/interactive-tutorials/events/import-user-events-inline.js @@ -0,0 +1,92 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main() { + // [START retail_import_user_events_inline] + + // Imports the Google Cloud client library. + const {UserEventServiceClient} = require('@google-cloud/retail').v2; + + // Instantiates a client. + const retailClient = new UserEventServiceClient(); + + const projectId = await retailClient.getProjectId(); + + // Placement + const parent = `projects/${projectId}/locations/global/catalogs/default_catalog`; + + // Create events + const generateEvent = eventType => { + return { + eventType, + visitorId: 'visitor_' + Math.random().toString(36).slice(2), + eventTime: { + seconds: Math.round(Date.now() / 1000), + }, + }; + }; + + // The desired input location of the data. + const inputConfig = { + userEventInlineSource: { + userEvents: [ + generateEvent('home-page-view'), + generateEvent('home-page-view'), + generateEvent('home-page-view'), + ], + }, + }; + + const IResponseParams = { + IImportUserEventsResponse: 0, + IImportMetadata: 1, + IOperation: 2, + }; + + const callImportUserEvents = async () => { + // Construct request + const request = { + parent, + inputConfig, + }; + + console.log('Import request: ', request); + + // Run request + const [operation] = await retailClient.importUserEvents(request); + const response = await operation.promise(); + const result = response[IResponseParams.IImportMetadata]; + console.log( + `Number of successfully imported events: ${result.successCount | 0}` + ); + console.log( + `Number of failures during the importing: ${result.failureCount | 0}` + ); + console.log(`Operation result: ${JSON.stringify(response)}`); + }; + + console.log('Start events import'); + await callImportUserEvents(); + console.log('Events import finished'); + // [END retail_import_user_events_inline] +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(); diff --git a/retail/interactive-tutorials/product/set-inventory.js b/retail/interactive-tutorials/product/set-inventory.js index 6d8586c592..28f1ca5d13 100644 --- a/retail/interactive-tutorials/product/set-inventory.js +++ b/retail/interactive-tutorials/product/set-inventory.js @@ -81,7 +81,7 @@ async function main(generatedProductId) { // Set inventory with current time console.log('Start set inventory'); await callSetInventory(); - await utils.delay(180000); + await utils.delay(200000); // Get product let changedProduct = await utils.getProduct(createdProduct.name); @@ -94,7 +94,7 @@ async function main(generatedProductId) { product.priceInfo.price = 20.0; setTime = {seconds: Math.round(Date.now() / 1000) - 86400}; await callSetInventory(); - await utils.delay(180000); + await utils.delay(200000); // Get product changedProduct = await utils.getProduct(createdProduct.name); diff --git a/retail/interactive-tutorials/setup/delete-events-bigquery-table.js b/retail/interactive-tutorials/setup/delete-events-bigquery-table.js new file mode 100644 index 0000000000..37f5e11434 --- /dev/null +++ b/retail/interactive-tutorials/setup/delete-events-bigquery-table.js @@ -0,0 +1,31 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main() { + const utils = require('./setup-cleanup'); + + const dataset = 'user_events'; + + //Delete created bigquery dataset + await utils.deleteBqDataset(dataset); +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(); diff --git a/retail/interactive-tutorials/setup/delete-events-gcs-bucket.js b/retail/interactive-tutorials/setup/delete-events-gcs-bucket.js new file mode 100644 index 0000000000..2367677c8a --- /dev/null +++ b/retail/interactive-tutorials/setup/delete-events-gcs-bucket.js @@ -0,0 +1,32 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main() { + const utils = require('./setup-cleanup'); + + // The ID of your GCS bucket + const bucketName = process.env['EVENTS_BUCKET_NAME']; + + //Delete created bucket + await utils.deleteBucket(bucketName); +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(); diff --git a/retail/interactive-tutorials/setup/events-create-bigquery-table.js b/retail/interactive-tutorials/setup/events-create-bigquery-table.js new file mode 100644 index 0000000000..5ae2892026 --- /dev/null +++ b/retail/interactive-tutorials/setup/events-create-bigquery-table.js @@ -0,0 +1,45 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main() { + const utils = require('./setup-cleanup'); + + const dataset = 'user_events'; + const validTable = 'events'; + const invalidTable = 'events_some_invalid'; + const schema = 'resources/events_schema.json'; + const validSourceFile = 'resources/user_events.json'; + const invalidSourceFile = 'resources/user_events_some_invalid.json'; + + await utils.createBqDataset(dataset); + await utils.createBqTable(dataset, validTable, schema); + await utils.uploadDataToBqTable(dataset, validTable, validSourceFile, schema); + + await utils.createBqTable(dataset, invalidTable, schema); + await utils.uploadDataToBqTable( + dataset, + invalidTable, + invalidSourceFile, + schema + ); +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(); diff --git a/retail/interactive-tutorials/setup/events-create-gcs-bucket.js b/retail/interactive-tutorials/setup/events-create-gcs-bucket.js new file mode 100644 index 0000000000..04f614c07e --- /dev/null +++ b/retail/interactive-tutorials/setup/events-create-gcs-bucket.js @@ -0,0 +1,52 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(generatedBucketName) { + // Imports the Google Cloud client library. + const {UserEventServiceClient} = require('@google-cloud/retail').v2; + const utils = require('./setup-cleanup'); + + // Instantiates a client. + const retailClient = new UserEventServiceClient(); + const projectId = await retailClient.getProjectId(); + + // The ID of your GCS bucket + const bucketName = generatedBucketName + ? generatedBucketName + : `${projectId}_events_${Math.round(Date.now() / 1000)}`; + + //Creates the new bucket + await utils.createBucket(bucketName); + + //Upload files + await utils.uploadFile( + bucketName, + 'resources/user_events.json', + 'user_events.json' + ); + await utils.uploadFile( + bucketName, + 'resources/user_events_some_invalid.json', + 'user_events_some_invalid.json' + ); +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(...process.argv.slice(2)); diff --git a/retail/interactive-tutorials/setup/update-user-events-json.js b/retail/interactive-tutorials/setup/update-user-events-json.js new file mode 100644 index 0000000000..b5e5936624 --- /dev/null +++ b/retail/interactive-tutorials/setup/update-user-events-json.js @@ -0,0 +1,51 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const fs = require('fs'); + +async function main() { + const updateEventsTimestamp = filePath => { + const events = fs.readFileSync(filePath).toString().split('\n'); + const changedEvents = []; + + for (let i = 0; i < events.length - 1; ++i) { + const event = JSON.parse(`[${events[i]}]`)[0]; + const date = new Date(event.eventTime); + date.setDate(date.getDate() - 1); + event.eventTime = date.toISOString(); + changedEvents.push(JSON.stringify(event)); + } + + const stream = fs.createWriteStream(filePath); + stream.on('error', error => { + throw error; + }); + changedEvents.forEach(item => { + stream.write(item + '\n'); + }); + stream.close(); + }; + + updateEventsTimestamp('resources/user_events.json'); + updateEventsTimestamp('resources/user_events_some_invalid.json'); +} + +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); + +main(...process.argv.slice(2)); diff --git a/retail/interactive-tutorials/test/add-fulfillment.test.js b/retail/interactive-tutorials/test/add-fulfillment.test.js deleted file mode 100644 index 080c922d8f..0000000000 --- a/retail/interactive-tutorials/test/add-fulfillment.test.js +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2022 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -'use strict'; - -const path = require('path'); -const cp = require('child_process'); -const {before, describe, it, after} = require('mocha'); -const {ProductServiceClient} = require('@google-cloud/retail'); -const {assert, expect} = require('chai'); - -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const cwd = path.join(__dirname, '..'); - -describe('Add fulfillment', () => { - const retailClient = new ProductServiceClient(); - const productId = Math.random().toString(36).slice(2).toUpperCase(); - const projectNumber = process.env['GCLOUD_PROJECT']; - const name = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; - - let stdout; - - before(async () => { - stdout = execSync( - `node interactive-tutorials/product/add-fulfillment-places.js ${productId}`, - { - cwd, - } - ); - }); - - it('should check that product created', () => { - const regex = new RegExp(`Product ${productId} created`, 'g'); - assert.match(stdout, regex); - }); - - it('should check that add fulfillment started', () => { - assert.match(stdout, /Start add fulfillment/); - }); - - it('should check that add fulfillment finished', () => { - assert.match(stdout, /Add fulfillment finished/); - }); - - it('should check that product updated correctly', async () => { - const regex = new RegExp('Updated product with current time: .*\\n', 'g'); - assert.match(stdout, regex); - const string = stdout - .match(regex) - .toString() - .replace('Updated product with current time: ', ''); - const updatedProduct = JSON.parse(string); - - expect(updatedProduct).to.be.an('object'); - expect(updatedProduct.fulfillmentInfo).to.be.an('array'); - expect( - updatedProduct.fulfillmentInfo.length, - 'Fulfillment array is empty' - ).to.equal(1); - - const item = updatedProduct.fulfillmentInfo[0]; - expect(item).to.be.an('object'); - expect(item).to.have.all.keys('type', 'placeIds'); - expect(item.type).to.equal('same-day-delivery'); - expect(item.placeIds) - .to.be.an('array') - .that.includes('store1', 'store2', 'store3'); - }); - - it('should check that product deleted', async () => { - const regex = new RegExp(`Product ${productId} deleted`, 'g'); - assert.match(stdout, regex); - }); - - after(async () => { - try { - const product = await retailClient.getProduct({name: name}); - expect(product, 'The product not deleted').to.be.undefined; - } catch (err) { - expect(err, 'Bad error code').to.include({code: 5}); - } - }); -}); diff --git a/retail/interactive-tutorials/test/import-user-events-big-query.test.js b/retail/interactive-tutorials/test/import-user-events-big-query.test.js new file mode 100644 index 0000000000..8242d9fc82 --- /dev/null +++ b/retail/interactive-tutorials/test/import-user-events-big-query.test.js @@ -0,0 +1,78 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, after, describe, it} = require('mocha'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cwd = path.join(__dirname, '..'); +const utils = require('../setup/setup-cleanup'); + +describe('Import user events from big query table', () => { + let stdout; + const dataset = `user_events_${Math.round(Date.now() / 1000)}`; + const table = 'events'; + const schema = 'interactive-tutorials/resources/events_schema.json'; + const sourceFile = 'interactive-tutorials/resources/user_events.json'; + + before(async () => { + await utils.createBqDataset(dataset); + await utils.createBqTable(dataset, table, schema); + await utils.uploadDataToBqTable(dataset, table, sourceFile, schema); + stdout = execSync( + `node interactive-tutorials/events/import-user-events-big-query.js ${dataset}`, + { + cwd, + } + ); + }); + + it('should check that import started', () => { + assert.match(stdout, /Start events import/); + }); + + it('should check that events imported correctly', async () => { + const regex = new RegExp('Operation result: .*\\n', 'g'); + assert.match(stdout, regex); + const string = stdout + .match(regex) + .toString() + .replace('Operation result: ', ''); + const importOperation = JSON.parse(string); + + expect(importOperation).to.be.an('array'); + expect(importOperation.length).to.equal(3); + + const response = importOperation[1]; + const metadata = importOperation[2]; + + expect(metadata).to.be.an('object'); + expect(metadata.done).to.be.true; + + expect(response).to.be.an('object'); + }); + + it('should check that import finished', () => { + assert.match(stdout, /Events import finished/); + }); + + after(async () => { + await utils.deleteBqDataset(dataset); + }); +}); diff --git a/retail/interactive-tutorials/test/import-user-events-gcs.test.js b/retail/interactive-tutorials/test/import-user-events-gcs.test.js new file mode 100644 index 0000000000..826ba5d512 --- /dev/null +++ b/retail/interactive-tutorials/test/import-user-events-gcs.test.js @@ -0,0 +1,78 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, after, describe, it} = require('mocha'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cwd = path.join(__dirname, '..'); +const utils = require('../setup/setup-cleanup'); + +describe('Import user events from gcs', () => { + let stdout; + const bucketName = `user_events_${Math.round(Date.now() / 1000)}`; + + before(async () => { + await utils.createBucket(bucketName); + await utils.uploadFile( + bucketName, + 'interactive-tutorials/resources/user_events.json', + 'user_events.json' + ); + stdout = execSync( + `node interactive-tutorials/events/import-user-events-gcs.js ${bucketName}`, + { + cwd, + } + ); + }); + + it('should check that import started', () => { + assert.match(stdout, /Start events import/); + }); + + it('should check that events imported correctly', async () => { + const regex = new RegExp('Operation result: .*\\n', 'g'); + assert.match(stdout, regex); + const string = stdout + .match(regex) + .toString() + .replace('Operation result: ', ''); + const importOperation = JSON.parse(string); + + expect(importOperation).to.be.an('array'); + expect(importOperation.length).to.equal(3); + + const response = importOperation[1]; + const metadata = importOperation[2]; + + expect(metadata).to.be.an('object'); + expect(metadata.done).to.be.true; + + expect(response).to.be.an('object'); + }); + + it('should check that import finished', () => { + assert.match(stdout, /Events import finished/); + }); + + after(async () => { + await utils.deleteBucket(bucketName); + }); +}); diff --git a/retail/interactive-tutorials/test/import-user-events-inline.test.js b/retail/interactive-tutorials/test/import-user-events-inline.test.js new file mode 100644 index 0000000000..e2e86aa825 --- /dev/null +++ b/retail/interactive-tutorials/test/import-user-events-inline.test.js @@ -0,0 +1,67 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const cp = require('child_process'); +const {before, describe, it} = require('mocha'); +const {assert, expect} = require('chai'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cwd = path.join(__dirname, '..'); + +describe('Import user events from inline', () => { + let stdout; + + before(async () => { + stdout = execSync( + 'node interactive-tutorials/events/import-user-events-inline.js', + { + cwd, + } + ); + }); + + it('should check that import started', () => { + assert.match(stdout, /Start events import/); + }); + + it('should check that events imported correctly', async () => { + const regex = new RegExp('Operation result: .*\\n', 'g'); + assert.match(stdout, regex); + const string = stdout + .match(regex) + .toString() + .replace('Operation result: ', ''); + const importOperation = JSON.parse(string); + + expect(importOperation).to.be.an('array'); + expect(importOperation.length).to.equal(3); + + const response = importOperation[1]; + const metadata = importOperation[2]; + + expect(metadata).to.be.an('object'); + expect(metadata.done).to.be.true; + + expect(response).to.be.an('object'); + expect(response.successCount).to.equal('3'); + }); + + it('should check that import finished', () => { + assert.match(stdout, /Events import finished/); + }); +}); diff --git a/retail/interactive-tutorials/test/remove-fulfillment.test.js b/retail/interactive-tutorials/test/remove-fulfillment.test.js deleted file mode 100644 index b3d7773344..0000000000 --- a/retail/interactive-tutorials/test/remove-fulfillment.test.js +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2022 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -'use strict'; - -const path = require('path'); -const cp = require('child_process'); -const {before, describe, it, after} = require('mocha'); -const {ProductServiceClient} = require('@google-cloud/retail'); -const {assert, expect} = require('chai'); - -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const cwd = path.join(__dirname, '..'); - -describe('Remove fulfillment', () => { - const retailClient = new ProductServiceClient(); - const productId = Math.random().toString(36).slice(2).toUpperCase(); - const projectNumber = process.env['GCLOUD_PROJECT']; - const name = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; - - let stdout; - - before(async () => { - stdout = execSync( - `node interactive-tutorials/product/remove-fulfillment-places.js ${productId}`, - {cwd} - ); - }); - - it('should check that product created', () => { - const regex = new RegExp(`Product ${productId} created`, 'g'); - assert.match(stdout, regex); - }); - - it('should check that remove fulfillment started', () => { - assert.match(stdout, /Start remove fulfillment/); - }); - - it('should check that add fulfillment finished', () => { - assert.match(stdout, /Remove fulfillment finished/); - }); - - const checkUpdatedProduct = updatedProduct => { - expect(updatedProduct).to.be.an('object'); - expect(updatedProduct.fulfillmentInfo).to.be.an('array'); - expect( - updatedProduct.fulfillmentInfo.length, - 'Fulfillment array is empty' - ).to.equal(1); - - const item = updatedProduct.fulfillmentInfo[0]; - expect(item).to.be.an('object'); - expect(item).to.have.all.keys('type', 'placeIds'); - expect(item.type).to.equal('same-day-delivery'); - expect(item.placeIds) - .to.be.an('array') - .that.includes('store3', 'store2') - .but.not.include('store1'); - }; - - it('should check that fulfillment removed correctly', async () => { - const regex = new RegExp('Updated product with current time: .*\\n', 'g'); - assert.match(stdout, regex); - const string = stdout - .match(regex) - .toString() - .replace('Updated product with current time: ', ''); - const updatedProduct = JSON.parse(string); - - checkUpdatedProduct(updatedProduct); - }); - - it('should check that product deleted', async () => { - const regex = new RegExp(`Product ${productId} deleted`, 'g'); - assert.match(stdout, regex); - }); - - after(async () => { - try { - const product = await retailClient.getProduct({name: name}); - expect(product, 'The product not deleted').to.be.undefined; - } catch (err) { - expect(err, 'Bad error code').to.include({code: 5}); - } - }); -}); diff --git a/retail/interactive-tutorials/test/search-with-query-expansion-spec.test.js b/retail/interactive-tutorials/test/search-with-query-expansion-spec.test.js index 246cc1df65..414523501d 100644 --- a/retail/interactive-tutorials/test/search-with-query-expansion-spec.test.js +++ b/retail/interactive-tutorials/test/search-with-query-expansion-spec.test.js @@ -96,7 +96,6 @@ describe('Search with query expansion spec', () => { it('should contain expanded query', () => { const searchResponse = response[IResponseParams.ISearchResponse]; - console.log(response); expect( searchResponse.queryExpansionInfo, 'Search response does not contain query expansion info' diff --git a/retail/interactive-tutorials/test/set-inventory.test.js b/retail/interactive-tutorials/test/set-inventory.test.js deleted file mode 100644 index 180051166b..0000000000 --- a/retail/interactive-tutorials/test/set-inventory.test.js +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2022 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -'use strict'; - -const path = require('path'); -const cp = require('child_process'); -const {before, describe, it, after} = require('mocha'); -const {ProductServiceClient} = require('@google-cloud/retail'); -const {assert, expect} = require('chai'); - -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const cwd = path.join(__dirname, '..'); - -describe('Set inventory', () => { - const retailClient = new ProductServiceClient(); - const productId = Math.random().toString(36).slice(2).toUpperCase(); - const projectNumber = process.env['GCLOUD_PROJECT']; - const name = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; - const product = { - priceInfo: { - price: 15.0, - originalPrice: 20.0, - cost: 8.0, - currencyCode: 'USD', - }, - fulfillmentInfo: [ - { - type: 'same-day-delivery', - placeIds: ['store3', 'store4'], - }, - ], - availableQuantity: { - value: 2, - }, - availability: 'IN_STOCK', - }; - let stdout; - - before(async () => { - stdout = execSync( - `node interactive-tutorials/product/set-inventory.js ${productId}`, - {cwd} - ); - }); - - it('should check that product created', () => { - const regex = new RegExp(`Product ${productId} created`, 'g'); - assert.match(stdout, regex); - }); - - it('should check that set inventory started', () => { - assert.match(stdout, /Start set inventory/); - }); - - it('should check that set inventory finished', () => { - assert.match(stdout, /Set inventory finished/); - }); - - const checkUpdatedProduct = updatedProduct => { - expect(updatedProduct).to.be.an('object'); - assert.containsAllDeepKeys(updatedProduct, product); - expect(updatedProduct.priceInfo.price, 'Price not equal').to.equal(15.0); - expect( - updatedProduct.priceInfo.originalPrice, - 'Original price not equal' - ).to.equal(20.0); - expect(updatedProduct.priceInfo.cost, 'Cost not equal').to.equal(8.0); - expect( - updatedProduct.priceInfo.currencyCode, - 'Currency code not equal' - ).to.equal('USD'); - expect(updatedProduct.fulfillmentInfo).to.be.an('array'); - expect( - updatedProduct.fulfillmentInfo.length, - 'Fulfillment array is empty' - ).to.equal(1); - - const fulfillmentItem = updatedProduct.fulfillmentInfo[0]; - expect(fulfillmentItem).to.be.an('object'); - expect(fulfillmentItem).to.have.all.keys('type', 'placeIds'); - expect(fulfillmentItem.type).to.equal('same-day-delivery'); - expect(fulfillmentItem.placeIds) - .to.be.an('array') - .that.includes('store3', 'store4'); - - expect( - updatedProduct.availableQuantity, - 'Available quantity not equal' - ).to.deep.equal({value: 2}); - expect(updatedProduct.availability, 'Availability not equal').to.equal( - 'IN_STOCK' - ); - }; - - it('should check that product updated correctly', async () => { - const regex = new RegExp( - `Updated product ${productId} with current time: .*\\n`, - 'g' - ); - assert.match(stdout, regex); - const string = stdout - .match(regex) - .toString() - .replace(`Updated product ${productId} with current time: `, ''); - const updatedProduct = JSON.parse(string); - - checkUpdatedProduct(updatedProduct); - }); - - it('should check that product has not been updated with outdated time', async () => { - const regex = new RegExp( - `Updated product ${productId} with outdated time: .*\\n`, - 'g' - ); - assert.match(stdout, regex); - const string = stdout - .match(regex) - .toString() - .replace(`Updated product ${productId} with outdated time: `, ''); - const updatedProduct = JSON.parse(string); - - checkUpdatedProduct(updatedProduct); - }); - - it('should check that product deleted', async () => { - const regex = new RegExp(`Product ${productId} deleted`, 'g'); - assert.match(stdout, regex); - }); - - after(async () => { - try { - const product = await retailClient.getProduct({name: name}); - expect(product, 'The product not deleted').to.be.undefined; - } catch (err) { - expect(err, 'Bad error code').to.include({code: 5}); - } - }); -}); From e29a2edbc1faf3d3d494ab12a44e3c4dbfa8911d Mon Sep 17 00:00:00 2001 From: nmykhailets <94851929+nmykhailets@users.noreply.github.com> Date: Tue, 15 Mar 2022 20:07:48 +0200 Subject: [PATCH 24/54] fix: remove gcloud_project env variable (#156) Co-authored-by: Karl Weinmeister <11586922+kweinmeister@users.noreply.github.com> --- .../events/purge-user-events.js | 10 +++--- .../events/rejoin-user-events.js | 10 +++--- .../events/write-user-event.js | 10 +++--- .../product/add-fulfillment-places.js | 10 +++--- .../product/create-product.js | 10 +++--- .../product/crud-product.js | 10 +++--- .../product/delete-product.js | 10 +++--- .../product/get-product.js | 10 +++--- .../product/get-products-list.js | 10 +++--- .../import-products-big-query-table.js | 11 +++--- .../product/import-products-gcs.js | 10 +++--- .../product/import-products-inline-source.js | 12 +++---- .../product/remove-fulfillment-places.js | 10 +++--- .../product/set-inventory.js | 10 +++--- .../product/update-product.js | 10 +++--- .../search/search-simple-query.js | 10 +++--- .../search/search-with-boost-spec.js | 10 +++--- .../search/search-with-facet-spec.js | 10 +++--- .../search/search-with-filtering.js | 10 +++--- .../search/search-with-ordering.js | 10 +++--- .../search/search-with-pagination.js | 10 +++--- .../search-with-query-expansion-spec.js | 10 +++--- .../setup/setup-cleanup.js | 4 +-- .../create-test-resources.js | 7 ++-- .../remove-test-resources.js | 6 ++-- .../test/create-product.test.js | 7 ++-- .../test/crud-product.test.js | 36 ++++++++++--------- .../test/delete-product.test.js | 7 ++-- .../test/get-product.test.js | 7 ++-- .../import-products-inline-source.test.js | 25 +++++++------ .../test/search-simple-query.test.js | 15 ++++---- .../test/search-with-boost-spec.test.js | 23 ++++++------ .../test/search-with-facet-spec.test.js | 18 +++++----- .../test/search-with-filtering.test.js | 16 +++++---- .../test/search-with-ordering.test.js | 16 +++++---- .../test/search-with-pagination.test.js | 20 ++++++----- .../search-with-query-expansion-spec.test.js | 22 ++++++------ .../test/update-product.test.js | 36 ++++++++++--------- 38 files changed, 260 insertions(+), 228 deletions(-) diff --git a/retail/interactive-tutorials/events/purge-user-events.js b/retail/interactive-tutorials/events/purge-user-events.js index e63c9f2c1a..3815fa78d0 100644 --- a/retail/interactive-tutorials/events/purge-user-events.js +++ b/retail/interactive-tutorials/events/purge-user-events.js @@ -21,11 +21,14 @@ async function main() { const {UserEventServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); - const projectNumber = process.env['GCLOUD_PROJECT']; + // Instantiates a client. + const retailClient = new UserEventServiceClient(); + + const projectId = await retailClient.getProjectId(); const visitorId = 'test_visitor_id'; // Placement - const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog`; + const parent = `projects/${projectId}/locations/global/catalogs/default_catalog`; // The filter string to specify the events to be deleted with a // length limit of 5,000 characters. @@ -34,9 +37,6 @@ async function main() { // Actually perform the purge. const force = true; - // Instantiates a client. - const retailClient = new UserEventServiceClient(); - const callPurgeUserEvents = async () => { // Construct request const request = { diff --git a/retail/interactive-tutorials/events/rejoin-user-events.js b/retail/interactive-tutorials/events/rejoin-user-events.js index 82e73a54b5..90bdcf3909 100644 --- a/retail/interactive-tutorials/events/rejoin-user-events.js +++ b/retail/interactive-tutorials/events/rejoin-user-events.js @@ -21,11 +21,14 @@ async function main() { const {UserEventServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); - const projectNumber = process.env['GCLOUD_PROJECT']; + // Instantiates a client. + const retailClient = new UserEventServiceClient(); + + const projectId = await retailClient.getProjectId(); const visitorId = 'test_visitor_id'; // Placement - const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog`; // TO CHECK ERROR HANDLING PASTE THE INVALID CATALOG NAME HERE + const parent = `projects/${projectId}/locations/global/catalogs/default_catalog`; // TO CHECK ERROR HANDLING PASTE THE INVALID CATALOG NAME HERE const UserEventRejoinScope = { USER_EVENT_REJOIN_SCOPE_UNSPECIFIED: 0, @@ -36,9 +39,6 @@ async function main() { // events to be rejoined with the latest product catalog const userEventRejoinScope = UserEventRejoinScope.UNJOINED_EVENTS; - // Instantiates a client. - const retailClient = new UserEventServiceClient(); - const callRejoinUserEvents = async () => { // Construct request const request = { diff --git a/retail/interactive-tutorials/events/write-user-event.js b/retail/interactive-tutorials/events/write-user-event.js index 6763abbde8..fbcbf04d28 100644 --- a/retail/interactive-tutorials/events/write-user-event.js +++ b/retail/interactive-tutorials/events/write-user-event.js @@ -21,11 +21,14 @@ async function main() { const {UserEventServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); - const projectNumber = process.env['GCLOUD_PROJECT']; + // Instantiates a client. + const retailClient = new UserEventServiceClient(); + + const projectId = await retailClient.getProjectId(); const visitorId = 'test_visitor_id'; // Placement - const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog`; // TO CHECK ERROR HANDLING PASTE THE INVALID CATALOG NAME HERE + const parent = `projects/${projectId}/locations/global/catalogs/default_catalog`; // TO CHECK ERROR HANDLING PASTE THE INVALID CATALOG NAME HERE // User event to write const userEvent = { @@ -36,9 +39,6 @@ async function main() { }, }; - // Instantiates a client. - const retailClient = new UserEventServiceClient(); - const callWriteUserEvent = async () => { // Construct request const request = { diff --git a/retail/interactive-tutorials/product/add-fulfillment-places.js b/retail/interactive-tutorials/product/add-fulfillment-places.js index 9612d1c829..dcb9972a96 100644 --- a/retail/interactive-tutorials/product/add-fulfillment-places.js +++ b/retail/interactive-tutorials/product/add-fulfillment-places.js @@ -21,11 +21,14 @@ async function main(generatedProductId) { const {ProductServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); - const projectNumber = process.env['GCLOUD_PROJECT']; + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const projectId = await retailClient.getProjectId(); // Create product const createdProduct = await utils.createProduct( - projectNumber, + projectId, generatedProductId ); @@ -50,9 +53,6 @@ async function main(generatedProductId) { // at most 1 day and processed once the product is created const allowMissing = true; - // Instantiates a client. - const retailClient = new ProductServiceClient(); - const calladdFulfillmentPlaces = async () => { // Construct request const request = { diff --git a/retail/interactive-tutorials/product/create-product.js b/retail/interactive-tutorials/product/create-product.js index a385af3c18..6823b29bbf 100644 --- a/retail/interactive-tutorials/product/create-product.js +++ b/retail/interactive-tutorials/product/create-product.js @@ -21,10 +21,13 @@ async function main(generatedProductId) { const {ProductServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); - const projectNumber = process.env['GCLOUD_PROJECT']; + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const projectId = await retailClient.getProjectId(); // The parent catalog resource name - const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch`; + const parent = `projects/${projectId}/locations/global/catalogs/default_catalog/branches/default_branch`; // The ID to use for the product const productId = generatedProductId @@ -45,9 +48,6 @@ async function main(generatedProductId) { availability: 'IN_STOCK', }; - // Instantiates a client. - const retailClient = new ProductServiceClient(); - const callCreateProduct = async () => { // Construct request const request = { diff --git a/retail/interactive-tutorials/product/crud-product.js b/retail/interactive-tutorials/product/crud-product.js index a4c3ea1ee8..bbf98d0110 100644 --- a/retail/interactive-tutorials/product/crud-product.js +++ b/retail/interactive-tutorials/product/crud-product.js @@ -20,10 +20,13 @@ async function main(generatedProductId) { // Imports the Google Cloud client library. const {ProductServiceClient} = require('@google-cloud/retail').v2; - const projectNumber = process.env['GCLOUD_PROJECT']; + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const projectId = await retailClient.getProjectId(); // The parent catalog resource name - const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch`; + const parent = `projects/${projectId}/locations/global/catalogs/default_catalog/branches/default_branch`; // The ID to use for the product const productId = generatedProductId @@ -63,9 +66,6 @@ async function main(generatedProductId) { availability: 'OUT_OF_STOCK', }; - // Instantiates a client. - const retailClient = new ProductServiceClient(); - const callCreateProduct = async () => { // Construct request const request = { diff --git a/retail/interactive-tutorials/product/delete-product.js b/retail/interactive-tutorials/product/delete-product.js index daee6c17ef..6965c0ea79 100644 --- a/retail/interactive-tutorials/product/delete-product.js +++ b/retail/interactive-tutorials/product/delete-product.js @@ -21,17 +21,17 @@ async function main(generatedProductId) { const {ProductServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); - const projectNumber = process.env['GCLOUD_PROJECT']; + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const projectId = await retailClient.getProjectId(); // Create product - const product = await utils.createProduct(projectNumber, generatedProductId); + const product = await utils.createProduct(projectId, generatedProductId); // Full resource name of Product const name = product.name; - // Instantiates a client. - const retailClient = new ProductServiceClient(); - const callDeleteProduct = async () => { // Construct request const request = { diff --git a/retail/interactive-tutorials/product/get-product.js b/retail/interactive-tutorials/product/get-product.js index ef015d8ece..d9ae491326 100644 --- a/retail/interactive-tutorials/product/get-product.js +++ b/retail/interactive-tutorials/product/get-product.js @@ -21,17 +21,17 @@ async function main(generatedProductId) { const {ProductServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); - const projectNumber = process.env['GCLOUD_PROJECT']; + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const projectId = await retailClient.getProjectId(); // Create product - const product = await utils.createProduct(projectNumber, generatedProductId); + const product = await utils.createProduct(projectId, generatedProductId); // Full resource name of Product const name = product.name; - // Instantiates a client. - const retailClient = new ProductServiceClient(); - const callGetProduct = async () => { // Construct request const request = { diff --git a/retail/interactive-tutorials/product/get-products-list.js b/retail/interactive-tutorials/product/get-products-list.js index cffc146512..63317a0558 100644 --- a/retail/interactive-tutorials/product/get-products-list.js +++ b/retail/interactive-tutorials/product/get-products-list.js @@ -20,14 +20,14 @@ async function main() { // Imports the Google Cloud client library. const {ProductServiceClient} = require('@google-cloud/retail').v2; - const projectNumber = process.env['GCLOUD_PROJECT']; - - // Placement - const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch`; - // Instantiates a client. const retailClient = new ProductServiceClient(); + const projectId = await retailClient.getProjectId(); + + // Placement + const parent = `projects/${projectId}/locations/global/catalogs/default_catalog/branches/default_branch`; + async function callListProducts() { console.log('Start get products list'); // Construct request diff --git a/retail/interactive-tutorials/product/import-products-big-query-table.js b/retail/interactive-tutorials/product/import-products-big-query-table.js index 2b9c3c842a..527240462c 100644 --- a/retail/interactive-tutorials/product/import-products-big-query-table.js +++ b/retail/interactive-tutorials/product/import-products-big-query-table.js @@ -20,15 +20,17 @@ async function main() { // Imports the Google Cloud client library. const {ProductServiceClient} = require('@google-cloud/retail').v2; - const projectNumber = process.env['GCLOUD_PROJECT']; - const projectId = process.env['PROJECT_ID']; + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const projectId = await retailClient.getProjectId(); const datasetId = 'products'; const tableId = 'products'; // TO CHECK ERROR HANDLING USE THE TABLE WITH INVALID PRODUCTS const dataSchema = 'product'; // Placement - const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch`; // TO CHECK ERROR HANDLING PASTE THE INVALID CATALOG NAME HERE + const parent = `projects/${projectId}/locations/global/catalogs/default_catalog/branches/default_branch`; // TO CHECK ERROR HANDLING PASTE THE INVALID CATALOG NAME HERE // The desired input location of the data. const inputConfig = { @@ -55,9 +57,6 @@ async function main() { // The mode of reconciliation between existing products and the products to be imported. const reconciliationMode = reconciliationModes.INCREMENTAL; - // Instantiates a client. - const retailClient = new ProductServiceClient(); - const callImportProducts = async () => { // Construct request const request = { diff --git a/retail/interactive-tutorials/product/import-products-gcs.js b/retail/interactive-tutorials/product/import-products-gcs.js index d5ddaa4282..e07e9ee7db 100644 --- a/retail/interactive-tutorials/product/import-products-gcs.js +++ b/retail/interactive-tutorials/product/import-products-gcs.js @@ -20,14 +20,17 @@ async function main(bucketName) { // Imports the Google Cloud client library. const {ProductServiceClient} = require('@google-cloud/retail').v2; - const projectNumber = process.env['GCLOUD_PROJECT']; + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const projectId = await retailClient.getProjectId(); const gcsBucket = `gs://${bucketName}`; const gcsErrorsBucket = `gs://${bucketName}/error`; const gcsProductsObject = 'products.json'; // TO CHECK ERROR HANDLING USE THE JSON WITH INVALID PRODUCT // Placement - const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch`; //TO CHECK ERROR HANDLING PASTE THE INVALID CATALOG NAME HERE + const parent = `projects/${projectId}/locations/global/catalogs/default_catalog/branches/default_branch`; //TO CHECK ERROR HANDLING PASTE THE INVALID CATALOG NAME HERE // The desired input location of the data. const inputConfig = { @@ -48,9 +51,6 @@ async function main(bucketName) { IOperation: 2, }; - // Instantiates a client. - const retailClient = new ProductServiceClient(); - const callImportProducts = async () => { // Construct request const request = { diff --git a/retail/interactive-tutorials/product/import-products-inline-source.js b/retail/interactive-tutorials/product/import-products-inline-source.js index 396646b2d2..4dea2f0b76 100644 --- a/retail/interactive-tutorials/product/import-products-inline-source.js +++ b/retail/interactive-tutorials/product/import-products-inline-source.js @@ -21,10 +21,13 @@ async function main(id1, id2) { const {ProductServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); - const projectNumber = process.env['GCLOUD_PROJECT']; + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const projectId = await retailClient.getProjectId(); // Placement - const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch`; + const parent = `projects/${projectId}/locations/global/catalogs/default_catalog/branches/default_branch`; const product1 = { id: id1 ? id1 : Math.random().toString(36).slice(2).toUpperCase(), @@ -89,9 +92,6 @@ async function main(id1, id2) { IOperation: 2, }; - // Instantiates a client. - const retailClient = new ProductServiceClient(); - const callImportProducts = async () => { // Construct request const request = { @@ -118,7 +118,7 @@ async function main(id1, id2) { console.log('Import products finished'); // Delete imported products - await utils.deleteProductsByIds(projectNumber, [product1.id, product2.id]); + await utils.deleteProductsByIds(projectId, [product1.id, product2.id]); console.log('Products deleted'); // [END retail_import_products_from_inline_source] } diff --git a/retail/interactive-tutorials/product/remove-fulfillment-places.js b/retail/interactive-tutorials/product/remove-fulfillment-places.js index 3e5ce00df4..217a72b9ab 100644 --- a/retail/interactive-tutorials/product/remove-fulfillment-places.js +++ b/retail/interactive-tutorials/product/remove-fulfillment-places.js @@ -21,11 +21,14 @@ async function main(generatedProductId) { const {ProductServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); - const projectNumber = process.env['GCLOUD_PROJECT']; + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const projectId = await retailClient.getProjectId(); // Create product const createdProduct = await utils.createProduct( - projectNumber, + projectId, generatedProductId, true ); @@ -47,9 +50,6 @@ async function main(generatedProductId) { seconds: Math.round(Date.now() / 1000), }; - // Instantiates a client. - const retailClient = new ProductServiceClient(); - const callRemoveFulfillmentPlaces = async () => { // Construct request const request = { diff --git a/retail/interactive-tutorials/product/set-inventory.js b/retail/interactive-tutorials/product/set-inventory.js index 28f1ca5d13..1b849cebdc 100644 --- a/retail/interactive-tutorials/product/set-inventory.js +++ b/retail/interactive-tutorials/product/set-inventory.js @@ -21,11 +21,14 @@ async function main(generatedProductId) { const {ProductServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); - const projectNumber = process.env['GCLOUD_PROJECT']; + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const projectId = await retailClient.getProjectId(); // Create product const createdProduct = await utils.createProduct( - projectNumber, + projectId, generatedProductId ); @@ -61,9 +64,6 @@ async function main(generatedProductId) { // inventory update will still be processed and retained for at most 1 day until the product is created const allowMissing = true; - // Instantiates a client. - const retailClient = new ProductServiceClient(); - const callSetInventory = async () => { // Construct request const request = { diff --git a/retail/interactive-tutorials/product/update-product.js b/retail/interactive-tutorials/product/update-product.js index 30a2da2a1c..dd309d50e8 100644 --- a/retail/interactive-tutorials/product/update-product.js +++ b/retail/interactive-tutorials/product/update-product.js @@ -21,11 +21,14 @@ async function main(generatedProductId) { const {ProductServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); - const projectNumber = process.env['GCLOUD_PROJECT']; + // Instantiates a client. + const retailClient = new ProductServiceClient(); + + const projectId = await retailClient.getProjectId(); // Create product const createdProduct = await utils.createProduct( - projectNumber, + projectId, generatedProductId ); @@ -51,9 +54,6 @@ async function main(generatedProductId) { availability: 'OUT_OF_STOCK', }; - // Instantiates a client. - const retailClient = new ProductServiceClient(); - const callUpdateProduct = async () => { // Construct request const request = { diff --git a/retail/interactive-tutorials/search/search-simple-query.js b/retail/interactive-tutorials/search/search-simple-query.js index 7a5bd03669..ae56a8616c 100644 --- a/retail/interactive-tutorials/search/search-simple-query.js +++ b/retail/interactive-tutorials/search/search-simple-query.js @@ -21,10 +21,13 @@ async function main() { // Imports the Google Cloud client library. const {SearchServiceClient} = require('@google-cloud/retail'); - const projectNumber = process.env['GCLOUD_PROJECT']; + // Instantiates a client. + const retailClient = new SearchServiceClient(); + + const projectId = await retailClient.getProjectId(); // Placement is used to identify the Serving Config name. - const placement = `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`; + const placement = `projects/${projectId}/locations/global/catalogs/default_catalog/placements/default_search`; // Raw search query. const query = 'Hoodie'; //TRY DIFFERENT QUERY PHRASES @@ -35,9 +38,6 @@ async function main() { // Maximum number of Products to return. const pageSize = 10; - // Instantiates a client. - const retailClient = new SearchServiceClient(); - const IResponseParams = { ISearchResult: 0, ISearchRequest: 1, diff --git a/retail/interactive-tutorials/search/search-with-boost-spec.js b/retail/interactive-tutorials/search/search-with-boost-spec.js index 52db62db08..6021635ff0 100644 --- a/retail/interactive-tutorials/search/search-with-boost-spec.js +++ b/retail/interactive-tutorials/search/search-with-boost-spec.js @@ -22,10 +22,13 @@ async function main() { // Imports the Google Cloud client library. const {SearchServiceClient} = require('@google-cloud/retail'); - const projectNumber = process.env['GCLOUD_PROJECT']; + // Instantiates a client + const retailClient = new SearchServiceClient(); + + const projectId = await retailClient.getProjectId(); // Placement is used to identify the Serving Config name. - const placement = `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`; + const placement = `projects/${projectId}/locations/global/catalogs/default_catalog/placements/default_search`; // Raw search query. const query = 'Hoodie'; @@ -46,9 +49,6 @@ async function main() { // Maximum number of Products to return. const pageSize = 10; - // Instantiates a client - const retailClient = new SearchServiceClient(); - const IResponseParams = { ISearchResult: 0, ISearchRequest: 1, diff --git a/retail/interactive-tutorials/search/search-with-facet-spec.js b/retail/interactive-tutorials/search/search-with-facet-spec.js index 7205c874bc..3fcac810d0 100644 --- a/retail/interactive-tutorials/search/search-with-facet-spec.js +++ b/retail/interactive-tutorials/search/search-with-facet-spec.js @@ -21,10 +21,13 @@ async function main() { // Imports the Google Cloud client library. const {SearchServiceClient} = require('@google-cloud/retail'); - const projectNumber = process.env['GCLOUD_PROJECT']; + // Instantiates a client. + const retailClient = new SearchServiceClient(); + + const projectId = await retailClient.getProjectId(); // Placement is used to identify the Serving Config name. - const placement = `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`; + const placement = `projects/${projectId}/locations/global/catalogs/default_catalog/placements/default_search`; // Raw search query. const query = 'Tee'; @@ -38,9 +41,6 @@ async function main() { // Maximum number of Products to return. const pageSize = 10; - // Instantiates a client. - const retailClient = new SearchServiceClient(); - const IResponseParams = { ISearchResult: 0, ISearchRequest: 1, diff --git a/retail/interactive-tutorials/search/search-with-filtering.js b/retail/interactive-tutorials/search/search-with-filtering.js index 3147809df4..c3d45108ad 100644 --- a/retail/interactive-tutorials/search/search-with-filtering.js +++ b/retail/interactive-tutorials/search/search-with-filtering.js @@ -21,10 +21,13 @@ async function main() { // Imports the Google Cloud client library. const {SearchServiceClient} = require('@google-cloud/retail'); - const projectNumber = process.env['GCLOUD_PROJECT']; + // Instantiates a client. + const retailClient = new SearchServiceClient(); + + const projectId = await retailClient.getProjectId(); // Placement is used to identify the Serving Config name. - const placement = `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`; + const placement = `projects/${projectId}/locations/global/catalogs/default_catalog/placements/default_search`; // Raw search query. const query = 'Tee'; @@ -39,9 +42,6 @@ async function main() { // Maximum number of Products to return. const pageSize = 10; - // Instantiates a client. - const retailClient = new SearchServiceClient(); - const IResponseParams = { ISearchResult: 0, ISearchRequest: 1, diff --git a/retail/interactive-tutorials/search/search-with-ordering.js b/retail/interactive-tutorials/search/search-with-ordering.js index af99188f29..d179f29480 100644 --- a/retail/interactive-tutorials/search/search-with-ordering.js +++ b/retail/interactive-tutorials/search/search-with-ordering.js @@ -21,10 +21,13 @@ async function main() { // Imports the Google Cloud client library. const {SearchServiceClient} = require('@google-cloud/retail'); - const projectNumber = process.env['GCLOUD_PROJECT']; + // Instantiates a client + const retailClient = new SearchServiceClient(); + + const projectId = await retailClient.getProjectId(); // Placement is used to identify the Serving Config name. - const placement = `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`; + const placement = `projects/${projectId}/locations/global/catalogs/default_catalog/placements/default_search`; // Raw search query. const query = 'Hoodie'; @@ -38,9 +41,6 @@ async function main() { // Maximum number of Products to return. const pageSize = 10; - // Instantiates a client - const retailClient = new SearchServiceClient(); - const IResponseParams = { ISearchResult: 0, ISearchRequest: 1, diff --git a/retail/interactive-tutorials/search/search-with-pagination.js b/retail/interactive-tutorials/search/search-with-pagination.js index 3158f3565a..7a153302d5 100644 --- a/retail/interactive-tutorials/search/search-with-pagination.js +++ b/retail/interactive-tutorials/search/search-with-pagination.js @@ -20,10 +20,13 @@ async function main() { // Imports the Google Cloud client library. const {SearchServiceClient} = require('@google-cloud/retail'); - const projectNumber = process.env['GCLOUD_PROJECT']; + // Instantiates a client. + const retailClient = new SearchServiceClient(); + + const projectId = await retailClient.getProjectId(); // Placement is used to identify the Serving Config name. - const placement = `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`; + const placement = `projects/${projectId}/locations/global/catalogs/default_catalog/placements/default_search`; // Raw search query. const query = 'Hoodie'; @@ -40,9 +43,6 @@ async function main() { //A page token received from a previous search call. let pageToken = ''; - // Instantiates a client. - const retailClient = new SearchServiceClient(); - const IResponseParams = { ISearchResult: 0, ISearchRequest: 1, diff --git a/retail/interactive-tutorials/search/search-with-query-expansion-spec.js b/retail/interactive-tutorials/search/search-with-query-expansion-spec.js index e70387f9e1..e5bc7d659d 100644 --- a/retail/interactive-tutorials/search/search-with-query-expansion-spec.js +++ b/retail/interactive-tutorials/search/search-with-query-expansion-spec.js @@ -20,10 +20,13 @@ async function main() { // Imports the Google Cloud client library. const {SearchServiceClient} = require('@google-cloud/retail'); - const projectNumber = process.env['GCLOUD_PROJECT']; + // Instantiates a client. + const retailClient = new SearchServiceClient(); + + const projectId = await retailClient.getProjectId(); // Placement is used to identify the Serving Config name. - const placement = `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`; + const placement = `projects/${projectId}/locations/global/catalogs/default_catalog/placements/default_search`; // Raw search query. const query = 'Google Youth Hero Tee Grey'; @@ -40,9 +43,6 @@ async function main() { //Maximum number of products to return const pageSize = 10; - // Instantiates a client. - const retailClient = new SearchServiceClient(); - const IResponseParams = { ISearchResult: 0, ISearchRequest: 1, diff --git a/retail/interactive-tutorials/setup/setup-cleanup.js b/retail/interactive-tutorials/setup/setup-cleanup.js index a0561c3256..4889f429c9 100644 --- a/retail/interactive-tutorials/setup/setup-cleanup.js +++ b/retail/interactive-tutorials/setup/setup-cleanup.js @@ -280,9 +280,9 @@ const uploadDataToBqTable = async (datasetId, tableId, source, schemaFile) => { }; const writeUserEvent = async visitorId => { - const projectNumber = process.env['GCLOUD_PROJECT']; - const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog`; const retailClient = new UserEventServiceClient(); + const projectId = await retailClient.getProjectId(); + const parent = `projects/${projectId}/locations/global/catalogs/default_catalog`; const userEvent = { eventType: 'detail-page-view', diff --git a/retail/interactive-tutorials/test-resources-setup/create-test-resources.js b/retail/interactive-tutorials/test-resources-setup/create-test-resources.js index dc7e47b5e3..3baba0a1c5 100644 --- a/retail/interactive-tutorials/test-resources-setup/create-test-resources.js +++ b/retail/interactive-tutorials/test-resources-setup/create-test-resources.js @@ -18,7 +18,8 @@ async function main() { const {ProductServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); - const projectNumber = process.env['GCLOUD_PROJECT']; + const retailClient = new ProductServiceClient(); + const projectId = await retailClient.getProjectId(); const productsBucketName = process.env['BUCKET_NAME']; const eventsBucketName = process.env['EVENTS_BUCKET_NAME']; @@ -37,7 +38,7 @@ async function main() { const productsSourceFile = 'interactive-tutorials/resources/products.json'; const eventsSourceFile = 'interactive-tutorials/resources/user_events.json'; - const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch`; + const parent = `projects/${projectId}/locations/global/catalogs/default_catalog/branches/default_branch`; const inputConfig = { gcsSource: { @@ -56,8 +57,6 @@ async function main() { IOperation: 2, }; - const retailClient = new ProductServiceClient(); - const importProducts = async () => { // Construct request const request = { diff --git a/retail/interactive-tutorials/test-resources-setup/remove-test-resources.js b/retail/interactive-tutorials/test-resources-setup/remove-test-resources.js index 614add7017..27450449e9 100644 --- a/retail/interactive-tutorials/test-resources-setup/remove-test-resources.js +++ b/retail/interactive-tutorials/test-resources-setup/remove-test-resources.js @@ -15,9 +15,11 @@ 'use strict'; async function main() { + const {ProductServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); - const projectNumber = process.env['GCLOUD_PROJECT']; + const retailClient = new ProductServiceClient(); + const projectId = await retailClient.getProjectId(); const productsBucketName = process.env['BUCKET_NAME']; const eventsBucketName = process.env['EVENTS_BUCKET_NAME']; @@ -25,7 +27,7 @@ async function main() { const productsDataset = 'products'; const eventsDataset = 'user_events'; - const parent = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch`; + const parent = `projects/${projectId}/locations/global/catalogs/default_catalog/branches/default_branch`; await utils.deleteBucket(productsBucketName); await utils.deleteBucket(eventsBucketName); diff --git a/retail/interactive-tutorials/test/create-product.test.js b/retail/interactive-tutorials/test/create-product.test.js index 060cdc07af..75c263e333 100644 --- a/retail/interactive-tutorials/test/create-product.test.js +++ b/retail/interactive-tutorials/test/create-product.test.js @@ -27,11 +27,14 @@ const cwd = path.join(__dirname, '..'); describe('Create product', () => { const retailClient = new ProductServiceClient(); const productId = Math.random().toString(36).slice(2).toUpperCase(); - const projectNumber = process.env['GCLOUD_PROJECT']; - const name = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; + let projectId; + let name; let stdout; before(async () => { + projectId = await retailClient.getProjectId(); + name = `projects/${projectId}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; + stdout = execSync( `node interactive-tutorials/product/create-product.js ${productId}`, {cwd} diff --git a/retail/interactive-tutorials/test/crud-product.test.js b/retail/interactive-tutorials/test/crud-product.test.js index b7f83bf8ae..1301aee954 100644 --- a/retail/interactive-tutorials/test/crud-product.test.js +++ b/retail/interactive-tutorials/test/crud-product.test.js @@ -26,25 +26,29 @@ const cwd = path.join(__dirname, '..'); describe('CRUD product', () => { const retailClient = new ProductServiceClient(); const productId = Math.random().toString(36).slice(2).toUpperCase(); - const projectNumber = process.env['GCLOUD_PROJECT']; - const name = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; - const product = { - productId, - name, - title: 'Updated Nest Mini', - type: 'PRIMARY', - categories: ['Updated Speakers and displays'], - brands: ['Updated Google'], - priceInfo: { - price: 20.0, - originalPrice: 25.5, - currencyCode: 'EUR', - }, - availability: 'OUT_OF_STOCK', - }; + let projectId; + let name; + let product; let stdout; before(async () => { + projectId = await retailClient.getProjectId(); + name = `projects/${projectId}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; + product = { + productId, + name, + title: 'Updated Nest Mini', + type: 'PRIMARY', + categories: ['Updated Speakers and displays'], + brands: ['Updated Google'], + priceInfo: { + price: 20.0, + originalPrice: 25.5, + currencyCode: 'EUR', + }, + availability: 'OUT_OF_STOCK', + }; + stdout = execSync( `node interactive-tutorials/product/crud-product.js ${productId}`, {cwd} diff --git a/retail/interactive-tutorials/test/delete-product.test.js b/retail/interactive-tutorials/test/delete-product.test.js index 18b8d9dbda..77cb4dde06 100644 --- a/retail/interactive-tutorials/test/delete-product.test.js +++ b/retail/interactive-tutorials/test/delete-product.test.js @@ -27,11 +27,14 @@ const cwd = path.join(__dirname, '..'); describe('Delete product', () => { const retailClient = new ProductServiceClient(); const productId = Math.random().toString(36).slice(2).toUpperCase(); - const projectNumber = process.env['GCLOUD_PROJECT']; - const name = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; + let projectId; + let name; let stdout; before(async () => { + projectId = await retailClient.getProjectId(); + name = `projects/${projectId}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; + stdout = execSync( `node interactive-tutorials/product/delete-product.js ${productId}`, {cwd} diff --git a/retail/interactive-tutorials/test/get-product.test.js b/retail/interactive-tutorials/test/get-product.test.js index 7898314b6c..f5673b8d61 100644 --- a/retail/interactive-tutorials/test/get-product.test.js +++ b/retail/interactive-tutorials/test/get-product.test.js @@ -26,11 +26,14 @@ const cwd = path.join(__dirname, '..'); describe('Get product', () => { const retailClient = new ProductServiceClient(); const productId = Math.random().toString(36).slice(2).toUpperCase(); - const projectNumber = process.env['GCLOUD_PROJECT']; - const name = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; + let projectId; + let name; let stdout; before(async () => { + projectId = await retailClient.getProjectId(); + name = `projects/${projectId}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; + stdout = execSync( `node interactive-tutorials/product/get-product.js ${productId}`, {cwd} diff --git a/retail/interactive-tutorials/test/import-products-inline-source.test.js b/retail/interactive-tutorials/test/import-products-inline-source.test.js index 319bca5e1e..44a0ac00ed 100644 --- a/retail/interactive-tutorials/test/import-products-inline-source.test.js +++ b/retail/interactive-tutorials/test/import-products-inline-source.test.js @@ -26,24 +26,27 @@ const cwd = path.join(__dirname, '..'); describe('Import product from inline source', () => { const retailClient = new ProductServiceClient(); - const projectNumber = process.env['GCLOUD_PROJECT']; const id1 = Math.random().toString(36).slice(2).toUpperCase(); const id2 = Math.random().toString(36).slice(2).toUpperCase(); - const product1 = { - id: id1, - name: `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${id1}`, - }; - - const product2 = { - id: id2, - name: `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${id2}`, - }; - + let projectId; + let product1; + let product2; let stdout; before(async () => { + projectId = await retailClient.getProjectId(); + product1 = { + id: id1, + name: `projects/${projectId}/locations/global/catalogs/default_catalog/branches/default_branch/products/${id1}`, + }; + + product2 = { + id: id2, + name: `projects/${projectId}/locations/global/catalogs/default_catalog/branches/default_branch/products/${id2}`, + }; + stdout = execSync( `node interactive-tutorials/product/import-products-inline-source.js ${product1.id} ${product2.id}`, {cwd} diff --git a/retail/interactive-tutorials/test/search-simple-query.test.js b/retail/interactive-tutorials/test/search-simple-query.test.js index ff74a29d24..9b54fcb977 100644 --- a/retail/interactive-tutorials/test/search-simple-query.test.js +++ b/retail/interactive-tutorials/test/search-simple-query.test.js @@ -45,13 +45,8 @@ describe('Search simple query', () => { describe('Search simple query sample result', () => { const retailClient = new SearchServiceClient(); - - const projectNumber = process.env['GCLOUD_PROJECT']; - const request = { - placement: `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`, - query: 'Hoodie', - visitorId: '12345', - }; + let projectId; + let request; const IResponseParams = { ISearchResult: 0, ISearchRequest: 1, @@ -60,6 +55,12 @@ describe('Search simple query', () => { let response = []; before(async () => { + projectId = await retailClient.getProjectId(); + request = { + placement: `projects/${projectId}/locations/global/catalogs/default_catalog/placements/default_search`, + query: 'Hoodie', + visitorId: '12345', + }; response = await retailClient.search(request, {autoPaginate: false}); }); diff --git a/retail/interactive-tutorials/test/search-with-boost-spec.test.js b/retail/interactive-tutorials/test/search-with-boost-spec.test.js index 54d07dfd4d..5d741d3bbd 100644 --- a/retail/interactive-tutorials/test/search-with-boost-spec.test.js +++ b/retail/interactive-tutorials/test/search-with-boost-spec.test.js @@ -45,17 +45,8 @@ describe('Search with boost spec', () => { describe('Search with boost spec sample result', () => { const retailClient = new SearchServiceClient(); - - const projectNumber = process.env['GCLOUD_PROJECT']; - const request = { - placement: `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`, - query: 'Hoodie', - visitorId: '12345', - boostSpec: { - condition: '(colorFamilies: ANY("Blue"))', - boost: 0.0, - }, - }; + let projectId; + let request; const IResponseParams = { ISearchResult: 0, ISearchRequest: 1, @@ -64,6 +55,16 @@ describe('Search with boost spec', () => { let response = []; before(async () => { + projectId = await retailClient.getProjectId(); + request = { + placement: `projects/${projectId}/locations/global/catalogs/default_catalog/placements/default_search`, + query: 'Hoodie', + visitorId: '12345', + boostSpec: { + condition: '(colorFamilies: ANY("Blue"))', + boost: 0.0, + }, + }; response = await retailClient.search(request, {autoPaginate: false}); }); diff --git a/retail/interactive-tutorials/test/search-with-facet-spec.test.js b/retail/interactive-tutorials/test/search-with-facet-spec.test.js index 6f79d3fc5b..fcd8070192 100644 --- a/retail/interactive-tutorials/test/search-with-facet-spec.test.js +++ b/retail/interactive-tutorials/test/search-with-facet-spec.test.js @@ -45,14 +45,8 @@ describe('Search with facet spec', () => { describe('Search with facet spec result', () => { const retailClient = new SearchServiceClient(); - const projectNumber = process.env['GCLOUD_PROJECT']; - const request = { - placement: `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`, - query: 'Tee', - visitorId: '12345', - facetSpecs: [{facetKey: {key: 'colorFamilies'}}], - pageSize: 10, - }; + let projectId; + let request; const IResponseParams = { ISearchResult: 0, ISearchRequest: 1, @@ -61,6 +55,14 @@ describe('Search with facet spec', () => { let response = []; before(async () => { + projectId = await retailClient.getProjectId(); + request = { + placement: `projects/${projectId}/locations/global/catalogs/default_catalog/placements/default_search`, + query: 'Tee', + visitorId: '12345', + facetSpecs: [{facetKey: {key: 'colorFamilies'}}], + pageSize: 10, + }; response = await retailClient.search(request, {autoPaginate: false}); }); diff --git a/retail/interactive-tutorials/test/search-with-filtering.test.js b/retail/interactive-tutorials/test/search-with-filtering.test.js index 0aaa1b10ae..850c41c65b 100644 --- a/retail/interactive-tutorials/test/search-with-filtering.test.js +++ b/retail/interactive-tutorials/test/search-with-filtering.test.js @@ -45,13 +45,8 @@ describe('Search with filtering', () => { describe('Search with filtering sample result', () => { const retailClient = new SearchServiceClient(); - const projectNumber = process.env['GCLOUD_PROJECT']; - const request = { - placement: `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`, - query: 'Tee', - visitorId: '12345', - filter: '(colorFamilies: ANY("Black"))', - }; + let projectId; + let request; const IResponseParams = { ISearchResult: 0, ISearchRequest: 1, @@ -60,6 +55,13 @@ describe('Search with filtering', () => { let response = []; before(async () => { + projectId = await retailClient.getProjectId(); + request = { + placement: `projects/${projectId}/locations/global/catalogs/default_catalog/placements/default_search`, + query: 'Tee', + visitorId: '12345', + filter: '(colorFamilies: ANY("Black"))', + }; response = await retailClient.search(request, {autoPaginate: false}); }); diff --git a/retail/interactive-tutorials/test/search-with-ordering.test.js b/retail/interactive-tutorials/test/search-with-ordering.test.js index 4ddd6f0c0a..f05e8a49ab 100644 --- a/retail/interactive-tutorials/test/search-with-ordering.test.js +++ b/retail/interactive-tutorials/test/search-with-ordering.test.js @@ -45,13 +45,8 @@ describe('Search with ordering', () => { describe('Search with ordering sample result', () => { const retailClient = new SearchServiceClient(); - const projectNumber = process.env['GCLOUD_PROJECT']; - const request = { - placement: `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`, - query: 'Hoodie', - visitorId: '12345', - orderBy: 'price desc', - }; + let projectId; + let request; const IResponseParams = { ISearchResult: 0, ISearchRequest: 1, @@ -60,6 +55,13 @@ describe('Search with ordering', () => { let response = []; before(async () => { + projectId = await retailClient.getProjectId(); + request = { + placement: `projects/${projectId}/locations/global/catalogs/default_catalog/placements/default_search`, + query: 'Hoodie', + visitorId: '12345', + orderBy: 'price desc', + }; response = await retailClient.search(request, {autoPaginate: false}); }); diff --git a/retail/interactive-tutorials/test/search-with-pagination.test.js b/retail/interactive-tutorials/test/search-with-pagination.test.js index 59c1c24277..cb7166ca70 100644 --- a/retail/interactive-tutorials/test/search-with-pagination.test.js +++ b/retail/interactive-tutorials/test/search-with-pagination.test.js @@ -49,18 +49,11 @@ describe('Search with pagination', () => { describe('Search with pagination sample result', () => { const retailClient = new SearchServiceClient(); - const projectNumber = process.env['GCLOUD_PROJECT']; + let projectId; const pageSize = 2; const offset = 0; const pageToken = ''; - const request = { - placement: `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`, - query: 'Hoodie', - visitorId: '12345', - pageSize, - offset, - pageToken, - }; + let request; let response; const IResponseParams = { @@ -70,6 +63,15 @@ describe('Search with pagination', () => { }; before(async () => { + projectId = await retailClient.getProjectId(); + request = { + placement: `projects/${projectId}/locations/global/catalogs/default_catalog/placements/default_search`, + query: 'Hoodie', + visitorId: '12345', + pageSize, + offset, + pageToken, + }; response = await retailClient.search(request, {autoPaginate: false}); }); diff --git a/retail/interactive-tutorials/test/search-with-query-expansion-spec.test.js b/retail/interactive-tutorials/test/search-with-query-expansion-spec.test.js index 414523501d..2446b26345 100644 --- a/retail/interactive-tutorials/test/search-with-query-expansion-spec.test.js +++ b/retail/interactive-tutorials/test/search-with-query-expansion-spec.test.js @@ -47,16 +47,8 @@ describe('Search with query expansion spec', () => { describe('Search with query expansion spec sample result', () => { const retailClient = new SearchServiceClient(); - const projectNumber = process.env['GCLOUD_PROJECT']; - const request = { - placement: `projects/${projectNumber}/locations/global/catalogs/default_catalog/placements/default_search`, - query: 'Google Youth Hero Tee Grey', - visitorId: '12345', - queryExpansionSpec: { - condition: 'AUTO', - }, - pageSize: 10, - }; + let projectId; + let request; const IResponseParams = { ISearchResult: 0, ISearchRequest: 1, @@ -65,6 +57,16 @@ describe('Search with query expansion spec', () => { let response = []; before(async () => { + projectId = await retailClient.getProjectId(); + request = { + placement: `projects/${projectId}/locations/global/catalogs/default_catalog/placements/default_search`, + query: 'Google Youth Hero Tee Grey', + visitorId: '12345', + queryExpansionSpec: { + condition: 'AUTO', + }, + pageSize: 10, + }; response = await retailClient.search(request, {autoPaginate: false}); }); diff --git a/retail/interactive-tutorials/test/update-product.test.js b/retail/interactive-tutorials/test/update-product.test.js index 0f50ff290a..9035ccaf64 100644 --- a/retail/interactive-tutorials/test/update-product.test.js +++ b/retail/interactive-tutorials/test/update-product.test.js @@ -27,25 +27,29 @@ const cwd = path.join(__dirname, '..'); describe('Update product', () => { const retailClient = new ProductServiceClient(); const productId = Math.random().toString(36).slice(2).toUpperCase(); - const projectNumber = process.env['GCLOUD_PROJECT']; - const name = `projects/${projectNumber}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; - const product = { - productId, - name, - title: 'Updated Nest Mini', - type: 'PRIMARY', - categories: ['Updated Speakers and displays'], - brands: ['Updated Google'], - priceInfo: { - price: 20.0, - originalPrice: 25.5, - currencyCode: 'EUR', - }, - availability: 'OUT_OF_STOCK', - }; + let projectId; + let name; + let product; let stdout; before(async () => { + projectId = await retailClient.getProjectId(); + name = `projects/${projectId}/locations/global/catalogs/default_catalog/branches/default_branch/products/${productId}`; + product = { + productId, + name, + title: 'Updated Nest Mini', + type: 'PRIMARY', + categories: ['Updated Speakers and displays'], + brands: ['Updated Google'], + priceInfo: { + price: 20.0, + originalPrice: 25.5, + currencyCode: 'EUR', + }, + availability: 'OUT_OF_STOCK', + }; + stdout = execSync( `node interactive-tutorials/product/update-product.js ${productId}`, {cwd} From a705ca463c3f13ecfbe0f8422daa92c50632fb1f Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Wed, 23 Mar 2022 16:58:17 +0000 Subject: [PATCH 25/54] chore(main): release 1.6.1 (#158) :robot: I have created a release *beep* *boop* --- ### [1.6.1](https://github.com/googleapis/nodejs-retail/compare/v1.6.0...v1.6.1) (2022-03-15) ### Bug Fixes * remove gcloud_project env variable ([#156](https://github.com/googleapis/nodejs-retail/issues/156)) ([16cefb4](https://github.com/googleapis/nodejs-retail/commit/16cefb46e213f094daca8121bb09ec1e5c4da206)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index 77ebaa7428..909a04fcc7 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha" }, "dependencies": { - "@google-cloud/retail": "^1.6.0", + "@google-cloud/retail": "^1.6.1", "@google-cloud/bigquery": "^5.9.2", "@google-cloud/storage": "^5.16.1" }, From c20eab58c37d07f4d84f7e0acc7d57cec0d0c59e Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Mon, 4 Apr 2022 11:36:27 -0700 Subject: [PATCH 26/54] chore(main): release 1.7.0 (#161) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index 909a04fcc7..ebb5a52d18 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha" }, "dependencies": { - "@google-cloud/retail": "^1.6.1", + "@google-cloud/retail": "^1.7.0", "@google-cloud/bigquery": "^5.9.2", "@google-cloud/storage": "^5.16.1" }, From 5f6e987fc81ad987486fe50a26727f73423c94c8 Mon Sep 17 00:00:00 2001 From: t-karasova <91195610+t-karasova@users.noreply.github.com> Date: Fri, 8 Apr 2022 17:07:47 +0200 Subject: [PATCH 27/54] feat: Retail Tutorials. If create BQ table is requested, check if it exists and remove before creation (#157) * Update setup-cleanup.js * fix: change BQ table creation logic Co-authored-by: Karl Weinmeister <11586922+kweinmeister@users.noreply.github.com> Co-authored-by: tkarasyova --- .../setup/setup-cleanup.js | 35 ++++++++------- .../test/get-products-list.test.js | 43 ------------------- 2 files changed, 17 insertions(+), 61 deletions(-) delete mode 100644 retail/interactive-tutorials/test/get-products-list.test.js diff --git a/retail/interactive-tutorials/setup/setup-cleanup.js b/retail/interactive-tutorials/setup/setup-cleanup.js index 4889f429c9..b011993d81 100644 --- a/retail/interactive-tutorials/setup/setup-cleanup.js +++ b/retail/interactive-tutorials/setup/setup-cleanup.js @@ -231,26 +231,25 @@ const isTableExist = async (datasetId, tableId) => { const createBqTable = async (datasetId, tableId, schemaFile) => { if (await isTableExist(datasetId, tableId)) { - console.log(`Table ${tableId} already exists`); - return false; - } else { - const schemaFileData = fs.readFileSync(schemaFile); - const schema = JSON.parse(schemaFileData); - - const bigquery = new BigQuery(); - const options = { - schema: schema, - location: 'US', - }; + console.log(`Table ${tableId} exists and will be removed`); + await deleteBqTable(datasetId, tableId); + } + console.log(`Table name ${tableId} is unique for the dataset ${datasetId}`); + //Create a new table in the dataset + const schemaFileData = fs.readFileSync(schemaFile); + const schema = JSON.parse(schemaFileData); + const bigquery = new BigQuery(); + const options = { + schema: schema, + location: 'US', + }; - //Create a new table in the dataset - const [table] = await bigquery - .dataset(datasetId) - .createTable(tableId, options); + const [table] = await bigquery + .dataset(datasetId) + .createTable(tableId, options); - console.log(`Table ${table.id} created.`); - return true; - } + console.log(`Table ${table.id} created.`); + return true; }; const deleteBqTable = async (datasetId, tableId) => { diff --git a/retail/interactive-tutorials/test/get-products-list.test.js b/retail/interactive-tutorials/test/get-products-list.test.js deleted file mode 100644 index d2a8350322..0000000000 --- a/retail/interactive-tutorials/test/get-products-list.test.js +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2022 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -'use strict'; - -const path = require('path'); -const cp = require('child_process'); -const {before, describe, it} = require('mocha'); -const {assert} = require('chai'); - -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const cwd = path.join(__dirname, '..'); - -describe('Get products list', () => { - let stdout; - - before(async () => { - stdout = execSync( - 'node interactive-tutorials/product/get-products-list.js', - {cwd} - ); - }); - - it('should check that get products list started', () => { - assert.match(stdout, /Start get products list/); - }); - - it('should check that get product list finished', async () => { - assert.match(stdout, /Get products list finished/); - }); -}); From 72b74c769eef1acc637840a6573c2a7315e8e3fd Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Mon, 11 Apr 2022 16:31:05 -0400 Subject: [PATCH 28/54] chore(main): release 1.8.0 (#168) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index ebb5a52d18..332fa5e55d 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha" }, "dependencies": { - "@google-cloud/retail": "^1.7.0", + "@google-cloud/retail": "^1.8.0", "@google-cloud/bigquery": "^5.9.2", "@google-cloud/storage": "^5.16.1" }, From d0e6d707f7480d90cced711e901425a31c5d5fa2 Mon Sep 17 00:00:00 2001 From: t-karasova <91195610+t-karasova@users.noreply.github.com> Date: Wed, 13 Apr 2022 20:57:47 +0200 Subject: [PATCH 29/54] fix: read projectId from retailClient.getProjectId (#159) --- retail/interactive-tutorials/README.md | 4 +- .../product/delete-product.js | 2 +- .../setup/create-gcs-bucket.js | 7 ++- .../test/delete-product.test.js | 2 +- .../user_environment_setup.sh | 53 +++++++++++++++++++ .../user_import_data_to_catalog.sh | 33 ++++++++++++ 6 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 retail/interactive-tutorials/user_environment_setup.sh create mode 100644 retail/interactive-tutorials/user_import_data_to_catalog.sh diff --git a/retail/interactive-tutorials/README.md b/retail/interactive-tutorials/README.md index bb5332f61b..e4c91fe0f8 100644 --- a/retail/interactive-tutorials/README.md +++ b/retail/interactive-tutorials/README.md @@ -51,7 +51,7 @@ Because you are going to run the code samples in your own Google Cloud project, To install all the dependencies, run ``` -cd cloudshell_open/retail-search-nodejs-samples +cd cloudshell_open/nodejs-retail npm install ``` @@ -61,4 +61,4 @@ To execute an individual code sample, invoke `node` with a file as a parameter a ``` node search/search-simple-query.js -``` \ No newline at end of file +``` diff --git a/retail/interactive-tutorials/product/delete-product.js b/retail/interactive-tutorials/product/delete-product.js index 6965c0ea79..f70256a892 100644 --- a/retail/interactive-tutorials/product/delete-product.js +++ b/retail/interactive-tutorials/product/delete-product.js @@ -46,7 +46,7 @@ async function main(generatedProductId) { // Delete product console.log('Start deleting the product'); await callDeleteProduct(); - console.log(`Product ${product.id} deleted`); + console.log(`Product ${product.name} deleted`); // [END retail_delete_product] } diff --git a/retail/interactive-tutorials/setup/create-gcs-bucket.js b/retail/interactive-tutorials/setup/create-gcs-bucket.js index 6d5172ea79..93ef7f913c 100644 --- a/retail/interactive-tutorials/setup/create-gcs-bucket.js +++ b/retail/interactive-tutorials/setup/create-gcs-bucket.js @@ -17,8 +17,11 @@ async function main(generatedBucketName) { const utils = require('./setup-cleanup'); - //Get your project ID - const projectId = process.env['PROJECT_ID']; + // Instantiates a client. + const {ProductServiceClient} = require('@google-cloud/retail').v2; + const retailClient = new ProductServiceClient(); + + const projectId = await retailClient.getProjectId(); // The ID of your GCS bucket const bucketName = generatedBucketName diff --git a/retail/interactive-tutorials/test/delete-product.test.js b/retail/interactive-tutorials/test/delete-product.test.js index 77cb4dde06..d4f94fece3 100644 --- a/retail/interactive-tutorials/test/delete-product.test.js +++ b/retail/interactive-tutorials/test/delete-product.test.js @@ -51,7 +51,7 @@ describe('Delete product', () => { }); it('should check that product deleted', async () => { - const regex = new RegExp(`Product ${productId} deleted`, 'g'); + const regex = new RegExp(`Product .*${productId} deleted`, 'g'); assert.match(stdout, regex); }); diff --git a/retail/interactive-tutorials/user_environment_setup.sh b/retail/interactive-tutorials/user_environment_setup.sh new file mode 100644 index 0000000000..0eca5fbcc4 --- /dev/null +++ b/retail/interactive-tutorials/user_environment_setup.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +# Copyright 2022 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# set the Google Cloud Project ID +project_id=$1 +echo "Project ID: $project_id" +gcloud config set project "$project_id" + +timestamp=$(date +%s) + +service_account_id="service-acc-$timestamp" +echo "Service Account: $service_account_id" + +# create service account (your service-acc-$timestamp) +gcloud iam service-accounts create "$service_account_id" + +# assign necessary roles to your new service account +for role in {retail.admin,editor,bigquery.admin} + do + gcloud projects add-iam-policy-binding "$project_id" --member="serviceAccount:$service_account_id@$project_id.iam.gserviceaccount.com" --role=roles/"${role}" +done + +echo "Wait ~60 seconds to be sure the appropriate roles have been assigned to your service account" +sleep 60 + +# upload your service account key file +service_acc_email="$service_account_id@$project_id.iam.gserviceaccount.com" +gcloud iam service-accounts keys create ~/key.json --iam-account "$service_acc_email" + +# activate the service account using the key +gcloud auth activate-service-account --key-file ~/key.json + +# install needed Google client libraries +cd ~/cloudshell_open/nodejs-retail/samples || exit +npm install + +echo "=======================================" +echo "The Google Cloud setup is completed." +echo "Please proceed with the Tutorial steps" +echo "=======================================" diff --git a/retail/interactive-tutorials/user_import_data_to_catalog.sh b/retail/interactive-tutorials/user_import_data_to_catalog.sh new file mode 100644 index 0000000000..f7c00bcf12 --- /dev/null +++ b/retail/interactive-tutorials/user_import_data_to_catalog.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# Copyright 2022 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# set the key as GOOGLE_APPLICATION_CREDENTIALS +export GOOGLE_APPLICATION_CREDENTIALS=~/key.json + +# Create a GCS bucket and upload the product data to the bucket +output=$(node ~/cloudshell_open/nodejs-retail/samples/interactive-tutorials/setup/create-gcs-bucket.js) + +# Get the bucket name and store it in the env variable BUCKET_NAME +temp="${output#*Bucket }" +bucket_name="${temp% created*}" +export BUCKET_NAME=$bucket_name + +# Import products to the Retail catalog +node ~/cloudshell_open/nodejs-retail/samples/interactive-tutorials/product/import-products-gcs.js + +echo "=====================================" +echo "Your Retail catalog is ready to use!" +echo "=====================================" From df7df127142a2c2f43ca79e0f78c23e9e482150f Mon Sep 17 00:00:00 2001 From: t-karasova <91195610+t-karasova@users.noreply.github.com> Date: Thu, 21 Apr 2022 17:08:44 +0200 Subject: [PATCH 30/54] small fix in the script (#173) --- retail/interactive-tutorials/user_import_data_to_catalog.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/retail/interactive-tutorials/user_import_data_to_catalog.sh b/retail/interactive-tutorials/user_import_data_to_catalog.sh index f7c00bcf12..4d87f821f7 100644 --- a/retail/interactive-tutorials/user_import_data_to_catalog.sh +++ b/retail/interactive-tutorials/user_import_data_to_catalog.sh @@ -18,6 +18,7 @@ export GOOGLE_APPLICATION_CREDENTIALS=~/key.json # Create a GCS bucket and upload the product data to the bucket +cd ~/cloudshell_open/nodejs-retail/samples output=$(node ~/cloudshell_open/nodejs-retail/samples/interactive-tutorials/setup/create-gcs-bucket.js) # Get the bucket name and store it in the env variable BUCKET_NAME From a7caa4cb70dfdab08c22ca78fd97eef5046add03 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Fri, 6 May 2022 12:35:57 -0700 Subject: [PATCH 31/54] chore(main): release 1.8.1 (#170) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(main): release 1.8.1 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> Co-authored-by: Owl Bot --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index 332fa5e55d..487fd5b606 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha" }, "dependencies": { - "@google-cloud/retail": "^1.8.0", + "@google-cloud/retail": "^1.8.1", "@google-cloud/bigquery": "^5.9.2", "@google-cloud/storage": "^5.16.1" }, From 5a6188e318c030018270641f47c647945de51b38 Mon Sep 17 00:00:00 2001 From: sofisl <55454395+sofisl@users.noreply.github.com> Date: Fri, 20 May 2022 11:19:47 -0700 Subject: [PATCH 32/54] build!: update library to use Node 12 (#181) * build!: Update library to use Node 12 --- retail/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/retail/package.json b/retail/package.json index 487fd5b606..6ef964792e 100644 --- a/retail/package.json +++ b/retail/package.json @@ -4,7 +4,7 @@ "license": "Apache-2.0", "author": "Google LLC", "engines": { - "node": ">=10" + "node": ">=12.0.0" }, "files": [ "*.js" @@ -22,4 +22,4 @@ "chai": "^4.2.0", "mocha": "^8.0.0" } -} +} \ No newline at end of file From c338968fe36115513653d279e4c1084b7e03b7e3 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Mon, 20 Jun 2022 21:41:28 +0200 Subject: [PATCH 33/54] fix(deps): update dependency @google-cloud/bigquery to v6 (#186) --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index 6ef964792e..bff67a852d 100644 --- a/retail/package.json +++ b/retail/package.json @@ -14,7 +14,7 @@ }, "dependencies": { "@google-cloud/retail": "^1.8.1", - "@google-cloud/bigquery": "^5.9.2", + "@google-cloud/bigquery": "^6.0.0", "@google-cloud/storage": "^5.16.1" }, "devDependencies": { From 5efdd94d929870b1f15cf348d605c9ec3b16b699 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 30 Jun 2022 19:24:21 +0000 Subject: [PATCH 34/54] chore(main): release 2.0.0 (#184) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit :robot: I have created a release *beep* *boop* --- ## [2.0.0](https://github.com/googleapis/nodejs-retail/compare/v1.8.1...v2.0.0) (2022-06-20) ### ⚠ BREAKING CHANGES * update library to use Node 12 (#181) ### Features * allow users to disable spell check in search requests ([#183](https://github.com/googleapis/nodejs-retail/issues/183)) ([05005ea](https://github.com/googleapis/nodejs-retail/commit/05005ea09accff4d04b152f2fa2bf452f6b9768b)) ### Bug Fixes * **deps:** update dependency @google-cloud/bigquery to v6 ([#186](https://github.com/googleapis/nodejs-retail/issues/186)) ([fc07923](https://github.com/googleapis/nodejs-retail/commit/fc0792311aac235e917fe045fc491858408bd770)) ### Build System * update library to use Node 12 ([#181](https://github.com/googleapis/nodejs-retail/issues/181)) ([809853f](https://github.com/googleapis/nodejs-retail/commit/809853f84e0bfe0f09ccb59ca750963732e23965)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index bff67a852d..a9eef45378 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha" }, "dependencies": { - "@google-cloud/retail": "^1.8.1", + "@google-cloud/retail": "^2.0.0", "@google-cloud/bigquery": "^6.0.0", "@google-cloud/storage": "^5.16.1" }, From b63bd7a41c99539e85f02ffff59ec59891f394ca Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Mon, 4 Jul 2022 20:57:17 +0200 Subject: [PATCH 35/54] fix(deps): update dependency @google-cloud/storage to v6 (#185) Co-authored-by: Benjamin E. Coe --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index a9eef45378..0794a15e61 100644 --- a/retail/package.json +++ b/retail/package.json @@ -15,7 +15,7 @@ "dependencies": { "@google-cloud/retail": "^2.0.0", "@google-cloud/bigquery": "^6.0.0", - "@google-cloud/storage": "^5.16.1" + "@google-cloud/storage": "^6.0.0" }, "devDependencies": { "c8": "^7.1.0", From 6fcb5c48c4afe787650445c3bac9d10520c6fdd7 Mon Sep 17 00:00:00 2001 From: Arakel2811 <38522242+Arakel2811@users.noreply.github.com> Date: Thu, 28 Jul 2022 21:20:49 +0400 Subject: [PATCH 36/54] samples: bugfix-GRST-147-warn-user-about-fails-on-bucket-creation (#195) --- .../user_import_data_to_catalog.sh | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/retail/interactive-tutorials/user_import_data_to_catalog.sh b/retail/interactive-tutorials/user_import_data_to_catalog.sh index 4d87f821f7..21fbb900c6 100644 --- a/retail/interactive-tutorials/user_import_data_to_catalog.sh +++ b/retail/interactive-tutorials/user_import_data_to_catalog.sh @@ -15,20 +15,26 @@ # limitations under the License. # set the key as GOOGLE_APPLICATION_CREDENTIALS -export GOOGLE_APPLICATION_CREDENTIALS=~/key.json +{ + export GOOGLE_APPLICATION_CREDENTIALS=~/key.json -# Create a GCS bucket and upload the product data to the bucket -cd ~/cloudshell_open/nodejs-retail/samples -output=$(node ~/cloudshell_open/nodejs-retail/samples/interactive-tutorials/setup/create-gcs-bucket.js) + # Create a GCS bucket and upload the product data to the bucket + cd ~/cloudshell_open/nodejs-retail/samples + output=$(node ~/cloudshell_open/nodejs-retail/samples/interactive-tutorials/setup/create-gcs-bucket.js) -# Get the bucket name and store it in the env variable BUCKET_NAME -temp="${output#*Bucket }" -bucket_name="${temp% created*}" -export BUCKET_NAME=$bucket_name + # Get the bucket name and store it in the env variable BUCKET_NAME + temp="${output#*Bucket }" + bucket_name="${temp% created*}" + export BUCKET_NAME=$bucket_name -# Import products to the Retail catalog -node ~/cloudshell_open/nodejs-retail/samples/interactive-tutorials/product/import-products-gcs.js - -echo "=====================================" -echo "Your Retail catalog is ready to use!" -echo "=====================================" + # Import products to the Retail catalog + node ~/cloudshell_open/nodejs-retail/samples/interactive-tutorials/product/import-products-gcs.js +} && { + echo "=====================================" + echo "Your Retail catalog is ready to use!" + echo "=====================================" +} || { + echo "================================================================" + echo "Your Retail catalog wasn't created! Please fix the errors above!" + echo "================================================================" +} From 753cc1f38262f0fb07f8e7454acf03a82a91a50c Mon Sep 17 00:00:00 2001 From: Arakel2811 <38522242+Arakel2811@users.noreply.github.com> Date: Sat, 30 Jul 2022 01:10:26 +0400 Subject: [PATCH 37/54] samples: fixed number of failures during importing. (#198) Co-authored-by: Alexander Fenster --- retail/interactive-tutorials/setup/create-bigquery-table.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/interactive-tutorials/setup/create-bigquery-table.js b/retail/interactive-tutorials/setup/create-bigquery-table.js index 77990b35cf..7b185b727b 100644 --- a/retail/interactive-tutorials/setup/create-bigquery-table.js +++ b/retail/interactive-tutorials/setup/create-bigquery-table.js @@ -32,7 +32,7 @@ async function main() { await utils.createBqTable(dataset, invalidTable, schema); await utils.uploadDataToBqTable( dataset, - validTable, + invalidTable, invalidSourceFile, schema ); From 82ecff4696c25b644065e88ff8c464d1cc451df8 Mon Sep 17 00:00:00 2001 From: Arakel2811 <38522242+Arakel2811@users.noreply.github.com> Date: Tue, 2 Aug 2022 23:38:12 +0400 Subject: [PATCH 38/54] samples: properly catch errors (#197) * Fixed issues in some cases when user setting up environment. * fix: use bash trap Co-authored-by: Alexander Fenster --- .../user_environment_setup.sh | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/retail/interactive-tutorials/user_environment_setup.sh b/retail/interactive-tutorials/user_environment_setup.sh index 0eca5fbcc4..a48c1b56ca 100644 --- a/retail/interactive-tutorials/user_environment_setup.sh +++ b/retail/interactive-tutorials/user_environment_setup.sh @@ -1,5 +1,4 @@ #!/bin/bash - # Copyright 2022 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,28 +13,44 @@ # See the License for the specific language governing permissions and # limitations under the License. +success() { + echo "=========================================" + echo "The Google Cloud setup is completed." + echo "Please proceed with the Tutorial steps" + echo "=========================================" + exit 0 +} + +failure() { + echo "=========================================" + echo "The Google Cloud setup was not completed." + echo "Please fix the errors above!" + echo "=========================================" + exit 1 +} + +# catch any error that happened during execution +trap 'failure' ERR + # set the Google Cloud Project ID project_id=$1 echo "Project ID: $project_id" gcloud config set project "$project_id" timestamp=$(date +%s) - service_account_id="service-acc-$timestamp" echo "Service Account: $service_account_id" - # create service account (your service-acc-$timestamp) gcloud iam service-accounts create "$service_account_id" # assign necessary roles to your new service account for role in {retail.admin,editor,bigquery.admin} - do +do gcloud projects add-iam-policy-binding "$project_id" --member="serviceAccount:$service_account_id@$project_id.iam.gserviceaccount.com" --role=roles/"${role}" done echo "Wait ~60 seconds to be sure the appropriate roles have been assigned to your service account" sleep 60 - # upload your service account key file service_acc_email="$service_account_id@$project_id.iam.gserviceaccount.com" gcloud iam service-accounts keys create ~/key.json --iam-account "$service_acc_email" @@ -44,10 +59,5 @@ gcloud iam service-accounts keys create ~/key.json --iam-account "$service_acc_e gcloud auth activate-service-account --key-file ~/key.json # install needed Google client libraries -cd ~/cloudshell_open/nodejs-retail/samples || exit +cd ~/cloudshell_open/nodejs-retail/samples npm install - -echo "=======================================" -echo "The Google Cloud setup is completed." -echo "Please proceed with the Tutorial steps" -echo "=======================================" From 2bea9771ec245d1ad2a841af62bb3e3bb62c61cf Mon Sep 17 00:00:00 2001 From: Arakel2811 <38522242+Arakel2811@users.noreply.github.com> Date: Wed, 3 Aug 2022 01:14:13 +0400 Subject: [PATCH 39/54] samples: corrected eventTime update. (#200) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly: - [ ] Make sure to open an issue as a [bug/issue](https://github.com/googleapis/nodejs-retail/issues/new/choose) before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea - [ ] Ensure the tests and linter pass - [ ] Code coverage does not decrease (if any source code was changed) - [ ] Appropriate docs were updated (if necessary) Fixes # 🦕 --- .../setup/update-user-events-json.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/retail/interactive-tutorials/setup/update-user-events-json.js b/retail/interactive-tutorials/setup/update-user-events-json.js index b5e5936624..b3709608f4 100644 --- a/retail/interactive-tutorials/setup/update-user-events-json.js +++ b/retail/interactive-tutorials/setup/update-user-events-json.js @@ -23,8 +23,14 @@ async function main() { for (let i = 0; i < events.length - 1; ++i) { const event = JSON.parse(`[${events[i]}]`)[0]; - const date = new Date(event.eventTime); - date.setDate(date.getDate() - 1); + let date = new Date(event.eventTime); + const nowDate = new Date(); + const timeDiff = nowDate - date; + + if (timeDiff > 1000 * 60 * 60 * 24 * 90) { + const yesterday = nowDate - 1000 * 60 * 60 * 24; + date = new Date(yesterday); + } event.eventTime = date.toISOString(); changedEvents.push(JSON.stringify(event)); } @@ -37,6 +43,7 @@ async function main() { stream.write(item + '\n'); }); stream.close(); + console.log(`${filePath} is updated`); }; updateEventsTimestamp('resources/user_events.json'); From bf2e32636d571f6e7b34f61e5972c07787ca2676 Mon Sep 17 00:00:00 2001 From: Arakel2811 <38522242+Arakel2811@users.noreply.github.com> Date: Tue, 23 Aug 2022 19:22:17 +0400 Subject: [PATCH 40/54] =?UTF-8?q?samples:=20removed=20bigquery.admin=20fro?= =?UTF-8?q?m=20{retail.admin,editor,bigquery.admin}=20from=E2=80=A6=20(#20?= =?UTF-8?q?3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … user_environment_setup.sh file. Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly: - [ ] Make sure to open an issue as a [bug/issue](https://github.com/googleapis/nodejs-retail/issues/new/choose) before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea - [ ] Ensure the tests and linter pass - [ ] Code coverage does not decrease (if any source code was changed) - [ ] Appropriate docs were updated (if necessary) Fixes # 🦕 --- retail/interactive-tutorials/user_environment_setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/interactive-tutorials/user_environment_setup.sh b/retail/interactive-tutorials/user_environment_setup.sh index a48c1b56ca..9cbfa65bf7 100644 --- a/retail/interactive-tutorials/user_environment_setup.sh +++ b/retail/interactive-tutorials/user_environment_setup.sh @@ -44,7 +44,7 @@ echo "Service Account: $service_account_id" gcloud iam service-accounts create "$service_account_id" # assign necessary roles to your new service account -for role in {retail.admin,editor,bigquery.admin} +for role in {retail.admin,editor} do gcloud projects add-iam-policy-binding "$project_id" --member="serviceAccount:$service_account_id@$project_id.iam.gserviceaccount.com" --role=roles/"${role}" done From 7db53cb746a699b4ecc699fc889d9d56c1d488c6 Mon Sep 17 00:00:00 2001 From: Arakel2811 <38522242+Arakel2811@users.noreply.github.com> Date: Tue, 23 Aug 2022 20:50:17 +0400 Subject: [PATCH 41/54] samples: GRST-149 set inventory tutorial add created product detailed log (#202) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly: - [ ] Make sure to open an issue as a [bug/issue](https://github.com/googleapis/nodejs-retail/issues/new/choose) before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea - [ ] Ensure the tests and linter pass - [ ] Code coverage does not decrease (if any source code was changed) - [ ] Appropriate docs were updated (if necessary) Fixes # 🦕 --- retail/interactive-tutorials/setup/setup-cleanup.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/retail/interactive-tutorials/setup/setup-cleanup.js b/retail/interactive-tutorials/setup/setup-cleanup.js index b011993d81..745243f9ee 100644 --- a/retail/interactive-tutorials/setup/setup-cleanup.js +++ b/retail/interactive-tutorials/setup/setup-cleanup.js @@ -71,6 +71,16 @@ const createProduct = async ( // Run request const response = await retailClient.createProduct(request); console.log(`Product ${response[0].id} created`); + + const createdProduct = {}; + createdProduct.id = response[0].id; + createdProduct.name = response[0].name; + createdProduct.priceInfo = response[0].priceInfo; + createdProduct.fulfillmentInfo = response[0].fulfillmentInfo; + createdProduct.availableQuantity = response[0].availableQuantity; + createdProduct.availability = response[0].availability; + console.log('Created product: ', createdProduct); + return response[0]; }; From 98849be7f76236e4a19eb9292f6a1bf4bf4b4abd Mon Sep 17 00:00:00 2001 From: Arakel2811 <38522242+Arakel2811@users.noreply.github.com> Date: Wed, 24 Aug 2022 20:00:19 +0400 Subject: [PATCH 42/54] GRST 159 warn user about fails on user environment setup.sh (#201) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly: - [ ] Make sure to open an issue as a [bug/issue](https://github.com/googleapis/nodejs-retail/issues/new/choose) before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea - [ ] Ensure the tests and linter pass - [ ] Code coverage does not decrease (if any source code was changed) - [ ] Appropriate docs were updated (if necessary) Fixes # 🦕 --- retail/interactive-tutorials/user_environment_setup.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/retail/interactive-tutorials/user_environment_setup.sh b/retail/interactive-tutorials/user_environment_setup.sh index 9cbfa65bf7..9b7d823796 100644 --- a/retail/interactive-tutorials/user_environment_setup.sh +++ b/retail/interactive-tutorials/user_environment_setup.sh @@ -61,3 +61,4 @@ gcloud auth activate-service-account --key-file ~/key.json # install needed Google client libraries cd ~/cloudshell_open/nodejs-retail/samples npm install +'success' From 73550e004ced0b535098741cbdee57d9bf20119d Mon Sep 17 00:00:00 2001 From: Arakel2811 <38522242+Arakel2811@users.noreply.github.com> Date: Fri, 9 Sep 2022 09:13:51 +0400 Subject: [PATCH 43/54] samples: long running operations - removed delays, added correct logic (#209) * Removed delays from add-fulfillment-places.js, remove-fulfillment-places.js, set-inventory.js files. * Removed delays, added correct logic. * Code clean up. Co-authored-by: Alexander Fenster --- .../interactive-tutorials/product/add-fulfillment-places.js | 4 ++-- .../product/remove-fulfillment-places.js | 4 ++-- retail/interactive-tutorials/product/set-inventory.js | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/retail/interactive-tutorials/product/add-fulfillment-places.js b/retail/interactive-tutorials/product/add-fulfillment-places.js index dcb9972a96..97dbfc290a 100644 --- a/retail/interactive-tutorials/product/add-fulfillment-places.js +++ b/retail/interactive-tutorials/product/add-fulfillment-places.js @@ -66,7 +66,8 @@ async function main(generatedProductId) { console.log('Add fulfillment request:', request); // Run request - await retailClient.addFulfillmentPlaces(request); + const [operation] = await retailClient.addFulfillmentPlaces(request); + await operation.promise(); console.log('Waiting to complete add operation..'); }; @@ -74,7 +75,6 @@ async function main(generatedProductId) { // Add fulfillment places with current time console.log('Start add fulfillment'); await calladdFulfillmentPlaces(); - await utils.delay(180000); //Get product const response = await utils.getProduct(product); diff --git a/retail/interactive-tutorials/product/remove-fulfillment-places.js b/retail/interactive-tutorials/product/remove-fulfillment-places.js index 217a72b9ab..a6b3756f04 100644 --- a/retail/interactive-tutorials/product/remove-fulfillment-places.js +++ b/retail/interactive-tutorials/product/remove-fulfillment-places.js @@ -61,7 +61,8 @@ async function main(generatedProductId) { console.log('Remove fulfillment request:', request); // Run request - await retailClient.removeFulfillmentPlaces(request); + const [operation] = await retailClient.removeFulfillmentPlaces(request); + await operation.promise(); console.log('Waiting to complete remove operation..'); }; @@ -69,7 +70,6 @@ async function main(generatedProductId) { // Remove fulfillment places with current time console.log('Start remove fulfillment'); await callRemoveFulfillmentPlaces(); - await utils.delay(180000); //Get product const response = await utils.getProduct(product); diff --git a/retail/interactive-tutorials/product/set-inventory.js b/retail/interactive-tutorials/product/set-inventory.js index 1b849cebdc..79083cad8d 100644 --- a/retail/interactive-tutorials/product/set-inventory.js +++ b/retail/interactive-tutorials/product/set-inventory.js @@ -74,14 +74,14 @@ async function main(generatedProductId) { console.log('Set inventory request:', request); // Run request - await retailClient.setInventory(request); + const [operation] = await retailClient.setInventory(request); + await operation.promise(); console.log('Waiting to complete set inventory operation..'); }; // Set inventory with current time console.log('Start set inventory'); await callSetInventory(); - await utils.delay(200000); // Get product let changedProduct = await utils.getProduct(createdProduct.name); @@ -94,7 +94,6 @@ async function main(generatedProductId) { product.priceInfo.price = 20.0; setTime = {seconds: Math.round(Date.now() / 1000) - 86400}; await callSetInventory(); - await utils.delay(200000); // Get product changedProduct = await utils.getProduct(createdProduct.name); From a3e4a55c15323f8dce10f3df5908cff55d0e3ac4 Mon Sep 17 00:00:00 2001 From: Arakel2811 <38522242+Arakel2811@users.noreply.github.com> Date: Fri, 16 Sep 2022 23:10:27 +0400 Subject: [PATCH 44/54] samples: remove unused region tags (#212) --- .../interactive-tutorials/product/add-fulfillment-places.js | 3 --- retail/interactive-tutorials/product/create-product.js | 4 ---- retail/interactive-tutorials/product/crud-product.js | 3 --- retail/interactive-tutorials/product/delete-product.js | 3 --- retail/interactive-tutorials/product/get-product.js | 3 --- retail/interactive-tutorials/product/get-products-list.js | 3 --- .../product/import-products-big-query-table.js | 3 --- retail/interactive-tutorials/product/import-products-gcs.js | 3 --- .../product/import-products-inline-source.js | 3 --- .../product/remove-fulfillment-places.js | 3 --- retail/interactive-tutorials/product/set-inventory.js | 3 --- retail/interactive-tutorials/product/update-product.js | 4 ---- 12 files changed, 38 deletions(-) diff --git a/retail/interactive-tutorials/product/add-fulfillment-places.js b/retail/interactive-tutorials/product/add-fulfillment-places.js index 97dbfc290a..6a0187bce3 100644 --- a/retail/interactive-tutorials/product/add-fulfillment-places.js +++ b/retail/interactive-tutorials/product/add-fulfillment-places.js @@ -15,8 +15,6 @@ 'use strict'; async function main(generatedProductId) { - // [START retail_add_remove_fulfillment_places] - // Imports the Google Cloud client library. const {ProductServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); @@ -87,7 +85,6 @@ async function main(generatedProductId) { // Delete product await utils.deleteProduct(product); console.log(`Product ${createdProduct.id} deleted`); - // [END retail_add_remove_fulfillment_places] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/product/create-product.js b/retail/interactive-tutorials/product/create-product.js index 6823b29bbf..2673167cfd 100644 --- a/retail/interactive-tutorials/product/create-product.js +++ b/retail/interactive-tutorials/product/create-product.js @@ -15,8 +15,6 @@ 'use strict'; async function main(generatedProductId) { - // [START retail_create_product] - // Imports the Google Cloud client library. const {ProductServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); @@ -71,8 +69,6 @@ async function main(generatedProductId) { // Delete product await utils.deleteProduct(createdProduct.name); console.log(`Product ${createdProduct.id} deleted`); - - // [END retail_create_product] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/product/crud-product.js b/retail/interactive-tutorials/product/crud-product.js index bbf98d0110..eada4a5f6a 100644 --- a/retail/interactive-tutorials/product/crud-product.js +++ b/retail/interactive-tutorials/product/crud-product.js @@ -15,8 +15,6 @@ 'use strict'; async function main(generatedProductId) { - // [START retail_crud_product] - // Imports the Google Cloud client library. const {ProductServiceClient} = require('@google-cloud/retail').v2; @@ -144,7 +142,6 @@ async function main(generatedProductId) { await callDeleteProduct(); console.log(`Product ${createdProduct.id} deleted`); console.log('CRUD product finished'); - // [END retail_crud_product] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/product/delete-product.js b/retail/interactive-tutorials/product/delete-product.js index f70256a892..8d9a87be43 100644 --- a/retail/interactive-tutorials/product/delete-product.js +++ b/retail/interactive-tutorials/product/delete-product.js @@ -15,8 +15,6 @@ 'use strict'; async function main(generatedProductId) { - // [START retail_delete_product] - // Imports the Google Cloud client library. const {ProductServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); @@ -47,7 +45,6 @@ async function main(generatedProductId) { console.log('Start deleting the product'); await callDeleteProduct(); console.log(`Product ${product.name} deleted`); - // [END retail_delete_product] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/product/get-product.js b/retail/interactive-tutorials/product/get-product.js index d9ae491326..5b9d8b0961 100644 --- a/retail/interactive-tutorials/product/get-product.js +++ b/retail/interactive-tutorials/product/get-product.js @@ -15,8 +15,6 @@ 'use strict'; async function main(generatedProductId) { - // [START retail_get_product] - // Imports the Google Cloud client library. const {ProductServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); @@ -54,7 +52,6 @@ async function main(generatedProductId) { // Delete product await utils.deleteProduct(name); console.log(`Product ${foundProduct.id} deleted`); - // [END retail_get_product] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/product/get-products-list.js b/retail/interactive-tutorials/product/get-products-list.js index 63317a0558..fae5634f62 100644 --- a/retail/interactive-tutorials/product/get-products-list.js +++ b/retail/interactive-tutorials/product/get-products-list.js @@ -15,8 +15,6 @@ 'use strict'; async function main() { - // [START retail_get_products_list] - // Imports the Google Cloud client library. const {ProductServiceClient} = require('@google-cloud/retail').v2; @@ -45,7 +43,6 @@ async function main() { } callListProducts(); - // [END retail_get_products_list] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/product/import-products-big-query-table.js b/retail/interactive-tutorials/product/import-products-big-query-table.js index 527240462c..1bb9944cf4 100644 --- a/retail/interactive-tutorials/product/import-products-big-query-table.js +++ b/retail/interactive-tutorials/product/import-products-big-query-table.js @@ -15,8 +15,6 @@ 'use strict'; async function main() { - // [START retail_import_products_from_big_query] - // Imports the Google Cloud client library. const {ProductServiceClient} = require('@google-cloud/retail').v2; @@ -82,7 +80,6 @@ async function main() { console.log('Start import products'); await callImportProducts(); console.log('Import products finished'); - // [END retail_import_products_from_big_query] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/product/import-products-gcs.js b/retail/interactive-tutorials/product/import-products-gcs.js index e07e9ee7db..4b6b4b4ea0 100644 --- a/retail/interactive-tutorials/product/import-products-gcs.js +++ b/retail/interactive-tutorials/product/import-products-gcs.js @@ -15,8 +15,6 @@ 'use strict'; async function main(bucketName) { - // [START retail_import_products_from_gcs] - // Imports the Google Cloud client library. const {ProductServiceClient} = require('@google-cloud/retail').v2; @@ -75,7 +73,6 @@ async function main(bucketName) { console.log('Start import products'); await callImportProducts(); console.log('Import products finished'); - // [END retail_import_products_from_gcs] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/product/import-products-inline-source.js b/retail/interactive-tutorials/product/import-products-inline-source.js index 4dea2f0b76..dcdcf86c14 100644 --- a/retail/interactive-tutorials/product/import-products-inline-source.js +++ b/retail/interactive-tutorials/product/import-products-inline-source.js @@ -15,8 +15,6 @@ 'use strict'; async function main(id1, id2) { - // [START retail_import_products_from_inline_source] - // Imports the Google Cloud client library. const {ProductServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); @@ -120,7 +118,6 @@ async function main(id1, id2) { // Delete imported products await utils.deleteProductsByIds(projectId, [product1.id, product2.id]); console.log('Products deleted'); - // [END retail_import_products_from_inline_source] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/product/remove-fulfillment-places.js b/retail/interactive-tutorials/product/remove-fulfillment-places.js index a6b3756f04..c58c2eee9a 100644 --- a/retail/interactive-tutorials/product/remove-fulfillment-places.js +++ b/retail/interactive-tutorials/product/remove-fulfillment-places.js @@ -15,8 +15,6 @@ 'use strict'; async function main(generatedProductId) { - // [START retail_remove_fulfillment_places] - // Imports the Google Cloud client library. const {ProductServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); @@ -82,7 +80,6 @@ async function main(generatedProductId) { // Delete product await utils.deleteProduct(product); console.log(`Product ${createdProduct.id} deleted`); - // [END retail_remove_fulfillment_places] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/product/set-inventory.js b/retail/interactive-tutorials/product/set-inventory.js index 79083cad8d..749ea2378f 100644 --- a/retail/interactive-tutorials/product/set-inventory.js +++ b/retail/interactive-tutorials/product/set-inventory.js @@ -15,8 +15,6 @@ 'use strict'; async function main(generatedProductId) { - // [START retail_set_inventory] - // Imports the Google Cloud client library. const {ProductServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); @@ -106,7 +104,6 @@ async function main(generatedProductId) { // Delete product await utils.deleteProduct(createdProduct.name); console.log(`Product ${createdProduct.id} deleted`); - // [END retail_set_inventory] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/product/update-product.js b/retail/interactive-tutorials/product/update-product.js index dd309d50e8..75c62d8bb0 100644 --- a/retail/interactive-tutorials/product/update-product.js +++ b/retail/interactive-tutorials/product/update-product.js @@ -15,8 +15,6 @@ 'use strict'; async function main(generatedProductId) { - // [START retail_update_product] - // Imports the Google Cloud client library. const {ProductServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); @@ -79,8 +77,6 @@ async function main(generatedProductId) { // Delete product await utils.deleteProduct(updatedProduct.name); console.log(`Product ${updatedProduct.id} deleted`); - - // [END retail_update_product] } process.on('unhandledRejection', err => { From 436240ef2a8f1e2fcb54bc568099fd8414945998 Mon Sep 17 00:00:00 2001 From: Arakel2811 <38522242+Arakel2811@users.noreply.github.com> Date: Fri, 16 Sep 2022 23:19:50 +0400 Subject: [PATCH 45/54] samples(tests): removed unused times. (#211) Co-authored-by: Benjamin E. Coe --- .../interactive-tutorials/product/add-fulfillment-places.js | 4 ---- .../product/remove-fulfillment-places.js | 4 ---- retail/interactive-tutorials/product/set-inventory.js | 5 ----- 3 files changed, 13 deletions(-) diff --git a/retail/interactive-tutorials/product/add-fulfillment-places.js b/retail/interactive-tutorials/product/add-fulfillment-places.js index 6a0187bce3..c92637a73d 100644 --- a/retail/interactive-tutorials/product/add-fulfillment-places.js +++ b/retail/interactive-tutorials/product/add-fulfillment-places.js @@ -43,9 +43,6 @@ async function main(generatedProductId) { // The time when the fulfillment updates are issued, used to prevent // out-of-order updates on fulfillment information. - const addTime = { - seconds: Math.round(Date.now() / 1000), - }; //If set to true, and the product is not found, the fulfillment information will still be processed and retained for // at most 1 day and processed once the product is created @@ -57,7 +54,6 @@ async function main(generatedProductId) { product, type, placeIds, - addTime, allowMissing, }; diff --git a/retail/interactive-tutorials/product/remove-fulfillment-places.js b/retail/interactive-tutorials/product/remove-fulfillment-places.js index c58c2eee9a..8264fcceac 100644 --- a/retail/interactive-tutorials/product/remove-fulfillment-places.js +++ b/retail/interactive-tutorials/product/remove-fulfillment-places.js @@ -44,9 +44,6 @@ async function main(generatedProductId) { // The time when the fulfillment updates are issued, used to prevent // out-of-order updates on fulfillment information. - const removeTime = { - seconds: Math.round(Date.now() / 1000), - }; const callRemoveFulfillmentPlaces = async () => { // Construct request @@ -54,7 +51,6 @@ async function main(generatedProductId) { product, type, placeIds, - removeTime, }; console.log('Remove fulfillment request:', request); diff --git a/retail/interactive-tutorials/product/set-inventory.js b/retail/interactive-tutorials/product/set-inventory.js index 749ea2378f..8f14f14ddb 100644 --- a/retail/interactive-tutorials/product/set-inventory.js +++ b/retail/interactive-tutorials/product/set-inventory.js @@ -54,9 +54,6 @@ async function main(generatedProductId) { // The time when the request is issued, used to prevent // out-of-order updates on inventory fields with the last update time recorded. - let setTime = { - seconds: Math.round(Date.now() / 1000), - }; // If set to true, and the product with name is not found, the // inventory update will still be processed and retained for at most 1 day until the product is created @@ -66,7 +63,6 @@ async function main(generatedProductId) { // Construct request const request = { inventory: product, - setTime, allowMissing, }; console.log('Set inventory request:', request); @@ -90,7 +86,6 @@ async function main(generatedProductId) { // Set inventory with outdated time product.priceInfo.price = 20.0; - setTime = {seconds: Math.round(Date.now() / 1000) - 86400}; await callSetInventory(); // Get product From 49533bbc43aa8c3436768cc7cfa283a46a009b82 Mon Sep 17 00:00:00 2001 From: Arakel2811 <38522242+Arakel2811@users.noreply.github.com> Date: Sat, 17 Sep 2022 00:14:43 +0400 Subject: [PATCH 46/54] samples: environment setup twice error. (#213) --- .../user_environment_setup.sh | 50 ++++++++++++++----- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/retail/interactive-tutorials/user_environment_setup.sh b/retail/interactive-tutorials/user_environment_setup.sh index 9b7d823796..145e97933b 100644 --- a/retail/interactive-tutorials/user_environment_setup.sh +++ b/retail/interactive-tutorials/user_environment_setup.sh @@ -37,20 +37,46 @@ project_id=$1 echo "Project ID: $project_id" gcloud config set project "$project_id" -timestamp=$(date +%s) -service_account_id="service-acc-$timestamp" -echo "Service Account: $service_account_id" -# create service account (your service-acc-$timestamp) -gcloud iam service-accounts create "$service_account_id" +email=$(gcloud auth list --filter="status:ACTIVE account:$project_id.iam.gserviceaccount.com" --format="value(account)") +echo $email -# assign necessary roles to your new service account -for role in {retail.admin,editor} -do - gcloud projects add-iam-policy-binding "$project_id" --member="serviceAccount:$service_account_id@$project_id.iam.gserviceaccount.com" --role=roles/"${role}" -done +# check if user has service account active +if [ -z "$email" ] +then + # create a new service account + timestamp=$(date +%s) + service_account_id="service-acc-$timestamp" + echo "Service Account: $service_account_id" + gcloud iam service-accounts create "$service_account_id" +else + service_account_id="${email%@*}" + # log out of service account + gcloud auth revoke 2>/dev/null +fi +echo "$service_account_id" + +editor=$(gcloud projects get-iam-policy $project_id \ +--flatten="bindings[].members" \ +--format='table(bindings.role)' \ +--filter="bindings.members:$service_account_id ROLE=roles/editor") + +retail_admin=$(gcloud projects get-iam-policy $project_id \ +--flatten="bindings[].members" \ +--format='table(bindings.role)' \ +--filter="bindings.members:$service_account_id ROLE=roles/retail.admin") + +# check if any of the needed roles is missing +if [ -z "$editor" ] || [ -z "$retail_admin" ] +then + # assign necessary roles to your new service account. + for role in {retail.admin,editor} + do + gcloud projects add-iam-policy-binding "$project_id" --member="serviceAccount:$service_account_id@$project_id.iam.gserviceaccount.com" --role=roles/"${role}" + done + echo "Wait ~60 seconds to be sure the appropriate roles have been assigned to your service account" + sleep 60 +fi -echo "Wait ~60 seconds to be sure the appropriate roles have been assigned to your service account" -sleep 60 # upload your service account key file service_acc_email="$service_account_id@$project_id.iam.gserviceaccount.com" gcloud iam service-accounts keys create ~/key.json --iam-account "$service_acc_email" From aaec045354cda1629d4439d2d9e19f95ea0841b3 Mon Sep 17 00:00:00 2001 From: Arakel2811 <38522242+Arakel2811@users.noreply.github.com> Date: Tue, 20 Sep 2022 19:08:53 +0400 Subject: [PATCH 47/54] samples: improved massage in case of an empty search result (#214) --- .../search/search-simple-query.js | 6 +++++- .../search/search-with-boost-spec.js | 6 +++++- .../search/search-with-facet-spec.js | 6 +++++- .../search/search-with-filtering.js | 6 +++++- .../search/search-with-ordering.js | 6 +++++- .../search/search-with-pagination.js | 16 ++++++++++------ .../search/search-with-query-expansion-spec.js | 6 +++++- 7 files changed, 40 insertions(+), 12 deletions(-) diff --git a/retail/interactive-tutorials/search/search-simple-query.js b/retail/interactive-tutorials/search/search-simple-query.js index ae56a8616c..393f7ab78f 100644 --- a/retail/interactive-tutorials/search/search-simple-query.js +++ b/retail/interactive-tutorials/search/search-simple-query.js @@ -60,7 +60,11 @@ async function main() { autoPaginate: false, }); const searchResponse = response[IResponseParams.ISearchResponse]; - console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); + if (searchResponse.totalSize === 0) { + console.log('The search operation returned no matching results.'); + } else { + console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); + } console.log('Search end'); }; diff --git a/retail/interactive-tutorials/search/search-with-boost-spec.js b/retail/interactive-tutorials/search/search-with-boost-spec.js index 6021635ff0..64c5c812fe 100644 --- a/retail/interactive-tutorials/search/search-with-boost-spec.js +++ b/retail/interactive-tutorials/search/search-with-boost-spec.js @@ -73,7 +73,11 @@ async function main() { autoPaginate: false, }); const searchResponse = response[IResponseParams.ISearchResponse]; - console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); + if (searchResponse.totalSize === 0) { + console.log('The search operation returned no matching results.'); + } else { + console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); + } console.log('Search end'); }; diff --git a/retail/interactive-tutorials/search/search-with-facet-spec.js b/retail/interactive-tutorials/search/search-with-facet-spec.js index 3fcac810d0..c07e7dbda1 100644 --- a/retail/interactive-tutorials/search/search-with-facet-spec.js +++ b/retail/interactive-tutorials/search/search-with-facet-spec.js @@ -64,7 +64,11 @@ async function main() { autoPaginate: false, }); const searchResponse = response[IResponseParams.ISearchResponse]; - console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); + if (searchResponse.totalSize === 0) { + console.log('The search operation returned no matching results.'); + } else { + console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); + } console.log('Search end'); }; diff --git a/retail/interactive-tutorials/search/search-with-filtering.js b/retail/interactive-tutorials/search/search-with-filtering.js index c3d45108ad..a357ff3019 100644 --- a/retail/interactive-tutorials/search/search-with-filtering.js +++ b/retail/interactive-tutorials/search/search-with-filtering.js @@ -66,7 +66,11 @@ async function main() { autoPaginate: false, }); const searchResponse = response[IResponseParams.ISearchResponse]; - console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); + if (searchResponse.totalSize === 0) { + console.log('The search operation returned no matching results.'); + } else { + console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); + } console.log('Search end'); }; diff --git a/retail/interactive-tutorials/search/search-with-ordering.js b/retail/interactive-tutorials/search/search-with-ordering.js index d179f29480..53e55a3e28 100644 --- a/retail/interactive-tutorials/search/search-with-ordering.js +++ b/retail/interactive-tutorials/search/search-with-ordering.js @@ -65,7 +65,11 @@ async function main() { autoPaginate: false, }); const searchResponse = response[IResponseParams.ISearchResponse]; - console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); + if (searchResponse.totalSize === 0) { + console.log('The search operation returned no matching results.'); + } else { + console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); + } console.log('Search end'); }; diff --git a/retail/interactive-tutorials/search/search-with-pagination.js b/retail/interactive-tutorials/search/search-with-pagination.js index 7a153302d5..cd6f79b272 100644 --- a/retail/interactive-tutorials/search/search-with-pagination.js +++ b/retail/interactive-tutorials/search/search-with-pagination.js @@ -66,12 +66,16 @@ async function main() { autoPaginate: false, }); const searchResponse = response[IResponseParams.ISearchResponse]; - console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); - pageToken = response[IResponseParams.ISearchResponse].nextPageToken; - console.log( - 'Next page token:', - response[IResponseParams.ISearchResponse].nextPageToken - ); + if (searchResponse.totalSize === 0) { + console.log('The search operation returned no matching results.'); + } else { + console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); + pageToken = response[IResponseParams.ISearchResponse].nextPageToken; + console.log( + 'Next page token:', + response[IResponseParams.ISearchResponse].nextPageToken + ); + } console.log('Search end'); }; diff --git a/retail/interactive-tutorials/search/search-with-query-expansion-spec.js b/retail/interactive-tutorials/search/search-with-query-expansion-spec.js index e5bc7d659d..0492b16325 100644 --- a/retail/interactive-tutorials/search/search-with-query-expansion-spec.js +++ b/retail/interactive-tutorials/search/search-with-query-expansion-spec.js @@ -67,7 +67,11 @@ async function main() { autoPaginate: false, }); const searchResponse = response[IResponseParams.ISearchResponse]; - console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); + if (searchResponse.totalSize === 0) { + console.log('The search operation returned no matching results.'); + } else { + console.log('Search result: ', JSON.stringify(searchResponse, null, 4)); + } console.log('Search end'); }; From c09774d2c87e41633fca1adc8df7a3bf20788cfb Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 20 Sep 2022 15:55:58 -0700 Subject: [PATCH 48/54] feat: Model Services, BatchRemoveCatalogAttributes, ExactSearchableOption MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: release Model Services to v2beta version feat: release BatchRemoveCatalogAttributes API to v2beta version feat: release ExactSearchableOption for attribute config to v2beta version feat: release diversity_type for ServingConfig in v2beta version feat: add local inventories info to the Product resource feat: deprecate unused page_token field of PredictionRequest in v2beta version feat: deprecate unused facet_spec field of Control in v2beta version docs: improve documentation of SearchRequest for Search Personalization docs: improve documentation for Fullfillment and Inventory API in ProductService docs: minor documentation fixes and improvements PiperOrigin-RevId: 471846764 Source-Link: https://github.com/googleapis/googleapis/commit/15132940942b0c70083f9c7f6e0bf722fe620a8d Source-Link: https://github.com/googleapis/googleapis-gen/commit/c371ea8df2e34940875d51200cd57e300a2bc0a8 Copy-Tag: eyJwIjoiLmdpdGh1Yi8uT3dsQm90LnlhbWwiLCJoIjoiYzM3MWVhOGRmMmUzNDk0MDg3NWQ1MTIwMGNkNTdlMzAwYTJiYzBhOCJ9 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * chore: use gapic-generator-typescript v2.17.0 PiperOrigin-RevId: 474338479 Source-Link: https://github.com/googleapis/googleapis/commit/d5d35e0353b59719e8917103b1bc7df2782bf6ba Source-Link: https://github.com/googleapis/googleapis-gen/commit/efcd3f93962a103f68f003e2a1eecde6fa216a27 Copy-Tag: eyJwIjoiLmdpdGh1Yi8uT3dsQm90LnlhbWwiLCJoIjoiZWZjZDNmOTM5NjJhMTAzZjY4ZjAwM2UyYTFlZWNkZTZmYTIxNmEyNyJ9 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * Update search-simple-query.test.js * Update search-with-boost-spec.test.js * Update search-with-facet-spec.test.js * Update search-with-filtering.test.js * Update search-with-ordering.test.js * Update search-with-pagination.test.js * Update search-with-query-expansion-spec.test.js * Update search-simple-query.test.js * Update search-with-boost-spec.test.js * Update search-with-facet-spec.test.js * Update search-with-filtering.test.js * Update search-with-ordering.test.js * Update search-with-pagination.test.js * Update search-with-query-expansion-spec.test.js Co-authored-by: Owl Bot Co-authored-by: sofisl <55454395+sofisl@users.noreply.github.com> --- retail/interactive-tutorials/test/search-simple-query.test.js | 1 + retail/interactive-tutorials/test/search-with-boost-spec.test.js | 1 + retail/interactive-tutorials/test/search-with-facet-spec.test.js | 1 + retail/interactive-tutorials/test/search-with-filtering.test.js | 1 + retail/interactive-tutorials/test/search-with-ordering.test.js | 1 + retail/interactive-tutorials/test/search-with-pagination.test.js | 1 + .../test/search-with-query-expansion-spec.test.js | 1 + 7 files changed, 7 insertions(+) diff --git a/retail/interactive-tutorials/test/search-simple-query.test.js b/retail/interactive-tutorials/test/search-simple-query.test.js index 9b54fcb977..4929883e23 100644 --- a/retail/interactive-tutorials/test/search-simple-query.test.js +++ b/retail/interactive-tutorials/test/search-simple-query.test.js @@ -81,6 +81,7 @@ describe('Search simple query', () => { 'variantRollupValues', 'id', 'product', + 'personalLabels', 'matchingVariantCount' ); }); diff --git a/retail/interactive-tutorials/test/search-with-boost-spec.test.js b/retail/interactive-tutorials/test/search-with-boost-spec.test.js index 5d741d3bbd..d3d7ead8bc 100644 --- a/retail/interactive-tutorials/test/search-with-boost-spec.test.js +++ b/retail/interactive-tutorials/test/search-with-boost-spec.test.js @@ -85,6 +85,7 @@ describe('Search with boost spec', () => { 'variantRollupValues', 'id', 'product', + 'personalLabels', 'matchingVariantCount' ); }); diff --git a/retail/interactive-tutorials/test/search-with-facet-spec.test.js b/retail/interactive-tutorials/test/search-with-facet-spec.test.js index fcd8070192..9f4a7450ae 100644 --- a/retail/interactive-tutorials/test/search-with-facet-spec.test.js +++ b/retail/interactive-tutorials/test/search-with-facet-spec.test.js @@ -83,6 +83,7 @@ describe('Search with facet spec', () => { 'variantRollupValues', 'id', 'product', + 'personalLabels', 'matchingVariantCount' ); }); diff --git a/retail/interactive-tutorials/test/search-with-filtering.test.js b/retail/interactive-tutorials/test/search-with-filtering.test.js index 850c41c65b..c950a82a7d 100644 --- a/retail/interactive-tutorials/test/search-with-filtering.test.js +++ b/retail/interactive-tutorials/test/search-with-filtering.test.js @@ -82,6 +82,7 @@ describe('Search with filtering', () => { 'variantRollupValues', 'id', 'product', + 'personalLabels', 'matchingVariantCount' ); }); diff --git a/retail/interactive-tutorials/test/search-with-ordering.test.js b/retail/interactive-tutorials/test/search-with-ordering.test.js index f05e8a49ab..8bb72b4e35 100644 --- a/retail/interactive-tutorials/test/search-with-ordering.test.js +++ b/retail/interactive-tutorials/test/search-with-ordering.test.js @@ -82,6 +82,7 @@ describe('Search with ordering', () => { 'variantRollupValues', 'id', 'product', + 'personalLabels', 'matchingVariantCount' ); }); diff --git a/retail/interactive-tutorials/test/search-with-pagination.test.js b/retail/interactive-tutorials/test/search-with-pagination.test.js index cb7166ca70..bf62bf3265 100644 --- a/retail/interactive-tutorials/test/search-with-pagination.test.js +++ b/retail/interactive-tutorials/test/search-with-pagination.test.js @@ -92,6 +92,7 @@ describe('Search with pagination', () => { 'variantRollupValues', 'id', 'product', + 'personalLabels', 'matchingVariantCount' ); }); diff --git a/retail/interactive-tutorials/test/search-with-query-expansion-spec.test.js b/retail/interactive-tutorials/test/search-with-query-expansion-spec.test.js index 2446b26345..bf59ca0495 100644 --- a/retail/interactive-tutorials/test/search-with-query-expansion-spec.test.js +++ b/retail/interactive-tutorials/test/search-with-query-expansion-spec.test.js @@ -87,6 +87,7 @@ describe('Search with query expansion spec', () => { 'variantRollupValues', 'id', 'product', + 'personalLabels', 'matchingVariantCount' ); }); From 73c064bed9fad5011b8b297d0552f20c57a5e3db Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 20 Sep 2022 16:51:17 -0700 Subject: [PATCH 49/54] chore(main): release 2.1.0 (#193) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(main): release 2.1.0 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> Co-authored-by: Owl Bot --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index 0794a15e61..a1e9c64d61 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha" }, "dependencies": { - "@google-cloud/retail": "^2.0.0", + "@google-cloud/retail": "^2.1.0", "@google-cloud/bigquery": "^6.0.0", "@google-cloud/storage": "^6.0.0" }, From 439ee1f09e3d89f85e8d0d9812c9b1af7a95b8cf Mon Sep 17 00:00:00 2001 From: Arakel2811 <38522242+Arakel2811@users.noreply.github.com> Date: Fri, 23 Sep 2022 18:27:58 +0400 Subject: [PATCH 50/54] samples: moved console.log placements in add/remove fulfillment and set inventory. (#215) --- .../product/add-fulfillment-places.js | 16 ++++++------ .../product/remove-fulfillment-places.js | 14 +++++----- .../product/set-inventory.js | 26 +++++++------------ 3 files changed, 24 insertions(+), 32 deletions(-) diff --git a/retail/interactive-tutorials/product/add-fulfillment-places.js b/retail/interactive-tutorials/product/add-fulfillment-places.js index c92637a73d..edb138f3d0 100644 --- a/retail/interactive-tutorials/product/add-fulfillment-places.js +++ b/retail/interactive-tutorials/product/add-fulfillment-places.js @@ -27,23 +27,21 @@ async function main(generatedProductId) { // Create product const createdProduct = await utils.createProduct( projectId, - generatedProductId + generatedProductId, + true ); // Full resource name of Product const product = createdProduct.name; // The fulfillment type, including commonly used types (such as - // pickup in store and same day delivery), and custom types. + // pickup in store and same-day delivery), and custom types. const type = 'same-day-delivery'; // The IDs for this type, such as the store IDs for "pickup-in-store" or the region IDs for // "same-day-delivery" to be added for this type. const placeIds = ['store1', 'store2', 'store3']; - // The time when the fulfillment updates are issued, used to prevent - // out-of-order updates on fulfillment information. - //If set to true, and the product is not found, the fulfillment information will still be processed and retained for // at most 1 day and processed once the product is created const allowMissing = true; @@ -57,16 +55,18 @@ async function main(generatedProductId) { allowMissing, }; + // To send an out-of-order request assign the invalid addTime here: + // request.addTime = {seconds: Math.round(Date.now() / 1000) - 86400}; + console.log('Add fulfillment request:', request); + console.log('Waiting to complete add operation...'); // Run request const [operation] = await retailClient.addFulfillmentPlaces(request); await operation.promise(); - - console.log('Waiting to complete add operation..'); }; - // Add fulfillment places with current time + // Add fulfillment places console.log('Start add fulfillment'); await calladdFulfillmentPlaces(); diff --git a/retail/interactive-tutorials/product/remove-fulfillment-places.js b/retail/interactive-tutorials/product/remove-fulfillment-places.js index 8264fcceac..75adf40bbe 100644 --- a/retail/interactive-tutorials/product/remove-fulfillment-places.js +++ b/retail/interactive-tutorials/product/remove-fulfillment-places.js @@ -35,16 +35,13 @@ async function main(generatedProductId) { const product = createdProduct.name; // The fulfillment type, including commonly used types (such as - // pickup in store and same day delivery), and custom types. + // pickup in store and same-day delivery), and custom types. const type = 'same-day-delivery'; // The IDs for this type, such as the store IDs for "pickup-in-store" or the region IDs for // "same-day-delivery" to be added for this type. const placeIds = ['store1']; - // The time when the fulfillment updates are issued, used to prevent - // out-of-order updates on fulfillment information. - const callRemoveFulfillmentPlaces = async () => { // Construct request const request = { @@ -53,15 +50,18 @@ async function main(generatedProductId) { placeIds, }; + // To send an out-of-order request assign the invalid removeTime here: + // request.removeTime = {seconds: Math.round(Date.now() / 1000) - 86400}; + console.log('Remove fulfillment request:', request); + console.log('Waiting to complete remove operation...'); + // Run request const [operation] = await retailClient.removeFulfillmentPlaces(request); await operation.promise(); - - console.log('Waiting to complete remove operation..'); }; - // Remove fulfillment places with current time + // Remove fulfillment places console.log('Start remove fulfillment'); await callRemoveFulfillmentPlaces(); diff --git a/retail/interactive-tutorials/product/set-inventory.js b/retail/interactive-tutorials/product/set-inventory.js index 8f14f14ddb..f8e1295504 100644 --- a/retail/interactive-tutorials/product/set-inventory.js +++ b/retail/interactive-tutorials/product/set-inventory.js @@ -27,7 +27,8 @@ async function main(generatedProductId) { // Create product const createdProduct = await utils.createProduct( projectId, - generatedProductId + generatedProductId, + true ); // The inventory information to update @@ -52,9 +53,6 @@ async function main(generatedProductId) { availability: 'IN_STOCK', }; - // The time when the request is issued, used to prevent - // out-of-order updates on inventory fields with the last update time recorded. - // If set to true, and the product with name is not found, the // inventory update will still be processed and retained for at most 1 day until the product is created const allowMissing = true; @@ -65,35 +63,29 @@ async function main(generatedProductId) { inventory: product, allowMissing, }; + + // To send an out-of-order request assign the invalid setTime here: + // request.setTime = {seconds: Math.round(Date.now() / 1000) - 86400}; + console.log('Set inventory request:', request); + console.log('Waiting to complete set inventory operation...'); // Run request const [operation] = await retailClient.setInventory(request); await operation.promise(); - console.log('Waiting to complete set inventory operation..'); }; - // Set inventory with current time + // Set inventory console.log('Start set inventory'); await callSetInventory(); // Get product - let changedProduct = await utils.getProduct(createdProduct.name); + const changedProduct = await utils.getProduct(createdProduct.name); console.log( `Updated product ${createdProduct.id} with current time: `, JSON.stringify(changedProduct[0]) ); - // Set inventory with outdated time - product.priceInfo.price = 20.0; - await callSetInventory(); - - // Get product - changedProduct = await utils.getProduct(createdProduct.name); - console.log( - `Updated product ${createdProduct.id} with outdated time: `, - JSON.stringify(changedProduct[0]) - ); console.log('Set inventory finished'); // Delete product From f032a03f0f195aa4a9307c6f15a8888b8634f393 Mon Sep 17 00:00:00 2001 From: Arakel2811 <38522242+Arakel2811@users.noreply.github.com> Date: Mon, 26 Sep 2022 19:38:29 +0400 Subject: [PATCH 51/54] samples: removed region tags from events and search directories (#216) --- .../events/import-user-events-big-query.js | 3 --- retail/interactive-tutorials/events/import-user-events-gcs.js | 3 --- .../interactive-tutorials/events/import-user-events-inline.js | 3 --- retail/interactive-tutorials/events/purge-user-events.js | 3 --- retail/interactive-tutorials/events/rejoin-user-events.js | 3 --- retail/interactive-tutorials/events/write-user-event.js | 3 --- retail/interactive-tutorials/search/search-simple-query.js | 2 -- retail/interactive-tutorials/search/search-with-boost-spec.js | 2 -- retail/interactive-tutorials/search/search-with-facet-spec.js | 2 -- retail/interactive-tutorials/search/search-with-filtering.js | 2 -- retail/interactive-tutorials/search/search-with-ordering.js | 2 -- retail/interactive-tutorials/search/search-with-pagination.js | 4 ---- .../search/search-with-query-expansion-spec.js | 3 --- 13 files changed, 35 deletions(-) diff --git a/retail/interactive-tutorials/events/import-user-events-big-query.js b/retail/interactive-tutorials/events/import-user-events-big-query.js index 2c49490084..a822476a53 100644 --- a/retail/interactive-tutorials/events/import-user-events-big-query.js +++ b/retail/interactive-tutorials/events/import-user-events-big-query.js @@ -15,8 +15,6 @@ 'use strict'; async function main(datasetId) { - // [START retail_import_user_events_big_query] - // Imports the Google Cloud client library. const {UserEventServiceClient} = require('@google-cloud/retail').v2; @@ -71,7 +69,6 @@ async function main(datasetId) { console.log('Start events import'); await callImportUserEvents(); console.log('Events import finished'); - // [END retail_import_user_events_big_query] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/events/import-user-events-gcs.js b/retail/interactive-tutorials/events/import-user-events-gcs.js index e42a908acc..bc8af4d553 100644 --- a/retail/interactive-tutorials/events/import-user-events-gcs.js +++ b/retail/interactive-tutorials/events/import-user-events-gcs.js @@ -15,8 +15,6 @@ 'use strict'; async function main(bucketName) { - // [START retail_import_user_events_gcs] - // Imports the Google Cloud client library. const {UserEventServiceClient} = require('@google-cloud/retail').v2; @@ -78,7 +76,6 @@ async function main(bucketName) { console.log('Start events import'); await callImportUserEvents(); console.log('Events import finished'); - // [END retail_import_user_events_gcs] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/events/import-user-events-inline.js b/retail/interactive-tutorials/events/import-user-events-inline.js index 99a628e1a5..c063cd2d03 100644 --- a/retail/interactive-tutorials/events/import-user-events-inline.js +++ b/retail/interactive-tutorials/events/import-user-events-inline.js @@ -15,8 +15,6 @@ 'use strict'; async function main() { - // [START retail_import_user_events_inline] - // Imports the Google Cloud client library. const {UserEventServiceClient} = require('@google-cloud/retail').v2; @@ -81,7 +79,6 @@ async function main() { console.log('Start events import'); await callImportUserEvents(); console.log('Events import finished'); - // [END retail_import_user_events_inline] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/events/purge-user-events.js b/retail/interactive-tutorials/events/purge-user-events.js index 3815fa78d0..78695dc7af 100644 --- a/retail/interactive-tutorials/events/purge-user-events.js +++ b/retail/interactive-tutorials/events/purge-user-events.js @@ -15,8 +15,6 @@ 'use strict'; async function main() { - // [START retail_purge_user_events] - // Imports the Google Cloud client library. const {UserEventServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); @@ -62,7 +60,6 @@ async function main() { // Purge events await callPurgeUserEvents(); - // [END retail_purge_user_events] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/events/rejoin-user-events.js b/retail/interactive-tutorials/events/rejoin-user-events.js index 90bdcf3909..173f1e04ef 100644 --- a/retail/interactive-tutorials/events/rejoin-user-events.js +++ b/retail/interactive-tutorials/events/rejoin-user-events.js @@ -15,8 +15,6 @@ 'use strict'; async function main() { - // [START retail_rejoin_user_event] - // Imports the Google Cloud client library. const {UserEventServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); @@ -66,7 +64,6 @@ async function main() { // Purge events utils.purgeUserEvents(parent, visitorId); - // [END retail_rejoin_user_event] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/events/write-user-event.js b/retail/interactive-tutorials/events/write-user-event.js index fbcbf04d28..ee24e072ab 100644 --- a/retail/interactive-tutorials/events/write-user-event.js +++ b/retail/interactive-tutorials/events/write-user-event.js @@ -15,8 +15,6 @@ 'use strict'; async function main() { - // [START retail_write_user_event] - // Imports the Google Cloud client library. const {UserEventServiceClient} = require('@google-cloud/retail').v2; const utils = require('../setup/setup-cleanup'); @@ -60,7 +58,6 @@ async function main() { // Purge user events by visitor id await utils.purgeUserEvents(parent, visitorId); - // [END retail_write_user_event] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/search/search-simple-query.js b/retail/interactive-tutorials/search/search-simple-query.js index 393f7ab78f..c6cb52f30d 100644 --- a/retail/interactive-tutorials/search/search-simple-query.js +++ b/retail/interactive-tutorials/search/search-simple-query.js @@ -15,7 +15,6 @@ 'use strict'; async function main() { - // [START retail_search_for_products_with_query_parameter] // Call Retail API to search for a products in a catalog using only search query. // Imports the Google Cloud client library. @@ -69,7 +68,6 @@ async function main() { }; callSearch(); - // [END retail_search_for_products_with_query_parameter] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/search/search-with-boost-spec.js b/retail/interactive-tutorials/search/search-with-boost-spec.js index 64c5c812fe..7ebeee41d9 100644 --- a/retail/interactive-tutorials/search/search-with-boost-spec.js +++ b/retail/interactive-tutorials/search/search-with-boost-spec.js @@ -15,7 +15,6 @@ 'use strict'; async function main() { - // [START retail_search_product_with_boost_spec] // Call Retail API to search for a products in a catalog, rerank the // results boosting or burying the products that match defined condition. @@ -82,7 +81,6 @@ async function main() { }; callSearch(); - // [END retail_search_product_with_boost_spec] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/search/search-with-facet-spec.js b/retail/interactive-tutorials/search/search-with-facet-spec.js index c07e7dbda1..c8dca4c1c8 100644 --- a/retail/interactive-tutorials/search/search-with-facet-spec.js +++ b/retail/interactive-tutorials/search/search-with-facet-spec.js @@ -15,7 +15,6 @@ 'use strict'; async function main() { - // [START retail_search_products_with_facet_spec] // Call Retail API to search for a products in a catalog using only search query. // Imports the Google Cloud client library. @@ -73,7 +72,6 @@ async function main() { }; callSearch(); - // [END retail_search_products_with_facet_spec] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/search/search-with-filtering.js b/retail/interactive-tutorials/search/search-with-filtering.js index a357ff3019..f12099219d 100644 --- a/retail/interactive-tutorials/search/search-with-filtering.js +++ b/retail/interactive-tutorials/search/search-with-filtering.js @@ -15,7 +15,6 @@ 'use strict'; async function main() { - // [START retail_search_for_products_with_filter] // Call Retail API to search for a products in a catalog, filter the results by different product fields. // Imports the Google Cloud client library. @@ -75,7 +74,6 @@ async function main() { }; callSearch(); - // [END retail_search_for_products_with_filter] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/search/search-with-ordering.js b/retail/interactive-tutorials/search/search-with-ordering.js index 53e55a3e28..05993b5b9b 100644 --- a/retail/interactive-tutorials/search/search-with-ordering.js +++ b/retail/interactive-tutorials/search/search-with-ordering.js @@ -15,7 +15,6 @@ 'use strict'; async function main() { - // [START retail_search_for_products_with_ordering] // Call Retail API to search for a products in a catalog, order the results by different product fields. // Imports the Google Cloud client library. @@ -74,7 +73,6 @@ async function main() { }; callSearch(); - // [END retail_search_for_products_with_ordering] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/search/search-with-pagination.js b/retail/interactive-tutorials/search/search-with-pagination.js index cd6f79b272..b391c4a65b 100644 --- a/retail/interactive-tutorials/search/search-with-pagination.js +++ b/retail/interactive-tutorials/search/search-with-pagination.js @@ -15,8 +15,6 @@ 'use strict'; async function main() { - // [START retail_search_for_products_with_pagination] - // Imports the Google Cloud client library. const {SearchServiceClient} = require('@google-cloud/retail'); @@ -83,8 +81,6 @@ async function main() { await callSearch(); //PASTE CALL WITH NEXT PAGE TOKEN HERE: - - // [END retail_search_for_products_with_pagination] } process.on('unhandledRejection', err => { diff --git a/retail/interactive-tutorials/search/search-with-query-expansion-spec.js b/retail/interactive-tutorials/search/search-with-query-expansion-spec.js index 0492b16325..626d45ec58 100644 --- a/retail/interactive-tutorials/search/search-with-query-expansion-spec.js +++ b/retail/interactive-tutorials/search/search-with-query-expansion-spec.js @@ -15,8 +15,6 @@ 'use strict'; async function main() { - // [START retail_search_for_products_with_query_expansion_specification] - // Imports the Google Cloud client library. const {SearchServiceClient} = require('@google-cloud/retail'); @@ -76,7 +74,6 @@ async function main() { }; callSearch(); - // [END retail_search_for_products_with_query_expansion_specification] } process.on('unhandledRejection', err => { From 99ebfb0dd02ad3f5340ff56d9f20ea1e541036d0 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Wed, 16 Nov 2022 01:02:14 +0000 Subject: [PATCH 52/54] chore(main): release 2.1.1 (#225) :robot: I have created a release *beep* *boop* --- ## [2.1.1](https://togithub.com/googleapis/nodejs-retail/compare/v2.1.0...v2.1.1) (2022-11-16) ### Bug Fixes * **deps:** Use google-gax v3.5.2 ([#221](https://togithub.com/googleapis/nodejs-retail/issues/221)) ([5eb17fc](https://togithub.com/googleapis/nodejs-retail/commit/5eb17fc9c340cacbb8627442c58597015a2d4134)) --- This PR was generated with [Release Please](https://togithub.com/googleapis/release-please). See [documentation](https://togithub.com/googleapis/release-please#release-please). --- retail/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retail/package.json b/retail/package.json index a1e9c64d61..c4e6019e86 100644 --- a/retail/package.json +++ b/retail/package.json @@ -13,7 +13,7 @@ "test": "c8 mocha" }, "dependencies": { - "@google-cloud/retail": "^2.1.0", + "@google-cloud/retail": "^2.1.1", "@google-cloud/bigquery": "^6.0.0", "@google-cloud/storage": "^6.0.0" }, From 7997894778e30d7242e8ae46e04111581ce438ca Mon Sep 17 00:00:00 2001 From: Karl Weinmeister Date: Wed, 11 Jan 2023 13:47:07 -0600 Subject: [PATCH 53/54] add tests and CODEOWNERS update --- .github/workflows/generate.js | 0 .github/workflows/retail.yaml | 71 ++++++++++++++++++++++++++++++++ .github/workflows/workflows.json | 1 + CODEOWNERS | 3 ++ 4 files changed, 75 insertions(+) mode change 100644 => 100755 .github/workflows/generate.js create mode 100644 .github/workflows/retail.yaml diff --git a/.github/workflows/generate.js b/.github/workflows/generate.js old mode 100644 new mode 100755 diff --git a/.github/workflows/retail.yaml b/.github/workflows/retail.yaml new file mode 100644 index 0000000000..560ba6d150 --- /dev/null +++ b/.github/workflows/retail.yaml @@ -0,0 +1,71 @@ +name: retail +on: + push: + branches: + - main + paths: + - 'retail/**' + - '.github/workflows/retail.yaml' + pull_request: + paths: + - 'retail/**' + - '.github/workflows/retail.yaml' + pull_request_target: + types: [labeled] + paths: + - 'retail/**' + - '.github/workflows/retail.yaml' + schedule: + - cron: '0 0 * * 0' +jobs: + test: + if: ${{ github.event.action != 'labeled' || github.event.label.name == 'actions:force-run' }} + runs-on: ubuntu-latest + timeout-minutes: 60 + permissions: + contents: 'write' + pull-requests: 'write' + id-token: 'write' + steps: + - uses: actions/checkout@v3.1.0 + with: + ref: ${{github.event.pull_request.head.sha}} + - uses: 'google-github-actions/auth@v1.0.0' + with: + workload_identity_provider: 'projects/1046198160504/locations/global/workloadIdentityPools/github-actions-pool/providers/github-actions-provider' + service_account: 'kokoro-system-test@long-door-651.iam.gserviceaccount.com' + create_credentials_file: 'true' + access_token_lifetime: 600s + - uses: actions/setup-node@v3.5.1 + with: + node-version: 16 + - run: npm install + working-directory: retail + - run: npm test + working-directory: retail + env: + MOCHA_REPORTER_SUITENAME: retail + MOCHA_REPORTER_OUTPUT: retail_sponge_log.xml + MOCHA_REPORTER: xunit + - if: ${{ github.event.action == 'labeled' && github.event.label.name == 'actions:force-run' }} + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + try { + await github.rest.issues.removeLabel({ + name: 'actions:force-run', + owner: 'GoogleCloudPlatform', + repo: 'nodejs-docs-samples', + issue_number: context.payload.pull_request.number + }); + } catch (e) { + if (!e.message.includes('Label does not exist')) { + throw e; + } + } + - if: ${{ github.event_name == 'schedule' && always() }} + run: | + curl https://github.com/googleapis/repo-automation-bots/releases/download/flakybot-1.1.0/flakybot -o flakybot -s -L + chmod +x ./flakybot + ./flakybot --repo GoogleCloudPlatform/nodejs-docs-samples --commit_hash ${{github.sha}} --build_url https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} diff --git a/.github/workflows/workflows.json b/.github/workflows/workflows.json index 61f36c7418..a920b52213 100644 --- a/.github/workflows/workflows.json +++ b/.github/workflows/workflows.json @@ -73,6 +73,7 @@ "monitoring/opencensus", "monitoring/prometheus", "monitoring/snippets", + "retail", "scheduler", "security-center/snippets", "service-directory/snippets", diff --git a/CODEOWNERS b/CODEOWNERS index 11c2d15619..638ba27838 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -73,3 +73,6 @@ texttospeech @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/nodejs-sample translate @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/nodejs-samples-reviewers video-intelligence @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/nodejs-samples-reviewers vision @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/nodejs-samples-reviewers + +# Self-service +retail @GoogleCloudPlatform/cloud-retail-team @GoogleCloudPlatform/nodejs-samples-reviewers From 56d04e6a70654135eaea1413456f2f4b0ae79786 Mon Sep 17 00:00:00 2001 From: Karl Weinmeister Date: Wed, 11 Jan 2023 15:39:54 -0600 Subject: [PATCH 54/54] add auto-label entry --- .github/auto-label.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/auto-label.yaml b/.github/auto-label.yaml index 615405af1e..9c711f361a 100644 --- a/.github/auto-label.yaml +++ b/.github/auto-label.yaml @@ -33,6 +33,7 @@ path: mediatranslation: "mediatranslation" memorystore: "memorystore" monitoring: "monitoring" + retail: "retail" run: "run" scheduler: "cloudscheduler" secret-manager: "secretmanager"