diff --git a/README.md b/README.md index 4b66f17..5faef92 100644 --- a/README.md +++ b/README.md @@ -1396,36 +1396,53 @@ For non-PCI use-cases, retrieving data from the vault and revealing it in the mo - #### Using Skyflow ID's or Unique Column Values For retrieving data from the vault, use the `get(getInput: IGetInput, options: IGetOptions)` method. - The `getInput` parameter takes an object that contains an array of the records to fetch. Each object inside array should contain: + The `getInput` parameter takes an object that contains an array of the records to fetch. Each object inside the array should contain: - Either an array of Skyflow IDs to fetch - Or a column name and an array of column values - The second parameter, `options`, is a `GetOptions` object that retrieves tokens of Skyflow IDs. + The second parameter, `options`, is a `GetOptions` object that controls how records are retrieved. - Notes: - - You can use either Skyflow IDs or unique values to retrieve records. You can't use both at the same time. - - GetOptions parameter is applicable only for retrieving tokens using Skyflow ID. - - You can't pass GetOptions along with the redaction type. + Notes: + - You can use either Skyflow IDs or unique column values to retrieve records. You can't use both at the same time. + - `tokens: true` is only applicable when fetching by Skyflow IDs and cannot be combined with `redaction`. + - Use `fields` to restrict which columns are returned — required when column-scoped policies limit access to certain fields. + - `offset` and `limit` are per-record and support pagination; they are only valid with `columnName`/`columnValues` queries or standalone — they cannot be used with `ids`. + - `orderBy` accepts `OrderBy.ASCENDING`, `OrderBy.DESCENDING`, or `OrderBy.NONE`. - `tokens` defaults to false. - + ```json5 { - "records":[ + "records": [ { "ids": Array, // Array of SkyflowID's of the records to be fetched "table": String, // name of table holding the above skyflow_id's - "redaction": RedactionType // redaction to be applied to retrieved data + "redaction": RedactionType, // redaction to be applied to retrieved data + "fields": Array // (optional) columns to return; omit to return all permitted columns + // NOTE: offset and limit are NOT supported when using ids }, { "table": String, // name of table from where records are to be fetched "redaction": RedactionType, // redaction to be applied to retrieved data "columnName": String, // a unique column name - "columnValues": Array // Array of Column Values of the records to be fetched + "columnValues": Array, // Array of Column Values of the records to be fetched + "fields": Array, // (optional) columns to return; omit to return all permitted columns + "offset": String, // (optional) pagination start position + "limit": String // (optional) max number of records to return } ] } ``` + + ```json5 + // options + { + "tokens": Boolean, // if true, returns tokens instead of plain-text values + "downloadURL": Boolean, // (optional) if true, returns pre-signed download URLs for file columns + "orderBy": OrderBy // (optional) sort order: OrderBy.ASCENDING | OrderBy.DESCENDING | OrderBy.NONE + } + ``` + An Example of Get call to fetch records ```js @@ -1527,11 +1544,97 @@ For non-PCI use-cases, retrieving data from the vault and revealing it in the mo "code": "404", "description": "No Records Found" }, - "columnName": "email", + "columnName": "email" } ] } ``` + + An Example of Get call to fetch specific fields (column-scoped policy compatible) + + ```js + const skyflowContainer = useSkyflow(); + + const getRequestInput = { + records: [ + { + ids: ['h4f5k569-c577-8o1j-r91c-x9gfd0b0fd9'], + table: 'persons', + redaction: RedactionType.PLAIN_TEXT, + fields: ['occupation', 'annual_income'], + }, + ], + }; + + skyflowContainer + .get(getRequestInput, { tokens: false }) + .then((response) => { + console.log(JSON.stringify(response)); + }) + .catch((err) => { + console.error(JSON.stringify(err)); + }); + ``` + + An Example of Get call to fetch records with pagination and ordering + + ```js + import { useSkyflow, RedactionType, OrderBy } from 'skyflow-react-native'; + + const skyflowContainer = useSkyflow(); + + const getRequestInput = { + records: [ + { + table: 'customers', + redaction: RedactionType.PLAIN_TEXT, + columnName: 'email', + columnValues: ['john.doe@gmail.com'], + fields: ['name', 'email'], + offset: '0', + limit: '10', + }, + ], + }; + + skyflowContainer + .get(getRequestInput, { tokens: false, orderBy: OrderBy.ASCENDING }) + .then((response) => { + console.log(JSON.stringify(response)); + }) + .catch((err) => { + console.error(JSON.stringify(err)); + }); + ``` + + An Example of Get call to fetch all records with pagination (no Skyflow IDs or column filter) + + ```js + import { useSkyflow, RedactionType, OrderBy } from 'skyflow-react-native'; + + const skyflowContainer = useSkyflow(); + + const getRequestInput = { + records: [ + { + table: 'customers', + redaction: RedactionType.PLAIN_TEXT, + offset: '0', + limit: '25', + }, + ], + }; + + skyflowContainer + .get(getRequestInput, { tokens: false, orderBy: OrderBy.ASCENDING }) + .then((response) => { + console.log(JSON.stringify(response)); + }) + .catch((err) => { + console.error(JSON.stringify(err)); + }); + ``` + An Example of Get call to fetch Tokens ```js diff --git a/__tests__/core-utils/element-validations.test.js b/__tests__/core-utils/element-validations.test.js index 67c090f..aaa83f5 100644 --- a/__tests__/core-utils/element-validations.test.js +++ b/__tests__/core-utils/element-validations.test.js @@ -328,7 +328,7 @@ describe('test validateGetInput', () => { } }); - it('should throw error for empty ids', () => { + it('should throw error for empty ids array', () => { try { validateGetInput({ records: [{ ids: [] }] }); } catch (err) { @@ -468,7 +468,7 @@ describe('test validateGetInput', () => { } }); - it('should throw error for empty column values', () => { + it('should throw error for empty column values when columnValues is null', () => { try { validateGetInput({ records: [ @@ -704,6 +704,41 @@ describe('test validateGetInput', () => { } }); + it('should throw error for empty string columnName', () => { + expect(() => + validateGetInput({ + records: [ + { + columnValues: ['value1'], + columnName: '', + table: 'test', + redaction: RedactionType.PLAIN_TEXT, + }, + ], + }) + ).toThrow(); + + try { + validateGetInput({ + records: [ + { + columnValues: ['value1'], + columnName: '', + table: 'test', + redaction: RedactionType.PLAIN_TEXT, + }, + ], + }); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + parameterizedString( + SKYFLOW_ERROR_CODE.EMPTY_RECORD_COLUMN_NAME.description, + 0 + ) + ); + } + }); + it('should throw error for empty column values error', () => { try { validateGetInput({ @@ -806,6 +841,140 @@ describe('test validateGetInput', () => { ); } }); + + // ids + columnValues without columnName + it('should throw MISSING_RECORD_COLUMN_NAME when ids and columnValues are present without columnName', () => { + try { + validateGetInput({ + records: [ + { + ids: ['123'], + table: 'test', + redaction: RedactionType.PLAIN_TEXT, + columnValues: ['val1'], + }, + ], + }); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + parameterizedString( + SKYFLOW_ERROR_CODE.MISSING_RECORD_COLUMN_NAME.description, + 0 + ) + ); + } + }); + + // fields with ids → valid + it('should not throw when fields is provided with ids', () => { + expect(() => + validateGetInput({ + records: [ + { + ids: ['123'], + table: 'test', + redaction: RedactionType.PLAIN_TEXT, + fields: ['name', 'email'], + }, + ], + }) + ).not.toThrow(); + }); + + // tokens:true + fields → valid (no restriction) + it('should not throw when tokens:true is combined with fields', () => { + expect(() => + validateGetInput( + { + records: [ + { + ids: ['123'], + table: 'test', + fields: ['name'], + }, + ], + }, + { tokens: true } + ) + ).not.toThrow(); + }); + + // error at record index 1 + it('should include correct index in error when second record is invalid', () => { + try { + validateGetInput({ + records: [ + { ids: ['123'], table: 'test', redaction: RedactionType.DEFAULT }, + { ids: ['456'], table: null, redaction: RedactionType.DEFAULT }, + ], + }); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + parameterizedString( + SKYFLOW_ERROR_CODE.EMPTY_TABLE_IN_GET.description, + 1 + ) + ); + } + }); + + // offset alone without limit (column query) → valid + it('should not throw when only offset is provided with columnName and columnValues', () => { + expect(() => + validateGetInput({ + records: [ + { + table: 'test', + redaction: RedactionType.DEFAULT, + columnName: 'email', + columnValues: ['test@example.com'], + offset: '5', + }, + ], + }) + ).not.toThrow(); + }); + + // limit alone without offset (column query) → valid + it('should not throw when only limit is provided with columnName and columnValues', () => { + expect(() => + validateGetInput({ + records: [ + { + table: 'test', + redaction: RedactionType.DEFAULT, + columnName: 'email', + columnValues: ['test@example.com'], + limit: '10', + }, + ], + }) + ).not.toThrow(); + }); + + // offset/limit with columnName but missing columnValues + it('should throw MISSING_RECORD_COLUMN_VALUE when offset/limit with columnName but no columnValues', () => { + try { + validateGetInput({ + records: [ + { + table: 'test', + redaction: RedactionType.DEFAULT, + columnName: 'email', + offset: '0', + limit: '10', + }, + ], + }); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + parameterizedString( + SKYFLOW_ERROR_CODE.MISSING_RECORD_COLUMN_VALUE.description, + 0 + ) + ); + } + }); }); describe('test get options validation', () => { @@ -996,4 +1165,438 @@ describe('test get options validation', () => { ); } }); + + it('should throw error for non-string offset in record', () => { + try { + validateGetInput({ + records: [ + { + table: 'test', + redaction: RedactionType.DEFAULT, + columnName: 'email', + columnValues: ['test@example.com'], + offset: 10, + }, + ], + }); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + parameterizedString( + SKYFLOW_ERROR_CODE.INVALID_OFFSET_IN_GET.description, + 0 + ) + ); + } + }); + + it('should throw error for null offset in record', () => { + try { + validateGetInput({ + records: [ + { + table: 'test', + redaction: RedactionType.DEFAULT, + columnName: 'email', + columnValues: ['test@example.com'], + offset: null, + }, + ], + }); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + parameterizedString( + SKYFLOW_ERROR_CODE.INVALID_OFFSET_IN_GET.description, + 0 + ) + ); + } + }); + + it('should throw error for non-string limit in record', () => { + try { + validateGetInput({ + records: [ + { + table: 'test', + redaction: RedactionType.DEFAULT, + columnName: 'email', + columnValues: ['test@example.com'], + limit: true, + }, + ], + }); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + parameterizedString( + SKYFLOW_ERROR_CODE.INVALID_LIMIT_IN_GET.description, + 0 + ) + ); + } + }); + + it('should throw error for null limit in record', () => { + try { + validateGetInput({ + records: [ + { + table: 'test', + redaction: RedactionType.DEFAULT, + columnName: 'email', + columnValues: ['test@example.com'], + limit: null, + }, + ], + }); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + parameterizedString( + SKYFLOW_ERROR_CODE.INVALID_LIMIT_IN_GET.description, + 0 + ) + ); + } + }); + + it('should throw error for empty string offset in record', () => { + try { + validateGetInput({ + records: [ + { + table: 'test', + redaction: RedactionType.DEFAULT, + columnName: 'email', + columnValues: ['test@example.com'], + offset: '', + }, + ], + }); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + parameterizedString( + SKYFLOW_ERROR_CODE.EMPTY_OFFSET_IN_GET.description, + 0 + ) + ); + } + }); + + it('should throw error for empty string limit in record', () => { + try { + validateGetInput({ + records: [ + { + table: 'test', + redaction: RedactionType.DEFAULT, + columnName: 'email', + columnValues: ['test@example.com'], + limit: '', + }, + ], + }); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + parameterizedString( + SKYFLOW_ERROR_CODE.EMPTY_LIMIT_IN_GET.description, + 0 + ) + ); + } + }); + + it('should throw error for non-boolean downloadURL in get options', () => { + try { + validateGetInput( + { records: [{ ids: ['123'], table: 'test', redaction: RedactionType.DEFAULT }] }, + { downloadURL: 'true' } + ); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + SKYFLOW_ERROR_CODE.INVALID_DOWNLOAD_URL_IN_GET.description + ); + } + }); + + it('should throw error for number passed as downloadURL in get options', () => { + try { + validateGetInput( + { records: [{ ids: ['123'], table: 'test', redaction: RedactionType.DEFAULT }] }, + { downloadURL: 1 } + ); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + SKYFLOW_ERROR_CODE.INVALID_DOWNLOAD_URL_IN_GET.description + ); + } + }); + + it('should throw error for null downloadURL in get options', () => { + try { + validateGetInput( + { records: [{ ids: ['123'], table: 'test', redaction: RedactionType.DEFAULT }] }, + { downloadURL: null } + ); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + SKYFLOW_ERROR_CODE.INVALID_DOWNLOAD_URL_IN_GET.description + ); + } + }); + + it('should throw error for invalid orderBy value in get options', () => { + try { + validateGetInput( + { records: [{ ids: ['123'], table: 'test', redaction: RedactionType.DEFAULT }] }, + { orderBy: 'INVALID_ORDER' } + ); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + SKYFLOW_ERROR_CODE.INVALID_ORDER_BY_IN_GET.description + ); + } + }); + + it('should throw error for null orderBy in get options', () => { + try { + validateGetInput( + { records: [{ ids: ['123'], table: 'test', redaction: RedactionType.DEFAULT }] }, + { orderBy: null } + ); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + SKYFLOW_ERROR_CODE.INVALID_ORDER_BY_IN_GET.description + ); + } + }); + + it('should throw error when ids and offset are both specified', () => { + try { + validateGetInput({ + records: [ + { + ids: ['123'], + table: 'test', + redaction: RedactionType.DEFAULT, + offset: '5', + }, + ], + }); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + SKYFLOW_ERROR_CODE.IDS_AND_OFFSET_LIMIT_BOTH_SPECIFIED.description + ); + } + }); + + it('should throw error when ids and limit are both specified', () => { + try { + validateGetInput({ + records: [ + { + ids: ['123'], + table: 'test', + redaction: RedactionType.DEFAULT, + limit: '10', + }, + ], + }); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + SKYFLOW_ERROR_CODE.IDS_AND_OFFSET_LIMIT_BOTH_SPECIFIED.description + ); + } + }); + + it('should throw error when ids, offset and limit are all specified', () => { + try { + validateGetInput({ + records: [ + { + ids: ['123'], + table: 'test', + redaction: RedactionType.DEFAULT, + offset: '0', + limit: '10', + }, + ], + }); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + SKYFLOW_ERROR_CODE.IDS_AND_OFFSET_LIMIT_BOTH_SPECIFIED.description + ); + } + }); + + it('should not throw when offset and limit are used with columnName and columnValues', () => { + expect(() => + validateGetInput({ + records: [ + { + table: 'test', + redaction: RedactionType.DEFAULT, + columnName: 'email', + columnValues: ['test@example.com'], + offset: '5', + limit: '10', + }, + ], + }) + ).not.toThrow(); + }); + + it('should not throw when only offset and limit are provided without ids or columnName', () => { + expect(() => + validateGetInput({ + records: [ + { + table: 'test', + redaction: RedactionType.DEFAULT, + offset: '0', + limit: '10', + }, + ], + }) + ).not.toThrow(); + }); + + it('should throw MISSING_IDS_OR_COLUMN_VALUES_IN_GET when no identifier and no offset/limit', () => { + try { + validateGetInput({ + records: [{ table: 'test', redaction: RedactionType.PLAIN_TEXT }], + }); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + parameterizedString( + SKYFLOW_ERROR_CODE.MISSING_IDS_OR_COLUMN_VALUES_IN_GET.description, + 0 + ) + ); + } + }); + + it('should not throw for valid downloadURL in get options', () => { + expect(() => + validateGetInput( + { records: [{ ids: ['123'], table: 'test', redaction: RedactionType.DEFAULT }] }, + { downloadURL: true } + ) + ).not.toThrow(); + }); + + it('should not throw for valid orderBy ASCENDING in get options', () => { + expect(() => + validateGetInput( + { records: [{ ids: ['123'], table: 'test', redaction: RedactionType.DEFAULT }] }, + { orderBy: 'ASCENDING' } + ) + ).not.toThrow(); + }); + + it('should not throw for valid orderBy DESCENDING in get options', () => { + expect(() => + validateGetInput( + { records: [{ ids: ['123'], table: 'test', redaction: RedactionType.DEFAULT }] }, + { orderBy: 'DESCENDING' } + ) + ).not.toThrow(); + }); + + it('should not throw for valid orderBy NONE in get options', () => { + expect(() => + validateGetInput( + { records: [{ ids: ['123'], table: 'test', redaction: RedactionType.DEFAULT }] }, + { orderBy: 'NONE' } + ) + ).not.toThrow(); + }); +}); + +describe('test validateGetInput fields in record', () => { + const validRecord = { ids: ['123'], table: 'test', redaction: RedactionType.PLAIN_TEXT }; + + it('should throw error for null fields in record', () => { + try { + validateGetInput({ records: [{ ...validRecord, fields: null }] }); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + parameterizedString( + SKYFLOW_ERROR_CODE.INVALID_FIELDS_IN_GET.description, + 0 + ) + ); + } + }); + + it('should throw error for non-array fields in record', () => { + try { + validateGetInput({ records: [{ ...validRecord, fields: 'occupation' }] }); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + parameterizedString( + SKYFLOW_ERROR_CODE.INVALID_FIELDS_IN_GET.description, + 0 + ) + ); + } + }); + + it('should throw error for empty fields array in record', () => { + try { + validateGetInput({ records: [{ ...validRecord, fields: [] }] }); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + parameterizedString( + SKYFLOW_ERROR_CODE.EMPTY_FIELDS_IN_GET.description, + 0 + ) + ); + } + }); + + it('should throw error for non-string value inside fields array in record', () => { + try { + validateGetInput({ records: [{ ...validRecord, fields: [123] }] }); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + parameterizedString( + SKYFLOW_ERROR_CODE.INVALID_FIELD_VALUE_IN_GET.description, + 0 + ) + ); + } + }); + + it('should throw error for null value inside fields array in record', () => { + try { + validateGetInput({ records: [{ ...validRecord, fields: [null] }] }); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + parameterizedString( + SKYFLOW_ERROR_CODE.INVALID_FIELD_VALUE_IN_GET.description, + 0 + ) + ); + } + }); + + it('should throw error for empty string inside fields array in record', () => { + try { + validateGetInput({ records: [{ ...validRecord, fields: [''] }] }); + } catch (err) { + expect(err?.errors[0]?.description).toEqual( + parameterizedString( + SKYFLOW_ERROR_CODE.EMPTY_FIELD_VALUE_IN_GET.description, + 0 + ) + ); + } + }); + + it('should not throw for valid fields array in record', () => { + expect(() => + validateGetInput({ + records: [{ ...validRecord, fields: ['occupation', 'annual_income'] }], + }) + ).not.toThrow(); + }); }); diff --git a/__tests__/core-utils/reveal.test.js b/__tests__/core-utils/reveal.test.js index 6ebfc1a..51ad602 100644 --- a/__tests__/core-utils/reveal.test.js +++ b/__tests__/core-utils/reveal.test.js @@ -675,4 +675,422 @@ describe('fetchRecordGET fn test', () => { done(err); }); }); + + it('should call rootReject when Promise.all rejects', (done) => { + const promiseAllError = new Error('Promise.all internal failure'); + const promiseAllSpy = jest + .spyOn(Promise, 'all') + .mockRejectedValueOnce(promiseAllError); + + jest.spyOn(ClientModule, 'default').mockImplementation(() => ({ + request: () => Promise.resolve(getSuccessResponse), + })); + + const testSkyflowClient = new Skyflow({ + vaultID: '1234', + vaultURL: 'https://url.com', + getBearerToken: () => Promise.resolve('valid_token'), + }); + + jest + .spyOn(testSkyflowClient, 'getAccessToken') + .mockResolvedValue('valid token'); + + fetchRecordsGET(testSkyflowClient, [getRecordID], optionsFalse) + .then( + () => { + promiseAllSpy.mockRestore(); + done(new Error('should have rejected')); + }, + (err) => { + promiseAllSpy.mockRestore(); + expect(err).toBe(promiseAllError); + done(); + } + ) + .catch((err) => { + promiseAllSpy.mockRestore(); + done(err); + }); + }); + + it('should not include ids key in error response for column-based record', (done) => { + jest.spyOn(ClientModule, 'default').mockImplementation(() => ({ + request: () => Promise.reject(getErrorResponse), + })); + + const testSkyflowClient = new Skyflow({ + vaultID: '1234', + vaultURL: 'https://url.com', + getBearerToken: () => Promise.resolve('valid_token'), + }); + + jest + .spyOn(testSkyflowClient, 'getAccessToken') + .mockResolvedValue('valid token'); + + fetchRecordsGET(testSkyflowClient, [getRecordColumn], optionsFalse) + .then( + (res) => {}, + (err) => { + expect(err.errors[0].ids).toBeUndefined(); + expect(err.errors[0].columnName).toBe(getRecordColumn.columnName); + done(); + } + ) + .catch((err) => { + done(err); + }); + }); + + it('should include record with empty fields when fields key is missing in vault response', (done) => { + const responseWithMissingFields = { + records: [{ skyflow_id: 'id1' }], // no `fields` key + }; + + jest.spyOn(ClientModule, 'default').mockImplementation(() => ({ + request: () => Promise.resolve(responseWithMissingFields), + })); + + const testSkyflowClient = new Skyflow({ + vaultID: '1234', + vaultURL: 'https://url.com', + getBearerToken: () => Promise.resolve('valid_token'), + }); + + jest + .spyOn(testSkyflowClient, 'getAccessToken') + .mockResolvedValue('valid token'); + + fetchRecordsGET(testSkyflowClient, [getRecordID], optionsFalse) + .then((res) => { + expect(res.records.length).toBe(1); + expect(res.records[0].fields).toEqual({}); + expect(res.records[0].table).toBe(getRecordID.table); + done(); + }) + .catch((err) => { + done(err); + }); + }); + + it('should not include id field in success record when skyflow_id is absent', (done) => { + const responseWithoutSkyflowId = { + records: [ + { + fields: { + card_number: '4111111111111111', + // no skyflow_id + }, + table: 'pii_fields', + }, + ], + }; + + jest.spyOn(ClientModule, 'default').mockImplementation(() => ({ + request: () => Promise.resolve(responseWithoutSkyflowId), + })); + + const testSkyflowClient = new Skyflow({ + vaultID: '1234', + vaultURL: 'https://url.com', + getBearerToken: () => Promise.resolve('valid_token'), + }); + + jest + .spyOn(testSkyflowClient, 'getAccessToken') + .mockResolvedValue('valid token'); + + fetchRecordsGET(testSkyflowClient, [getRecordID], optionsFalse) + .then((res) => { + expect(res.records.length).toBe(1); + expect(res.records[0].fields.id).toBeUndefined(); + expect(res.records[0].fields.card_number).toBe('4111111111111111'); + done(); + }) + .catch((err) => { + done(err); + }); + }); + + it('should include columnName in error response when column-based record fails', (done) => { + jest.spyOn(ClientModule, 'default').mockImplementation(() => ({ + request: () => Promise.reject(getErrorResponse), + })); + + const testSkyflowClient = new Skyflow({ + vaultID: '1234', + vaultURL: 'https://url.com', + getBearerToken: () => Promise.resolve('valid_token'), + }); + + jest + .spyOn(testSkyflowClient, 'getAccessToken') + .mockResolvedValue('valid token'); + + fetchRecordsGET(testSkyflowClient, [getRecordColumn], optionsFalse) + .then( + (res) => {}, + (err) => { + expect(err.errors.length).toBe(1); + expect(err.errors[0].error.code).toBe(404); + expect(err.errors[0].columnName).toBe(getRecordColumn.columnName); + done(); + } + ) + .catch((err) => { + done(err); + }); + }); + + it('should include fields params in url when fields are specified in options', (done) => { + let reqArg; + jest.spyOn(ClientModule, 'default').mockImplementation(() => ({ + request: (args) => { + reqArg = args; + return Promise.resolve(getSuccessResponse); + }, + })); + + const testSkyflowClient = new Skyflow({ + vaultID: '1234', + vaultURL: 'https://url.com', + getBearerToken: () => Promise.resolve('valid_token'), + }); + + jest.spyOn(testSkyflowClient, 'getAccessToken').mockResolvedValue('valid token'); + + const recordWithFields = { + ...getRecordID, + fields: ['occupation', 'annual_income'], + }; + fetchRecordsGET(testSkyflowClient, [recordWithFields], optionsFalse) + .then((res) => { + expect(reqArg.url).toContain('fields=occupation'); + expect(reqArg.url).toContain('fields=annual_income'); + done(); + }) + .catch((err) => { + done(err); + }); + }); + + it('should include offset and limit params in url when specified in record', (done) => { + let reqArg; + jest.spyOn(ClientModule, 'default').mockImplementation(() => ({ + request: (args) => { + reqArg = args; + return Promise.resolve(getSuccessResponse); + }, + })); + + const testSkyflowClient = new Skyflow({ + vaultID: '1234', + vaultURL: 'https://url.com', + getBearerToken: () => Promise.resolve('valid_token'), + }); + + jest.spyOn(testSkyflowClient, 'getAccessToken').mockResolvedValue('valid token'); + + const recordWithPagination = { ...getRecordID, offset: '5', limit: '10' }; + fetchRecordsGET(testSkyflowClient, [recordWithPagination], optionsFalse) + .then((res) => { + expect(reqArg.url).toContain('offset=5'); + expect(reqArg.url).toContain('limit=10'); + done(); + }) + .catch((err) => { + done(err); + }); + }); + + it('should include downloadURL param in url when specified in options', (done) => { + let reqArg; + jest.spyOn(ClientModule, 'default').mockImplementation(() => ({ + request: (args) => { + reqArg = args; + return Promise.resolve(getSuccessResponse); + }, + })); + + const testSkyflowClient = new Skyflow({ + vaultID: '1234', + vaultURL: 'https://url.com', + getBearerToken: () => Promise.resolve('valid_token'), + }); + + jest.spyOn(testSkyflowClient, 'getAccessToken').mockResolvedValue('valid token'); + + fetchRecordsGET(testSkyflowClient, [getRecordID], { ...optionsFalse, downloadURL: true }) + .then((res) => { + expect(reqArg.url).toContain('downloadURL=true'); + done(); + }) + .catch((err) => { + done(err); + }); + }); + + it('should include order_by param in url when orderBy is specified in options', (done) => { + let reqArg; + jest.spyOn(ClientModule, 'default').mockImplementation(() => ({ + request: (args) => { + reqArg = args; + return Promise.resolve(getSuccessResponse); + }, + })); + + const testSkyflowClient = new Skyflow({ + vaultID: '1234', + vaultURL: 'https://url.com', + getBearerToken: () => Promise.resolve('valid_token'), + }); + + jest.spyOn(testSkyflowClient, 'getAccessToken').mockResolvedValue('valid token'); + + fetchRecordsGET(testSkyflowClient, [getRecordID], { ...optionsFalse, orderBy: 'ASCENDING' }) + .then((res) => { + expect(reqArg.url).toContain('order_by=ASCENDING'); + done(); + }) + .catch((err) => { + done(err); + }); + }); + + it('should not include trailing & when all optional params are absent', (done) => { + let reqArg; + jest.spyOn(ClientModule, 'default').mockImplementation(() => ({ + request: (args) => { + reqArg = args; + return Promise.resolve(getSuccessResponse); + }, + })); + + const testSkyflowClient = new Skyflow({ + vaultID: '1234', + vaultURL: 'https://url.com', + getBearerToken: () => Promise.resolve('valid_token'), + }); + + jest.spyOn(testSkyflowClient, 'getAccessToken').mockResolvedValue('valid token'); + + fetchRecordsGET(testSkyflowClient, [getRecordID], optionsFalse) + .then((res) => { + expect(reqArg.url).not.toMatch(/&$/); + done(); + }) + .catch((err) => { + done(err); + }); + }); + + it('should include all new params together in url', (done) => { + let reqArg; + jest.spyOn(ClientModule, 'default').mockImplementation(() => ({ + request: (args) => { + reqArg = args; + return Promise.resolve(getSuccessResponse); + }, + })); + + const testSkyflowClient = new Skyflow({ + vaultID: '1234', + vaultURL: 'https://url.com', + getBearerToken: () => Promise.resolve('valid_token'), + }); + + jest.spyOn(testSkyflowClient, 'getAccessToken').mockResolvedValue('valid token'); + + const recordWithFields = { + ...getRecordID, + fields: ['name', 'dob'], + offset: '0', + limit: '25', + }; + const opts = { + ...optionsFalse, + downloadURL: false, + orderBy: 'DESCENDING', + }; + + fetchRecordsGET(testSkyflowClient, [recordWithFields], opts) + .then((res) => { + expect(reqArg.url).toContain('fields=name'); + expect(reqArg.url).toContain('fields=dob'); + expect(reqArg.url).toContain('offset=0'); + expect(reqArg.url).toContain('limit=25'); + expect(reqArg.url).toContain('downloadURL=false'); + expect(reqArg.url).toContain('order_by=DESCENDING'); + expect(reqArg.url).not.toMatch(/&$/); + done(); + }) + .catch((err) => { + done(err); + }); + }); + + it('should include order_by=NONE in url when orderBy is NONE', (done) => { + let reqArg; + jest.spyOn(ClientModule, 'default').mockImplementation(() => ({ + request: (args) => { + reqArg = args; + return Promise.resolve(getSuccessResponse); + }, + })); + + const testSkyflowClient = new Skyflow({ + vaultID: '1234', + vaultURL: 'https://url.com', + getBearerToken: () => Promise.resolve('valid_token'), + }); + + jest.spyOn(testSkyflowClient, 'getAccessToken').mockResolvedValue('valid token'); + + fetchRecordsGET(testSkyflowClient, [getRecordID], { + ...optionsFalse, + orderBy: 'NONE', + }) + .then((res) => { + expect(reqArg.url).toContain('order_by=NONE'); + done(); + }) + .catch((err) => { + done(err); + }); + }); + + it('should not include new params in url when only fields is set', (done) => { + let reqArg; + jest.spyOn(ClientModule, 'default').mockImplementation(() => ({ + request: (args) => { + reqArg = args; + return Promise.resolve(getSuccessResponse); + }, + })); + + const testSkyflowClient = new Skyflow({ + vaultID: '1234', + vaultURL: 'https://url.com', + getBearerToken: () => Promise.resolve('valid_token'), + }); + + jest + .spyOn(testSkyflowClient, 'getAccessToken') + .mockResolvedValue('valid token'); + + const recordWithFields = { ...getRecordID, fields: ['name'] }; + fetchRecordsGET(testSkyflowClient, [recordWithFields], optionsFalse) + .then((res) => { + expect(reqArg.url).toContain('fields=name'); + expect(reqArg.url).not.toContain('offset'); + expect(reqArg.url).not.toContain('limit'); + expect(reqArg.url).not.toContain('downloadURL'); + expect(reqArg.url).not.toContain('order_by'); + done(); + }) + .catch((err) => { + done(err); + }); + }); }); diff --git a/example/src/RevealElements.tsx b/example/src/RevealElements.tsx index 0cd6cab..efd95f9 100644 --- a/example/src/RevealElements.tsx +++ b/example/src/RevealElements.tsx @@ -5,6 +5,7 @@ import React from 'react'; import { Button, StyleSheet, View } from 'react-native'; import { + OrderBy, RedactionType, RevealElement, useRevealContainer, @@ -27,47 +28,94 @@ const RevealElements = (props) => { }; const handleGet = () =>{ - const getRecord1 = { - ids: [ - '', - '', - ], + const getRecordByIds = { + ids: ['', ''], table: 'cards', }; - const getRecord2 = { + const getRecordByColumn = { table: 'cards', columnName: '', columnValues: ['', ''], }; - const getRequest1 = { records: [getRecord1] }; + // Get tokens by Skyflow ID + skyflowContainer + .get( + { records: [getRecordByIds] }, + { tokens: true } + ) + .then((response) => { + console.log('Get tokens Success', JSON.stringify(response)); + }) + .catch((err) => { + console.error('Get tokens Failed', JSON.stringify(err)); + }); - const getRequest2 = { - records: [ - { ...getRecord1, redaction: RedactionType.PLAIN_TEXT }, - { ...getRecord2, redaction: RedactionType.PLAIN_TEXT }, - ], - }; + // Get plain text by Skyflow ID and column values + skyflowContainer + .get( + { + records: [ + { ...getRecordByIds, redaction: RedactionType.PLAIN_TEXT }, + { ...getRecordByColumn, redaction: RedactionType.PLAIN_TEXT }, + ], + }, + { tokens: false } + ) + .then((response) => { + console.log('Get plain text Success', JSON.stringify(response)); + }) + .catch((err) => { + console.error('Get plain text Failed', JSON.stringify(err)); + }); - // Get Tokens by Skyflow ID + // Get specific fields only (column-scoped policy compatible) skyflowContainer - .get(getRequest1, { tokens: true }) + .get( + { + records: [ + { + ...getRecordByIds, + redaction: RedactionType.PLAIN_TEXT, + fields: ['occupation', 'annual_income'], + }, + ], + }, + { tokens: false } + ) .then((response) => { - console.log('Get request 1 Success', JSON.stringify(response)); + console.log('Get with fields Success', JSON.stringify(response)); }) .catch((err) => { - console.error('Get request 1 Failed', JSON.stringify(err)); + console.error('Get with fields Failed', JSON.stringify(err)); }); - // get by Skyflow ID and Column Values + // Get with pagination and ordering skyflowContainer - .get(getRequest2, { tokens: false }) + .get( + { + records: [ + { + ...getRecordByColumn, + redaction: RedactionType.PLAIN_TEXT, + fields: ['name', 'email'], + offset: '0', + limit: '10', + }, + ], + }, + { + tokens: false, + orderBy: OrderBy.ASCENDING, + downloadURL: false, + } + ) .then((response) => { - console.log('Get request 2 Success', JSON.stringify(response)); + console.log('Get with pagination Success', JSON.stringify(response)); }) .catch((err) => { - console.error('Get request 2 Failed', JSON.stringify(err)); + console.error('Get with pagination Failed', JSON.stringify(err)); }); }; diff --git a/package.json b/package.json index 63f6cf9..99c9bd5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "skyflow-react-native", - "version": "1.10.3", + "version": "1.10.3-dev.aeb9d68", "description": "Skyflow React Native SDK", "main": "lib/commonjs/index", "module": "lib/module/index", diff --git a/src/core-utils/element-validations/index.ts b/src/core-utils/element-validations/index.ts index 540a434..1e44d0e 100644 --- a/src/core-utils/element-validations/index.ts +++ b/src/core-utils/element-validations/index.ts @@ -14,6 +14,7 @@ import { IGetInput, IGetOptions, IInsertRecordInput, + OrderBy, RedactionType, RevealElementInput, } from '../../utils/constants'; @@ -444,18 +445,45 @@ export const validateGetInput = ( throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_TOKENS_IN_GET); } + if ( + options && + Object.prototype.hasOwnProperty.call(options, 'downloadURL') && + typeof options.downloadURL !== 'boolean' + ) { + throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_DOWNLOAD_URL_IN_GET); + } + + if ( + options && + Object.prototype.hasOwnProperty.call(options, 'orderBy') && + !Object.values(OrderBy).includes(options.orderBy as OrderBy) + ) { + throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_ORDER_BY_IN_GET); + } + records.forEach((record: any, index: number) => { if (Object.keys(record).length === 0) { throw new SkyflowError(SKYFLOW_ERROR_CODE.EMPTY_RECORDS_GET); } if (record.ids?.length === 0) { - throw new SkyflowError(SKYFLOW_ERROR_CODE.EMPTY_IDS_IN_GET, [`${index}`]); + throw new SkyflowError(SKYFLOW_ERROR_CODE.EMPTY_IDS_IN_GET, [ + `${index}`, + ]); } if (record.ids != null && !(record.ids && Array.isArray(record.ids))) { throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_IDS_IN_GET, [ `${index}`, ]); } + if ( + Object.prototype.hasOwnProperty.call(record, 'ids') && + (Object.prototype.hasOwnProperty.call(record, 'offset') || + Object.prototype.hasOwnProperty.call(record, 'limit')) + ) { + throw new SkyflowError( + SKYFLOW_ERROR_CODE.IDS_AND_OFFSET_LIMIT_BOTH_SPECIFIED + ); + } record.ids?.forEach((skyflowId) => { if (!skyflowId) { throw new SkyflowError(SKYFLOW_ERROR_CODE.EMPTY_SKYFLOWID_IN_GET, [ @@ -521,10 +549,12 @@ export const validateGetInput = ( ); } if (!Object.prototype.hasOwnProperty.call(record, 'columnName')) { - if ( - Object.prototype.hasOwnProperty.call(record, 'ids') === false && - Object.prototype.hasOwnProperty.call(record, 'columnValues') === false - ) { + const hasIds = Object.prototype.hasOwnProperty.call(record, 'ids'); + const hasColumnValues = Object.prototype.hasOwnProperty.call(record, 'columnValues'); + const hasOffsetOrLimit = + Object.prototype.hasOwnProperty.call(record, 'offset') || + Object.prototype.hasOwnProperty.call(record, 'limit'); + if (!hasIds && !hasColumnValues && !hasOffsetOrLimit) { throw new SkyflowError( SKYFLOW_ERROR_CODE.MISSING_IDS_OR_COLUMN_VALUES_IN_GET, [`${index}`] @@ -553,11 +583,6 @@ export const validateGetInput = ( `${index}`, ]); } - if (record.columnName !== undefined && record.columnValues === undefined) { - throw new SkyflowError(SKYFLOW_ERROR_CODE.MISSING_RECORD_COLUMN_VALUE, [ - `${index}`, - ]); - } if (record.columnName === undefined && record.columnValues !== undefined) { throw new SkyflowError(SKYFLOW_ERROR_CODE.MISSING_RECORD_COLUMN_NAME, [ `${index}`, @@ -571,6 +596,11 @@ export const validateGetInput = ( [`${index}`] ); } + if (columnName === '') { + throw new SkyflowError(SKYFLOW_ERROR_CODE.EMPTY_RECORD_COLUMN_NAME, [ + `${index}`, + ]); + } const columnValues = record.columnValues; if (columnValues != null) { columnValues.forEach((eachColumnValue) => { @@ -602,5 +632,56 @@ export const validateGetInput = ( ); } } + + if (Object.prototype.hasOwnProperty.call(record, 'offset')) { + if (typeof record.offset !== 'string') { + throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_OFFSET_IN_GET, [ + `${index}`, + ]); + } + if (record.offset === '') { + throw new SkyflowError(SKYFLOW_ERROR_CODE.EMPTY_OFFSET_IN_GET, [ + `${index}`, + ]); + } + } + + if (Object.prototype.hasOwnProperty.call(record, 'limit')) { + if (typeof record.limit !== 'string') { + throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_LIMIT_IN_GET, [ + `${index}`, + ]); + } + if (record.limit === '') { + throw new SkyflowError(SKYFLOW_ERROR_CODE.EMPTY_LIMIT_IN_GET, [ + `${index}`, + ]); + } + } + + if (Object.prototype.hasOwnProperty.call(record, 'fields')) { + if (!Array.isArray(record.fields)) { + throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_FIELDS_IN_GET, [ + `${index}`, + ]); + } + if (record.fields.length === 0) { + throw new SkyflowError(SKYFLOW_ERROR_CODE.EMPTY_FIELDS_IN_GET, [ + `${index}`, + ]); + } + record.fields.forEach((field: any) => { + if (typeof field !== 'string') { + throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_FIELD_VALUE_IN_GET, [ + `${index}`, + ]); + } + if (!field) { + throw new SkyflowError(SKYFLOW_ERROR_CODE.EMPTY_FIELD_VALUE_IN_GET, [ + `${index}`, + ]); + } + }); + } }); }; diff --git a/src/core-utils/reveal/index.ts b/src/core-utils/reveal/index.ts index 9433756..c7fcf43 100644 --- a/src/core-utils/reveal/index.ts +++ b/src/core-utils/reveal/index.ts @@ -203,11 +203,12 @@ export const fetchRecordsGET = async ( (resolvedResult: any) => { const recordsData: any[] = resolvedResult.records; recordsData.forEach((fieldData) => { - const id = fieldData.fields.skyflow_id; - const currentRecord = { + const fields = fieldData?.fields ?? {}; + const skyflowId = fields?.skyflow_id; + const currentRecord: any = { fields: { - id, - ...fieldData.fields, + ...(skyflowId ? { id: skyflowId } : {}), + ...fields, }, table: skyflowIdRecord.table, }; @@ -223,7 +224,9 @@ export const fetchRecordsGET = async ( code: rejectedResult?.error?.code, description: rejectedResult?.error?.description, }, - ids: skyflowIdRecord.ids, + ...(skyflowIdRecord.ids + ? { ids: skyflowIdRecord.ids } + : {}), ...(skyflowIdRecord?.columnName ? { columnName: skyflowIdRecord?.columnName } : {}), @@ -265,7 +268,7 @@ export const fetchRecordsGET = async ( rootReject({ records: recordsResponse, errors: errorResponse }); }) .catch((err) => { - console.log(err); + rootReject(err); }); }) .catch((err) => { @@ -296,7 +299,31 @@ export const getRecordsFromVault = ( } if (getRecord?.redaction) { - paramList += `redaction=${getRecord.redaction}`; + paramList += `redaction=${getRecord.redaction}&`; + } + + getRecord.fields?.forEach((field) => { + paramList += `fields=${field}&`; + }); + + if (getRecord.offset !== undefined) { + paramList += `offset=${getRecord.offset}&`; + } + + if (getRecord.limit !== undefined) { + paramList += `limit=${getRecord.limit}&`; + } + + if (options && Object.prototype.hasOwnProperty.call(options, 'downloadURL')) { + paramList += `downloadURL=${options.downloadURL}&`; + } + + if (options && Object.prototype.hasOwnProperty.call(options, 'orderBy')) { + paramList += `order_by=${options.orderBy}&`; + } + + if (paramList.endsWith('&')) { + paramList = paramList.slice(0, -1); } const vault = config.vaultURL; diff --git a/src/index.ts b/src/index.ts index 009b7dc..eea484b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,6 +7,7 @@ export { ElementType, Env, LogLevel, + OrderBy, ValidationRuleType, RedactionType, SkyflowRevealElementRef, diff --git a/src/utils/constants/index.ts b/src/utils/constants/index.ts index 406745e..9b58ab6 100644 --- a/src/utils/constants/index.ts +++ b/src/utils/constants/index.ts @@ -245,6 +245,12 @@ export enum ContainerType { COMPOSABLE = 'COMPOSABLE', } +export enum OrderBy { + ASCENDING = 'ASCENDING', + DESCENDING = 'DESCENDING', + NONE = 'NONE', +} + export const PUREJS_TYPES = { GET: 'GET', }; @@ -255,6 +261,9 @@ export interface IGetRecord { table: string; columnName?: string; columnValues?: string[]; + fields?: string[]; + offset?: string; + limit?: string; } export interface IGetInput { @@ -263,6 +272,8 @@ export interface IGetInput { export interface IGetOptions { tokens?: Boolean; + downloadURL?: boolean; + orderBy?: OrderBy; } export const CARD_ICON_DEFAULT_STYLE = { diff --git a/src/utils/logs/index.ts b/src/utils/logs/index.ts index 81c9bb3..fe3ef2b 100644 --- a/src/utils/logs/index.ts +++ b/src/utils/logs/index.ts @@ -207,6 +207,7 @@ const logs = { `${SDK_NAME_VERSION} Validation error. Column Values is required when Column Name is specified.`, MISSING_RECORD_COLUMN_NAME: `${SDK_NAME_VERSION} Validation error. Column Name is required when Column Values are specified.`, + EMPTY_RECORD_COLUMN_NAME: `${SDK_NAME_VERSION} Validation error. 'columnName' cannot be empty in records at index %s1. Specify a non-empty string value instead.`, INVALID_RECORD_COLUMN_NAME_TYPE: `${SDK_NAME_VERSION} Validation error. Invalid Type of Records Column Name.`, INVALID_RECORD_COLUMN_VALUE_TYPE: `${SDK_NAME_VERSION} Validation error. Invalid Type of Records Column Values in records at index %s1`, INVALID_COLUMN_VALUES_TYPE: @@ -215,6 +216,28 @@ const logs = { EMPTY_COLUMN_VALUE: `${SDK_NAME_VERSION} Validation error. Column Value is empty in records at index %s1`, MISSING_IDS_OR_COLUMN_VALUES_IN_GET: `${SDK_NAME_VERSION} Validation error. Both 'ids' or 'columnValues' keys are missing. Either provide 'ids' or 'columnValues' with 'columnName' to fetch records.`, + INVALID_FIELDS_IN_GET: + `${SDK_NAME_VERSION} Validation error. Invalid 'fields' key in records at index %s1. Specify a value of type array instead.`, + EMPTY_FIELDS_IN_GET: + `${SDK_NAME_VERSION} Validation error. 'fields' key cannot be empty in records at index %s1. Specify a non-empty array instead.`, + EMPTY_FIELD_VALUE_IN_GET: + `${SDK_NAME_VERSION} Validation error. 'fields' array contains an empty string in records at index %s1. Specify non-empty string values.`, + INVALID_FIELD_VALUE_IN_GET: + `${SDK_NAME_VERSION} Validation error. 'fields' array contains a non-string value in records at index %s1. Specify string values instead.`, + IDS_AND_OFFSET_LIMIT_BOTH_SPECIFIED: + `${SDK_NAME_VERSION} Validation error. Invalid request. 'offset' and 'limit' aren't supported when fetching records by 'skyflow_id'. Remove 'offset' and 'limit'.`, + INVALID_OFFSET_IN_GET: + `${SDK_NAME_VERSION} Validation error. Invalid 'offset' in records at index %s1. Specify a value of type string instead.`, + EMPTY_OFFSET_IN_GET: + `${SDK_NAME_VERSION} Validation error. 'offset' cannot be empty in records at index %s1. Specify a non-empty string value instead.`, + INVALID_LIMIT_IN_GET: + `${SDK_NAME_VERSION} Validation error. Invalid 'limit' in records at index %s1. Specify a value of type string instead.`, + EMPTY_LIMIT_IN_GET: + `${SDK_NAME_VERSION} Validation error. 'limit' cannot be empty in records at index %s1. Specify a non-empty string value instead.`, + INVALID_DOWNLOAD_URL_IN_GET: + `${SDK_NAME_VERSION} Validation error. Invalid 'downloadURL' in get options. Specify a boolean value instead.`, + INVALID_ORDER_BY_IN_GET: + `${SDK_NAME_VERSION} Validation error. Invalid 'orderBy' in get options. Specify a valid OrderBy value (ASCENDING, DESCENDING, NONE).`, SKYFLOW_IDS_AND_COLUMN_NAME_BOTH_SPECIFIED: `${SDK_NAME_VERSION} Validation error. ids and columnName can not be specified together.`, GET_BY_SKYFLOWID_RESOLVED: '%s1 - GetById request is resolved.', diff --git a/src/utils/skyflow-error-code/index.ts b/src/utils/skyflow-error-code/index.ts index 9cb8163..a6d3695 100644 --- a/src/utils/skyflow-error-code/index.ts +++ b/src/utils/skyflow-error-code/index.ts @@ -330,6 +330,50 @@ const SKYFLOW_ERROR_CODE = { code: 400, description: logs.errorLogs.MISSING_IDS_OR_COLUMN_VALUES_IN_GET, }, + INVALID_FIELDS_IN_GET: { + code: 400, + description: logs.errorLogs.INVALID_FIELDS_IN_GET, + }, + EMPTY_FIELDS_IN_GET: { + code: 400, + description: logs.errorLogs.EMPTY_FIELDS_IN_GET, + }, + EMPTY_FIELD_VALUE_IN_GET: { + code: 400, + description: logs.errorLogs.EMPTY_FIELD_VALUE_IN_GET, + }, + INVALID_FIELD_VALUE_IN_GET: { + code: 400, + description: logs.errorLogs.INVALID_FIELD_VALUE_IN_GET, + }, + IDS_AND_OFFSET_LIMIT_BOTH_SPECIFIED: { + code: 400, + description: logs.errorLogs.IDS_AND_OFFSET_LIMIT_BOTH_SPECIFIED, + }, + INVALID_OFFSET_IN_GET: { + code: 400, + description: logs.errorLogs.INVALID_OFFSET_IN_GET, + }, + EMPTY_OFFSET_IN_GET: { + code: 400, + description: logs.errorLogs.EMPTY_OFFSET_IN_GET, + }, + INVALID_LIMIT_IN_GET: { + code: 400, + description: logs.errorLogs.INVALID_LIMIT_IN_GET, + }, + EMPTY_LIMIT_IN_GET: { + code: 400, + description: logs.errorLogs.EMPTY_LIMIT_IN_GET, + }, + INVALID_DOWNLOAD_URL_IN_GET: { + code: 400, + description: logs.errorLogs.INVALID_DOWNLOAD_URL_IN_GET, + }, + INVALID_ORDER_BY_IN_GET: { + code: 400, + description: logs.errorLogs.INVALID_ORDER_BY_IN_GET, + }, MISSING_RECORD_COLUMN_VALUE: { code: 400, description: logs.errorLogs.MISSING_RECORD_COLUMN_VALUE, @@ -346,6 +390,10 @@ const SKYFLOW_ERROR_CODE = { code: 400, description: logs.errorLogs.MISSING_RECORD_COLUMN_NAME, }, + EMPTY_RECORD_COLUMN_NAME: { + code: 400, + description: logs.errorLogs.EMPTY_RECORD_COLUMN_NAME, + }, INVALID_RECORD_COLUMN_VALUE: { code: 400, description: logs.errorLogs.INVALID_RECORD_COLUMN_VALUE,