2024-05-30 (C) Questetra, In. (MIT License) 3 2 This item gets data in a specified row from a Google Sheet. この工程は、Google スプレッドシートから指定した行のデータを取得します。 https://support.questetra.com/bpmn-icons/service-task-google-sheets-row-get/ https://support.questetra.com/ja/bpmn-icons/service-task-google-sheets-row-get/ iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADbElEQVRYR8WXS0hUURjH/2dGJFDz lqNimmORhAU5hRVFojgTQSTarl3azN5x1aboQdAqGoVc2AyOFoGCpQuN7E6MRIVW4BBZUqJkbYTw +H7M48Sdx3Ve986d0crFuDjfd8/v+5/vcQ7Bf/4jyezPWfX1IKQKDDoAHIj/P8AwBoCCYAwETnqF 71f63YQAXEc1B19aE8DMAOGUfZhRgFig8rTQRieV85EF4Gw1DQC5r3zj6K0YBUMjNTn6pCAkATir 3gJCmpRFnNDKQo18czyruACcVW8HIZcTfjYpA2anRkdjtEsMQHjkvefuoqawQvTxMV8w54S8Y2DM /4uhmRGUZhfj9gcbBn+8lcZirIWaHOZwgwiAwJmrOkIGzro2lOeUJozzxcwITuYf8ts1v2lB39Sw HMTF8JwQAQLZrp4KT7hkAbj0LMxvLOHquwfonuQlIBiFyrsvVB2bADbDTQA3wr1SARD8F9zLuD7a jq6JQSklblEjL+yHTQCrQWgk2akC7FCnY2d6hug+uzqHSy+vSapAjY5dIkCwwz2LtlaqwNz6Ihbd yxHuK551nHpqSpgLfgWkal4pQLxdlj1rKOqqTVgRAQCbwQmgKlUFUgIAhqmRrw4pMA1CtHIAK541 LGxEyhxtr1apkbsjMC4SK4AxauKPhhRg8aIIPwLX7294NPEch3fvR/d3HpUFOuzJ0IhuHuYF//M9 us/eUQYgjE8jT5ICGJoZhU5TivbxPpwvPo2izLxNAJ8X9omBFAGs+oRHICjw6tdHHNMcRNvnXtRq z2BvZr4I4PZ58PBLfxIAzEWNDp3iJBQAeiYdOJJzAJ1fB2AoOoHCzFwRwOvzon/6dRIAkUkYd/RG 58Do7DgqcsvQ+qkHdSWV0GYVRChwz/VEOUBwMIWqQLhqyTaibU9CxvxDSXErFspwyb0q3VgAqAiB RkkZMsxTE++v120ZRik0ojjDSBjH3rTp8IH0V1oxwzzUnpKYcRxoyZEXkqELrTieVyYru9Si0DW1 j+tjl4NnH1qQvZKltLO8kyi9JEBwOm7/pZSxTmpyNETz/atreUzksgqEFv0XFRB79E1J8dEICQfW kNLDRIQIPM3MYDArBhE2JhCeZpYtPc2iIw0ogmoQogMYB5DygA1zAYSCMeGR6pSLWHEOKJZ5i4Z/ AEwJzTC2ALrNAAAAAElFTkSuQmCC { const auth = httpClient.createAuthSettingOAuth2( 'Google', 'https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=force', 'https://accounts.google.com/o/oauth2/token', 'spreadsheets', 'consumer_key', 'consumer_secret', 'access_token' ); configs.putObject('conf_OAuth2', auth); // スプレッドシートの ID を設定した文字型データ項目(単一行)を準備 const spreadSheetIdDef = engine.createDataDefinition('スプレッドシートの ID', 1, 'q_SpreadSheetId', 'STRING_TEXTFIELD'); engine.setData(spreadSheetIdDef, sheetId); configs.putObject('conf_SheetId', spreadSheetIdDef); // シートのタイトルを設定した文字型データ項目(単一行)を準備 const sheetTitleDef = engine.createDataDefinition('シートのタイトル', 2, 'q_SheetTitle', 'STRING_TEXTFIELD'); engine.setData(sheetTitleDef, sheetTitle); configs.putObject('conf_SheetTitle', sheetTitleDef); configs.put('conf_Range', range); // 行番号を設定したデータ項目を作成し、C4 に設定 const rowNoDef = engine.createDataDefinition('行番号', 1, 'q_rowNo', 'STRING_TEXTFIELD'); engine.setData(rowNoDef, rowNo); configs.putObject('conf_RowNo', rowNoDef); const columnDefList = []; types.forEach((type, i) => { // 指定したタイプのデータ項目を作成し、C6 以降に順に設定 if (type !== null){ const columnDef = engine.createDataDefinition(`データ${i+1}`, i+2, `q_data${i+1}`, type); engine.setData(columnDef, '事前文字列'); configs.putObject(`conf_Column${i+1}`, columnDef); columnDefList.push(columnDef); } }); return columnDefList; }; /** * 異常系のテスト * @param func * @param errorMsg */ const assertError = (func, errorMsg) => { let failed = false; try { func(); } catch (e) { failed = true; expect(e.message).toEqual(errorMsg); } if (!failed) { fail('No error was thrown.'); } }; test('Row Number is invalid', () => { //行番号が不適切な場合 prepareConfigs(configs, 'id', 'title', 'invalidrow', 'A:B', 'STRING_TEXTFIELD', 'STRING_TEXTFIELD'); assertError(main, 'Invalid Row number.'); }); test('Row Number is empty', () => { //行番号が入力されていない場合 prepareConfigs(configs, 'id', 'title', null, 'A:B', 'STRING_TEXTFIELD', 'STRING_TEXTFIELD'); assertError(main, 'Row number is empty.'); }); test('Column Range is invalid', () => { //列範囲が不適切である場合 prepareConfigs(configs, 'id', 'title', '1', 'invalidrange', 'STRING_TEXTFIELD', 'STRING_TEXTFIELD'); assertError(main, 'Invalid Range.'); }); test('Same Data Item is set twice', () => { //同じデータ項目がC6に2回セットされている場合 const columnDefList = prepareConfigs(configs, 'id', 'title', '1', 'A:B', 'STRING_TEXTFIELD', 'STRING_TEXTFIELD'); configs.putObject("conf_Column2", columnDefList[0]); assertError(main, 'The same data item is set multiple times.'); }); test('No Data Item is set', () => { //保存先データ項目がひとつも設定されていない場合 const columnDefList = prepareConfigs(configs, 'id', 'title', '1', 'A:B'); assertError(main, 'No Data Item is set.'); }); /** * リクエストのテスト * @param url * @param method * @param contentType * @param body * @param sheetId * @param sheetTitle * @param range */ const assertRequest = ({url, method, contentType, body}, sheetId, sheetTitle, range) => { const enSheetId = encodeURIComponent(sheetId); const enSheetTitle = encodeURIComponent(sheetTitle); expect(url).toEqual(`https://sheets.googleapis.com/v4/spreadsheets/${enSheetId}/values/${enSheetTitle}!${range}?valueRenderOption=UNFORMATTED_VALUE&dateTimeRenderOption=FORMATTED_STRING&majorDimension=ROWS`); expect(method).toEqual('GET'); }; test('Succeed to get - TEXTFIELD and TEXTAREA', () => { //行取得に成功する場合 const columnDefList = prepareConfigs(configs, 'id', 'シート 1', '1', 'A:B', 'STRING_TEXTFIELD', 'STRING_TEXTAREA'); httpClient.setRequestHandler((request) => { assertRequest(request, 'id', 'シート 1', 'A1:B1'); const ret = JSON.stringify({"values":[['A列','B列\n複数行']]}); return httpClient.createHttpResponse(200, 'application/json', ret); }); main(); expect(engine.findData(columnDefList[0])).toEqual('A列'); expect(engine.findData(columnDefList[1])).toEqual('B列\n複数行'); }); test('Succeed to get - 10 columns', () => { //保存先データ項目がすべて設定されている場合 const types = new Array(10).fill('STRING_TEXTFIELD'); const columnDefList = prepareConfigs(configs, 'id', 'シート 2!', '70', 'XA:XJ', ...types); const rowData = Array.from({length: 10}, (_, i) => `値${i+1}`); httpClient.setRequestHandler((request) => { assertRequest(request, 'id', 'シート 2!', 'XA70:XJ70'); const ret = JSON.stringify({"values":[rowData]}); return httpClient.createHttpResponse(200, 'application/json', ret); }); main(); columnDefList.forEach((def, i) => { expect(engine.findData(def)).toEqual(`値${i+1}`); }); }); test('Succeed to get - Some data items are not set', () => { //保存先データ項目が設定されていない列がある場合 const types = new Array(10).fill('STRING_TEXTFIELD'); const columnDefList = prepareConfigs(configs, 'id', 'シート 1', '1', 'A:J', ...types); configs.put('conf_Column5', ''); configs.put('conf_Column8', ''); const rowData = Array.from({length: 10}, (_, i) => `値${i+1}`); httpClient.setRequestHandler((request) => { assertRequest(request, 'id', 'シート 1', 'A1:J1'); const ret = JSON.stringify({"values":[rowData]}); return httpClient.createHttpResponse(200, 'application/json', ret); }); main(); columnDefList.forEach((def, i) => { if (i === 4 || i === 7) { // 5, 8列目は保存先が未設定 expect(engine.findData(def)).toEqual('事前文字列'); return; } expect(engine.findData(def)).toEqual(`値${i+1}`); }); }); test('Succeed to get - Number of Returned values is bigger than 10', () => { //取得した行データの値の数が 10 を超える場合 const types = new Array(10).fill('STRING_TEXTFIELD'); const columnDefList = prepareConfigs(configs, 'id', 'シート 1', '1', 'A:Z', ...types); const rowData = Array.from({length: 11}, (_, i) => `値${i+1}`); httpClient.setRequestHandler((request) => { assertRequest(request, 'id', 'シート 1', 'A1:Z1'); const ret = JSON.stringify({"values":[rowData]}); return httpClient.createHttpResponse(200, 'application/json', ret); }); main(); columnDefList.forEach((def, i) => { expect(engine.findData(def)).toEqual(`値${i+1}`); }); }); test('Succeed to get - Number of Returned values is smaller than that of data items', () => { //取得した行データの値の数が設定した保存先データ項目数より少ない場合 const types = new Array(10).fill('STRING_TEXTFIELD'); const columnDefList = prepareConfigs(configs, 'id', 'シート 1', '1', 'A:J', ...types); const rowData = Array.from({length: 8}, (_, i) => `値${i+1}`); httpClient.setRequestHandler((request) => { assertRequest(request, 'id', 'シート 1', 'A1:J1'); const ret = JSON.stringify({"values":[rowData]}); return httpClient.createHttpResponse(200, 'application/json', ret); }); main(); columnDefList.forEach((def, i) => { if (i > 7) { // 9列目、10列目の保存される値は null expect(engine.findData(def)).toEqual(null); return; } expect(engine.findData(def)).toEqual(`値${i+1}`); }); }); test('Succeed to get Numeric data', () => { //数値データは文字列に変換され保存される const columnDefList = prepareConfigs(configs, 'id', 'シート 1', '1', 'A:A', 'STRING_TEXTFIELD'); httpClient.setRequestHandler((request) => { assertRequest(request, 'id', 'シート 1', 'A1:A1'); const ret = JSON.stringify({"values":[[100]]}); return httpClient.createHttpResponse(200, 'application/json', ret); }); main(); expect(engine.findData(columnDefList[0])).toEqual('100'); }); test('404 Error', () => { //APIからエラーが返ってくる場合 const columnDefList = prepareConfigs(configs, 'id', 'title', '1', 'A:B', 'STRING_TEXTFIELD', 'STRING_TEXTAREA'); httpClient.setRequestHandler((request) => { assertRequest(request, 'id', 'title', 'A1:B1', 1); return httpClient.createHttpResponse(404, 'application/json', JSON.stringify({})); }); assertError(main, 'Failed to get. status:404'); }); test('All cells are empty', () => { //範囲内のセルがすべて空の場合 const columnDefList = prepareConfigs(configs, 'id', 'title', '1', 'A:B', 'STRING_TEXTFIELD', 'STRING_TEXTAREA'); httpClient.setRequestHandler((request) => { assertRequest(request, 'id', 'title', 'A1:B1', 1); return httpClient.createHttpResponse(200, 'application/json', JSON.stringify({})); }); assertError(main, 'No Data in range.'); }); test('Validation Error - Unable to save multi-line string to STRING_TEXTFIELD', () => { //単一行データ項目に複数行の文字列を保存しようとしてエラーになる場合 const columnDefList = prepareConfigs(configs, 'id', 'title', '1', 'A:A', 'STRING_TEXTFIELD'); httpClient.setRequestHandler((request) => { assertRequest(request, 'id', 'title', 'A1:A1', 1); return httpClient.createHttpResponse(200, 'application/json', JSON.stringify({"values":[['複数行の\n文字列']]})); }); expect(main()).toEqual(undefined); // QBPMS のバリデーションに任せているので、スクリプトは処理成功 }); /** * 設定の準備 * スプレッドシートの ID とシートのタイトルは固定値で指定 * @param configs * @param sheetId * @param sheetTitle * @param rowNo * @param range * @param types * @return {Object} */ const prepareConfigsWithFixedValue = (configs, sheetId, sheetTitle, rowNo, range, ...types) => { const auth = httpClient.createAuthSettingOAuth2( 'Google', 'https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=force', 'https://accounts.google.com/o/oauth2/token', 'spreadsheets', 'consumer_key', 'consumer_secret', 'access_token' ); configs.putObject('conf_OAuth2', auth); configs.put('conf_SheetId', sheetId); configs.put('conf_SheetTitle', sheetTitle); configs.put('conf_Range', range); // 行番号を設定したデータ項目を作成し、C4 に設定 const rowNoDef = engine.createDataDefinition('行番号', 1, 'q_rowNo', 'STRING_TEXTFIELD'); engine.setData(rowNoDef, rowNo); configs.putObject('conf_RowNo', rowNoDef); const columnDefList = []; types.forEach((type, i) => { // 指定したタイプのデータ項目を作成し、C6 以降に順に設定 if (type !== null){ const columnDef = engine.createDataDefinition(`データ${i+1}`, i+2, `q_data${i+1}`, type); engine.setData(columnDef, '事前文字列'); configs.putObject(`conf_Column${i+1}`, columnDef); columnDefList.push(columnDef); } }); return columnDefList; }; test('Succeed to get - 10 columns,Set the Spreadsheet ID and Title as a fixed value', () => { //保存先データ項目がすべて設定されている場合 const types = new Array(10).fill('STRING_TEXTFIELD'); const columnDefList = prepareConfigsWithFixedValue(configs, 'id', 'シート 2!', '70', 'XA:XJ', ...types); const rowData = Array.from({length: 10}, (_, i) => `値${i+1}`); httpClient.setRequestHandler((request) => { assertRequest(request, 'id', 'シート 2!', 'XA70:XJ70'); const ret = JSON.stringify({"values":[rowData]}); return httpClient.createHttpResponse(200, 'application/json', ret); }); main(); columnDefList.forEach((def, i) => { expect(engine.findData(def)).toEqual(`値${i+1}`); }); }); ]]>