diff --git a/.cspell.json b/.cspell.json index bda277c3..955c94be 100644 --- a/.cspell.json +++ b/.cspell.json @@ -116,7 +116,16 @@ "servname", "nodename", "flowdb", - "unrenamed" + "unrenamed", + "wordprocessingml", + "spreadsheetml", + "presentationml", + "msvideo", + "matroska", + "okio", + "LOPM", + "Ghvd", + "résumé" ], "languageSettings": [ { diff --git a/common/src/main/java/com/skyflow/errors/ErrorMessage.java b/common/src/main/java/com/skyflow/errors/ErrorMessage.java index 1e408cca..467a41c4 100644 --- a/common/src/main/java/com/skyflow/errors/ErrorMessage.java +++ b/common/src/main/java/com/skyflow/errors/ErrorMessage.java @@ -169,6 +169,40 @@ public enum ErrorMessage { MissingIndexInBulkTokenizeRecord("%s0 Validation error. Index in BulkTokenizeRequestRecord is null. Specify an index for every record."), DuplicateIndexInBulkTokenizeRecord("%s0 Validation error. Duplicate index in BulkTokenizeRequestRecord. Specify a unique index for every record."), + // Get Tokens + GetTokensRequestNull("%s0 Validation error. GetTokensRequest object is null. Specify a valid GetTokensRequest object."), + EmptyGetTokensRecords("%s0 Validation error. 'records' can't be empty. Specify at least one GetTokensRequestRecord."), + GetTokensRecordNull("%s0 Validation error. GetTokensRequestRecord in the list is null. Specify a valid GetTokensRequestRecord object."), + EmptyValueInGetTokensRecord("%s0 Validation error. 'value' in GetTokensRequestRecord is null or empty. Specify a valid value."), + EmptyTokenGroupNameInGetTokensRecord("%s0 Validation error. 'tokenGroupName' in GetTokensRequestRecord is null or empty. Specify a valid token group name."), + + // Upload Files + UploadFilesRequestNull("%s0 Validation error. UploadFilesRequest object is null. Specify a valid UploadFilesRequest object."), + EmptyUploadFilesRecords("%s0 Validation error. 'records' can't be empty. Specify at least one UploadFilesRequestRecord."), + UploadFilesRecordNull("%s0 Validation error. UploadFilesRequestRecord in the list is null. Specify a valid UploadFilesRequestRecord object."), + EmptyTableNameInUploadFilesRecord("%s0 Validation error. 'tableName' in UploadFilesRequestRecord is null or empty. Specify a valid table name."), + EmptySkyflowIdInUploadFilesRecord("%s0 Validation error. 'skyflowId' in UploadFilesRequestRecord is empty. Specify a valid skyflow ID, or omit it to create a new record."), + EmptyUploadFilesColumns("%s0 Validation error. 'columns' in UploadFilesRequestRecord can't be empty. Specify at least one UploadFilesRequestColumn."), + UploadFilesColumnNull("%s0 Validation error. UploadFilesRequestColumn in the list is null. Specify a valid UploadFilesRequestColumn object."), + EmptyColumnInUploadFilesColumn("%s0 Validation error. 'column' in UploadFilesRequestColumn is null or empty. Specify a valid column name."), + DuplicateColumnInUploadFilesRecord("%s0 Validation error. 'columns' in UploadFilesRequestRecord contains a duplicate column name. Specify each column only once."), + MissingFileSourceInUploadFilesColumn("%s0 Validation error. UploadFilesRequestColumn has no file. Provide one of filePath, base64, or fileObject."), + MultipleFileSourcesInUploadFilesColumn("%s0 Validation error. UploadFilesRequestColumn has more than one file. Provide exactly one of filePath, base64, or fileObject."), + InvalidFilePathInUploadFilesColumn("%s0 Validation error. No readable file at 'filePath' in UploadFilesRequestColumn. Specify the path of an existing file."), + InvalidBase64InUploadFilesColumn("%s0 Validation error. 'base64' in UploadFilesRequestColumn is not a valid base64 string. Specify valid base64-encoded content."), + FileNameRequiredWithBase64InUploadFilesColumn("%s0 Validation error. 'fileName' is required in UploadFilesRequestColumn when 'base64' is used. Specify a file name."), + InvalidFileObjectInUploadFilesColumn("%s0 Validation error. 'fileObject' in UploadFilesRequestColumn is not an existing file. Specify a valid file object."), + + // Delete Files + DeleteFilesRequestNull("%s0 Validation error. DeleteFilesRequest object is null. Specify a valid DeleteFilesRequest object."), + EmptyDeleteFilesRecords("%s0 Validation error. 'records' can't be empty. Specify at least one DeleteFilesRequestRecord."), + DeleteFilesRecordNull("%s0 Validation error. DeleteFilesRequestRecord in the list is null. Specify a valid DeleteFilesRequestRecord object."), + EmptyTableNameInDeleteFilesRecord("%s0 Validation error. 'tableName' in DeleteFilesRequestRecord is null or empty. Specify a valid table name."), + EmptyDeleteFilesColumns("%s0 Validation error. 'columns' in DeleteFilesRequestRecord can't be empty. Specify at least one file column."), + EmptyColumnInDeleteFilesColumns("%s0 Validation error. 'columns' in DeleteFilesRequestRecord contains a null or empty column name. Specify valid column names."), + DuplicateColumnInDeleteFilesColumns("%s0 Validation error. 'columns' in DeleteFilesRequestRecord contains a duplicate column name. Specify each column only once."), + InvalidIdOrUniqueValuesInDeleteFilesRecord("%s0 Validation error. DeleteFilesRequestRecord must set exactly one of 'skyflowId' or 'uniqueValues'. Specify one of them."), + // Connection InvalidRequestHeaders("%s0 Validation error. Request headers aren't valid. Specify valid request headers."), EmptyRequestHeaders("%s0 Validation error. Request headers are empty. Specify valid request headers."), diff --git a/common/src/main/java/com/skyflow/logs/ErrorLogs.java b/common/src/main/java/com/skyflow/logs/ErrorLogs.java index 418d08bc..53031bb7 100644 --- a/common/src/main/java/com/skyflow/logs/ErrorLogs.java +++ b/common/src/main/java/com/skyflow/logs/ErrorLogs.java @@ -147,6 +147,38 @@ public enum ErrorLogs { TOKENIZE_DATA_SIZE_EXCEED("Maximum number of tokenize records exceeded. The limit is 100000."), MISSING_INDEX_IN_BULK_TOKENIZE_RECORD("Invalid %s1 request. Index in BulkTokenizeRequestRecord can not be null at position %s2."), DUPLICATE_INDEX_IN_BULK_TOKENIZE_RECORD("Invalid %s1 request. Duplicate index %s2 in BulkTokenizeRequestRecord."), + GET_TOKENS_REQUEST_REJECTED("Get tokens request resulted in failure."), + GET_TOKENS_REQUEST_NULL("Invalid %s1 request. Get tokens request can not be null."), + EMPTY_GET_TOKENS_RECORDS("Invalid %s1 request. Records can not be null or empty."), + GET_TOKENS_RECORD_NULL("Invalid %s1 request. GetTokensRequestRecord can not be null at index %s2."), + EMPTY_VALUE_IN_GET_TOKENS_RECORD("Invalid %s1 request. Value in GetTokensRequestRecord can not be null or empty at index %s2."), + EMPTY_TOKEN_GROUP_NAME_IN_GET_TOKENS_RECORD("Invalid %s1 request. Token group name in GetTokensRequestRecord can not be null or empty at index %s2."), + UPLOAD_FILES_REQUEST_REJECTED("Upload files request resulted in failure."), + UPLOAD_FILES_REQUEST_NULL("Invalid %s1 request. Upload files request can not be null."), + EMPTY_UPLOAD_FILES_RECORDS("Invalid %s1 request. Records can not be null or empty."), + UPLOAD_FILES_RECORD_NULL("Invalid %s1 request. UploadFilesRequestRecord can not be null at index %s2."), + EMPTY_TABLE_NAME_IN_UPLOAD_FILES_RECORD("Invalid %s1 request. Table name in UploadFilesRequestRecord can not be null or empty at index %s2."), + EMPTY_SKYFLOW_ID_IN_UPLOAD_FILES_RECORD("Invalid %s1 request. Skyflow ID in UploadFilesRequestRecord can not be empty at index %s2."), + EMPTY_UPLOAD_FILES_COLUMNS("Invalid %s1 request. Columns in UploadFilesRequestRecord can not be null or empty at index %s2."), + UPLOAD_FILES_COLUMN_NULL("Invalid %s1 request. UploadFilesRequestColumn can not be null in record at index %s2."), + EMPTY_COLUMN_IN_UPLOAD_FILES_COLUMN("Invalid %s1 request. Column name in UploadFilesRequestColumn can not be null or empty in record at index %s2."), + DUPLICATE_COLUMN_IN_UPLOAD_FILES_RECORD("Invalid %s1 request. Column name in UploadFilesRequestRecord can not be repeated in record at index %s2."), + MISSING_FILE_SOURCE_IN_UPLOAD_FILES_COLUMN("Invalid %s1 request. UploadFilesRequestColumn has no filePath, base64 or fileObject in record at index %s2."), + MULTIPLE_FILE_SOURCES_IN_UPLOAD_FILES_COLUMN("Invalid %s1 request. UploadFilesRequestColumn sets more than one of filePath, base64 and fileObject in record at index %s2."), + INVALID_FILE_PATH_IN_UPLOAD_FILES_COLUMN("Invalid %s1 request. File path in UploadFilesRequestColumn does not point to a readable file in record at index %s2."), + INVALID_BASE64_IN_UPLOAD_FILES_COLUMN("Invalid %s1 request. Base64 content in UploadFilesRequestColumn is invalid in record at index %s2."), + FILE_NAME_REQUIRED_WITH_BASE64_IN_UPLOAD_FILES_COLUMN("Invalid %s1 request. File name is required with base64 content in UploadFilesRequestColumn in record at index %s2."), + INVALID_FILE_OBJECT_IN_UPLOAD_FILES_COLUMN("Invalid %s1 request. File object in UploadFilesRequestColumn is not an existing file in record at index %s2."), + SIGNED_URL_UPLOAD_FAILED("Upload of a file to its signed URL failed for column %s1."), + DELETE_FILES_REQUEST_REJECTED("Delete files request resulted in failure."), + DELETE_FILES_REQUEST_NULL("Invalid %s1 request. Delete files request can not be null."), + EMPTY_DELETE_FILES_RECORDS("Invalid %s1 request. Records can not be null or empty."), + DELETE_FILES_RECORD_NULL("Invalid %s1 request. DeleteFilesRequestRecord can not be null at index %s2."), + EMPTY_TABLE_NAME_IN_DELETE_FILES_RECORD("Invalid %s1 request. Table name in DeleteFilesRequestRecord can not be null or empty at index %s2."), + EMPTY_DELETE_FILES_COLUMNS("Invalid %s1 request. Columns in DeleteFilesRequestRecord can not be null or empty at index %s2."), + EMPTY_COLUMN_IN_DELETE_FILES_COLUMNS("Invalid %s1 request. Column name in DeleteFilesRequestRecord can not be null or empty at index %s2."), + DUPLICATE_COLUMN_IN_DELETE_FILES_COLUMNS("Invalid %s1 request. Column name in DeleteFilesRequestRecord can not be repeated at index %s2."), + INVALID_ID_OR_UNIQUE_VALUES_IN_DELETE_FILES_RECORD("Invalid %s1 request. DeleteFilesRequestRecord must set exactly one of skyflow ID or unique values at index %s2."), DELETE_REQUEST_NULL("Invalid %s1 request. Delete request can not be null."), DELETE_REQUEST_REJECTED("Delete request resulted in failure."), DELETE_TOKENS_REQUEST_NULL("Invalid %s1 request. DeleteTokens request can not be null."), diff --git a/common/src/main/java/com/skyflow/logs/InfoLogs.java b/common/src/main/java/com/skyflow/logs/InfoLogs.java index b4045229..af8a46eb 100644 --- a/common/src/main/java/com/skyflow/logs/InfoLogs.java +++ b/common/src/main/java/com/skyflow/logs/InfoLogs.java @@ -77,6 +77,22 @@ public enum InfoLogs { TOKENIZE_REQUEST_RESOLVED("Tokenize request resolved."), TOKENIZE_SUCCESS("Data tokenized."), + // Get tokens interface + GET_TOKENS_TRIGGERED("Get tokens method triggered."), + VALIDATING_GET_TOKENS_REQUEST("Validating get tokens request."), + GET_TOKENS_REQUEST_RESOLVED("Get tokens request resolved."), + + // Upload files interface + UPLOAD_FILES_TRIGGERED("Upload files method triggered."), + VALIDATING_UPLOAD_FILES_REQUEST("Validating upload files request."), + UPLOADING_FILES_TO_SIGNED_URLS("Signed upload URLs received. Uploading files."), + UPLOAD_FILES_REQUEST_RESOLVED("Upload files request resolved."), + + // Delete files interface + DELETE_FILES_TRIGGERED("Delete files method triggered."), + VALIDATING_DELETE_FILES_REQUEST("Validating delete files request."), + DELETE_FILES_REQUEST_RESOLVED("Delete files request resolved."), + // Invoke connection interface INVOKE_CONNECTION_TRIGGERED("Invoke connection method triggered."), diff --git a/common/src/main/java/com/skyflow/vault/data/BaseDeleteFilesRequest.java b/common/src/main/java/com/skyflow/vault/data/BaseDeleteFilesRequest.java new file mode 100644 index 00000000..98dd5cdf --- /dev/null +++ b/common/src/main/java/com/skyflow/vault/data/BaseDeleteFilesRequest.java @@ -0,0 +1,11 @@ +package com.skyflow.vault.data; + +public class BaseDeleteFilesRequest { + protected BaseDeleteFilesRequest(BaseDeleteFilesRequestBuilder builder) { + } + + static class BaseDeleteFilesRequestBuilder { + protected BaseDeleteFilesRequestBuilder() { + } + } +} diff --git a/common/src/main/java/com/skyflow/vault/data/BaseDeleteFilesResponse.java b/common/src/main/java/com/skyflow/vault/data/BaseDeleteFilesResponse.java new file mode 100644 index 00000000..47f300c4 --- /dev/null +++ b/common/src/main/java/com/skyflow/vault/data/BaseDeleteFilesResponse.java @@ -0,0 +1,30 @@ +package com.skyflow.vault.data; + +import com.google.gson.Gson; + +import java.util.ArrayList; +import java.util.HashMap; + +public class BaseDeleteFilesResponse { + private final ArrayList> records; + + public BaseDeleteFilesResponse(ArrayList> records) { + this.records = records; + } + + /** + * Returns one record map per resolved record. A record addressed by uniqueValues can resolve to + * several records, so there may be more entries than input records. Each map carries the + * skyflowId, table, the deleted columns (null on a failed record) and the per-record + * status/error. + */ + public ArrayList> getRecords() { + return records; + } + + @Override + public String toString() { + Gson gson = new Gson().newBuilder().serializeNulls().create(); + return gson.toJson(this); + } +} diff --git a/common/src/main/java/com/skyflow/vault/data/BaseGetTokensRequest.java b/common/src/main/java/com/skyflow/vault/data/BaseGetTokensRequest.java new file mode 100644 index 00000000..bc132f87 --- /dev/null +++ b/common/src/main/java/com/skyflow/vault/data/BaseGetTokensRequest.java @@ -0,0 +1,11 @@ +package com.skyflow.vault.data; + +public class BaseGetTokensRequest { + protected BaseGetTokensRequest(BaseGetTokensRequestBuilder builder) { + } + + static class BaseGetTokensRequestBuilder { + protected BaseGetTokensRequestBuilder() { + } + } +} diff --git a/common/src/main/java/com/skyflow/vault/data/BaseGetTokensResponse.java b/common/src/main/java/com/skyflow/vault/data/BaseGetTokensResponse.java new file mode 100644 index 00000000..1b7e929f --- /dev/null +++ b/common/src/main/java/com/skyflow/vault/data/BaseGetTokensResponse.java @@ -0,0 +1,28 @@ +package com.skyflow.vault.data; + +import com.google.gson.Gson; + +import java.util.ArrayList; +import java.util.HashMap; + +public class BaseGetTokensResponse { + private final ArrayList> records; + + public BaseGetTokensResponse(ArrayList> records) { + this.records = records; + } + + /** + * Returns one record map per input entry, in request order. Each map carries the looked-up + * value, its token group, the token (or "" when there is none), and the per-record status/error. + */ + public ArrayList> getRecords() { + return records; + } + + @Override + public String toString() { + Gson gson = new Gson().newBuilder().serializeNulls().create(); + return gson.toJson(this); + } +} diff --git a/common/src/main/java/com/skyflow/vault/data/BaseUploadFilesRequest.java b/common/src/main/java/com/skyflow/vault/data/BaseUploadFilesRequest.java new file mode 100644 index 00000000..531f20ad --- /dev/null +++ b/common/src/main/java/com/skyflow/vault/data/BaseUploadFilesRequest.java @@ -0,0 +1,11 @@ +package com.skyflow.vault.data; + +public class BaseUploadFilesRequest { + protected BaseUploadFilesRequest(BaseUploadFilesRequestBuilder builder) { + } + + static class BaseUploadFilesRequestBuilder { + protected BaseUploadFilesRequestBuilder() { + } + } +} diff --git a/common/src/main/java/com/skyflow/vault/data/BaseUploadFilesResponse.java b/common/src/main/java/com/skyflow/vault/data/BaseUploadFilesResponse.java new file mode 100644 index 00000000..e788cb3a --- /dev/null +++ b/common/src/main/java/com/skyflow/vault/data/BaseUploadFilesResponse.java @@ -0,0 +1,29 @@ +package com.skyflow.vault.data; + +import com.google.gson.Gson; + +import java.util.ArrayList; +import java.util.HashMap; + +public class BaseUploadFilesResponse { + private final ArrayList> records; + + public BaseUploadFilesResponse(ArrayList> records) { + this.records = records; + } + + /** + * Returns one record map per input record, in request order. Each map carries the record's + * skyflowId and table, the upload status of every requested column, and the per-record + * status/error. + */ + public ArrayList> getRecords() { + return records; + } + + @Override + public String toString() { + Gson gson = new Gson().newBuilder().serializeNulls().create(); + return gson.toJson(this); + } +} diff --git a/common/src/test/java/com/skyflow/vault/data/BaseDeleteFilesRequestTests.java b/common/src/test/java/com/skyflow/vault/data/BaseDeleteFilesRequestTests.java new file mode 100644 index 00000000..ebb98619 --- /dev/null +++ b/common/src/test/java/com/skyflow/vault/data/BaseDeleteFilesRequestTests.java @@ -0,0 +1,26 @@ +package com.skyflow.vault.data; + +import org.junit.Assert; +import org.junit.Test; + +public class BaseDeleteFilesRequestTests { + + @Test + public void testInstantiationDoesNotThrow() { + BaseDeleteFilesRequest request = new BaseDeleteFilesRequest(new BaseDeleteFilesRequest.BaseDeleteFilesRequestBuilder()); + + Assert.assertNotNull(request); + } + + @Test + public void testUsableAsExtensionPointForSubclasses() { + // BaseDeleteFilesRequest carries no state of its own; it exists so module-specific + // DeleteFilesRequest classes share a supertype and builder. Verify the subtype relationship holds. + BaseDeleteFilesRequest.BaseDeleteFilesRequestBuilder builder = new BaseDeleteFilesRequest.BaseDeleteFilesRequestBuilder() { + }; + BaseDeleteFilesRequest request = new BaseDeleteFilesRequest(builder) { + }; + + Assert.assertTrue(request instanceof BaseDeleteFilesRequest); + } +} diff --git a/common/src/test/java/com/skyflow/vault/data/BaseDeleteFilesResponseTests.java b/common/src/test/java/com/skyflow/vault/data/BaseDeleteFilesResponseTests.java new file mode 100644 index 00000000..a4939d1b --- /dev/null +++ b/common/src/test/java/com/skyflow/vault/data/BaseDeleteFilesResponseTests.java @@ -0,0 +1,47 @@ +package com.skyflow.vault.data; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; + +public class BaseDeleteFilesResponseTests { + + @Test + public void testGetRecordsReturnsConstructorValue() { + HashMap record = new HashMap<>(); + record.put("skyflowId", "sky-1"); + ArrayList> records = new ArrayList<>(Collections.singletonList(record)); + + BaseDeleteFilesResponse response = new BaseDeleteFilesResponse(records); + + Assert.assertSame(records, response.getRecords()); + } + + @Test + public void testNullRecordsAllowed() { + BaseDeleteFilesResponse response = new BaseDeleteFilesResponse(null); + + Assert.assertNull(response.getRecords()); + } + + @Test + public void testToStringSerializesNulls() { + HashMap record = new HashMap<>(); + record.put("columns", null); + record.put("error", "Invalid request. skyflowID is invalid."); + BaseDeleteFilesResponse response = new BaseDeleteFilesResponse(new ArrayList<>(Collections.singletonList(record))); + + String json = response.toString(); + + Assert.assertTrue(json, json.contains("\"columns\":null")); + Assert.assertTrue(json, json.contains("\"error\":\"Invalid request. skyflowID is invalid.\"")); + } + + @Test + public void testToStringWithNullRecords() { + Assert.assertEquals("{\"records\":null}", new BaseDeleteFilesResponse(null).toString()); + } +} diff --git a/common/src/test/java/com/skyflow/vault/data/BaseGetTokensRequestTests.java b/common/src/test/java/com/skyflow/vault/data/BaseGetTokensRequestTests.java new file mode 100644 index 00000000..8ec7f57c --- /dev/null +++ b/common/src/test/java/com/skyflow/vault/data/BaseGetTokensRequestTests.java @@ -0,0 +1,26 @@ +package com.skyflow.vault.data; + +import org.junit.Assert; +import org.junit.Test; + +public class BaseGetTokensRequestTests { + + @Test + public void testInstantiationDoesNotThrow() { + BaseGetTokensRequest request = new BaseGetTokensRequest(new BaseGetTokensRequest.BaseGetTokensRequestBuilder()); + + Assert.assertNotNull(request); + } + + @Test + public void testUsableAsExtensionPointForSubclasses() { + // BaseGetTokensRequest carries no state of its own; it exists so module-specific + // GetTokensRequest classes share a supertype and builder. Verify the subtype relationship holds. + BaseGetTokensRequest.BaseGetTokensRequestBuilder builder = new BaseGetTokensRequest.BaseGetTokensRequestBuilder() { + }; + BaseGetTokensRequest request = new BaseGetTokensRequest(builder) { + }; + + Assert.assertTrue(request instanceof BaseGetTokensRequest); + } +} diff --git a/common/src/test/java/com/skyflow/vault/data/BaseGetTokensResponseTests.java b/common/src/test/java/com/skyflow/vault/data/BaseGetTokensResponseTests.java new file mode 100644 index 00000000..fa945ec5 --- /dev/null +++ b/common/src/test/java/com/skyflow/vault/data/BaseGetTokensResponseTests.java @@ -0,0 +1,47 @@ +package com.skyflow.vault.data; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; + +public class BaseGetTokensResponseTests { + + @Test + public void testGetRecordsReturnsConstructorValue() { + HashMap record = new HashMap<>(); + record.put("token", "tok-1"); + ArrayList> records = new ArrayList<>(Collections.singletonList(record)); + + BaseGetTokensResponse response = new BaseGetTokensResponse(records); + + Assert.assertSame(records, response.getRecords()); + } + + @Test + public void testNullRecordsAllowed() { + BaseGetTokensResponse response = new BaseGetTokensResponse(null); + + Assert.assertNull(response.getRecords()); + } + + @Test + public void testToStringSerializesNulls() { + HashMap record = new HashMap<>(); + record.put("token", null); + record.put("error", "Token not found."); + BaseGetTokensResponse response = new BaseGetTokensResponse(new ArrayList<>(Collections.singletonList(record))); + + String json = response.toString(); + + Assert.assertTrue(json, json.contains("\"token\":null")); + Assert.assertTrue(json, json.contains("\"error\":\"Token not found.\"")); + } + + @Test + public void testToStringWithNullRecords() { + Assert.assertEquals("{\"records\":null}", new BaseGetTokensResponse(null).toString()); + } +} diff --git a/common/src/test/java/com/skyflow/vault/data/BaseUploadFilesRequestTests.java b/common/src/test/java/com/skyflow/vault/data/BaseUploadFilesRequestTests.java new file mode 100644 index 00000000..daa4b809 --- /dev/null +++ b/common/src/test/java/com/skyflow/vault/data/BaseUploadFilesRequestTests.java @@ -0,0 +1,26 @@ +package com.skyflow.vault.data; + +import org.junit.Assert; +import org.junit.Test; + +public class BaseUploadFilesRequestTests { + + @Test + public void testInstantiationDoesNotThrow() { + BaseUploadFilesRequest request = new BaseUploadFilesRequest(new BaseUploadFilesRequest.BaseUploadFilesRequestBuilder()); + + Assert.assertNotNull(request); + } + + @Test + public void testUsableAsExtensionPointForSubclasses() { + // BaseUploadFilesRequest carries no state of its own; it exists so module-specific + // UploadFilesRequest classes share a supertype and builder. Verify the subtype relationship holds. + BaseUploadFilesRequest.BaseUploadFilesRequestBuilder builder = new BaseUploadFilesRequest.BaseUploadFilesRequestBuilder() { + }; + BaseUploadFilesRequest request = new BaseUploadFilesRequest(builder) { + }; + + Assert.assertTrue(request instanceof BaseUploadFilesRequest); + } +} diff --git a/common/src/test/java/com/skyflow/vault/data/BaseUploadFilesResponseTests.java b/common/src/test/java/com/skyflow/vault/data/BaseUploadFilesResponseTests.java new file mode 100644 index 00000000..c5c8fcd1 --- /dev/null +++ b/common/src/test/java/com/skyflow/vault/data/BaseUploadFilesResponseTests.java @@ -0,0 +1,47 @@ +package com.skyflow.vault.data; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; + +public class BaseUploadFilesResponseTests { + + @Test + public void testGetRecordsReturnsConstructorValue() { + HashMap record = new HashMap<>(); + record.put("skyflowId", "sky-1"); + ArrayList> records = new ArrayList<>(Collections.singletonList(record)); + + BaseUploadFilesResponse response = new BaseUploadFilesResponse(records); + + Assert.assertSame(records, response.getRecords()); + } + + @Test + public void testNullRecordsAllowed() { + BaseUploadFilesResponse response = new BaseUploadFilesResponse(null); + + Assert.assertNull(response.getRecords()); + } + + @Test + public void testToStringSerializesNulls() { + HashMap record = new HashMap<>(); + record.put("skyflowId", null); + record.put("error", "Invalid request. skyflowID is invalid."); + BaseUploadFilesResponse response = new BaseUploadFilesResponse(new ArrayList<>(Collections.singletonList(record))); + + String json = response.toString(); + + Assert.assertTrue(json, json.contains("\"skyflowId\":null")); + Assert.assertTrue(json, json.contains("\"error\":\"Invalid request. skyflowID is invalid.\"")); + } + + @Test + public void testToStringWithNullRecords() { + Assert.assertEquals("{\"records\":null}", new BaseUploadFilesResponse(null).toString()); + } +} diff --git a/flowvault/README.md b/flowvault/README.md index c6d78f26..a68dec07 100644 --- a/flowvault/README.md +++ b/flowvault/README.md @@ -49,6 +49,10 @@ The `flowvault` module is a Skyflow Java SDK built for high-throughput vault ope - [Get](#get) - [Update](#update) - [Delete](#delete) +- [Query](#query) +- [Get Tokens](#get-tokens) +- [Upload Files](#upload-files) +- [Delete Files](#delete-files) - [Custom Request Headers](#custom-request-headers) - [Error Handling](#error-handling) - [Two layers of errors](#two-layers-of-errors) @@ -619,7 +623,7 @@ The 100,000-item ceiling per bulk call is a separate, fixed limit and is not con # VaultController — Unary operations -Alongside the bulk methods, `VaultController` exposes five **unary** operations. Each sends exactly one API call and hands the result straight back: +Alongside the bulk methods, `VaultController` exposes nine **unary** operations. Each sends exactly one API call and hands the result straight back: | Method | Parameters | Returns | Description | |--------|-----------|---------|-------------| @@ -628,10 +632,14 @@ Alongside the bulk methods, `VaultController` exposes five **unary** operations. | `get(GetRequest)` | `GetRequest`, optional `GetOptions` | `GetResponse` | Read records by skyflow ID or unique value, optionally with a redaction override per column | | `update(UpdateRequest)` | `UpdateRequest`, optional `UpdateOptions` | `UpdateResponse` | Update records by skyflow ID | | `delete(DeleteRequest)` | `DeleteRequest`, optional `DeleteOptions` | `DeleteResponse` | Delete records by skyflow ID or unique value | +| `query(QueryRequest)` | `QueryRequest`, optional `QueryOptions` | `QueryResponse` | Run a SQL `SELECT` against the vault | +| `getTokens(GetTokensRequest)` | `GetTokensRequest`, optional `GetTokensOptions` | `GetTokensResponse` | Look up the existing deterministic token for each value | +| `uploadFiles(UploadFilesRequest)` | `UploadFilesRequest`, optional `UploadFilesOptions` | `UploadFilesResponse` | Upload files into the file columns of new or existing records | +| `deleteFiles(DeleteFilesRequest)` | `DeleteFilesRequest`, optional `DeleteFilesOptions` | `DeleteFilesResponse` | Delete the files in file columns of existing records | -`insert` and `detokenize` are the unary counterparts of `bulkInsert` and `bulkDetokenize` — the same request builders, sent as one call instead of many batches. `get`, `update`, and `delete` have no bulk counterpart at all; they exist only in this unary form. +`insert` and `detokenize` are the unary counterparts of `bulkInsert` and `bulkDetokenize` — the same request builders, sent as one call instead of many batches. `get`, `update`, `delete`, `query`, `getTokens`, `uploadFiles`, and `deleteFiles` have no bulk counterpart at all; they exist only in this unary form. -Each method also accepts an optional options object (`InsertOptions`, `DetokenizeOptions`, `GetOptions`, `UpdateOptions`, `DeleteOptions`) — see [Custom Request Headers](#custom-request-headers). +Each method also accepts an optional options object (`InsertOptions`, `DetokenizeOptions`, `GetOptions`, `UpdateOptions`, `DeleteOptions`, `QueryOptions`, `GetTokensOptions`, `UploadFilesOptions`, `DeleteFilesOptions`) — see [Custom Request Headers](#custom-request-headers). ## Unary vs. bulk Parity @@ -649,7 +657,7 @@ Everything the bulk machinery adds — batching, concurrency, the payload ceilin ## Vault type support -The same distinction as [Schema vs. schemaless vaults](#schema-vs-schemaless-vaults) applies. Four of the five unary operations address records inside a table, so they only make sense against a structured vault: +The same distinction as [Schema vs. schemaless vaults](#schema-vs-schemaless-vaults) applies. Seven of the nine unary operations address records inside a table, so they only make sense against a structured vault: | Operation | Supported on | |---|---| @@ -658,6 +666,10 @@ The same distinction as [Schema vs. schemaless vaults](#schema-vs-schemaless-vau | `update` | Structured vaults — updates a table's records by skyflow ID. | | `delete` | Structured vaults — deletes a table's records. Distinct from `bulkDeleteTokens`, which removes tokens only and leaves the record in place. | | `detokenize` | Both — detokenizing only needs the token itself, not a table, so it works regardless of which kind of vault the token came from. | +| `query` | Structured vaults — runs a SQL `SELECT` over a table's records. | +| `getTokens` | Both — the lookup only needs a value and a deterministic token group, not a table. | +| `uploadFiles` | Structured vaults — uploads into a table's file columns. | +| `deleteFiles` | Structured vaults — deletes the files in a table's file columns. | # SDK Guidelines: Unary vs Bulk Operations @@ -1624,6 +1636,307 @@ for (DeleteResponseRecord record : deleteResponse.getRecords()) { } ``` +# Query + +Run a SQL `SELECT` against the vault, in a single API call. + +> **Vault type supported:** structured (schema) vaults. See [Vault type support](#vault-type-support). + +**Note:** + +- Only `SELECT` is supported. A call returns at most 25 records; to page, use SQL `OFFSET`. +- Values may be masked. They are never tokens or file URLs. +- There is no per-record status: any failure is thrown as a `SkyflowException`, and `getErrors()` is always `null`. `getRequestId()` is call-level and always populated. + +### Construct a query request + +Continuing from [Quickstart](#quickstart) — `skyflowClient` below is the `Skyflow` client built there. + +```java +import com.skyflow.errors.SkyflowException; +import com.skyflow.vault.controller.VaultController; +import com.skyflow.vault.data.QueryRequest; +import com.skyflow.vault.data.QueryResponse; + +public class QueryExample { + public static void main(String[] args) throws SkyflowException { + // skyflowClient is the Skyflow client built in Quickstart + VaultController vault = skyflowClient.vault(); + + QueryRequest queryRequest = QueryRequest.builder() + .query("SELECT * FROM persons WHERE name = 'John Doe'") + .build(); + + QueryResponse queryResponse = vault.query(queryRequest); + System.out.println(queryResponse); + } +} +``` + +There is no async variant: `query` returns its `QueryResponse` directly. + +Sample response: + +```json +{ + "fields": [ { "skyflow_id": "9f5b8e6e-...", "name": "John Doe", "email": "john@example.com" } ], + "errors": null, + "metadata": { "columns": ["skyflow_id", "name", "email"] }, + "requestId": "" +} +``` + +Accessors: `queryResponse.getFields()` (one `HashMap` per row), `getErrors()`, `getMetadata().getColumns()`, `getRequestId()`. + +# Get Tokens + +Look up the deterministic token previously issued for each plaintext value, in a single API call. + +> **Vault type supported:** both. See [Vault type support](#vault-type-support). + +**Note:** + +- `records`, and `value` and `tokenGroupName` on each record, are required. Only deterministic token groups are supported. +- One record comes back per input entry, in request order; duplicate inputs are not collapsed. +- Record-level failures come back on the response (HTTP 200/207); whole-call failures are thrown as a `SkyflowException`. + +### Construct a get tokens request + +Continuing from [Quickstart](#quickstart) — `skyflowClient` below is the `Skyflow` client built there. + +```java +import com.skyflow.errors.SkyflowException; +import com.skyflow.vault.controller.VaultController; +import com.skyflow.vault.data.GetTokensRequest; +import com.skyflow.vault.data.GetTokensRequestRecord; +import com.skyflow.vault.data.GetTokensResponse; + +import java.util.Arrays; + +public class GetTokensExample { + public static void main(String[] args) throws SkyflowException { + // skyflowClient is the Skyflow client built in Quickstart + VaultController vault = skyflowClient.vault(); + + GetTokensRequest getTokensRequest = GetTokensRequest.builder() + .records(Arrays.asList( + GetTokensRequestRecord.builder().value("john@example.com").tokenGroupName("det_reg_rtf").build(), + GetTokensRequestRecord.builder().value("unknown@example.com").tokenGroupName("det_reg_rtf").build() + )) + .build(); + + GetTokensResponse getTokensResponse = vault.getTokens(getTokensRequest); + System.out.println(getTokensResponse); + } +} +``` + +There is no async variant: `getTokens` returns its `GetTokensResponse` directly. + +Sample response: + +```json +{ + "records": [ + { "value": "john@example.com", "tokenGroupName": "det_reg_rtf", "token": "1R9kNnLOPM", "httpCode": 200, "error": null, "requestId": null }, + { "value": "unknown@example.com", "tokenGroupName": "det_reg_rtf", "token": "", "httpCode": 404, "error": "Token not found.", "requestId": "" } + ] +} +``` + +`getTokensResponse.getRecords()` returns one `HashMap` per input entry, with the keys `value`, `tokenGroupName`, `token`, `httpCode`, `error` and `requestId` (set only when `error` is non-null). `token` is `""` (never null) on a record that has no token. + +```java +for (HashMap record : getTokensResponse.getRecords()) { + if (record.get("error") == null) { + System.out.println(record.get("value") + " -> " + record.get("token")); + } else { + System.err.println(record.get("value") + " failed [" + + record.get("httpCode") + "] " + record.get("error")); + } +} +``` + +# Upload Files + +Upload files into the file columns of new or existing records. One call does two things inside the SDK: + +1. **(A)** It calls `POST /v2/files/upload`, which returns a signed upload URL for each column. +2. **(B)** It uploads each file's bytes to its signed URL with a separate HTTP `PUT`, the raw bytes as the body. The signed URL is an AWS S3 `PutObject` URL; that request carries no `Authorization` header, because the signature in the URL is the credential. + +The signed URL is a credential that expires after about 15 minutes. The SDK uses it straight away in step B and never returns it to you. + +> **Vault type supported:** structured. See [Vault type support](#vault-type-support). + +**Note:** + +- Each record needs a `tableName` and at least one column. Omit `skyflowId` to create a new record (needs CREATE permission); set it to upload into an existing record (needs UPDATE permission). +- Give each column its file in **exactly one** of three forms: + +| Field | Type | Notes | +|---|---|---| +| `filePath` | `String` | Local path; the file must exist. `fileName` defaults to the path's file name. | +| `base64` | `String` | Base64-encoded content. **Requires** `fileName`. | +| `fileObject` | `java.io.File` | `fileName` defaults to its `getName()`. | + + A column that sets none, or more than one, fails validation. If `fileName` is still unset, the server generates a random 16-byte UUID name. The file's content type is inferred from the file name, else `application/octet-stream`. +- Errors: + - Any error status from step A (400/401/403/404/500) is thrown as a `SkyflowException`, and nothing is uploaded. + - A record that fails in step A (inside a 207 response) comes back with its `error` set and every column `SKIPPED`. + - A column the vault returned no signed URL for is `SKIPPED`, with no error. + - A column whose upload fails in step B is `FAILED` (`"PUT failed: "`); other columns and records are unaffected. + +### Construct an upload files request + +Continuing from [Quickstart](#quickstart) — `skyflowClient` below is the `Skyflow` client built there. + +```java +import com.skyflow.errors.SkyflowException; +import com.skyflow.vault.controller.VaultController; +import com.skyflow.vault.data.UploadFilesRequest; +import com.skyflow.vault.data.UploadFilesRequestColumn; +import com.skyflow.vault.data.UploadFilesRequestRecord; +import com.skyflow.vault.data.UploadFilesResponse; + +import java.util.Arrays; +import java.util.Collections; + +public class UploadFilesExample { + public static void main(String[] args) throws SkyflowException { + // skyflowClient is the Skyflow client built in Quickstart + VaultController vault = skyflowClient.vault(); + + UploadFilesRequest uploadFilesRequest = UploadFilesRequest.builder() + .records(Arrays.asList( + // no skyflowId: creates a new record + UploadFilesRequestRecord.builder() + .tableName("onboarding") + .columns(Arrays.asList( + UploadFilesRequestColumn.builder().column("resumePDF").filePath("/path/to/resume.pdf").build(), + UploadFilesRequestColumn.builder().column("photoID").base64("").fileName("photo.jpg").build())) + .build(), + // with skyflowId: uploads into an existing record + UploadFilesRequestRecord.builder() + .tableName("onboarding") + .skyflowId("") + .columns(Collections.singletonList( + UploadFilesRequestColumn.builder().column("kyc").fileObject(new java.io.File("/path/to/kyc.pdf")).build())) + .build())) + .build(); + + UploadFilesResponse uploadFilesResponse = vault.uploadFiles(uploadFilesRequest); + System.out.println(uploadFilesResponse); + } +} +``` + +There is no async variant: `uploadFiles` returns its `UploadFilesResponse` directly. + +Sample response (partial success): + +```json +{ + "records": [ + { "skyflowId": "2a62a1fd-...", "tableName": "onboarding", + "columns": [ + { "column": "resumePDF", "fileName": "resume.pdf", "uploadStatus": "UPLOADED", "error": null }, + { "column": "photoID", "fileName": "photo.jpg", "uploadStatus": "FAILED", "error": "PUT failed: 403" } + ], "httpCode": 200, "error": null, "requestId": null }, + { "skyflowId": null, "tableName": "onboarding", + "columns": [ { "column": "kyc", "fileName": "kyc.pdf", "uploadStatus": "SKIPPED", "error": "Invalid request. skyflowID {ID} is invalid." } ], + "httpCode": 400, "error": "Invalid request. skyflowID {ID} is invalid.", "requestId": "" } + ] +} +``` + +`uploadFilesResponse.getRecords()` returns one `HashMap` per input record, with the keys `skyflowId`, `tableName`, `columns`, `httpCode`, `error` and `requestId` (set only when `error` is non-null). Each entry of `columns` has the keys `column`, `fileName`, `uploadStatus` (`UPLOADED`, `FAILED` or `SKIPPED`) and `error`. A record's `error` stays null when only some of its columns failed in step B, so check each column: + +```java +for (HashMap record : uploadFilesResponse.getRecords()) { + for (Map column : (List>) record.get("columns")) { + if (!"UPLOADED".equals(column.get("uploadStatus"))) { + System.err.println(record.get("skyflowId") + "." + column.get("column") + " " + + column.get("uploadStatus") + ": " + column.get("error")); + } + } +} +``` + +# Delete Files + +Delete the files in file columns of existing records, and the stored objects behind them (`POST /v2/files/delete`), in a single API call. + +> **Vault type supported:** structured. See [Vault type support](#vault-type-support). + +**Note:** + +- Each record needs a `tableName` and `columns` (the file columns to delete). Set **exactly one** of `skyflowId` or `uniqueValues`; a record that sets both or neither fails validation, and the call throws a `SkyflowException` before anything is sent. +- `uniqueValues` is a list of `{column: value}` maps, as in get and delete. Each one may match more than one record, which gives one response entry per matched `skyflowId`. +- It works whatever the file's `fileStatus`, and it is a hard delete: afterwards `get()` returns null for that column. A `PENDING` upload is cancelled and its signed URL invalidated; a `READY` file's object is removed; `FAILED`/`SCAN_ERROR` just clears the metadata. +- Record-level failures come back on the response; whole-call failures are thrown as a `SkyflowException`. + +### Construct a delete files request + +Continuing from [Quickstart](#quickstart) — `skyflowClient` below is the `Skyflow` client built there. + +```java +import com.skyflow.errors.SkyflowException; +import com.skyflow.vault.controller.VaultController; +import com.skyflow.vault.data.DeleteFilesRequest; +import com.skyflow.vault.data.DeleteFilesRequestRecord; +import com.skyflow.vault.data.DeleteFilesResponse; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class DeleteFilesExample { + public static void main(String[] args) throws SkyflowException { + // skyflowClient is the Skyflow client built in Quickstart + VaultController vault = skyflowClient.vault(); + + Map uniqueValue = new HashMap<>(); + uniqueValue.put("email", "john@example.com"); + + DeleteFilesRequest deleteFilesRequest = DeleteFilesRequest.builder() + .records(Arrays.asList( + DeleteFilesRequestRecord.builder() + .tableName("onboarding") + .skyflowId("") + .columns(Arrays.asList("resumePDF", "photoID")) + .build(), + DeleteFilesRequestRecord.builder() + .tableName("employees") + .uniqueValues(Collections.singletonList(uniqueValue)) + .columns(Collections.singletonList("photo")) + .build())) + .build(); + + DeleteFilesResponse deleteFilesResponse = vault.deleteFiles(deleteFilesRequest); + System.out.println(deleteFilesResponse); + } +} +``` + +There is no async variant: `deleteFiles` returns its `DeleteFilesResponse` directly. + +Sample response (partial success): + +```json +{ + "records": [ + { "skyflowId": "77ea0577-...", "tableName": "onboarding", + "columns": [ { "column": "resumePDF", "status": "DELETED" }, { "column": "photoID", "status": "DELETED" } ], + "httpCode": 200, "error": null, "requestId": null }, + { "skyflowId": "invalid-id-0000", "tableName": "employees", "columns": null, + "httpCode": 404, "error": "Invalid request. skyflowID invalid-id-0000 is invalid. Specify a valid skyflowID.", "requestId": "" } + ] +} +``` + +`deleteFilesResponse.getRecords()` returns one `HashMap` per resolved record, with the keys `skyflowId`, `tableName`, `columns`, `httpCode`, `error` and `requestId` (set only when `error` is non-null). `columns` is a list of `{column, status}` maps, or null on a failed record. + # Custom Request Headers To include custom HTTP headers on an outgoing request — bulk or unary — pass a `RequestInterceptor` via that operation's options object. The headers available are defined by the `CustomHeaderKey` enum: @@ -1662,6 +1975,8 @@ The same pattern applies to every operation, via its corresponding options class | `get` | `GetOptions` | | `update` | `UpdateOptions` | | `delete` | `DeleteOptions` | +| `query` | `QueryOptions` | +| `getTokens` | `GetTokensOptions` | # Error Handling diff --git a/flowvault/pom.xml b/flowvault/pom.xml index 6ea99c9a..a1e9c6dc 100644 --- a/flowvault/pom.xml +++ b/flowvault/pom.xml @@ -76,24 +76,17 @@ - - - - - org.apache.maven.plugins - maven-shade-plugin - 3.6.0 - + shade-for-japicmp package diff --git a/flowvault/samples/src/main/java/com/example/vault/DeleteFilesExample.java b/flowvault/samples/src/main/java/com/example/vault/DeleteFilesExample.java new file mode 100644 index 00000000..479344b7 --- /dev/null +++ b/flowvault/samples/src/main/java/com/example/vault/DeleteFilesExample.java @@ -0,0 +1,91 @@ +package com.example.vault; + +import com.skyflow.Skyflow; +import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; +import com.skyflow.enums.CustomHeaderKey; +import com.skyflow.enums.Env; +import com.skyflow.enums.LogLevel; +import com.skyflow.errors.SkyflowException; +import com.skyflow.vault.data.*; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * This sample demonstrates the Skyflow Java SDK's unary deleteFiles operation — deleting the files + * in file columns of existing records, and the stored objects behind them. This makes exactly one + * API call per invocation. + * + * Each record sets exactly one of skyflowId or uniqueValues; a uniqueValues entry may match several + * records, giving one response entry per matched record. Record-level failures are reported on the + * response, whole-call failures are thrown as a SkyflowException. + */ +public class DeleteFilesExample { + + public static void main(String[] args) { + try { + // Step 1: Initialize credentials with the path to your service account key file +// String filePath = ""; + Credentials credentials = new Credentials(); + credentials.setToken(""); + + // Step 2: Configure the vault with required parameters + VaultConfig vaultConfig = new VaultConfig(); + vaultConfig.setVaultId(""); + vaultConfig.setClusterId(""); + vaultConfig.setEnv(Env.DEV); + vaultConfig.setCredentials(credentials); + + // Step 3: Create Skyflow client instance with error logging + Skyflow skyflowClient = Skyflow.builder() + .setLogLevel(LogLevel.ERROR) + .addVaultConfig(vaultConfig) + .build(); + + // Step 4: Identify the records and the file columns to delete + Map uniqueValue = new HashMap<>(); + uniqueValue.put("", ""); + + List records = Arrays.asList( + DeleteFilesRequestRecord.builder() + .tableName("") + .skyflowId("") + .columns(Arrays.asList("", "")) + .build(), + DeleteFilesRequestRecord.builder() + .tableName("") + .uniqueValues(Collections.singletonList(uniqueValue)) + .columns(Collections.singletonList("")) + .build() + ); + + // Step 5: Build and execute the deleteFiles request + DeleteFilesRequest request = DeleteFilesRequest.builder() + .records(records) + .build(); + + DeleteFilesOptions options = DeleteFilesOptions.builder() + .interceptor(ctx -> { + ctx.addHeader(CustomHeaderKey.REQUEST_ID_HEADER, "DeleteFilesOptions"); // pass the request id here + }) + .build(); + DeleteFilesResponse response = skyflowClient.vault().deleteFiles(request, options); + + // Step 6: Read the outcome. A record succeeded when its error is null. + for (HashMap record : response.getRecords()) { + if (record.get("error") == null) { + System.out.printf("deleteFiles: %s -> %s%n", record.get("skyflowId"), record.get("columns")); + } else { + System.out.printf("deleteFiles failed (%s): %s%n", record.get("httpCode"), record.get("error")); + } + } + } catch (SkyflowException e) { + // Step 7: Handle any errors that occur during the process + System.err.println("Error in deleteFiles operation:\t" + e); + } + } +} diff --git a/flowvault/samples/src/main/java/com/example/vault/GetTokensExample.java b/flowvault/samples/src/main/java/com/example/vault/GetTokensExample.java new file mode 100644 index 00000000..0936f3c2 --- /dev/null +++ b/flowvault/samples/src/main/java/com/example/vault/GetTokensExample.java @@ -0,0 +1,84 @@ +package com.example.vault; + +import com.skyflow.Skyflow; +import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; +import com.skyflow.enums.CustomHeaderKey; +import com.skyflow.enums.Env; +import com.skyflow.enums.LogLevel; +import com.skyflow.errors.SkyflowException; +import com.skyflow.vault.data.*; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +/** + * This sample demonstrates the Skyflow Java SDK's unary getTokens operation — looking up the + * deterministic token previously issued for each plaintext value. This makes exactly one API call + * per invocation. + * + * Only deterministic token groups are supported. One record comes back per input entry, in request + * order; duplicate inputs are not collapsed. Record-level failures are reported on the response, + * whole-call failures are thrown as a SkyflowException. + */ +public class GetTokensExample { + + public static void main(String[] args) { + try { + // Step 1: Initialize credentials with the path to your service account key file +// String filePath = ""; + Credentials credentials = new Credentials(); + credentials.setToken(""); + + // Step 2: Configure the vault with required parameters + VaultConfig vaultConfig = new VaultConfig(); + vaultConfig.setVaultId(""); + vaultConfig.setClusterId(""); + vaultConfig.setEnv(Env.DEV); + vaultConfig.setCredentials(credentials); + + // Step 3: Create Skyflow client instance with error logging + Skyflow skyflowClient = Skyflow.builder() + .setLogLevel(LogLevel.ERROR) + .addVaultConfig(vaultConfig) + .build(); + + // Step 4: Prepare the value/token-group pairs to look up + List records = Arrays.asList( + GetTokensRequestRecord.builder() + .value("john@example.com") + .tokenGroupName("") + .build(), + GetTokensRequestRecord.builder() + .value("unknown@example.com") + .tokenGroupName("") + .build() + ); + + // Step 5: Build and execute the getTokens request + GetTokensRequest request = GetTokensRequest.builder() + .records(records) + .build(); + + GetTokensOptions options = GetTokensOptions.builder() + .interceptor(ctx -> { + ctx.addHeader(CustomHeaderKey.REQUEST_ID_HEADER, "GetTokensOptions"); // pass the request id here + }) + .build(); + GetTokensResponse response = skyflowClient.vault().getTokens(request, options); + + // Step 6: Read the outcome. A record succeeded when its error is null. + for (HashMap record : response.getRecords()) { + if (record.get("error") == null) { + System.out.printf("getTokens: %s -> %s%n", record.get("value"), record.get("token")); + } else { + System.out.printf("getTokens failed (%s): %s%n", record.get("httpCode"), record.get("error")); + } + } + } catch (SkyflowException e) { + // Step 7: Handle any errors that occur during the process + System.err.println("Error in getTokens operation:\t" + e); + } + } +} diff --git a/flowvault/samples/src/main/java/com/example/vault/QueryExample.java b/flowvault/samples/src/main/java/com/example/vault/QueryExample.java new file mode 100644 index 00000000..ded7fcc5 --- /dev/null +++ b/flowvault/samples/src/main/java/com/example/vault/QueryExample.java @@ -0,0 +1,67 @@ +package com.example.vault; + +import com.skyflow.Skyflow; +import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; +import com.skyflow.enums.CustomHeaderKey; +import com.skyflow.enums.Env; +import com.skyflow.enums.LogLevel; +import com.skyflow.errors.SkyflowException; +import com.skyflow.vault.data.*; + +import java.util.HashMap; + +/** + * This sample demonstrates the Skyflow Java SDK's unary query operation — running a SQL SELECT + * against the vault. This makes exactly one API call per invocation. + * + * Only SELECT is supported, and a call returns at most 25 records; page with SQL OFFSET. Values + * may come back masked, but are never tokens or file URLs. There is no per-record status: any + * failure is thrown as a SkyflowException. + */ +public class QueryExample { + + public static void main(String[] args) { + try { + // Step 1: Initialize credentials with the path to your service account key file +// String filePath = ""; + Credentials credentials = new Credentials(); + credentials.setToken(""); + + // Step 2: Configure the vault with required parameters + VaultConfig vaultConfig = new VaultConfig(); + vaultConfig.setVaultId(""); + vaultConfig.setClusterId(""); + vaultConfig.setEnv(Env.DEV); + vaultConfig.setCredentials(credentials); + + // Step 3: Create Skyflow client instance with error logging + Skyflow skyflowClient = Skyflow.builder() + .setLogLevel(LogLevel.ERROR) + .addVaultConfig(vaultConfig) + .build(); + + // Step 4: Build and execute the query request + QueryRequest request = QueryRequest.builder() + .query("SELECT * FROM LIMIT 25 OFFSET 0") + .build(); + + QueryOptions options = QueryOptions.builder() + .interceptor(ctx -> { + ctx.addHeader(CustomHeaderKey.REQUEST_ID_HEADER, "QueryOptions"); // pass the request id here + }) + .build(); + QueryResponse response = skyflowClient.vault().query(request, options); + + // Step 5: Read the rows. Each map holds one record's column/value pairs. + System.out.println("columns: " + response.getMetadata().getColumns()); + for (HashMap row : response.getFields()) { + System.out.println("row: " + row); + } + System.out.println("requestId: " + response.getRequestId()); + } catch (SkyflowException e) { + // Step 6: Handle any errors that occur during the process + System.err.println("Error in query operation:\t" + e); + } + } +} diff --git a/flowvault/samples/src/main/java/com/example/vault/UploadFilesExample.java b/flowvault/samples/src/main/java/com/example/vault/UploadFilesExample.java new file mode 100644 index 00000000..45f38fec --- /dev/null +++ b/flowvault/samples/src/main/java/com/example/vault/UploadFilesExample.java @@ -0,0 +1,103 @@ +package com.example.vault; + +import com.skyflow.Skyflow; +import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; +import com.skyflow.enums.CustomHeaderKey; +import com.skyflow.enums.Env; +import com.skyflow.enums.LogLevel; +import com.skyflow.errors.SkyflowException; +import com.skyflow.vault.data.*; + +import java.io.File; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * This sample demonstrates the Skyflow Java SDK's unary uploadFiles operation — uploading files + * into the file columns of new or existing records. + * + * One call runs two steps inside the SDK: it asks the vault for a signed upload URL per column, + * then PUTs each file's bytes to its URL. A record that fails in the first step has its columns + * SKIPPED; a column whose upload fails is FAILED and leaves the rest unaffected. Whole-call + * failures are thrown as a SkyflowException. + */ +public class UploadFilesExample { + + public static void main(String[] args) { + try { + // Step 1: Initialize credentials with the path to your service account key file +// String filePath = ""; + Credentials credentials = new Credentials(); + credentials.setToken(""); + + // Step 2: Configure the vault with required parameters + VaultConfig vaultConfig = new VaultConfig(); + vaultConfig.setVaultId(""); + vaultConfig.setClusterId(""); + vaultConfig.setEnv(Env.DEV); + vaultConfig.setCredentials(credentials); + + // Step 3: Create Skyflow client instance with error logging + Skyflow skyflowClient = Skyflow.builder() + .setLogLevel(LogLevel.ERROR) + .addVaultConfig(vaultConfig) + .build(); + + // Step 4: Describe the files to upload. Omit skyflowId to create a new record. + List records = Arrays.asList( + UploadFilesRequestRecord.builder() + .tableName("") + .columns(Arrays.asList( + UploadFilesRequestColumn.builder() + .column("") + .filePath("") + .build(), + UploadFilesRequestColumn.builder() + .column("") + .base64("") + .fileName("") // required with base64 + .build())) + .build(), + UploadFilesRequestRecord.builder() + .tableName("") + .skyflowId("") + .columns(Collections.singletonList( + UploadFilesRequestColumn.builder() + .column("") + .fileObject(new File("")) + .build())) + .build() + ); + + // Step 5: Build and execute the uploadFiles request + UploadFilesRequest request = UploadFilesRequest.builder() + .records(records) + .build(); + + UploadFilesOptions options = UploadFilesOptions.builder() + .interceptor(ctx -> { + ctx.addHeader(CustomHeaderKey.REQUEST_ID_HEADER, "UploadFilesOptions"); // pass the request id here + }) + .build(); + UploadFilesResponse response = skyflowClient.vault().uploadFiles(request, options); + + // Step 6: Read the outcome per column. A record's error stays null when only some of + // its columns failed to upload. + for (HashMap record : response.getRecords()) { + @SuppressWarnings("unchecked") + List> columns = (List>) record.get("columns"); + for (Map column : columns) { + System.out.printf("uploadFiles: %s.%s -> %s%s%n", record.get("skyflowId"), column.get("column"), + column.get("uploadStatus"), column.get("error") == null ? "" : " (" + column.get("error") + ")"); + } + } + } catch (SkyflowException e) { + // Step 7: Handle any errors that occur during the process + System.err.println("Error in uploadFiles operation:\t" + e); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/VaultClient.java b/flowvault/src/main/java/com/skyflow/VaultClient.java index 93a677e0..ca84de82 100644 --- a/flowvault/src/main/java/com/skyflow/VaultClient.java +++ b/flowvault/src/main/java/com/skyflow/VaultClient.java @@ -5,7 +5,10 @@ import com.skyflow.errors.SkyflowException; import com.skyflow.generated.rest.ApiClient; import com.skyflow.generated.rest.ApiClientBuilder; -import com.skyflow.generated.rest.resources.flowservice.FlowserviceClient; +import com.skyflow.generated.rest.resources.files.FilesClient; +import com.skyflow.generated.rest.resources.query.QueryClient; +import com.skyflow.generated.rest.resources.records.RecordsClient; +import com.skyflow.generated.rest.resources.tokens.TokensClient; import com.skyflow.utils.SkyflowRetryInterceptor; import com.skyflow.utils.Utils; @@ -82,8 +85,35 @@ private static Integer resolveNullableInt(Integer vaultLevel, Integer clientLeve return vaultLevel != null ? vaultLevel : clientLevel; } - protected FlowserviceClient getRecordsApi() { - return this.apiClient.flowservice(); + protected RecordsClient getRecordsApi() { + return this.apiClient.records(); + } + + protected TokensClient getTokensApi() { + return this.apiClient.tokens(); + } + + protected QueryClient getQueryApi() { + return this.apiClient.query(); + } + + protected FilesClient getFilesApi() { + return this.apiClient.files(); + } + + /** + * HTTP client for uploading straight to a signed URL. It shares the vault client's connection + * pool and connect/read/write timeouts but none of its interceptors, so no Authorization header + * is sent. The overall call timeout is lifted: it bounds a whole vault call, and a large file + * can take longer than that to transfer while still making steady progress. + */ + protected OkHttpClient getSignedUrlHttpClient() { + OkHttpClient.Builder builder = sharedHttpClient == null + ? new OkHttpClient.Builder() + : sharedHttpClient.newBuilder(); + builder.interceptors().clear(); + builder.networkInterceptors().clear(); + return builder.callTimeout(0, TimeUnit.SECONDS).build(); } protected void setCommonCredentials(Credentials commonCredentials) throws SkyflowException { diff --git a/flowvault/src/main/java/com/skyflow/enums/InterfaceName.java b/flowvault/src/main/java/com/skyflow/enums/InterfaceName.java index 7de88335..046c3d70 100644 --- a/flowvault/src/main/java/com/skyflow/enums/InterfaceName.java +++ b/flowvault/src/main/java/com/skyflow/enums/InterfaceName.java @@ -7,7 +7,11 @@ public enum InterfaceName { DELETE("delete tokens"), DELETE_RECORDS("delete"), TOKENIZE("tokenize"), - GET("get"); + GET("get"), + QUERY("query"), + GET_TOKENS("get tokens"), + UPLOAD_FILES("upload files"), + DELETE_FILES("delete files"); private final String interfaceName; diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/ApiClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/ApiClient.java index 02b972dd..6920fd1e 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/ApiClient.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/ApiClient.java @@ -4,31 +4,85 @@ package com.skyflow.generated.rest; import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.core.Suppliers; -import com.skyflow.generated.rest.resources.flowservice.FlowserviceClient; +import com.skyflow.generated.rest.requests.PatchV2VaultsIdRequest; +import com.skyflow.generated.rest.resources.files.FilesClient; +import com.skyflow.generated.rest.resources.query.QueryClient; import com.skyflow.generated.rest.resources.records.RecordsClient; - +import com.skyflow.generated.rest.resources.tokens.TokensClient; +import java.util.Optional; import java.util.function.Supplier; -public class ApiClient { +public class ApiClient implements AutoCloseable { protected final ClientOptions clientOptions; + private final RawApiClient rawClient; + + protected final Supplier filesClient; + + protected final Supplier queryClient; + protected final Supplier recordsClient; - protected final Supplier flowserviceClient; + protected final Supplier tokensClient; public ApiClient(ClientOptions clientOptions) { this.clientOptions = clientOptions; + this.rawClient = new RawApiClient(clientOptions); + this.filesClient = Suppliers.memoize(() -> new FilesClient(clientOptions)); + this.queryClient = Suppliers.memoize(() -> new QueryClient(clientOptions)); this.recordsClient = Suppliers.memoize(() -> new RecordsClient(clientOptions)); - this.flowserviceClient = Suppliers.memoize(() -> new FlowserviceClient(clientOptions)); + this.tokensClient = Suppliers.memoize(() -> new TokensClient(clientOptions)); + } + + /** + * Get responses with HTTP metadata like headers + */ + public RawApiClient withRawResponse() { + return this.rawClient; + } + + public void patchV2VaultsId(Optional vaultId) { + this.rawClient.patchV2VaultsId(vaultId).body(); + } + + public void patchV2VaultsId(Optional vaultId, RequestOptions requestOptions) { + this.rawClient.patchV2VaultsId(vaultId, requestOptions).body(); + } + + public void patchV2VaultsId(Optional vaultId, PatchV2VaultsIdRequest request) { + this.rawClient.patchV2VaultsId(vaultId, request).body(); + } + + public void patchV2VaultsId( + Optional vaultId, PatchV2VaultsIdRequest request, RequestOptions requestOptions) { + this.rawClient.patchV2VaultsId(vaultId, request, requestOptions).body(); + } + + public FilesClient files() { + return this.filesClient.get(); + } + + public QueryClient query() { + return this.queryClient.get(); } public RecordsClient records() { return this.recordsClient.get(); } - public FlowserviceClient flowservice() { - return this.flowserviceClient.get(); + public TokensClient tokens() { + return this.tokensClient.get(); + } + + /** + * Releases resources owned by this client. See {@code ClientOptions.close()} for what is + * and is not released. + */ + @Override + public void close() { + this.clientOptions.close(); } public static ApiClientBuilder builder() { diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/ApiClientBuilder.java b/flowvault/src/main/java/com/skyflow/generated/rest/ApiClientBuilder.java index fa3d6e9d..45fe1b68 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/ApiClientBuilder.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/ApiClientBuilder.java @@ -5,12 +5,47 @@ import com.skyflow.generated.rest.core.ClientOptions; import com.skyflow.generated.rest.core.Environment; +import com.skyflow.generated.rest.core.LogConfig; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; import okhttp3.OkHttpClient; -public final class ApiClientBuilder { - private ClientOptions.Builder clientOptionsBuilder = ClientOptions.builder(); +public class ApiClientBuilder { + private Optional timeout = Optional.empty(); - private Environment environment; + private Optional maxRetries = Optional.empty(); + + private Optional initialRetryDelayMillis = Optional.empty(); + + private Optional maxRetryDelayMillis = Optional.empty(); + + private Optional retryJitterFactor = Optional.empty(); + + private final Map customHeaders = new HashMap<>(); + + private String token = null; + + private Environment environment = Environment.PRODUCTION; + + private OkHttpClient httpClient; + + private Optional logging = Optional.empty(); + + private String vaultUrl; + + /** + * Sets token + */ + public ApiClientBuilder token(String token) { + this.token = token; + return this; + } + + public ApiClientBuilder environment(Environment environment) { + this.environment = environment; + return this; + } public ApiClientBuilder url(String url) { this.environment = Environment.custom(url); @@ -21,7 +56,7 @@ public ApiClientBuilder url(String url) { * Sets the timeout (in seconds) for the client. Defaults to 60 seconds. */ public ApiClientBuilder timeout(int timeout) { - this.clientOptionsBuilder.timeout(timeout); + this.timeout = Optional.of(timeout); return this; } @@ -29,7 +64,31 @@ public ApiClientBuilder timeout(int timeout) { * Sets the maximum number of retries for the client. Defaults to 2 retries. */ public ApiClientBuilder maxRetries(int maxRetries) { - this.clientOptionsBuilder.maxRetries(maxRetries); + this.maxRetries = Optional.of(maxRetries); + return this; + } + + /** + * Sets the initial delay (in milliseconds) used for exponential backoff between retries. Defaults to 1000 milliseconds. + */ + public ApiClientBuilder initialRetryDelayMillis(long initialRetryDelayMillis) { + this.initialRetryDelayMillis = Optional.of(initialRetryDelayMillis); + return this; + } + + /** + * Sets the maximum delay (in milliseconds) between retries. Defaults to 60000 milliseconds. + */ + public ApiClientBuilder maxRetryDelayMillis(long maxRetryDelayMillis) { + this.maxRetryDelayMillis = Optional.of(maxRetryDelayMillis); + return this; + } + + /** + * Sets the jitter factor (between 0 and 1) applied to retry delays. Defaults to 0.2. + */ + public ApiClientBuilder retryJitterFactor(double retryJitterFactor) { + this.retryJitterFactor = Optional.of(retryJitterFactor); return this; } @@ -37,12 +96,191 @@ public ApiClientBuilder maxRetries(int maxRetries) { * Sets the underlying OkHttp client */ public ApiClientBuilder httpClient(OkHttpClient httpClient) { - this.clientOptionsBuilder.httpClient(httpClient); + this.httpClient = httpClient; return this; } + /** + * Configure logging for the SDK. Silent by default — no log output unless explicitly configured. + */ + public ApiClientBuilder logging(LogConfig logging) { + this.logging = Optional.of(logging); + return this; + } + + /** + * Add a custom header to be sent with all requests. + * For headers that need to be computed dynamically or conditionally, use the setAdditional() method override instead. + * + * @param name The header name + * @param value The header value + * @return This builder for method chaining + */ + public ApiClientBuilder addHeader(String name, String value) { + this.customHeaders.put(name, value); + return this; + } + + public ApiClientBuilder vaultUrl(String vaultUrl) { + this.vaultUrl = vaultUrl; + return this; + } + + protected ClientOptions buildClientOptions() { + ClientOptions.Builder builder = ClientOptions.builder(); + setEnvironment(builder); + setAuthentication(builder); + setHttpClient(builder); + setTimeouts(builder); + setRetries(builder); + setLogging(builder); + for (Map.Entry header : this.customHeaders.entrySet()) { + builder.addHeader(header.getKey(), header.getValue()); + } + setAdditional(builder); + return builder.build(); + } + + /** + * Sets the environment configuration for the client. + * Override this method to modify URLs or add environment-specific logic. + * + * @param builder The ClientOptions.Builder to configure + */ + protected void setEnvironment(ClientOptions.Builder builder) { + if (this.vaultUrl != null) { + String _vaultUrl = this.vaultUrl != null ? this.vaultUrl : "{{vault_url}}"; + String _urlTemplate = null; + if (this.environment == null) { + _urlTemplate = "https://{vault_url}"; + } else if (this.environment.equals(Environment.PRODUCTION)) { + _urlTemplate = "https://{vault_url}"; + } else if (this.environment.equals(Environment.SANDBOX)) { + _urlTemplate = "https://{vault_url}"; + } + if (_urlTemplate != null) { + this.environment = Environment.custom(_urlTemplate.replace("{vault_url}", _vaultUrl)); + } + } + builder.environment(this.environment); + } + + /** + * Override this method to customize authentication. + * This method is called during client options construction to set up authentication headers. + * + * @param builder The ClientOptions.Builder to configure + * + * Example: + *
{@code
+     * @Override
+     * protected void setAuthentication(ClientOptions.Builder builder) {
+     *     super.setAuthentication(builder); // Keep existing auth
+     *     builder.addHeader("X-API-Key", this.apiKey);
+     * }
+     * }
+ */ + protected void setAuthentication(ClientOptions.Builder builder) { + if (this.token != null) { + builder.addHeader("Authorization", "Bearer " + this.token); + } + } + + /** + * Sets the request timeout configuration. + * Override this method to customize timeout behavior. + * + * @param builder The ClientOptions.Builder to configure + */ + protected void setTimeouts(ClientOptions.Builder builder) { + if (this.timeout.isPresent()) { + builder.timeout(this.timeout.get()); + } + } + + /** + * Sets the retry configuration for failed requests. + * Override this method to implement custom retry strategies. + * + * @param builder The ClientOptions.Builder to configure + */ + protected void setRetries(ClientOptions.Builder builder) { + if (this.maxRetries.isPresent()) { + builder.maxRetries(this.maxRetries.get()); + } + if (this.initialRetryDelayMillis.isPresent()) { + builder.initialRetryDelayMillis(this.initialRetryDelayMillis.get()); + } + if (this.maxRetryDelayMillis.isPresent()) { + builder.maxRetryDelayMillis(this.maxRetryDelayMillis.get()); + } + if (this.retryJitterFactor.isPresent()) { + builder.retryJitterFactor(this.retryJitterFactor.get()); + } + } + + /** + * Sets the OkHttp client configuration. + * Override this method to customize HTTP client behavior (interceptors, connection pools, etc). + * + * @param builder The ClientOptions.Builder to configure + */ + protected void setHttpClient(ClientOptions.Builder builder) { + if (this.httpClient != null) { + builder.httpClient(this.httpClient); + } + } + + /** + * Sets the logging configuration for the SDK. + * Override this method to customize logging behavior. + * + * @param builder The ClientOptions.Builder to configure + */ + protected void setLogging(ClientOptions.Builder builder) { + if (this.logging.isPresent()) { + builder.logging(this.logging.get()); + } + } + + /** + * Override this method to add any additional configuration to the client. + * This method is called at the end of the configuration chain, allowing you to add + * custom headers, modify settings, or perform any other client customization. + * + * @param builder The ClientOptions.Builder to configure + * + * Example: + *
{@code
+     * @Override
+     * protected void setAdditional(ClientOptions.Builder builder) {
+     *     builder.addHeader("X-Request-ID", () -> UUID.randomUUID().toString());
+     *     builder.addHeader("X-Client-Version", "1.0.0");
+     * }
+     * }
+ */ + protected void setAdditional(ClientOptions.Builder builder) {} + + /** + * Override this method to add custom validation logic before the client is built. + * This method is called at the beginning of the build() method to ensure the configuration is valid. + * Throw an exception to prevent client creation if validation fails. + * + * Example: + *
{@code
+     * @Override
+     * protected void validateConfiguration() {
+     *     super.validateConfiguration(); // Run parent validations
+     *     if (tenantId == null || tenantId.isEmpty()) {
+     *         throw new IllegalStateException("tenantId is required");
+     *     }
+     * }
+     * }
+ */ + protected void validateConfiguration() {} + public ApiClient build() { - clientOptionsBuilder.environment(this.environment); - return new ApiClient(clientOptionsBuilder.build()); + validateConfiguration(); + return new ApiClient(buildClientOptions()); } } diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java index 840c0bad..d82cb3e8 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/AsyncApiClient.java @@ -4,31 +4,86 @@ package com.skyflow.generated.rest; import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.RequestOptions; import com.skyflow.generated.rest.core.Suppliers; -import com.skyflow.generated.rest.resources.flowservice.AsyncFlowserviceClient; +import com.skyflow.generated.rest.requests.PatchV2VaultsIdRequest; +import com.skyflow.generated.rest.resources.files.AsyncFilesClient; +import com.skyflow.generated.rest.resources.query.AsyncQueryClient; import com.skyflow.generated.rest.resources.records.AsyncRecordsClient; - +import com.skyflow.generated.rest.resources.tokens.AsyncTokensClient; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; import java.util.function.Supplier; -public class AsyncApiClient { +public class AsyncApiClient implements AutoCloseable { protected final ClientOptions clientOptions; + private final AsyncRawApiClient rawClient; + + protected final Supplier filesClient; + + protected final Supplier queryClient; + protected final Supplier recordsClient; - protected final Supplier flowserviceClient; + protected final Supplier tokensClient; public AsyncApiClient(ClientOptions clientOptions) { this.clientOptions = clientOptions; + this.rawClient = new AsyncRawApiClient(clientOptions); + this.filesClient = Suppliers.memoize(() -> new AsyncFilesClient(clientOptions)); + this.queryClient = Suppliers.memoize(() -> new AsyncQueryClient(clientOptions)); this.recordsClient = Suppliers.memoize(() -> new AsyncRecordsClient(clientOptions)); - this.flowserviceClient = Suppliers.memoize(() -> new AsyncFlowserviceClient(clientOptions)); + this.tokensClient = Suppliers.memoize(() -> new AsyncTokensClient(clientOptions)); + } + + /** + * Get responses with HTTP metadata like headers + */ + public AsyncRawApiClient withRawResponse() { + return this.rawClient; + } + + public CompletableFuture patchV2VaultsId(Optional vaultId) { + return this.rawClient.patchV2VaultsId(vaultId).thenApply(response -> response.body()); + } + + public CompletableFuture patchV2VaultsId(Optional vaultId, RequestOptions requestOptions) { + return this.rawClient.patchV2VaultsId(vaultId, requestOptions).thenApply(response -> response.body()); + } + + public CompletableFuture patchV2VaultsId(Optional vaultId, PatchV2VaultsIdRequest request) { + return this.rawClient.patchV2VaultsId(vaultId, request).thenApply(response -> response.body()); + } + + public CompletableFuture patchV2VaultsId( + Optional vaultId, PatchV2VaultsIdRequest request, RequestOptions requestOptions) { + return this.rawClient.patchV2VaultsId(vaultId, request, requestOptions).thenApply(response -> response.body()); + } + + public AsyncFilesClient files() { + return this.filesClient.get(); + } + + public AsyncQueryClient query() { + return this.queryClient.get(); } public AsyncRecordsClient records() { return this.recordsClient.get(); } - public AsyncFlowserviceClient flowservice() { - return this.flowserviceClient.get(); + public AsyncTokensClient tokens() { + return this.tokensClient.get(); + } + + /** + * Releases resources owned by this client. See {@code ClientOptions.close()} for what is + * and is not released. + */ + @Override + public void close() { + this.clientOptions.close(); } public static AsyncApiClientBuilder builder() { diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/AsyncApiClientBuilder.java b/flowvault/src/main/java/com/skyflow/generated/rest/AsyncApiClientBuilder.java index 10c08d51..5def9ecf 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/AsyncApiClientBuilder.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/AsyncApiClientBuilder.java @@ -5,12 +5,47 @@ import com.skyflow.generated.rest.core.ClientOptions; import com.skyflow.generated.rest.core.Environment; +import com.skyflow.generated.rest.core.LogConfig; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; import okhttp3.OkHttpClient; -public final class AsyncApiClientBuilder { - private ClientOptions.Builder clientOptionsBuilder = ClientOptions.builder(); +public class AsyncApiClientBuilder { + private Optional timeout = Optional.empty(); - private Environment environment; + private Optional maxRetries = Optional.empty(); + + private Optional initialRetryDelayMillis = Optional.empty(); + + private Optional maxRetryDelayMillis = Optional.empty(); + + private Optional retryJitterFactor = Optional.empty(); + + private final Map customHeaders = new HashMap<>(); + + private String token = null; + + private Environment environment = Environment.PRODUCTION; + + private OkHttpClient httpClient; + + private Optional logging = Optional.empty(); + + private String vaultUrl; + + /** + * Sets token + */ + public AsyncApiClientBuilder token(String token) { + this.token = token; + return this; + } + + public AsyncApiClientBuilder environment(Environment environment) { + this.environment = environment; + return this; + } public AsyncApiClientBuilder url(String url) { this.environment = Environment.custom(url); @@ -21,7 +56,7 @@ public AsyncApiClientBuilder url(String url) { * Sets the timeout (in seconds) for the client. Defaults to 60 seconds. */ public AsyncApiClientBuilder timeout(int timeout) { - this.clientOptionsBuilder.timeout(timeout); + this.timeout = Optional.of(timeout); return this; } @@ -29,7 +64,31 @@ public AsyncApiClientBuilder timeout(int timeout) { * Sets the maximum number of retries for the client. Defaults to 2 retries. */ public AsyncApiClientBuilder maxRetries(int maxRetries) { - this.clientOptionsBuilder.maxRetries(maxRetries); + this.maxRetries = Optional.of(maxRetries); + return this; + } + + /** + * Sets the initial delay (in milliseconds) used for exponential backoff between retries. Defaults to 1000 milliseconds. + */ + public AsyncApiClientBuilder initialRetryDelayMillis(long initialRetryDelayMillis) { + this.initialRetryDelayMillis = Optional.of(initialRetryDelayMillis); + return this; + } + + /** + * Sets the maximum delay (in milliseconds) between retries. Defaults to 60000 milliseconds. + */ + public AsyncApiClientBuilder maxRetryDelayMillis(long maxRetryDelayMillis) { + this.maxRetryDelayMillis = Optional.of(maxRetryDelayMillis); + return this; + } + + /** + * Sets the jitter factor (between 0 and 1) applied to retry delays. Defaults to 0.2. + */ + public AsyncApiClientBuilder retryJitterFactor(double retryJitterFactor) { + this.retryJitterFactor = Optional.of(retryJitterFactor); return this; } @@ -37,12 +96,191 @@ public AsyncApiClientBuilder maxRetries(int maxRetries) { * Sets the underlying OkHttp client */ public AsyncApiClientBuilder httpClient(OkHttpClient httpClient) { - this.clientOptionsBuilder.httpClient(httpClient); + this.httpClient = httpClient; return this; } + /** + * Configure logging for the SDK. Silent by default — no log output unless explicitly configured. + */ + public AsyncApiClientBuilder logging(LogConfig logging) { + this.logging = Optional.of(logging); + return this; + } + + /** + * Add a custom header to be sent with all requests. + * For headers that need to be computed dynamically or conditionally, use the setAdditional() method override instead. + * + * @param name The header name + * @param value The header value + * @return This builder for method chaining + */ + public AsyncApiClientBuilder addHeader(String name, String value) { + this.customHeaders.put(name, value); + return this; + } + + public AsyncApiClientBuilder vaultUrl(String vaultUrl) { + this.vaultUrl = vaultUrl; + return this; + } + + protected ClientOptions buildClientOptions() { + ClientOptions.Builder builder = ClientOptions.builder(); + setEnvironment(builder); + setAuthentication(builder); + setHttpClient(builder); + setTimeouts(builder); + setRetries(builder); + setLogging(builder); + for (Map.Entry header : this.customHeaders.entrySet()) { + builder.addHeader(header.getKey(), header.getValue()); + } + setAdditional(builder); + return builder.build(); + } + + /** + * Sets the environment configuration for the client. + * Override this method to modify URLs or add environment-specific logic. + * + * @param builder The ClientOptions.Builder to configure + */ + protected void setEnvironment(ClientOptions.Builder builder) { + if (this.vaultUrl != null) { + String _vaultUrl = this.vaultUrl != null ? this.vaultUrl : "{{vault_url}}"; + String _urlTemplate = null; + if (this.environment == null) { + _urlTemplate = "https://{vault_url}"; + } else if (this.environment.equals(Environment.PRODUCTION)) { + _urlTemplate = "https://{vault_url}"; + } else if (this.environment.equals(Environment.SANDBOX)) { + _urlTemplate = "https://{vault_url}"; + } + if (_urlTemplate != null) { + this.environment = Environment.custom(_urlTemplate.replace("{vault_url}", _vaultUrl)); + } + } + builder.environment(this.environment); + } + + /** + * Override this method to customize authentication. + * This method is called during client options construction to set up authentication headers. + * + * @param builder The ClientOptions.Builder to configure + * + * Example: + *
{@code
+     * @Override
+     * protected void setAuthentication(ClientOptions.Builder builder) {
+     *     super.setAuthentication(builder); // Keep existing auth
+     *     builder.addHeader("X-API-Key", this.apiKey);
+     * }
+     * }
+ */ + protected void setAuthentication(ClientOptions.Builder builder) { + if (this.token != null) { + builder.addHeader("Authorization", "Bearer " + this.token); + } + } + + /** + * Sets the request timeout configuration. + * Override this method to customize timeout behavior. + * + * @param builder The ClientOptions.Builder to configure + */ + protected void setTimeouts(ClientOptions.Builder builder) { + if (this.timeout.isPresent()) { + builder.timeout(this.timeout.get()); + } + } + + /** + * Sets the retry configuration for failed requests. + * Override this method to implement custom retry strategies. + * + * @param builder The ClientOptions.Builder to configure + */ + protected void setRetries(ClientOptions.Builder builder) { + if (this.maxRetries.isPresent()) { + builder.maxRetries(this.maxRetries.get()); + } + if (this.initialRetryDelayMillis.isPresent()) { + builder.initialRetryDelayMillis(this.initialRetryDelayMillis.get()); + } + if (this.maxRetryDelayMillis.isPresent()) { + builder.maxRetryDelayMillis(this.maxRetryDelayMillis.get()); + } + if (this.retryJitterFactor.isPresent()) { + builder.retryJitterFactor(this.retryJitterFactor.get()); + } + } + + /** + * Sets the OkHttp client configuration. + * Override this method to customize HTTP client behavior (interceptors, connection pools, etc). + * + * @param builder The ClientOptions.Builder to configure + */ + protected void setHttpClient(ClientOptions.Builder builder) { + if (this.httpClient != null) { + builder.httpClient(this.httpClient); + } + } + + /** + * Sets the logging configuration for the SDK. + * Override this method to customize logging behavior. + * + * @param builder The ClientOptions.Builder to configure + */ + protected void setLogging(ClientOptions.Builder builder) { + if (this.logging.isPresent()) { + builder.logging(this.logging.get()); + } + } + + /** + * Override this method to add any additional configuration to the client. + * This method is called at the end of the configuration chain, allowing you to add + * custom headers, modify settings, or perform any other client customization. + * + * @param builder The ClientOptions.Builder to configure + * + * Example: + *
{@code
+     * @Override
+     * protected void setAdditional(ClientOptions.Builder builder) {
+     *     builder.addHeader("X-Request-ID", () -> UUID.randomUUID().toString());
+     *     builder.addHeader("X-Client-Version", "1.0.0");
+     * }
+     * }
+ */ + protected void setAdditional(ClientOptions.Builder builder) {} + + /** + * Override this method to add custom validation logic before the client is built. + * This method is called at the beginning of the build() method to ensure the configuration is valid. + * Throw an exception to prevent client creation if validation fails. + * + * Example: + *
{@code
+     * @Override
+     * protected void validateConfiguration() {
+     *     super.validateConfiguration(); // Run parent validations
+     *     if (tenantId == null || tenantId.isEmpty()) {
+     *         throw new IllegalStateException("tenantId is required");
+     *     }
+     * }
+     * }
+ */ + protected void validateConfiguration() {} + public AsyncApiClient build() { - clientOptionsBuilder.environment(this.environment); - return new AsyncApiClient(clientOptionsBuilder.build()); + validateConfiguration(); + return new AsyncApiClient(buildClientOptions()); } } diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/AsyncRawApiClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/AsyncRawApiClient.java new file mode 100644 index 00000000..da58025b --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/AsyncRawApiClient.java @@ -0,0 +1,110 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.RetryInterceptor; +import com.skyflow.generated.rest.requests.PatchV2VaultsIdRequest; +import java.io.IOException; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.jetbrains.annotations.NotNull; + +public class AsyncRawApiClient { + protected final ClientOptions clientOptions; + + public AsyncRawApiClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + } + + public CompletableFuture> patchV2VaultsId(Optional vaultId) { + return patchV2VaultsId(vaultId, PatchV2VaultsIdRequest.builder().build()); + } + + public CompletableFuture> patchV2VaultsId( + Optional vaultId, RequestOptions requestOptions) { + return patchV2VaultsId(vaultId, PatchV2VaultsIdRequest.builder().build(), requestOptions); + } + + public CompletableFuture> patchV2VaultsId( + Optional vaultId, PatchV2VaultsIdRequest request) { + return patchV2VaultsId(vaultId, request, null); + } + + public CompletableFuture> patchV2VaultsId( + Optional vaultId, PatchV2VaultsIdRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/vaults"); + if (vaultId.isPresent()) { + httpUrl.addPathSegment(vaultId.get()); + } + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + Request.Builder _requestBuilder = new Request.Builder() + .url(httpUrl.build()) + .method("PATCH", RequestBody.create("", null)) + .headers(Headers.of(clientOptions.headers(requestOptions))); + Request okhttpRequest = _requestBuilder.build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + if (response.isSuccessful()) { + future.complete(new ApiClientHttpResponse<>(null, response)); + return; + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + future.completeExceptionally(new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response)); + return; + } catch (JsonProcessingException e) { + future.completeExceptionally( + new ApiClientException("Failed to deserialize response: " + e.getMessage(), e)); + } catch (IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + }); + return future; + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/RawApiClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/RawApiClient.java new file mode 100644 index 00000000..a39d00ca --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/RawApiClient.java @@ -0,0 +1,90 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.RetryInterceptor; +import com.skyflow.generated.rest.requests.PatchV2VaultsIdRequest; +import java.io.IOException; +import java.util.Optional; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; + +public class RawApiClient { + protected final ClientOptions clientOptions; + + public RawApiClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + } + + public ApiClientHttpResponse patchV2VaultsId(Optional vaultId) { + return patchV2VaultsId(vaultId, PatchV2VaultsIdRequest.builder().build()); + } + + public ApiClientHttpResponse patchV2VaultsId(Optional vaultId, RequestOptions requestOptions) { + return patchV2VaultsId(vaultId, PatchV2VaultsIdRequest.builder().build(), requestOptions); + } + + public ApiClientHttpResponse patchV2VaultsId(Optional vaultId, PatchV2VaultsIdRequest request) { + return patchV2VaultsId(vaultId, request, null); + } + + public ApiClientHttpResponse patchV2VaultsId( + Optional vaultId, PatchV2VaultsIdRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/vaults"); + if (vaultId.isPresent()) { + httpUrl.addPathSegment(vaultId.get()); + } + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + Request.Builder _requestBuilder = new Request.Builder() + .url(httpUrl.build()) + .method("PATCH", RequestBody.create("", null)) + .headers(Headers.of(clientOptions.headers(requestOptions))); + Request okhttpRequest = _requestBuilder.build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + if (response.isSuccessful()) { + return new ApiClientHttpResponse<>(null, response); + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + throw new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to deserialize response: " + e.getMessage(), e); + } catch (IOException e) { + throw new ApiClientException("Network error executing HTTP request", e); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/ApiClientApiException.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/ApiClientApiException.java index be5247eb..c016a435 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/core/ApiClientApiException.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/ApiClientApiException.java @@ -3,12 +3,11 @@ */ package com.skyflow.generated.rest.core; -import okhttp3.Response; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import okhttp3.Response; /** * This exception type will be thrown for any non-2XX API responses. @@ -68,7 +67,7 @@ public Map> headers() { @Override public String toString() { - return "ApiClientApiException{" + "message: " + getMessage() + ", statusCode: " + statusCode + ", body: " + body - + "}"; + return "ApiClientApiException{" + "message: " + getMessage() + ", statusCode: " + statusCode + ", body: " + + ObjectMappers.stringify(body) + "}"; } } diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/ApiClientHttpResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/ApiClientHttpResponse.java index c743352c..9c81f1f5 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/core/ApiClientHttpResponse.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/ApiClientHttpResponse.java @@ -3,12 +3,11 @@ */ package com.skyflow.generated.rest.core; -import okhttp3.Response; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import okhttp3.Response; public final class ApiClientHttpResponse { diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java index 2a5f0710..3f3a7dc6 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java @@ -3,13 +3,12 @@ */ package com.skyflow.generated.rest.core; -import okhttp3.OkHttpClient; - import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; +import okhttp3.OkHttpClient; public final class ClientOptions { private final Environment environment; @@ -20,14 +19,32 @@ public final class ClientOptions { private final OkHttpClient httpClient; + private final boolean ownsHttpClient; + private final int timeout; + private final int maxRetries; + + private final Optional initialRetryDelayMillis; + + private final Optional maxRetryDelayMillis; + + private final Optional retryJitterFactor; + + private final Optional logging; + private ClientOptions( Environment environment, Map headers, Map> headerSuppliers, OkHttpClient httpClient, - int timeout) { + boolean ownsHttpClient, + int timeout, + int maxRetries, + Optional initialRetryDelayMillis, + Optional maxRetryDelayMillis, + Optional retryJitterFactor, + Optional logging) { this.environment = environment; this.headers = new HashMap<>(); this.headers.putAll(headers); @@ -40,7 +57,13 @@ private ClientOptions( }); this.headerSuppliers = headerSuppliers; this.httpClient = httpClient; + this.ownsHttpClient = ownsHttpClient; this.timeout = timeout; + this.maxRetries = maxRetries; + this.initialRetryDelayMillis = initialRetryDelayMillis; + this.maxRetryDelayMillis = maxRetryDelayMillis; + this.retryJitterFactor = retryJitterFactor; + this.logging = logging; } public Environment environment() { @@ -82,11 +105,50 @@ public OkHttpClient httpClientWithTimeout(RequestOptions requestOptions) { .build(); } + public int maxRetries() { + return this.maxRetries; + } + + public Optional initialRetryDelayMillis() { + return this.initialRetryDelayMillis; + } + + public Optional maxRetryDelayMillis() { + return this.maxRetryDelayMillis; + } + + public Optional retryJitterFactor() { + return this.retryJitterFactor; + } + + /** + * Releases resources owned by this client. Only shuts down the underlying OkHttpClient's + * dispatcher executor and evicts its connection pool when this client created that + * OkHttpClient itself; an OkHttpClient supplied via httpClient is left running, since the + * caller owns its lifecycle. + *

+ * In-flight calls are not cancelled or awaited, and any request issued after this method + * returns fails with a {@code RejectedExecutionException}. Options derived from this one via + * {@code Builder.from(...)} share the same dispatcher and connection pool, so closing either + * releases them for both. Calling this method more than once has no further effect. + */ + public void close() { + if (!this.ownsHttpClient) { + return; + } + this.httpClient.dispatcher().executorService().shutdown(); + this.httpClient.connectionPool().evictAll(); + } + + public Optional logging() { + return this.logging; + } + public static Builder builder() { return new Builder(); } - public static final class Builder { + public static class Builder { private Environment environment; private final Map headers = new HashMap<>(); @@ -95,17 +157,29 @@ public static final class Builder { private int maxRetries = 2; + private Optional initialRetryDelayMillis = Optional.empty(); + + private Optional maxRetryDelayMillis = Optional.empty(); + + private Optional retryJitterFactor = Optional.empty(); + private Optional timeout = Optional.empty(); private OkHttpClient httpClient = null; + private boolean ownsHttpClient = true; + + private Optional logging = Optional.empty(); + public Builder environment(Environment environment) { this.environment = environment; return this; } public Builder addHeader(String key, String value) { - this.headers.put(key, value); + if (value != null) { + this.headers.put(key, value); + } return this; } @@ -138,8 +212,45 @@ public Builder maxRetries(int maxRetries) { return this; } + /** + * Override the initial delay (in milliseconds) used for exponential backoff between retries. Defaults to 1000 milliseconds. + */ + public Builder initialRetryDelayMillis(long initialRetryDelayMillis) { + this.initialRetryDelayMillis = Optional.of(initialRetryDelayMillis); + return this; + } + + /** + * Override the maximum delay (in milliseconds) between retries. Defaults to 60000 milliseconds. + */ + public Builder maxRetryDelayMillis(long maxRetryDelayMillis) { + this.maxRetryDelayMillis = Optional.of(maxRetryDelayMillis); + return this; + } + + /** + * Override the jitter factor (between 0 and 1) applied to retry delays. Defaults to 0.2. + */ + public Builder retryJitterFactor(double retryJitterFactor) { + this.retryJitterFactor = Optional.of(retryJitterFactor); + return this; + } + + /** + * Sets the underlying OkHttp client. The caller retains ownership of its lifecycle: + * close() will not shut down its dispatcher executor or evict its connection pool. + */ public Builder httpClient(OkHttpClient httpClient) { this.httpClient = httpClient; + this.ownsHttpClient = httpClient == null; + return this; + } + + /** + * Configure logging for the SDK. Silent by default — no log output unless explicitly configured. + */ + public Builder logging(LogConfig logging) { + this.logging = Optional.of(logging); return this; } @@ -159,13 +270,51 @@ public ClientOptions build() { .connectTimeout(0, TimeUnit.SECONDS) .writeTimeout(0, TimeUnit.SECONDS) .readTimeout(0, TimeUnit.SECONDS) - .addInterceptor(new RetryInterceptor(this.maxRetries)); + .addInterceptor(new RetryInterceptor( + this.maxRetries, + this.initialRetryDelayMillis, + this.maxRetryDelayMillis, + this.retryJitterFactor)); } + Logger logger = Logger.from(this.logging); + httpClientBuilder.addInterceptor(new LoggingInterceptor(logger)); + httpClientBuilder.addInterceptor(new ResponseDecompressionInterceptor()); + this.httpClient = httpClientBuilder.build(); this.timeout = Optional.of(httpClient.callTimeoutMillis() / 1000); - return new ClientOptions(environment, headers, headerSuppliers, httpClient, this.timeout.get()); + return new ClientOptions( + environment, + headers, + headerSuppliers, + httpClient, + this.ownsHttpClient, + this.timeout.get(), + this.maxRetries, + this.initialRetryDelayMillis, + this.maxRetryDelayMillis, + this.retryJitterFactor, + this.logging); + } + + /** + * Create a new Builder initialized with values from an existing ClientOptions + */ + public static Builder from(ClientOptions clientOptions) { + Builder builder = new Builder(); + builder.environment = clientOptions.environment(); + builder.timeout = Optional.of(clientOptions.timeout(null)); + builder.httpClient = clientOptions.httpClient(); + builder.ownsHttpClient = clientOptions.ownsHttpClient; + builder.headers.putAll(clientOptions.headers); + builder.headerSuppliers.putAll(clientOptions.headerSuppliers); + builder.maxRetries = clientOptions.maxRetries(); + builder.initialRetryDelayMillis = clientOptions.initialRetryDelayMillis(); + builder.maxRetryDelayMillis = clientOptions.maxRetryDelayMillis(); + builder.retryJitterFactor = clientOptions.retryJitterFactor(); + builder.logging = clientOptions.logging(); + return builder; } } } diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/ConsoleLogger.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/ConsoleLogger.java new file mode 100644 index 00000000..d3786dcc --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/ConsoleLogger.java @@ -0,0 +1,52 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import java.util.logging.Level; + +/** + * Default logger implementation that writes to the console using {@link java.util.logging.Logger}. + * + *

Uses the "fern" logger name with a simple format of "LEVEL - message". + */ +public final class ConsoleLogger implements ILogger { + + private static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger("fern"); + + static { + if (logger.getHandlers().length == 0) { + java.util.logging.ConsoleHandler handler = new java.util.logging.ConsoleHandler(); + handler.setFormatter(new java.util.logging.SimpleFormatter() { + @Override + public String format(java.util.logging.LogRecord record) { + return record.getLevel() + " - " + record.getMessage() + System.lineSeparator(); + } + }); + handler.setLevel(Level.ALL); + logger.addHandler(handler); + logger.setUseParentHandlers(false); + logger.setLevel(Level.ALL); + } + } + + @Override + public void debug(String message) { + logger.log(Level.FINE, message); + } + + @Override + public void info(String message) { + logger.log(Level.INFO, message); + } + + @Override + public void warn(String message) { + logger.log(Level.WARNING, message); + } + + @Override + public void error(String message) { + logger.log(Level.SEVERE, message); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/DateTimeDeserializer.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/DateTimeDeserializer.java index a0a6d7c4..0f422bc2 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/core/DateTimeDeserializer.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/DateTimeDeserializer.java @@ -8,18 +8,19 @@ import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.module.SimpleModule; - import java.io.IOException; import java.time.Instant; import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalQueries; /** - * Custom deserializer that handles converting ISO8601 dates into {@link OffsetDateTime} objects. + * Custom deserializer that handles converting date-time strings into {@link OffsetDateTime} objects. + * Supports ISO 8601 format, space-separated variants, and RFC 1123 (RFC 2822) format. */ class DateTimeDeserializer extends JsonDeserializer { private static final SimpleModule MODULE; @@ -43,8 +44,21 @@ public OffsetDateTime deserialize(JsonParser parser, DeserializationContext cont if (token == JsonToken.VALUE_NUMBER_INT) { return OffsetDateTime.ofInstant(Instant.ofEpochSecond(parser.getValueAsLong()), ZoneOffset.UTC); } else { - TemporalAccessor temporal = DateTimeFormatter.ISO_DATE_TIME.parseBest( - parser.getValueAsString(), OffsetDateTime::from, LocalDateTime::from); + String value = parser.getValueAsString(); + TemporalAccessor temporal; + try { + temporal = DateTimeFormatter.ISO_DATE_TIME.parseBest(value, OffsetDateTime::from, LocalDateTime::from); + } catch (DateTimeParseException e) { + try { + // Fall back to space-separated format (e.g. "2025-02-15 10:30:00+00:00"). + temporal = DateTimeFormatter.ISO_DATE_TIME.parseBest( + value.replace(' ', 'T'), OffsetDateTime::from, LocalDateTime::from); + } catch (DateTimeParseException e2) { + // Fall back to RFC 1123 format (e.g. "Thu, 07 May 2026 14:23:38 +0000"). + temporal = DateTimeFormatter.RFC_1123_DATE_TIME.parseBest( + value, OffsetDateTime::from, LocalDateTime::from); + } + } if (temporal.query(TemporalQueries.offset()) == null) { return LocalDateTime.from(temporal).atOffset(ZoneOffset.UTC); diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/DoubleSerializer.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/DoubleSerializer.java new file mode 100644 index 00000000..131d0a9a --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/DoubleSerializer.java @@ -0,0 +1,43 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.module.SimpleModule; +import java.io.IOException; + +/** + * Custom serializer that writes integer-valued doubles without a decimal point. + * For example, {@code 24000.0} is serialized as {@code 24000} instead of {@code 24000.0}. + * Non-integer values like {@code 3.14} are serialized normally. + */ +class DoubleSerializer extends JsonSerializer { + private static final SimpleModule MODULE; + + static { + MODULE = new SimpleModule() + .addSerializer(Double.class, new DoubleSerializer()) + .addSerializer(double.class, new DoubleSerializer()); + } + + /** + * Gets a module wrapping this serializer as an adapter for the Jackson ObjectMapper. + * + * @return A {@link SimpleModule} to be plugged onto Jackson ObjectMapper. + */ + public static SimpleModule getModule() { + return MODULE; + } + + @Override + public void serialize(Double value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + if (value != null && value == Math.floor(value) && !Double.isInfinite(value) && !Double.isNaN(value)) { + gen.writeNumber(value.longValue()); + } else { + gen.writeNumber(value); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/Environment.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/Environment.java index 2fc27c36..a1ff2b36 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/core/Environment.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/Environment.java @@ -4,6 +4,10 @@ package com.skyflow.generated.rest.core; public final class Environment { + public static final Environment PRODUCTION = new Environment("https://%7B%7Bvault_url%7D%7D"); + + public static final Environment SANDBOX = new Environment("https://%7B%7Bvault_url%7D%7D"); + private final String url; private Environment(String url) { diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/FileStream.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/FileStream.java index 2131b0a4..6b459431 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/core/FileStream.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/FileStream.java @@ -3,13 +3,12 @@ */ package com.skyflow.generated.rest.core; +import java.io.InputStream; +import java.util.Objects; import okhttp3.MediaType; import okhttp3.RequestBody; import org.jetbrains.annotations.Nullable; -import java.io.InputStream; -import java.util.Objects; - /** * Represents a file stream with associated metadata for file uploads. */ diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/ILogger.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/ILogger.java new file mode 100644 index 00000000..a70ec8e6 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/ILogger.java @@ -0,0 +1,38 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +/** + * Interface for custom logger implementations. + * + *

Implement this interface to provide a custom logging backend for the SDK. + * The SDK will call the appropriate method based on the log level. + * + *

Example: + *

{@code
+ * public class MyCustomLogger implements ILogger {
+ *     public void debug(String message) {
+ *         System.out.println("[DBG] " + message);
+ *     }
+ *     public void info(String message) {
+ *         System.out.println("[INF] " + message);
+ *     }
+ *     public void warn(String message) {
+ *         System.out.println("[WRN] " + message);
+ *     }
+ *     public void error(String message) {
+ *         System.out.println("[ERR] " + message);
+ *     }
+ * }
+ * }
+ */ +public interface ILogger { + void debug(String message); + + void info(String message); + + void warn(String message); + + void error(String message); +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java index 55c3c971..5351a5f8 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/InputStreamRequestBody.java @@ -3,18 +3,16 @@ */ package com.skyflow.generated.rest.core; +import java.io.IOException; +import java.io.InputStream; +import java.util.Objects; import okhttp3.MediaType; import okhttp3.RequestBody; -import okhttp3.internal.Util; import okio.BufferedSink; import okio.Okio; import okio.Source; import org.jetbrains.annotations.Nullable; -import java.io.IOException; -import java.io.InputStream; -import java.util.Objects; - /** * A custom implementation of OkHttp's RequestBody that wraps an InputStream. * This class allows streaming of data from an InputStream directly to an HTTP request body, @@ -69,12 +67,8 @@ public long contentLength() throws IOException { */ @Override public void writeTo(BufferedSink sink) throws IOException { - Source source = null; - try { - source = Okio.source(inputStream); + try (Source source = Okio.source(inputStream)) { sink.writeAll(source); - } finally { - Util.closeQuietly(Objects.requireNonNull(source)); } } } diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/LogConfig.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/LogConfig.java new file mode 100644 index 00000000..7928e097 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/LogConfig.java @@ -0,0 +1,98 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +/** + * Configuration for SDK logging. + * + *

Use the builder to configure logging behavior: + *

{@code
+ * LogConfig config = LogConfig.builder()
+ *     .level(LogLevel.DEBUG)
+ *     .silent(false)
+ *     .build();
+ * }
+ * + *

Or with a custom logger: + *

{@code
+ * LogConfig config = LogConfig.builder()
+ *     .level(LogLevel.DEBUG)
+ *     .logger(new MyCustomLogger())
+ *     .silent(false)
+ *     .build();
+ * }
+ * + *

Defaults: + *

    + *
  • {@code level} — {@link LogLevel#INFO}
  • + *
  • {@code logger} — {@link ConsoleLogger} (writes to stderr via java.util.logging)
  • + *
  • {@code silent} — {@code true} (no output unless explicitly enabled)
  • + *
+ */ +public final class LogConfig { + + private final LogLevel level; + private final ILogger logger; + private final boolean silent; + + private LogConfig(LogLevel level, ILogger logger, boolean silent) { + this.level = level; + this.logger = logger; + this.silent = silent; + } + + public LogLevel level() { + return level; + } + + public ILogger logger() { + return logger; + } + + public boolean silent() { + return silent; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private LogLevel level = LogLevel.INFO; + private ILogger logger = new ConsoleLogger(); + private boolean silent = true; + + private Builder() {} + + /** + * Set the minimum log level. Only messages at this level or above will be logged. + * Defaults to {@link LogLevel#INFO}. + */ + public Builder level(LogLevel level) { + this.level = level; + return this; + } + + /** + * Set a custom logger implementation. Defaults to {@link ConsoleLogger}. + */ + public Builder logger(ILogger logger) { + this.logger = logger; + return this; + } + + /** + * Set whether logging is silent (disabled). Defaults to {@code true}. + * Set to {@code false} to enable log output. + */ + public Builder silent(boolean silent) { + this.silent = silent; + return this; + } + + public LogConfig build() { + return new LogConfig(level, logger, silent); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/LogLevel.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/LogLevel.java new file mode 100644 index 00000000..db72cd0a --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/LogLevel.java @@ -0,0 +1,36 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +/** + * Log levels for SDK logging configuration. + * Silent by default — no log output unless explicitly configured. + */ +public enum LogLevel { + DEBUG(1), + INFO(2), + WARN(3), + ERROR(4); + + private final int value; + + LogLevel(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + /** + * Parse a log level from a string (case-insensitive). + * + * @param level the level string (debug, info, warn, error) + * @return the corresponding LogLevel + * @throws IllegalArgumentException if the string does not match any level + */ + public static LogLevel fromString(String level) { + return LogLevel.valueOf(level.toUpperCase()); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/Logger.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/Logger.java new file mode 100644 index 00000000..a5603955 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/Logger.java @@ -0,0 +1,97 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +/** + * SDK logger that filters messages based on level and silent mode. + * + *

Silent by default — no log output unless explicitly configured. + * Create via {@link LogConfig} or directly: + *

{@code
+ * Logger logger = new Logger(LogLevel.DEBUG, new ConsoleLogger(), false);
+ * logger.debug("request sent");
+ * }
+ */ +public final class Logger { + + private static final Logger DEFAULT = new Logger(LogLevel.INFO, new ConsoleLogger(), true); + + private final LogLevel level; + private final ILogger logger; + private final boolean silent; + + public Logger(LogLevel level, ILogger logger, boolean silent) { + this.level = level; + this.logger = logger; + this.silent = silent; + } + + /** + * Returns a default silent logger (no output). + */ + public static Logger getDefault() { + return DEFAULT; + } + + /** + * Creates a Logger from a {@link LogConfig}. If config is {@code null}, returns the default silent logger. + */ + public static Logger from(LogConfig config) { + if (config == null) { + return DEFAULT; + } + return new Logger(config.level(), config.logger(), config.silent()); + } + + /** + * Creates a Logger from an {@code Optional}. If empty, returns the default silent logger. + */ + public static Logger from(java.util.Optional config) { + return config.map(Logger::from).orElse(DEFAULT); + } + + private boolean shouldLog(LogLevel messageLevel) { + return !silent && level.getValue() <= messageLevel.getValue(); + } + + public boolean isDebug() { + return shouldLog(LogLevel.DEBUG); + } + + public boolean isInfo() { + return shouldLog(LogLevel.INFO); + } + + public boolean isWarn() { + return shouldLog(LogLevel.WARN); + } + + public boolean isError() { + return shouldLog(LogLevel.ERROR); + } + + public void debug(String message) { + if (isDebug()) { + logger.debug(message); + } + } + + public void info(String message) { + if (isInfo()) { + logger.info(message); + } + } + + public void warn(String message) { + if (isWarn()) { + logger.warn(message); + } + } + + public void error(String message) { + if (isError()) { + logger.error(message); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/LoggingInterceptor.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/LoggingInterceptor.java new file mode 100644 index 00000000..407b7937 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/LoggingInterceptor.java @@ -0,0 +1,104 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import okhttp3.Interceptor; +import okhttp3.Request; +import okhttp3.Response; + +/** + * OkHttp interceptor that logs HTTP requests and responses. + * + *

Logs request method, URL, and headers (with sensitive values redacted) at debug level. + * Logs response status at debug level, and 4xx/5xx responses at error level. + * Does nothing if the logger is silent. + */ +public final class LoggingInterceptor implements Interceptor { + + private static final Set SENSITIVE_HEADERS = new HashSet<>(Arrays.asList( + "authorization", + "www-authenticate", + "x-api-key", + "api-key", + "apikey", + "x-api-token", + "x-auth-token", + "auth-token", + "proxy-authenticate", + "proxy-authorization", + "cookie", + "set-cookie", + "x-csrf-token", + "x-xsrf-token", + "x-session-token", + "x-access-token")); + + private final Logger logger; + + public LoggingInterceptor(Logger logger) { + this.logger = logger; + } + + @Override + public Response intercept(Chain chain) throws IOException { + Request request = chain.request(); + + if (logger.isDebug()) { + StringBuilder sb = new StringBuilder(); + sb.append("HTTP Request: ").append(request.method()).append(" ").append(request.url()); + sb.append(" headers={"); + boolean first = true; + for (String name : request.headers().names()) { + if (!first) { + sb.append(", "); + } + sb.append(name).append("="); + if (SENSITIVE_HEADERS.contains(name.toLowerCase())) { + sb.append("[REDACTED]"); + } else { + sb.append(request.header(name)); + } + first = false; + } + sb.append("}"); + sb.append(" has_body=").append(request.body() != null); + logger.debug(sb.toString()); + } + + Response response = chain.proceed(request); + + if (logger.isDebug()) { + StringBuilder sb = new StringBuilder(); + sb.append("HTTP Response: status=").append(response.code()); + sb.append(" url=").append(response.request().url()); + sb.append(" headers={"); + boolean first = true; + for (String name : response.headers().names()) { + if (!first) { + sb.append(", "); + } + sb.append(name).append("="); + if (SENSITIVE_HEADERS.contains(name.toLowerCase())) { + sb.append("[REDACTED]"); + } else { + sb.append(response.header(name)); + } + first = false; + } + sb.append("}"); + logger.debug(sb.toString()); + } + + if (response.code() >= 400 && logger.isError()) { + logger.error("HTTP Error: status=" + response.code() + " url=" + + response.request().url()); + } + + return response; + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/NullableNonemptyFilter.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/NullableNonemptyFilter.java index 98c33be4..a6cffd4d 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/core/NullableNonemptyFilter.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/NullableNonemptyFilter.java @@ -14,6 +14,9 @@ public boolean equals(Object o) { } private boolean isOptionalEmpty(Object o) { - return o instanceof Optional && !((Optional) o).isPresent(); + if (o instanceof Optional) { + return !((Optional) o).isPresent(); + } + return false; } } diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java index acec32b4..4f69f150 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/ObjectMappers.java @@ -4,13 +4,13 @@ package com.skyflow.generated.rest.core; import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; - import java.io.IOException; public final class ObjectMappers { @@ -18,6 +18,7 @@ public final class ObjectMappers { .addModule(new Jdk8Module()) .addModule(new JavaTimeModule()) .addModule(DateTimeDeserializer.getModule()) + .addModule(DoubleSerializer.getModule()) .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) .build(); @@ -34,4 +35,12 @@ public static String stringify(Object o) { return o.getClass().getName() + "@" + Integer.toHexString(o.hashCode()); } } + + public static Object parseErrorBody(String responseBodyString) { + try { + return JSON_MAPPER.readValue(responseBodyString, Object.class); + } catch (JsonProcessingException ignored) { + return responseBodyString; + } + } } diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java index c0687736..e9e18fb9 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/QueryStringMapper.java @@ -7,11 +7,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; import okhttp3.HttpUrl; import okhttp3.MultipartBody; -import java.util.*; - public class QueryStringMapper { private static final ObjectMapper MAPPER = ObjectMappers.JSON_MAPPER; diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/RequestOptions.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/RequestOptions.java index b8a8d14b..26b396e4 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/core/RequestOptions.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/RequestOptions.java @@ -10,23 +10,39 @@ import java.util.function.Supplier; public final class RequestOptions { + private final String token; + private final Optional timeout; private final TimeUnit timeoutTimeUnit; + private final Optional maxRetries; + private final Map headers; private final Map> headerSuppliers; + private final Map queryParameters; + + private final Map> queryParameterSuppliers; + private RequestOptions( + String token, Optional timeout, TimeUnit timeoutTimeUnit, + Optional maxRetries, Map headers, - Map> headerSuppliers) { + Map> headerSuppliers, + Map queryParameters, + Map> queryParameterSuppliers) { + this.token = token; this.timeout = timeout; this.timeoutTimeUnit = timeoutTimeUnit; + this.maxRetries = maxRetries; this.headers = headers; this.headerSuppliers = headerSuppliers; + this.queryParameters = queryParameters; + this.queryParameterSuppliers = queryParameterSuppliers; } public Optional getTimeout() { @@ -37,8 +53,15 @@ public TimeUnit getTimeoutTimeUnit() { return timeoutTimeUnit; } + public Optional getMaxRetries() { + return maxRetries; + } + public Map getHeaders() { Map headers = new HashMap<>(); + if (this.token != null) { + headers.put("Authorization", "Bearer " + this.token); + } headers.putAll(this.headers); this.headerSuppliers.forEach((key, supplier) -> { headers.put(key, supplier.get()); @@ -46,19 +69,40 @@ public Map getHeaders() { return headers; } + public Map getQueryParameters() { + Map queryParameters = new HashMap<>(this.queryParameters); + this.queryParameterSuppliers.forEach((key, supplier) -> { + queryParameters.put(key, supplier.get()); + }); + return queryParameters; + } + public static Builder builder() { return new Builder(); } - public static final class Builder { + public static class Builder { + private String token = null; + private Optional timeout = Optional.empty(); private TimeUnit timeoutTimeUnit = TimeUnit.SECONDS; + private Optional maxRetries = Optional.empty(); + private final Map headers = new HashMap<>(); private final Map> headerSuppliers = new HashMap<>(); + private final Map queryParameters = new HashMap<>(); + + private final Map> queryParameterSuppliers = new HashMap<>(); + + public Builder token(String token) { + this.token = token; + return this; + } + public Builder timeout(Integer timeout) { this.timeout = Optional.of(timeout); return this; @@ -70,6 +114,11 @@ public Builder timeout(Integer timeout, TimeUnit timeoutTimeUnit) { return this; } + public Builder maxRetries(Integer maxRetries) { + this.maxRetries = Optional.of(maxRetries); + return this; + } + public Builder addHeader(String key, String value) { this.headers.put(key, value); return this; @@ -80,8 +129,26 @@ public Builder addHeader(String key, Supplier value) { return this; } + public Builder addQueryParameter(String key, String value) { + this.queryParameters.put(key, value); + return this; + } + + public Builder addQueryParameter(String key, Supplier value) { + this.queryParameterSuppliers.put(key, value); + return this; + } + public RequestOptions build() { - return new RequestOptions(timeout, timeoutTimeUnit, headers, headerSuppliers); + return new RequestOptions( + token, + timeout, + timeoutTimeUnit, + maxRetries, + headers, + headerSuppliers, + queryParameters, + queryParameterSuppliers); } } } diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java index 1bb0b5dc..d8df7715 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/ResponseBodyInputStream.java @@ -3,10 +3,9 @@ */ package com.skyflow.generated.rest.core; -import okhttp3.Response; - import java.io.FilterInputStream; import java.io.IOException; +import okhttp3.Response; /** * A custom InputStream that wraps the InputStream from the OkHttp Response and ensures that the diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java index e6c1a525..ed894407 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/ResponseBodyReader.java @@ -3,10 +3,9 @@ */ package com.skyflow.generated.rest.core; -import okhttp3.Response; - import java.io.FilterReader; import java.io.IOException; +import okhttp3.Response; /** * A custom Reader that wraps the Reader from the OkHttp Response and ensures that the diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/ResponseDecompressionInterceptor.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/ResponseDecompressionInterceptor.java new file mode 100644 index 00000000..d6938347 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/ResponseDecompressionInterceptor.java @@ -0,0 +1,56 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import java.io.IOException; +import java.util.zip.Inflater; +import okhttp3.Interceptor; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okio.GzipSource; +import okio.InflaterSource; +import okio.Okio; +import okio.Source; + +/** + * Decompresses gzip and deflate encoded response bodies. OkHttp only performs + * transparent decompression when it adds the Accept-Encoding header itself, so + * responses to requests with an explicitly set Accept-Encoding header would + * otherwise be returned as raw compressed bytes. + */ +public class ResponseDecompressionInterceptor implements Interceptor { + + @Override + public Response intercept(Chain chain) throws IOException { + return decompress(chain.proceed(chain.request())); + } + + private Response decompress(Response response) { + ResponseBody body = response.body(); + if (body == null) { + return response; + } + String encoding = response.header("Content-Encoding"); + if (encoding == null) { + return response; + } + Source decompressedSource; + if (encoding.equalsIgnoreCase("gzip") || encoding.equalsIgnoreCase("x-gzip")) { + decompressedSource = new GzipSource(body.source()); + } else if (encoding.equalsIgnoreCase("deflate")) { + decompressedSource = new InflaterSource(body.source(), new Inflater()); + } else { + return response; + } + ResponseBody decompressedBody = ResponseBody.create(body.contentType(), -1L, Okio.buffer(decompressedSource)); + return response.newBuilder() + .headers(response.headers() + .newBuilder() + .removeAll("Content-Encoding") + .removeAll("Content-Length") + .build()) + .body(decompressedBody) + .build(); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java index 7a28c3c9..7d89751d 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/RetryInterceptor.java @@ -3,37 +3,80 @@ */ package com.skyflow.generated.rest.core; -import okhttp3.Interceptor; -import okhttp3.Response; - import java.io.IOException; import java.time.Duration; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.util.Optional; import java.util.Random; +import okhttp3.Interceptor; +import okhttp3.Request; +import okhttp3.Response; public class RetryInterceptor implements Interceptor { - private static final Duration ONE_SECOND = Duration.ofSeconds(1); - private final ExponentialBackoff backoff; + private static final Duration DEFAULT_INITIAL_RETRY_DELAY = Duration.ofMillis(1000); + private static final Duration DEFAULT_MAX_RETRY_DELAY = Duration.ofMillis(60000); + private static final double DEFAULT_JITTER_FACTOR = 0.2; + + private final int maxRetries; + private final Duration initialRetryDelay; + private final Duration maxRetryDelay; + private final double jitterFactor; private final Random random = new Random(); public RetryInterceptor(int maxRetries) { - this.backoff = new ExponentialBackoff(maxRetries); + this(maxRetries, Optional.empty(), Optional.empty(), Optional.empty()); + } + + public RetryInterceptor( + int maxRetries, + Optional initialRetryDelayMillis, + Optional maxRetryDelayMillis, + Optional jitterFactor) { + initialRetryDelayMillis.ifPresent(delay -> { + if (delay < 0) { + throw new IllegalArgumentException("initialRetryDelayMillis must be non-negative"); + } + }); + maxRetryDelayMillis.ifPresent(delay -> { + if (delay < 0) { + throw new IllegalArgumentException("maxRetryDelayMillis must be non-negative"); + } + }); + jitterFactor.ifPresent(factor -> { + if (factor < 0 || factor > 1) { + throw new IllegalArgumentException("jitterFactor must be between 0 and 1"); + } + }); + this.maxRetries = maxRetries; + this.initialRetryDelay = initialRetryDelayMillis.map(Duration::ofMillis).orElse(DEFAULT_INITIAL_RETRY_DELAY); + this.maxRetryDelay = maxRetryDelayMillis.map(Duration::ofMillis).orElse(DEFAULT_MAX_RETRY_DELAY); + this.jitterFactor = jitterFactor.orElse(DEFAULT_JITTER_FACTOR); } @Override public Response intercept(Chain chain) throws IOException { - Response response = chain.proceed(chain.request()); + Request request = chain.request(); + int effectiveMaxRetries = resolveMaxRetries(request); + Response response = chain.proceed(request); if (shouldRetry(response.code())) { - return retryChain(response, chain); + return retryChain(response, chain, effectiveMaxRetries); } return response; } - private Response retryChain(Response response, Chain chain) throws IOException { - Optional nextBackoff = this.backoff.nextBackoff(); + private int resolveMaxRetries(Request request) { + MaxRetriesOverride override = request.tag(MaxRetriesOverride.class); + return override != null ? override.getValue() : this.maxRetries; + } + + private Response retryChain(Response response, Chain chain, int maxRetries) throws IOException { + ExponentialBackoff backoff = new ExponentialBackoff(maxRetries); + Optional nextBackoff = backoff.nextBackoff(response); while (nextBackoff.isPresent()) { try { Thread.sleep(nextBackoff.get().toMillis()); @@ -43,7 +86,7 @@ private Response retryChain(Response response, Chain chain) throws IOException { response.close(); response = chain.proceed(chain.request()); if (shouldRetry(response.code())) { - nextBackoff = this.backoff.nextBackoff(); + nextBackoff = backoff.nextBackoff(response); } else { return response; } @@ -52,10 +95,130 @@ private Response retryChain(Response response, Chain chain) throws IOException { return response; } + /** + * Calculates the retry delay from response headers, with fallback to exponential backoff. + * Priority: Retry-After > X-RateLimit-Reset > Exponential Backoff + */ + private Duration getRetryDelayFromHeaders(Response response, int retryAttempt) { + // Check for Retry-After header first (RFC 7231), with no jitter + String retryAfter = response.header("Retry-After"); + if (retryAfter != null) { + // Parse as number of seconds... + Optional secondsDelay = tryParseLong(retryAfter) + .map(seconds -> seconds * 1000) + .filter(delayMs -> delayMs > 0) + .map(delayMs -> Math.min(delayMs, maxRetryDelay.toMillis())) + .map(Duration::ofMillis); + if (secondsDelay.isPresent()) { + return secondsDelay.get(); + } + + // ...or as an HTTP date; both are valid + Optional dateDelay = tryParseHttpDate(retryAfter) + .map(resetTime -> resetTime.toInstant().toEpochMilli() - System.currentTimeMillis()) + .filter(delayMs -> delayMs > 0) + .map(delayMs -> Math.min(delayMs, maxRetryDelay.toMillis())) + .map(Duration::ofMillis); + if (dateDelay.isPresent()) { + return dateDelay.get(); + } + } + + // Then check for industry-standard X-RateLimit-Reset header, with positive jitter + String rateLimitReset = response.header("X-RateLimit-Reset"); + if (rateLimitReset != null) { + // Assume Unix timestamp in epoch seconds + Optional rateLimitDelay = tryParseLong(rateLimitReset) + .map(resetTimeSeconds -> (resetTimeSeconds * 1000) - System.currentTimeMillis()) + .filter(delayMs -> delayMs > 0) + .map(delayMs -> Math.min(delayMs, maxRetryDelay.toMillis())) + .map(this::addPositiveJitter) + .map(Duration::ofMillis); + if (rateLimitDelay.isPresent()) { + return rateLimitDelay.get(); + } + } + + // Fall back to exponential backoff, with symmetric jitter + long initialDelayMillis = initialRetryDelay.toMillis(); + long maxDelayMillis = maxRetryDelay.toMillis(); + long cappedDelay; + if (retryAttempt >= Long.SIZE - 1 || initialDelayMillis > (maxDelayMillis >> retryAttempt)) { + // initialDelayMillis * 2^retryAttempt would exceed maxDelayMillis (or overflow) + cappedDelay = maxDelayMillis; + } else { + cappedDelay = Math.min(initialDelayMillis << retryAttempt, maxDelayMillis); // 2^retryAttempt + } + return Duration.ofMillis(addSymmetricJitter(cappedDelay)); + } + + /** + * Attempts to parse a string as a long, returning empty Optional on failure. + */ + private Optional tryParseLong(String value) { + if (value == null) { + return Optional.empty(); + } + try { + return Optional.of(Long.parseLong(value)); + } catch (NumberFormatException e) { + return Optional.empty(); + } + } + + /** + * Attempts to parse a string as an HTTP date (RFC 1123), returning empty Optional on failure. + */ + private Optional tryParseHttpDate(String value) { + if (value == null) { + return Optional.empty(); + } + try { + return Optional.of(ZonedDateTime.parse(value, DateTimeFormatter.RFC_1123_DATE_TIME)); + } catch (DateTimeParseException e) { + return Optional.empty(); + } + } + + /** + * Adds positive jitter (100-120% of original value) to prevent thundering herd. + * Used for X-RateLimit-Reset header delays. + */ + private long addPositiveJitter(long delayMs) { + double jitterMultiplier = 1.0 + (random.nextDouble() * jitterFactor); + return (long) (delayMs * jitterMultiplier); + } + + /** + * Adds symmetric jitter (90-110% of original value) to prevent thundering herd. + * Used for exponential backoff delays. + */ + private long addSymmetricJitter(long delayMs) { + double jitterMultiplier = 1.0 + ((random.nextDouble() - 0.5) * jitterFactor); + return (long) (delayMs * jitterMultiplier); + } + private static boolean shouldRetry(int statusCode) { return statusCode == 408 || statusCode == 429 || statusCode >= 500; } + /** + * Per-request override carried on the OkHttp {@link Request} as a tag. + * When present, the interceptor uses this value instead of the client-wide + * {@code maxRetries} configured at construction time. + */ + public static final class MaxRetriesOverride { + private final int value; + + public MaxRetriesOverride(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + private final class ExponentialBackoff { private final int maxNumRetries; @@ -66,14 +229,14 @@ private final class ExponentialBackoff { this.maxNumRetries = maxNumRetries; } - public Optional nextBackoff() { - retryNumber += 1; - if (retryNumber > maxNumRetries) { + public Optional nextBackoff(Response response) { + if (retryNumber >= maxNumRetries) { return Optional.empty(); } - int upperBound = (int) Math.pow(2, retryNumber); - return Optional.of(ONE_SECOND.multipliedBy(random.nextInt(upperBound))); + Duration delay = getRetryDelayFromHeaders(response, retryNumber); + retryNumber += 1; + return Optional.of(delay); } } } diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/Rfc2822DateTimeDeserializer.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/Rfc2822DateTimeDeserializer.java new file mode 100644 index 00000000..3a826210 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/Rfc2822DateTimeDeserializer.java @@ -0,0 +1,25 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import java.io.IOException; +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + +/** + * Custom deserializer that handles converting RFC 2822 (RFC 1123) dates into {@link OffsetDateTime} objects. + * This is used for fields with format "date-time-rfc-2822", such as Twilio's dateCreated, dateSent, dateUpdated. + */ +public class Rfc2822DateTimeDeserializer extends JsonDeserializer { + + @Override + public OffsetDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException { + String raw = parser.getValueAsString(); + return ZonedDateTime.parse(raw, DateTimeFormatter.RFC_1123_DATE_TIME).toOffsetDateTime(); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/SseEvent.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/SseEvent.java new file mode 100644 index 00000000..9ab823d5 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/SseEvent.java @@ -0,0 +1,114 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Objects; +import java.util.Optional; + +/** + * Represents a Server-Sent Event with all standard fields. + * Used for event-level discrimination where the discriminator is at the SSE envelope level. + * + * @param The type of the data field + */ +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonIgnoreProperties(ignoreUnknown = true) +public final class SseEvent { + private final String event; + private final T data; + private final String id; + private final Long retry; + + private SseEvent(String event, T data, String id, Long retry) { + this.event = event; + this.data = data; + this.id = id; + this.retry = retry; + } + + @JsonProperty("event") + public Optional getEvent() { + return Optional.ofNullable(event); + } + + @JsonProperty("data") + public T getData() { + return data; + } + + @JsonProperty("id") + public Optional getId() { + return Optional.ofNullable(id); + } + + @JsonProperty("retry") + public Optional getRetry() { + return Optional.ofNullable(retry); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SseEvent sseEvent = (SseEvent) o; + return Objects.equals(event, sseEvent.event) + && Objects.equals(data, sseEvent.data) + && Objects.equals(id, sseEvent.id) + && Objects.equals(retry, sseEvent.retry); + } + + @Override + public int hashCode() { + return Objects.hash(event, data, id, retry); + } + + @Override + public String toString() { + return "SseEvent{" + "event='" + + event + '\'' + ", data=" + + data + ", id='" + + id + '\'' + ", retry=" + + retry + '}'; + } + + public static Builder builder() { + return new Builder<>(); + } + + public static final class Builder { + private String event; + private T data; + private String id; + private Long retry; + + private Builder() {} + + public Builder event(String event) { + this.event = event; + return this; + } + + public Builder data(T data) { + this.data = data; + return this; + } + + public Builder id(String id) { + this.id = id; + return this; + } + + public Builder retry(Long retry) { + this.retry = retry; + return this; + } + + public SseEvent build() { + return new SseEvent<>(event, data, id, retry); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/SseEventParser.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/SseEventParser.java new file mode 100644 index 00000000..ce50f86b --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/SseEventParser.java @@ -0,0 +1,228 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.core.type.TypeReference; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +/** + * Utility class for parsing Server-Sent Events with support for discriminated unions. + *

+ * Handles two discrimination patterns: + *

    + *
  1. Data-level discrimination: The discriminator (e.g., 'type') is inside the JSON data payload. + * Jackson's polymorphic deserialization handles this automatically.
  2. + *
  3. Event-level discrimination: The discriminator (e.g., 'event') is at the SSE envelope level. + * This requires constructing the full SSE envelope for Jackson to process.
  4. + *
+ */ +public final class SseEventParser { + + private static final Set SSE_ENVELOPE_FIELDS = new HashSet<>(Arrays.asList("event", "data", "id", "retry")); + + private SseEventParser() { + // Utility class + } + + /** + * Parse an SSE event using event-level discrimination. + *

+ * Constructs the full SSE envelope object with event, data, id, and retry fields, + * then deserializes it to the target union type. + * + * @param eventType The SSE event type (from event: field) + * @param data The SSE data content (from data: field) + * @param id The SSE event ID (from id: field), may be null + * @param retry The SSE retry value (from retry: field), may be null + * @param unionClass The target union class + * @param discriminatorProperty The property name used for discrimination (e.g., "event") + * @param The target type + * @return The deserialized object + */ + public static T parseEventLevelUnion( + String eventType, String data, String id, Long retry, Class unionClass, String discriminatorProperty) { + try { + // Determine if data should be parsed as JSON based on the variant's expected type + Object parsedData = parseDataForVariant(eventType, data, unionClass, discriminatorProperty); + + // Construct the SSE envelope object + Map envelope = new HashMap<>(); + envelope.put(discriminatorProperty, eventType); + envelope.put("data", parsedData); + if (id != null) { + envelope.put("id", id); + } + if (retry != null) { + envelope.put("retry", retry); + } + + // Serialize to JSON and deserialize to target type + String envelopeJson = ObjectMappers.JSON_MAPPER.writeValueAsString(envelope); + return ObjectMappers.JSON_MAPPER.readValue(envelopeJson, unionClass); + } catch (Exception e) { + throw new RuntimeException("Failed to parse SSE event with event-level discrimination", e); + } + } + + /** + * Parse an SSE event using data-level discrimination. + *

+ * Simply parses the data field as JSON and deserializes it to the target type. + * Jackson's polymorphic deserialization handles the discrimination automatically. + * + * @param data The SSE data content (from data: field) + * @param valueType The target type + * @param The target type + * @return The deserialized object + */ + public static T parseDataLevelUnion(String data, Class valueType) { + try { + return ObjectMappers.JSON_MAPPER.readValue(data, valueType); + } catch (Exception e) { + throw new RuntimeException("Failed to parse SSE data with data-level discrimination", e); + } + } + + /** + * Determines if the given discriminator property indicates event-level discrimination. + * Event-level discrimination occurs when the discriminator is an SSE envelope field. + * + * @param discriminatorProperty The discriminator property name + * @return true if event-level discrimination, false otherwise + */ + public static boolean isEventLevelDiscrimination(String discriminatorProperty) { + return SSE_ENVELOPE_FIELDS.contains(discriminatorProperty); + } + + /** + * Attempts to find the discriminator property from the union class's Jackson annotations. + * + * @param unionClass The union class to inspect + * @return The discriminator property name, or empty if not found + */ + public static Optional findDiscriminatorProperty(Class unionClass) { + try { + // Look for JsonTypeInfo on the class itself + JsonTypeInfo typeInfo = unionClass.getAnnotation(JsonTypeInfo.class); + if (typeInfo != null && !typeInfo.property().isEmpty()) { + return Optional.of(typeInfo.property()); + } + + // Look for inner Value interface with JsonTypeInfo + for (Class innerClass : unionClass.getDeclaredClasses()) { + typeInfo = innerClass.getAnnotation(JsonTypeInfo.class); + if (typeInfo != null && !typeInfo.property().isEmpty()) { + return Optional.of(typeInfo.property()); + } + } + } catch (Exception e) { + // Ignore reflection errors + } + return Optional.empty(); + } + + /** + * Parse the data field based on what the matching variant expects. + * If the variant expects a String for its data field, returns the raw string. + * Otherwise, parses the data as JSON. + */ + private static Object parseDataForVariant( + String eventType, String data, Class unionClass, String discriminatorProperty) { + if (data == null || data.isEmpty()) { + return data; + } + + try { + // Try to find the variant class that matches this event type + Class variantClass = findVariantClass(unionClass, eventType, discriminatorProperty); + if (variantClass != null) { + // Check if the variant expects a String for the data field + Field dataField = findField(variantClass, "data"); + if (dataField != null && String.class.equals(dataField.getType())) { + // Variant expects String - return raw data + return data; + } + } + + // Try to parse as JSON + return ObjectMappers.JSON_MAPPER.readValue(data, new TypeReference>() {}); + } catch (Exception e) { + // If JSON parsing fails, return as string + return data; + } + } + + /** + * Find the variant class that matches the given discriminator value. + */ + private static Class findVariantClass( + Class unionClass, String discriminatorValue, String discriminatorProperty) { + try { + // Look for JsonSubTypes annotation + JsonSubTypes subTypes = findJsonSubTypes(unionClass); + if (subTypes == null) { + return null; + } + + for (JsonSubTypes.Type subType : subTypes.value()) { + JsonTypeName typeName = subType.value().getAnnotation(JsonTypeName.class); + if (typeName != null && typeName.value().equals(discriminatorValue)) { + return subType.value(); + } + // Also check the name attribute of @JsonSubTypes.Type + if (subType.name().equals(discriminatorValue)) { + return subType.value(); + } + } + } catch (Exception e) { + // Ignore reflection errors + } + return null; + } + + /** + * Find JsonSubTypes annotation on the class or its inner classes. + */ + private static JsonSubTypes findJsonSubTypes(Class unionClass) { + // Check the class itself + JsonSubTypes subTypes = unionClass.getAnnotation(JsonSubTypes.class); + if (subTypes != null) { + return subTypes; + } + + // Check inner classes (for Fern-style unions with inner Value interface) + for (Class innerClass : unionClass.getDeclaredClasses()) { + subTypes = innerClass.getAnnotation(JsonSubTypes.class); + if (subTypes != null) { + return subTypes; + } + } + return null; + } + + /** + * Find a field by name in a class, including private fields. + */ + private static Field findField(Class clazz, String fieldName) { + try { + return clazz.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + // Check superclass + Class superClass = clazz.getSuperclass(); + if (superClass != null && superClass != Object.class) { + return findField(superClass, fieldName); + } + return null; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/Stream.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/Stream.java index f037712a..3822aa81 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/core/Stream.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/Stream.java @@ -3,6 +3,8 @@ */ package com.skyflow.generated.rest.core; +import java.io.Closeable; +import java.io.IOException; import java.io.Reader; import java.util.Iterator; import java.util.NoSuchElementException; @@ -14,18 +16,30 @@ *

* {@code Stream} assumes that data is being pushed to the provided {@link Reader} asynchronously and utilizes a * {@code Scanner} to block during iteration if the next object is not available. + * Iterable stream for parsing JSON and Server-Sent Events (SSE) data. + * Supports both newline-delimited JSON and SSE with optional stream termination. * * @param The type of objects in the stream. */ -public final class Stream implements Iterable { - /** - * The {@link Class} of the objects in the stream. - */ +public final class Stream implements Iterable, Closeable { + + private static final String NEWLINE = "\n"; + private static final String DATA_PREFIX = "data:"; + + public enum StreamType { + JSON, + SSE, + SSE_EVENT_DISCRIMINATED + } + private final Class valueType; - /** - * The {@link Scanner} used for reading from the input stream and blocking when needed during iteration. - */ private final Scanner scanner; + private final StreamType streamType; + private final String messageTerminator; + private final String streamTerminator; + private final Reader sseReader; + private final String discriminatorProperty; + private boolean isClosed = false; /** * Constructs a new {@code Stream} with the specified value type, reader, and delimiter. @@ -35,8 +49,100 @@ public final class Stream implements Iterable { * @param delimiter The delimiter used to separate elements in the stream. */ public Stream(Class valueType, Reader reader, String delimiter) { + this.valueType = valueType; this.scanner = new Scanner(reader).useDelimiter(delimiter); + this.streamType = StreamType.JSON; + this.messageTerminator = delimiter; + this.streamTerminator = null; + this.sseReader = null; + this.discriminatorProperty = null; + } + + private Stream(Class valueType, StreamType type, Reader reader, String terminator) { + this(valueType, type, reader, terminator, null); + } + + private Stream( + Class valueType, StreamType type, Reader reader, String terminator, String discriminatorProperty) { this.valueType = valueType; + this.streamType = type; + this.discriminatorProperty = discriminatorProperty; + if (type == StreamType.JSON) { + this.scanner = new Scanner(reader).useDelimiter(terminator); + this.messageTerminator = terminator; + this.streamTerminator = null; + this.sseReader = null; + } else { + this.scanner = null; + this.messageTerminator = NEWLINE; + this.streamTerminator = terminator; + this.sseReader = reader; + } + } + + public static Stream fromJson(Class valueType, Reader reader, String delimiter) { + return new Stream<>(valueType, reader, delimiter); + } + + public static Stream fromJson(Class valueType, Reader reader) { + return new Stream<>(valueType, reader, NEWLINE); + } + + public static Stream fromSse(Class valueType, Reader sseReader) { + return new Stream<>(valueType, StreamType.SSE, sseReader, null); + } + + public static Stream fromSse(Class valueType, Reader sseReader, String streamTerminator) { + return new Stream<>(valueType, StreamType.SSE, sseReader, streamTerminator); + } + + /** + * Creates a stream from SSE data with event-level discrimination support. + * Use this when the SSE payload is a discriminated union where the discriminator + * is an SSE envelope field (e.g., 'event'). + * + * @param valueType The class of the objects in the stream. + * @param sseReader The reader that provides the SSE data. + * @param discriminatorProperty The property name used for discrimination (e.g., "event"). + * @param The type of objects in the stream. + * @return A new Stream instance configured for SSE with event-level discrimination. + */ + public static Stream fromSseWithEventDiscrimination( + Class valueType, Reader sseReader, String discriminatorProperty) { + return new Stream<>(valueType, StreamType.SSE_EVENT_DISCRIMINATED, sseReader, null, discriminatorProperty); + } + + /** + * Creates a stream from SSE data with event-level discrimination support and a stream terminator. + * + * @param valueType The class of the objects in the stream. + * @param sseReader The reader that provides the SSE data. + * @param discriminatorProperty The property name used for discrimination (e.g., "event"). + * @param streamTerminator The terminator string that signals end of stream (e.g., "[DONE]"). + * @param The type of objects in the stream. + * @return A new Stream instance configured for SSE with event-level discrimination. + */ + public static Stream fromSseWithEventDiscrimination( + Class valueType, Reader sseReader, String discriminatorProperty, String streamTerminator) { + return new Stream<>( + valueType, StreamType.SSE_EVENT_DISCRIMINATED, sseReader, streamTerminator, discriminatorProperty); + } + + @Override + public void close() throws IOException { + if (!isClosed) { + isClosed = true; + if (scanner != null) { + scanner.close(); + } + if (sseReader != null) { + sseReader.close(); + } + } + } + + private boolean isStreamClosed() { + return isClosed; } /** @@ -47,51 +153,361 @@ public Stream(Class valueType, Reader reader, String delimiter) { */ @Override public Iterator iterator() { - return new Iterator() { - /** - * Returns {@code true} if there are more elements in the stream. - *

- * Will block and wait for input if the stream has not ended and the next object is not yet available. - * - * @return {@code true} if there are more elements, {@code false} otherwise. - */ - @Override - public boolean hasNext() { - return scanner.hasNext(); - } - - /** - * Returns the next element in the stream. - *

- * Will block and wait for input if the stream has not ended and the next object is not yet available. - * - * @return The next element in the stream. - * @throws NoSuchElementException If there are no more elements in the stream. - */ - @Override - public T next() { - if (!scanner.hasNext()) { - throw new NoSuchElementException(); - } else { + switch (streamType) { + case SSE: + return new SSEIterator(); + case SSE_EVENT_DISCRIMINATED: + return new SSEEventDiscriminatedIterator(); + case JSON: + default: + return new JsonIterator(); + } + } + + private final class JsonIterator implements Iterator { + + /** + * Returns {@code true} if there are more elements in the stream. + *

+ * Will block and wait for input if the stream has not ended and the next object is not yet available. + * + * @return {@code true} if there are more elements, {@code false} otherwise. + */ + @Override + public boolean hasNext() { + if (isStreamClosed()) { + return false; + } + return scanner.hasNext(); + } + + /** + * Returns the next element in the stream. + *

+ * Will block and wait for input if the stream has not ended and the next object is not yet available. + * + * @return The next element in the stream. + * @throws NoSuchElementException If there are no more elements in the stream. + */ + @Override + public T next() { + if (isStreamClosed()) { + throw new NoSuchElementException("Stream is closed"); + } + + if (!scanner.hasNext()) { + throw new NoSuchElementException(); + } else { + try { + T parsedResponse = + ObjectMappers.JSON_MAPPER.readValue(scanner.next().trim(), valueType); + return parsedResponse; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + private final class SSEIterator implements Iterator { + private Scanner sseScanner; + private T nextItem; + private boolean hasNextItem = false; + private boolean endOfStream = false; + private StringBuilder eventDataBuffer = new StringBuilder(); + private String currentEventType = null; + + private SSEIterator() { + if (sseReader != null && !isStreamClosed()) { + this.sseScanner = new Scanner(sseReader); + } else { + this.endOfStream = true; + } + } + + @Override + public boolean hasNext() { + if (isStreamClosed() || endOfStream) { + return false; + } + + if (hasNextItem) { + return true; + } + + return readNextMessage(); + } + + @Override + public T next() { + if (!hasNext()) { + throw new NoSuchElementException("No more elements in stream"); + } + + T result = nextItem; + nextItem = null; + hasNextItem = false; + return result; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + private boolean readNextMessage() { + if (sseScanner == null || isStreamClosed()) { + endOfStream = true; + return false; + } + + try { + while (sseScanner.hasNextLine()) { + String line = sseScanner.nextLine(); + + if (line.trim().isEmpty()) { + if (eventDataBuffer.length() > 0) { + try { + nextItem = ObjectMappers.JSON_MAPPER.readValue(eventDataBuffer.toString(), valueType); + hasNextItem = true; + eventDataBuffer.setLength(0); + currentEventType = null; + return true; + } catch (Exception parseEx) { + System.err.println("Failed to parse SSE event: " + parseEx.getMessage()); + eventDataBuffer.setLength(0); + currentEventType = null; + continue; + } + } + continue; + } + + if (line.startsWith(DATA_PREFIX)) { + String dataContent = line.substring(DATA_PREFIX.length()); + if (dataContent.startsWith(" ")) { + dataContent = dataContent.substring(1); + } + + if (eventDataBuffer.length() == 0 + && streamTerminator != null + && dataContent.trim().equals(streamTerminator)) { + endOfStream = true; + return false; + } + + if (eventDataBuffer.length() > 0) { + eventDataBuffer.append('\n'); + } + eventDataBuffer.append(dataContent); + } else if (line.startsWith("event:")) { + String eventValue = line.length() > 6 ? line.substring(6) : ""; + if (eventValue.startsWith(" ")) { + eventValue = eventValue.substring(1); + } + currentEventType = eventValue; + } else if (line.startsWith("id:")) { + // Event ID field (ignored) + } else if (line.startsWith("retry:")) { + // Retry field (ignored) + } else if (line.startsWith(":")) { + // Comment line (ignored) + } + } + + if (eventDataBuffer.length() > 0) { try { - T parsedResponse = ObjectMappers.JSON_MAPPER.readValue( - scanner.next().trim(), valueType); - return parsedResponse; - } catch (Exception e) { - throw new RuntimeException(e); + nextItem = ObjectMappers.JSON_MAPPER.readValue(eventDataBuffer.toString(), valueType); + hasNextItem = true; + eventDataBuffer.setLength(0); + currentEventType = null; + return true; + } catch (Exception parseEx) { + System.err.println("Failed to parse final SSE event: " + parseEx.getMessage()); + eventDataBuffer.setLength(0); + currentEventType = null; } } + + endOfStream = true; + return false; + + } catch (Exception e) { + System.err.println("Failed to parse SSE stream: " + e.getMessage()); + endOfStream = true; + return false; + } + } + } + + /** + * Iterator for SSE streams with event-level discrimination. + * Uses SseEventParser to construct the full SSE envelope for Jackson deserialization. + */ + private final class SSEEventDiscriminatedIterator implements Iterator { + private Scanner sseScanner; + private T nextItem; + private boolean hasNextItem = false; + private boolean endOfStream = false; + private StringBuilder eventDataBuffer = new StringBuilder(); + private String currentEventType = null; + private String currentEventId = null; + private Long currentRetry = null; + + private SSEEventDiscriminatedIterator() { + if (sseReader != null && !isStreamClosed()) { + this.sseScanner = new Scanner(sseReader); + } else { + this.endOfStream = true; + } + } + + @Override + public boolean hasNext() { + if (isStreamClosed() || endOfStream) { + return false; } - /** - * Removing elements from {@code Stream} is not supported. - * - * @throws UnsupportedOperationException Always, as removal is not supported. - */ - @Override - public void remove() { - throw new UnsupportedOperationException(); + if (hasNextItem) { + return true; + } + + return readNextMessage(); + } + + @Override + public T next() { + if (!hasNext()) { + throw new NoSuchElementException("No more elements in stream"); + } + + T result = nextItem; + nextItem = null; + hasNextItem = false; + return result; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + private boolean readNextMessage() { + if (sseScanner == null || isStreamClosed()) { + endOfStream = true; + return false; + } + + try { + while (sseScanner.hasNextLine()) { + String line = sseScanner.nextLine(); + + if (line.trim().isEmpty()) { + if (eventDataBuffer.length() > 0 || currentEventType != null) { + try { + // Use SseEventParser for event-level discrimination + nextItem = SseEventParser.parseEventLevelUnion( + currentEventType, + eventDataBuffer.toString(), + currentEventId, + currentRetry, + valueType, + discriminatorProperty); + hasNextItem = true; + resetEventState(); + return true; + } catch (Exception parseEx) { + System.err.println("Failed to parse SSE event: " + parseEx.getMessage()); + resetEventState(); + continue; + } + } + continue; + } + + if (line.startsWith(DATA_PREFIX)) { + String dataContent = line.substring(DATA_PREFIX.length()); + if (dataContent.startsWith(" ")) { + dataContent = dataContent.substring(1); + } + + if (eventDataBuffer.length() == 0 + && streamTerminator != null + && dataContent.trim().equals(streamTerminator)) { + endOfStream = true; + return false; + } + + if (eventDataBuffer.length() > 0) { + eventDataBuffer.append('\n'); + } + eventDataBuffer.append(dataContent); + } else if (line.startsWith("event:")) { + String eventValue = line.length() > 6 ? line.substring(6) : ""; + if (eventValue.startsWith(" ")) { + eventValue = eventValue.substring(1); + } + currentEventType = eventValue; + } else if (line.startsWith("id:")) { + String idValue = line.length() > 3 ? line.substring(3) : ""; + if (idValue.startsWith(" ")) { + idValue = idValue.substring(1); + } + currentEventId = idValue; + } else if (line.startsWith("retry:")) { + String retryValue = line.length() > 6 ? line.substring(6) : ""; + if (retryValue.startsWith(" ")) { + retryValue = retryValue.substring(1); + } + try { + currentRetry = Long.parseLong(retryValue.trim()); + } catch (NumberFormatException e) { + // Ignore invalid retry values + } + } else if (line.startsWith(":")) { + // Comment line (ignored) + } + } + + // Handle any remaining buffered data at end of stream + if (eventDataBuffer.length() > 0 || currentEventType != null) { + try { + nextItem = SseEventParser.parseEventLevelUnion( + currentEventType, + eventDataBuffer.toString(), + currentEventId, + currentRetry, + valueType, + discriminatorProperty); + hasNextItem = true; + resetEventState(); + return true; + } catch (Exception parseEx) { + System.err.println("Failed to parse final SSE event: " + parseEx.getMessage()); + resetEventState(); + } + } + + endOfStream = true; + return false; + + } catch (Exception e) { + System.err.println("Failed to parse SSE stream: " + e.getMessage()); + endOfStream = true; + return false; } - }; + } + + private void resetEventState() { + eventDataBuffer.setLength(0); + currentEventType = null; + currentEventId = null; + currentRetry = null; + } } } diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/core/WrappedAlias.java b/flowvault/src/main/java/com/skyflow/generated/rest/core/WrappedAlias.java new file mode 100644 index 00000000..352c364e --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/core/WrappedAlias.java @@ -0,0 +1,8 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.core; + +public interface WrappedAlias { + Object get(); +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/errors/BadRequestError.java b/flowvault/src/main/java/com/skyflow/generated/rest/errors/BadRequestError.java new file mode 100644 index 00000000..9f8ce586 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/errors/BadRequestError.java @@ -0,0 +1,33 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.errors; + +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.types.ErrorResponse; +import okhttp3.Response; + +public final class BadRequestError extends ApiClientApiException { + /** + * The body of the response that triggered the exception. + */ + private final ErrorResponse body; + + public BadRequestError(ErrorResponse body) { + super("BadRequestError", 400, body); + this.body = body; + } + + public BadRequestError(ErrorResponse body, Response rawResponse) { + super("BadRequestError", 400, body, rawResponse); + this.body = body; + } + + /** + * @return the body + */ + @java.lang.Override + public ErrorResponse body() { + return this.body; + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/errors/ForbiddenError.java b/flowvault/src/main/java/com/skyflow/generated/rest/errors/ForbiddenError.java new file mode 100644 index 00000000..f8eb18ff --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/errors/ForbiddenError.java @@ -0,0 +1,33 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.errors; + +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.types.ErrorResponse; +import okhttp3.Response; + +public final class ForbiddenError extends ApiClientApiException { + /** + * The body of the response that triggered the exception. + */ + private final ErrorResponse body; + + public ForbiddenError(ErrorResponse body) { + super("ForbiddenError", 403, body); + this.body = body; + } + + public ForbiddenError(ErrorResponse body, Response rawResponse) { + super("ForbiddenError", 403, body, rawResponse); + this.body = body; + } + + /** + * @return the body + */ + @java.lang.Override + public ErrorResponse body() { + return this.body; + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/errors/InternalServerError.java b/flowvault/src/main/java/com/skyflow/generated/rest/errors/InternalServerError.java new file mode 100644 index 00000000..d29f2b82 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/errors/InternalServerError.java @@ -0,0 +1,33 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.errors; + +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.types.ErrorResponse; +import okhttp3.Response; + +public final class InternalServerError extends ApiClientApiException { + /** + * The body of the response that triggered the exception. + */ + private final ErrorResponse body; + + public InternalServerError(ErrorResponse body) { + super("InternalServerError", 500, body); + this.body = body; + } + + public InternalServerError(ErrorResponse body, Response rawResponse) { + super("InternalServerError", 500, body, rawResponse); + this.body = body; + } + + /** + * @return the body + */ + @java.lang.Override + public ErrorResponse body() { + return this.body; + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/errors/NotFoundError.java b/flowvault/src/main/java/com/skyflow/generated/rest/errors/NotFoundError.java new file mode 100644 index 00000000..f0cdf5b0 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/errors/NotFoundError.java @@ -0,0 +1,33 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.errors; + +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.types.ErrorResponse; +import okhttp3.Response; + +public final class NotFoundError extends ApiClientApiException { + /** + * The body of the response that triggered the exception. + */ + private final ErrorResponse body; + + public NotFoundError(ErrorResponse body) { + super("NotFoundError", 404, body); + this.body = body; + } + + public NotFoundError(ErrorResponse body, Response rawResponse) { + super("NotFoundError", 404, body, rawResponse); + this.body = body; + } + + /** + * @return the body + */ + @java.lang.Override + public ErrorResponse body() { + return this.body; + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/errors/TooManyRequestsError.java b/flowvault/src/main/java/com/skyflow/generated/rest/errors/TooManyRequestsError.java new file mode 100644 index 00000000..e49ef7ef --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/errors/TooManyRequestsError.java @@ -0,0 +1,33 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.errors; + +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.types.ErrorResponse; +import okhttp3.Response; + +public final class TooManyRequestsError extends ApiClientApiException { + /** + * The body of the response that triggered the exception. + */ + private final ErrorResponse body; + + public TooManyRequestsError(ErrorResponse body) { + super("TooManyRequestsError", 429, body); + this.body = body; + } + + public TooManyRequestsError(ErrorResponse body, Response rawResponse) { + super("TooManyRequestsError", 429, body, rawResponse); + this.body = body; + } + + /** + * @return the body + */ + @java.lang.Override + public ErrorResponse body() { + return this.body; + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/errors/UnauthorizedError.java b/flowvault/src/main/java/com/skyflow/generated/rest/errors/UnauthorizedError.java new file mode 100644 index 00000000..1035b7f0 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/errors/UnauthorizedError.java @@ -0,0 +1,33 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.errors; + +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.types.ErrorResponse; +import okhttp3.Response; + +public final class UnauthorizedError extends ApiClientApiException { + /** + * The body of the response that triggered the exception. + */ + private final ErrorResponse body; + + public UnauthorizedError(ErrorResponse body) { + super("UnauthorizedError", 401, body); + this.body = body; + } + + public UnauthorizedError(ErrorResponse body, Response rawResponse) { + super("UnauthorizedError", 401, body, rawResponse); + this.body = body; + } + + /** + * @return the body + */ + @java.lang.Override + public ErrorResponse body() { + return this.body; + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/requests/PatchV2VaultsIdRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/requests/PatchV2VaultsIdRequest.java new file mode 100644 index 00000000..083579b6 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/requests/PatchV2VaultsIdRequest.java @@ -0,0 +1,69 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.requests; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = PatchV2VaultsIdRequest.Builder.class) +public final class PatchV2VaultsIdRequest { + private final Map additionalProperties; + + private PatchV2VaultsIdRequest(Map additionalProperties) { + this.additionalProperties = additionalProperties; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof PatchV2VaultsIdRequest; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(PatchV2VaultsIdRequest other) { + return this; + } + + public PatchV2VaultsIdRequest build() { + return new PatchV2VaultsIdRequest(additionalProperties); + } + + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/files/AsyncFilesClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/files/AsyncFilesClient.java new file mode 100644 index 00000000..c8ac6d43 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/files/AsyncFilesClient.java @@ -0,0 +1,58 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.files; + +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.resources.files.requests.FileDeleteRequest; +import com.skyflow.generated.rest.resources.files.requests.FileUploadRequest; +import com.skyflow.generated.rest.types.FileDeleteResponse; +import com.skyflow.generated.rest.types.FileUploadResponse; +import java.util.concurrent.CompletableFuture; + +public class AsyncFilesClient { + protected final ClientOptions clientOptions; + + private final AsyncRawFilesClient rawClient; + + public AsyncFilesClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.rawClient = new AsyncRawFilesClient(clientOptions); + } + + /** + * Get responses with HTTP metadata like headers + */ + public AsyncRawFilesClient withRawResponse() { + return this.rawClient; + } + + /** + * Deletes one or more files from the specified file column(s) of existing record(s) in a vault, and removes the underlying object from cloud storage. + */ + public CompletableFuture deleteFiles(FileDeleteRequest request) { + return this.rawClient.deleteFiles(request).thenApply(response -> response.body()); + } + + /** + * Deletes one or more files from the specified file column(s) of existing record(s) in a vault, and removes the underlying object from cloud storage. + */ + public CompletableFuture deleteFiles(FileDeleteRequest request, RequestOptions requestOptions) { + return this.rawClient.deleteFiles(request, requestOptions).thenApply(response -> response.body()); + } + + /** + * Generates signed URLs for uploading files to specified columns in a vault. Returns a signed URL per column that expires in 15 minutes by default. If a skyflowID is not provided for a record, a new record is created and its skyflowID is returned. + */ + public CompletableFuture uploadFiles(FileUploadRequest request) { + return this.rawClient.uploadFiles(request).thenApply(response -> response.body()); + } + + /** + * Generates signed URLs for uploading files to specified columns in a vault. Returns a signed URL per column that expires in 15 minutes by default. If a skyflowID is not provided for a record, a new record is created and its skyflowID is returned. + */ + public CompletableFuture uploadFiles(FileUploadRequest request, RequestOptions requestOptions) { + return this.rawClient.uploadFiles(request, requestOptions).thenApply(response -> response.body()); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/files/AsyncRawFilesClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/files/AsyncRawFilesClient.java new file mode 100644 index 00000000..635bc5aa --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/files/AsyncRawFilesClient.java @@ -0,0 +1,275 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.files; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.RetryInterceptor; +import com.skyflow.generated.rest.errors.BadRequestError; +import com.skyflow.generated.rest.errors.ForbiddenError; +import com.skyflow.generated.rest.errors.InternalServerError; +import com.skyflow.generated.rest.errors.NotFoundError; +import com.skyflow.generated.rest.errors.TooManyRequestsError; +import com.skyflow.generated.rest.errors.UnauthorizedError; +import com.skyflow.generated.rest.resources.files.requests.FileDeleteRequest; +import com.skyflow.generated.rest.resources.files.requests.FileUploadRequest; +import com.skyflow.generated.rest.types.ErrorResponse; +import com.skyflow.generated.rest.types.FileDeleteResponse; +import com.skyflow.generated.rest.types.FileUploadResponse; +import java.io.IOException; +import java.util.concurrent.CompletableFuture; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.jetbrains.annotations.NotNull; + +public class AsyncRawFilesClient { + protected final ClientOptions clientOptions; + + public AsyncRawFilesClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + } + + /** + * Deletes one or more files from the specified file column(s) of existing record(s) in a vault, and removes the underlying object from cloud storage. + */ + public CompletableFuture> deleteFiles(FileDeleteRequest request) { + return deleteFiles(request, null); + } + + /** + * Deletes one or more files from the specified file column(s) of existing record(s) in a vault, and removes the underlying object from cloud storage. + */ + public CompletableFuture> deleteFiles( + FileDeleteRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/files/delete"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + future.complete(new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, FileDeleteResponse.class), + response)); + return; + } + try { + switch (response.code()) { + case 400: + future.completeExceptionally(new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 401: + future.completeExceptionally(new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 403: + future.completeExceptionally(new ForbiddenError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 404: + future.completeExceptionally(new NotFoundError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 429: + future.completeExceptionally(new TooManyRequestsError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 500: + future.completeExceptionally(new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + future.completeExceptionally(new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response)); + return; + } catch (JsonProcessingException e) { + future.completeExceptionally( + new ApiClientException("Failed to deserialize response: " + e.getMessage(), e)); + } catch (IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + }); + return future; + } + + /** + * Generates signed URLs for uploading files to specified columns in a vault. Returns a signed URL per column that expires in 15 minutes by default. If a skyflowID is not provided for a record, a new record is created and its skyflowID is returned. + */ + public CompletableFuture> uploadFiles(FileUploadRequest request) { + return uploadFiles(request, null); + } + + /** + * Generates signed URLs for uploading files to specified columns in a vault. Returns a signed URL per column that expires in 15 minutes by default. If a skyflowID is not provided for a record, a new record is created and its skyflowID is returned. + */ + public CompletableFuture> uploadFiles( + FileUploadRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/files/upload"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + future.complete(new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, FileUploadResponse.class), + response)); + return; + } + try { + switch (response.code()) { + case 400: + future.completeExceptionally(new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 401: + future.completeExceptionally(new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 403: + future.completeExceptionally(new ForbiddenError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 404: + future.completeExceptionally(new NotFoundError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 429: + future.completeExceptionally(new TooManyRequestsError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 500: + future.completeExceptionally(new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + future.completeExceptionally(new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response)); + return; + } catch (JsonProcessingException e) { + future.completeExceptionally( + new ApiClientException("Failed to deserialize response: " + e.getMessage(), e)); + } catch (IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + }); + return future; + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/files/FilesClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/files/FilesClient.java new file mode 100644 index 00000000..34e08d6e --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/files/FilesClient.java @@ -0,0 +1,57 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.files; + +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.resources.files.requests.FileDeleteRequest; +import com.skyflow.generated.rest.resources.files.requests.FileUploadRequest; +import com.skyflow.generated.rest.types.FileDeleteResponse; +import com.skyflow.generated.rest.types.FileUploadResponse; + +public class FilesClient { + protected final ClientOptions clientOptions; + + private final RawFilesClient rawClient; + + public FilesClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.rawClient = new RawFilesClient(clientOptions); + } + + /** + * Get responses with HTTP metadata like headers + */ + public RawFilesClient withRawResponse() { + return this.rawClient; + } + + /** + * Deletes one or more files from the specified file column(s) of existing record(s) in a vault, and removes the underlying object from cloud storage. + */ + public FileDeleteResponse deleteFiles(FileDeleteRequest request) { + return this.rawClient.deleteFiles(request).body(); + } + + /** + * Deletes one or more files from the specified file column(s) of existing record(s) in a vault, and removes the underlying object from cloud storage. + */ + public FileDeleteResponse deleteFiles(FileDeleteRequest request, RequestOptions requestOptions) { + return this.rawClient.deleteFiles(request, requestOptions).body(); + } + + /** + * Generates signed URLs for uploading files to specified columns in a vault. Returns a signed URL per column that expires in 15 minutes by default. If a skyflowID is not provided for a record, a new record is created and its skyflowID is returned. + */ + public FileUploadResponse uploadFiles(FileUploadRequest request) { + return this.rawClient.uploadFiles(request).body(); + } + + /** + * Generates signed URLs for uploading files to specified columns in a vault. Returns a signed URL per column that expires in 15 minutes by default. If a skyflowID is not provided for a record, a new record is created and its skyflowID is returned. + */ + public FileUploadResponse uploadFiles(FileUploadRequest request, RequestOptions requestOptions) { + return this.rawClient.uploadFiles(request, requestOptions).body(); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/files/RawFilesClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/files/RawFilesClient.java new file mode 100644 index 00000000..521e0ad9 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/files/RawFilesClient.java @@ -0,0 +1,217 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.files; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.RetryInterceptor; +import com.skyflow.generated.rest.errors.BadRequestError; +import com.skyflow.generated.rest.errors.ForbiddenError; +import com.skyflow.generated.rest.errors.InternalServerError; +import com.skyflow.generated.rest.errors.NotFoundError; +import com.skyflow.generated.rest.errors.TooManyRequestsError; +import com.skyflow.generated.rest.errors.UnauthorizedError; +import com.skyflow.generated.rest.resources.files.requests.FileDeleteRequest; +import com.skyflow.generated.rest.resources.files.requests.FileUploadRequest; +import com.skyflow.generated.rest.types.ErrorResponse; +import com.skyflow.generated.rest.types.FileDeleteResponse; +import com.skyflow.generated.rest.types.FileUploadResponse; +import java.io.IOException; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; + +public class RawFilesClient { + protected final ClientOptions clientOptions; + + public RawFilesClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + } + + /** + * Deletes one or more files from the specified file column(s) of existing record(s) in a vault, and removes the underlying object from cloud storage. + */ + public ApiClientHttpResponse deleteFiles(FileDeleteRequest request) { + return deleteFiles(request, null); + } + + /** + * Deletes one or more files from the specified file column(s) of existing record(s) in a vault, and removes the underlying object from cloud storage. + */ + public ApiClientHttpResponse deleteFiles( + FileDeleteRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/files/delete"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + return new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, FileDeleteResponse.class), response); + } + try { + switch (response.code()) { + case 400: + throw new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 401: + throw new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 403: + throw new ForbiddenError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 404: + throw new NotFoundError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 429: + throw new TooManyRequestsError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 500: + throw new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + throw new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to deserialize response: " + e.getMessage(), e); + } catch (IOException e) { + throw new ApiClientException("Network error executing HTTP request", e); + } + } + + /** + * Generates signed URLs for uploading files to specified columns in a vault. Returns a signed URL per column that expires in 15 minutes by default. If a skyflowID is not provided for a record, a new record is created and its skyflowID is returned. + */ + public ApiClientHttpResponse uploadFiles(FileUploadRequest request) { + return uploadFiles(request, null); + } + + /** + * Generates signed URLs for uploading files to specified columns in a vault. Returns a signed URL per column that expires in 15 minutes by default. If a skyflowID is not provided for a record, a new record is created and its skyflowID is returned. + */ + public ApiClientHttpResponse uploadFiles( + FileUploadRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/files/upload"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + return new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, FileUploadResponse.class), response); + } + try { + switch (response.code()) { + case 400: + throw new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 401: + throw new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 403: + throw new ForbiddenError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 404: + throw new NotFoundError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 429: + throw new TooManyRequestsError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 500: + throw new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + throw new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to deserialize response: " + e.getMessage(), e); + } catch (IOException e) { + throw new ApiClientException("Network error executing HTTP request", e); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/files/requests/FileDeleteRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/files/requests/FileDeleteRequest.java new file mode 100644 index 00000000..50fdb91c --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/files/requests/FileDeleteRequest.java @@ -0,0 +1,191 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.files.requests; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.types.FileDeleteRecord; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = FileDeleteRequest.Builder.class) +public final class FileDeleteRequest { + private final String vaultId; + + private final List records; + + private final Map additionalProperties; + + private FileDeleteRequest( + String vaultId, List records, Map additionalProperties) { + this.vaultId = vaultId; + this.records = records; + this.additionalProperties = additionalProperties; + } + + /** + * @return ID of the vault. + */ + @JsonProperty("vaultID") + public String getVaultId() { + return vaultId; + } + + /** + * @return List of record objects (max 20,000) identifying the file columns to delete. + */ + @JsonProperty("records") + public List getRecords() { + return records; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof FileDeleteRequest && equalTo((FileDeleteRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(FileDeleteRequest other) { + return vaultId.equals(other.vaultId) && records.equals(other.records); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.vaultId, this.records); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static VaultIdStage builder() { + return new Builder(); + } + + public interface VaultIdStage { + /** + *

ID of the vault.

+ */ + _FinalStage vaultId(@NotNull String vaultId); + + Builder from(FileDeleteRequest other); + } + + public interface _FinalStage { + FileDeleteRequest build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + /** + *

List of record objects (max 20,000) identifying the file columns to delete.

+ */ + _FinalStage records(List records); + + _FinalStage addRecords(FileDeleteRecord records); + + _FinalStage addAllRecords(List records); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements VaultIdStage, _FinalStage { + private String vaultId; + + private List records = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(FileDeleteRequest other) { + vaultId(other.getVaultId()); + records(other.getRecords()); + return this; + } + + /** + *

ID of the vault.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("vaultID") + public _FinalStage vaultId(@NotNull String vaultId) { + this.vaultId = Objects.requireNonNull(vaultId, "vaultId must not be null"); + return this; + } + + /** + *

List of record objects (max 20,000) identifying the file columns to delete.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addAllRecords(List records) { + if (records != null) { + this.records.addAll(records); + } + return this; + } + + /** + *

List of record objects (max 20,000) identifying the file columns to delete.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addRecords(FileDeleteRecord records) { + this.records.add(records); + return this; + } + + /** + *

List of record objects (max 20,000) identifying the file columns to delete.

+ */ + @java.lang.Override + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public _FinalStage records(List records) { + this.records.clear(); + if (records != null) { + this.records.addAll(records); + } + return this; + } + + @java.lang.Override + public FileDeleteRequest build() { + return new FileDeleteRequest(vaultId, records, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/files/requests/FileUploadRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/files/requests/FileUploadRequest.java new file mode 100644 index 00000000..0db8c62b --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/files/requests/FileUploadRequest.java @@ -0,0 +1,191 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.files.requests; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.types.FileUploadRecord; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = FileUploadRequest.Builder.class) +public final class FileUploadRequest { + private final String vaultId; + + private final List records; + + private final Map additionalProperties; + + private FileUploadRequest( + String vaultId, List records, Map additionalProperties) { + this.vaultId = vaultId; + this.records = records; + this.additionalProperties = additionalProperties; + } + + /** + * @return ID of the vault. + */ + @JsonProperty("vaultID") + public String getVaultId() { + return vaultId; + } + + /** + * @return List of records for which signed file upload URLs are requested. + */ + @JsonProperty("records") + public List getRecords() { + return records; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof FileUploadRequest && equalTo((FileUploadRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(FileUploadRequest other) { + return vaultId.equals(other.vaultId) && records.equals(other.records); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.vaultId, this.records); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static VaultIdStage builder() { + return new Builder(); + } + + public interface VaultIdStage { + /** + *

ID of the vault.

+ */ + _FinalStage vaultId(@NotNull String vaultId); + + Builder from(FileUploadRequest other); + } + + public interface _FinalStage { + FileUploadRequest build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + /** + *

List of records for which signed file upload URLs are requested.

+ */ + _FinalStage records(List records); + + _FinalStage addRecords(FileUploadRecord records); + + _FinalStage addAllRecords(List records); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements VaultIdStage, _FinalStage { + private String vaultId; + + private List records = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(FileUploadRequest other) { + vaultId(other.getVaultId()); + records(other.getRecords()); + return this; + } + + /** + *

ID of the vault.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("vaultID") + public _FinalStage vaultId(@NotNull String vaultId) { + this.vaultId = Objects.requireNonNull(vaultId, "vaultId must not be null"); + return this; + } + + /** + *

List of records for which signed file upload URLs are requested.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addAllRecords(List records) { + if (records != null) { + this.records.addAll(records); + } + return this; + } + + /** + *

List of records for which signed file upload URLs are requested.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addRecords(FileUploadRecord records) { + this.records.add(records); + return this; + } + + /** + *

List of records for which signed file upload URLs are requested.

+ */ + @java.lang.Override + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public _FinalStage records(List records) { + this.records.clear(); + if (records != null) { + this.records.addAll(records); + } + return this; + } + + @java.lang.Override + public FileUploadRequest build() { + return new FileUploadRequest(vaultId, records, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/AsyncFlowserviceClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/AsyncFlowserviceClient.java deleted file mode 100644 index 1fd59fe9..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/AsyncFlowserviceClient.java +++ /dev/null @@ -1,129 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.resources.flowservice; - -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.flowservice.requests.*; -import com.skyflow.generated.rest.types.*; - -import java.util.concurrent.CompletableFuture; - -public class AsyncFlowserviceClient { - protected final ClientOptions clientOptions; - - private final AsyncRawFlowserviceClient rawClient; - - public AsyncFlowserviceClient(ClientOptions clientOptions) { - this.clientOptions = clientOptions; - this.rawClient = new AsyncRawFlowserviceClient(clientOptions); - } - - /** - * Get responses with HTTP metadata like headers - */ - public AsyncRawFlowserviceClient withRawResponse() { - return this.rawClient; - } - - public CompletableFuture delete() { - return this.rawClient.delete().thenApply(response -> response.body()); - } - - public CompletableFuture delete(V1DeleteRequest request) { - return this.rawClient.delete(request).thenApply(response -> response.body()); - } - - public CompletableFuture delete(V1DeleteRequest request, RequestOptions requestOptions) { - return this.rawClient.delete(request, requestOptions).thenApply(response -> response.body()); - } - - public CompletableFuture get() { - return this.rawClient.get().thenApply(response -> response.body()); - } - - public CompletableFuture get(V1GetRequest request) { - return this.rawClient.get(request).thenApply(response -> response.body()); - } - - public CompletableFuture get(V1GetRequest request, RequestOptions requestOptions) { - return this.rawClient.get(request, requestOptions).thenApply(response -> response.body()); - } - - public CompletableFuture insert() { - return this.rawClient.insert().thenApply(response -> response.body()); - } - - public CompletableFuture insert(V1InsertRequest request) { - return this.rawClient.insert(request).thenApply(response -> response.body()); - } - - public CompletableFuture insert(V1InsertRequest request, RequestOptions requestOptions) { - return this.rawClient.insert(request, requestOptions).thenApply(response -> response.body()); - } - - public CompletableFuture update() { - return this.rawClient.update().thenApply(response -> response.body()); - } - - public CompletableFuture update(V1UpdateRequest request) { - return this.rawClient.update(request).thenApply(response -> response.body()); - } - - public CompletableFuture update(V1UpdateRequest request, RequestOptions requestOptions) { - return this.rawClient.update(request, requestOptions).thenApply(response -> response.body()); - } - - public CompletableFuture deletetoken() { - return this.rawClient.deletetoken().thenApply(response -> response.body()); - } - - public CompletableFuture deletetoken(V1FlowDeleteTokenRequest request) { - return this.rawClient.deletetoken(request).thenApply(response -> response.body()); - } - - public CompletableFuture deletetoken( - V1FlowDeleteTokenRequest request, RequestOptions requestOptions) { - return this.rawClient.deletetoken(request, requestOptions).thenApply(response -> response.body()); - } - - public CompletableFuture detokenize() { - return this.rawClient.detokenize().thenApply(response -> response.body()); - } - - public CompletableFuture detokenize(V1FlowDetokenizeRequest request) { - return this.rawClient.detokenize(request).thenApply(response -> response.body()); - } - - public CompletableFuture detokenize( - V1FlowDetokenizeRequest request, RequestOptions requestOptions) { - return this.rawClient.detokenize(request, requestOptions).thenApply(response -> response.body()); - } - - public CompletableFuture tokenize() { - return this.rawClient.tokenize().thenApply(response -> response.body()); - } - - public CompletableFuture tokenize(V1FlowTokenizeRequest request) { - return this.rawClient.tokenize(request).thenApply(response -> response.body()); - } - - public CompletableFuture tokenize( - V1FlowTokenizeRequest request, RequestOptions requestOptions) { - return this.rawClient.tokenize(request, requestOptions).thenApply(response -> response.body()); - } - - public CompletableFuture flowvaultmetrics() { - return this.rawClient.flowvaultmetrics().thenApply(response -> response.body()); - } - - public CompletableFuture flowvaultmetrics(V1FlowVaultMetricsRequest request) { - return this.rawClient.flowvaultmetrics(request).thenApply(response -> response.body()); - } - - public CompletableFuture flowvaultmetrics( - V1FlowVaultMetricsRequest request, RequestOptions requestOptions) { - return this.rawClient.flowvaultmetrics(request, requestOptions).thenApply(response -> response.body()); - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/AsyncRawFlowserviceClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/AsyncRawFlowserviceClient.java deleted file mode 100644 index 17f85d0c..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/AsyncRawFlowserviceClient.java +++ /dev/null @@ -1,533 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.resources.flowservice; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.*; -import com.skyflow.generated.rest.resources.flowservice.requests.*; -import com.skyflow.generated.rest.types.*; -import okhttp3.*; -import org.jetbrains.annotations.NotNull; - -import java.io.IOException; -import java.util.concurrent.CompletableFuture; - -public class AsyncRawFlowserviceClient { - protected final ClientOptions clientOptions; - - public AsyncRawFlowserviceClient(ClientOptions clientOptions) { - this.clientOptions = clientOptions; - } - - public CompletableFuture> delete() { - return delete(V1DeleteRequest.builder().build()); - } - - public CompletableFuture> delete(V1DeleteRequest request) { - return delete(request, null); - } - - public CompletableFuture> delete( - V1DeleteRequest request, RequestOptions requestOptions) { - HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) - .newBuilder() - .addPathSegments("v2/records/delete") - .build(); - RequestBody body; - try { - body = RequestBody.create( - ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); - } catch (JsonProcessingException e) { - throw new ApiClientException("Failed to serialize request", e); - } - Request okhttpRequest = new Request.Builder() - .url(httpUrl) - .method("POST", body) - .headers(Headers.of(clientOptions.headers(requestOptions))) - .addHeader("Content-Type", "application/json") - .addHeader("Accept", "application/json") - .build(); - OkHttpClient client = clientOptions.httpClient(); - if (requestOptions != null && requestOptions.getTimeout().isPresent()) { - client = clientOptions.httpClientWithTimeout(requestOptions); - } - CompletableFuture> future = new CompletableFuture<>(); - client.newCall(okhttpRequest).enqueue(new Callback() { - @Override - public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { - try (ResponseBody responseBody = response.body()) { - if (response.isSuccessful()) { - future.complete(new ApiClientHttpResponse<>( - ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1DeleteResponse.class), - response)); - return; - } - String responseBodyString = responseBody != null ? responseBody.string() : "{}"; - future.completeExceptionally(new ApiClientApiException( - "Error with status code " + response.code(), - response.code(), - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), - response)); - return; - } catch (IOException e) { - future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); - } - } - - @Override - public void onFailure(@NotNull Call call, @NotNull IOException e) { - future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); - } - }); - return future; - } - - public CompletableFuture> get() { - return get(V1GetRequest.builder().build()); - } - - public CompletableFuture> get(V1GetRequest request) { - return get(request, null); - } - - public CompletableFuture> get( - V1GetRequest request, RequestOptions requestOptions) { - HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) - .newBuilder() - .addPathSegments("v2/records/get") - .build(); - RequestBody body; - try { - body = RequestBody.create( - ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); - } catch (JsonProcessingException e) { - throw new ApiClientException("Failed to serialize request", e); - } - Request okhttpRequest = new Request.Builder() - .url(httpUrl) - .method("POST", body) - .headers(Headers.of(clientOptions.headers(requestOptions))) - .addHeader("Content-Type", "application/json") - .addHeader("Accept", "application/json") - .build(); - OkHttpClient client = clientOptions.httpClient(); - if (requestOptions != null && requestOptions.getTimeout().isPresent()) { - client = clientOptions.httpClientWithTimeout(requestOptions); - } - CompletableFuture> future = new CompletableFuture<>(); - client.newCall(okhttpRequest).enqueue(new Callback() { - @Override - public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { - try (ResponseBody responseBody = response.body()) { - if (response.isSuccessful()) { - future.complete(new ApiClientHttpResponse<>( - ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1GetResponse.class), - response)); - return; - } - String responseBodyString = responseBody != null ? responseBody.string() : "{}"; - future.completeExceptionally(new ApiClientApiException( - "Error with status code " + response.code(), - response.code(), - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), - response)); - return; - } catch (IOException e) { - future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); - } - } - - @Override - public void onFailure(@NotNull Call call, @NotNull IOException e) { - future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); - } - }); - return future; - } - - public CompletableFuture> insert() { - return insert(V1InsertRequest.builder().build()); - } - - public CompletableFuture> insert(V1InsertRequest request) { - return insert(request, null); - } - - public CompletableFuture> insert( - V1InsertRequest request, RequestOptions requestOptions) { - HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) - .newBuilder() - .addPathSegments("v2/records/insert") - .build(); - RequestBody body; - try { - body = RequestBody.create( - ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); - } catch (JsonProcessingException e) { - throw new ApiClientException("Failed to serialize request", e); - } - Request okhttpRequest = new Request.Builder() - .url(httpUrl) - .method("POST", body) - .headers(Headers.of(clientOptions.headers(requestOptions))) - .addHeader("Content-Type", "application/json") - .addHeader("Accept", "application/json") - .build(); - OkHttpClient client = clientOptions.httpClient(); - if (requestOptions != null && requestOptions.getTimeout().isPresent()) { - client = clientOptions.httpClientWithTimeout(requestOptions); - } - CompletableFuture> future = new CompletableFuture<>(); - client.newCall(okhttpRequest).enqueue(new Callback() { - @Override - public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { - try (ResponseBody responseBody = response.body()) { - if (response.isSuccessful()) { - future.complete(new ApiClientHttpResponse<>( - ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1InsertResponse.class), - response)); - return; - } - String responseBodyString = responseBody != null ? responseBody.string() : "{}"; - future.completeExceptionally(new ApiClientApiException( - "Error with status code " + response.code(), - response.code(), - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), - response)); - return; - } catch (IOException e) { - future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); - } - } - - @Override - public void onFailure(@NotNull Call call, @NotNull IOException e) { - future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); - } - }); - return future; - } - - public CompletableFuture> update() { - return update(V1UpdateRequest.builder().build()); - } - - public CompletableFuture> update(V1UpdateRequest request) { - return update(request, null); - } - - public CompletableFuture> update( - V1UpdateRequest request, RequestOptions requestOptions) { - HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) - .newBuilder() - .addPathSegments("v2/records/update") - .build(); - RequestBody body; - try { - body = RequestBody.create( - ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); - } catch (JsonProcessingException e) { - throw new ApiClientException("Failed to serialize request", e); - } - Request okhttpRequest = new Request.Builder() - .url(httpUrl) - .method("POST", body) - .headers(Headers.of(clientOptions.headers(requestOptions))) - .addHeader("Content-Type", "application/json") - .addHeader("Accept", "application/json") - .build(); - OkHttpClient client = clientOptions.httpClient(); - if (requestOptions != null && requestOptions.getTimeout().isPresent()) { - client = clientOptions.httpClientWithTimeout(requestOptions); - } - CompletableFuture> future = new CompletableFuture<>(); - client.newCall(okhttpRequest).enqueue(new Callback() { - @Override - public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { - try (ResponseBody responseBody = response.body()) { - if (response.isSuccessful()) { - future.complete(new ApiClientHttpResponse<>( - ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1UpdateResponse.class), - response)); - return; - } - String responseBodyString = responseBody != null ? responseBody.string() : "{}"; - future.completeExceptionally(new ApiClientApiException( - "Error with status code " + response.code(), - response.code(), - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), - response)); - return; - } catch (IOException e) { - future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); - } - } - - @Override - public void onFailure(@NotNull Call call, @NotNull IOException e) { - future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); - } - }); - return future; - } - - public CompletableFuture> deletetoken() { - return deletetoken(V1FlowDeleteTokenRequest.builder().build()); - } - - public CompletableFuture> deletetoken( - V1FlowDeleteTokenRequest request) { - return deletetoken(request, null); - } - - public CompletableFuture> deletetoken( - V1FlowDeleteTokenRequest request, RequestOptions requestOptions) { - HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) - .newBuilder() - .addPathSegments("v2/tokens/delete") - .build(); - RequestBody body; - try { - body = RequestBody.create( - ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); - } catch (JsonProcessingException e) { - throw new ApiClientException("Failed to serialize request", e); - } - Request okhttpRequest = new Request.Builder() - .url(httpUrl) - .method("POST", body) - .headers(Headers.of(clientOptions.headers(requestOptions))) - .addHeader("Content-Type", "application/json") - .addHeader("Accept", "application/json") - .build(); - OkHttpClient client = clientOptions.httpClient(); - if (requestOptions != null && requestOptions.getTimeout().isPresent()) { - client = clientOptions.httpClientWithTimeout(requestOptions); - } - CompletableFuture> future = new CompletableFuture<>(); - client.newCall(okhttpRequest).enqueue(new Callback() { - @Override - public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { - try (ResponseBody responseBody = response.body()) { - if (response.isSuccessful()) { - future.complete(new ApiClientHttpResponse<>( - ObjectMappers.JSON_MAPPER.readValue( - responseBody.string(), V1FlowDeleteTokenResponse.class), - response)); - return; - } - String responseBodyString = responseBody != null ? responseBody.string() : "{}"; - future.completeExceptionally(new ApiClientApiException( - "Error with status code " + response.code(), - response.code(), - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), - response)); - return; - } catch (IOException e) { - future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); - } - } - - @Override - public void onFailure(@NotNull Call call, @NotNull IOException e) { - future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); - } - }); - return future; - } - - public CompletableFuture> detokenize() { - return detokenize(V1FlowDetokenizeRequest.builder().build()); - } - - public CompletableFuture> detokenize( - V1FlowDetokenizeRequest request) { - return detokenize(request, null); - } - - public CompletableFuture> detokenize( - V1FlowDetokenizeRequest request, RequestOptions requestOptions) { - HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) - .newBuilder() - .addPathSegments("v2/tokens/detokenize") - .build(); - RequestBody body; - try { - body = RequestBody.create( - ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); - } catch (JsonProcessingException e) { - throw new ApiClientException("Failed to serialize request", e); - } - Request okhttpRequest = new Request.Builder() - .url(httpUrl) - .method("POST", body) - .headers(Headers.of(clientOptions.headers(requestOptions))) - .addHeader("Content-Type", "application/json") - .addHeader("Accept", "application/json") - .build(); - OkHttpClient client = clientOptions.httpClient(); - if (requestOptions != null && requestOptions.getTimeout().isPresent()) { - client = clientOptions.httpClientWithTimeout(requestOptions); - } - CompletableFuture> future = new CompletableFuture<>(); - client.newCall(okhttpRequest).enqueue(new Callback() { - @Override - public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { - try (ResponseBody responseBody = response.body()) { - if (response.isSuccessful()) { - future.complete(new ApiClientHttpResponse<>( - ObjectMappers.JSON_MAPPER.readValue( - responseBody.string(), V1FlowDetokenizeResponse.class), - response)); - return; - } - String responseBodyString = responseBody != null ? responseBody.string() : "{}"; - future.completeExceptionally(new ApiClientApiException( - "Error with status code " + response.code(), - response.code(), - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), - response)); - return; - } catch (IOException e) { - future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); - } - } - - @Override - public void onFailure(@NotNull Call call, @NotNull IOException e) { - future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); - } - }); - return future; - } - - public CompletableFuture> tokenize() { - return tokenize(V1FlowTokenizeRequest.builder().build()); - } - - public CompletableFuture> tokenize(V1FlowTokenizeRequest request) { - return tokenize(request, null); - } - - public CompletableFuture> tokenize( - V1FlowTokenizeRequest request, RequestOptions requestOptions) { - HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) - .newBuilder() - .addPathSegments("v2/tokens/tokenize") - .build(); - RequestBody body; - try { - body = RequestBody.create( - ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); - } catch (JsonProcessingException e) { - throw new ApiClientException("Failed to serialize request", e); - } - Request okhttpRequest = new Request.Builder() - .url(httpUrl) - .method("POST", body) - .headers(Headers.of(clientOptions.headers(requestOptions))) - .addHeader("Content-Type", "application/json") - .addHeader("Accept", "application/json") - .build(); - OkHttpClient client = clientOptions.httpClient(); - if (requestOptions != null && requestOptions.getTimeout().isPresent()) { - client = clientOptions.httpClientWithTimeout(requestOptions); - } - CompletableFuture> future = new CompletableFuture<>(); - client.newCall(okhttpRequest).enqueue(new Callback() { - @Override - public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { - try (ResponseBody responseBody = response.body()) { - if (response.isSuccessful()) { - future.complete(new ApiClientHttpResponse<>( - ObjectMappers.JSON_MAPPER.readValue( - responseBody.string(), V1FlowTokenizeResponse.class), - response)); - return; - } - String responseBodyString = responseBody != null ? responseBody.string() : "{}"; - future.completeExceptionally(new ApiClientApiException( - "Error with status code " + response.code(), - response.code(), - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), - response)); - return; - } catch (IOException e) { - future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); - } - } - - @Override - public void onFailure(@NotNull Call call, @NotNull IOException e) { - future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); - } - }); - return future; - } - - public CompletableFuture> flowvaultmetrics() { - return flowvaultmetrics(V1FlowVaultMetricsRequest.builder().build()); - } - - public CompletableFuture> flowvaultmetrics( - V1FlowVaultMetricsRequest request) { - return flowvaultmetrics(request, null); - } - - public CompletableFuture> flowvaultmetrics( - V1FlowVaultMetricsRequest request, RequestOptions requestOptions) { - HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) - .newBuilder() - .addPathSegments("v2/vaults/metrics") - .build(); - RequestBody body; - try { - body = RequestBody.create( - ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); - } catch (JsonProcessingException e) { - throw new ApiClientException("Failed to serialize request", e); - } - Request okhttpRequest = new Request.Builder() - .url(httpUrl) - .method("POST", body) - .headers(Headers.of(clientOptions.headers(requestOptions))) - .addHeader("Content-Type", "application/json") - .addHeader("Accept", "application/json") - .build(); - OkHttpClient client = clientOptions.httpClient(); - if (requestOptions != null && requestOptions.getTimeout().isPresent()) { - client = clientOptions.httpClientWithTimeout(requestOptions); - } - CompletableFuture> future = new CompletableFuture<>(); - client.newCall(okhttpRequest).enqueue(new Callback() { - @Override - public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { - try (ResponseBody responseBody = response.body()) { - if (response.isSuccessful()) { - future.complete(new ApiClientHttpResponse<>( - ObjectMappers.JSON_MAPPER.readValue( - responseBody.string(), V1FlowVaultMetricsResponse.class), - response)); - return; - } - String responseBodyString = responseBody != null ? responseBody.string() : "{}"; - future.completeExceptionally(new ApiClientApiException( - "Error with status code " + response.code(), - response.code(), - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), - response)); - return; - } catch (IOException e) { - future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); - } - } - - @Override - public void onFailure(@NotNull Call call, @NotNull IOException e) { - future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); - } - }); - return future; - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/FlowserviceClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/FlowserviceClient.java deleted file mode 100644 index 8da9c9a5..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/FlowserviceClient.java +++ /dev/null @@ -1,124 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.resources.flowservice; - -import com.skyflow.generated.rest.core.ClientOptions; -import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.flowservice.requests.*; -import com.skyflow.generated.rest.types.*; - -public class FlowserviceClient { - protected final ClientOptions clientOptions; - - private final RawFlowserviceClient rawClient; - - public FlowserviceClient(ClientOptions clientOptions) { - this.clientOptions = clientOptions; - this.rawClient = new RawFlowserviceClient(clientOptions); - } - - /** - * Get responses with HTTP metadata like headers - */ - public RawFlowserviceClient withRawResponse() { - return this.rawClient; - } - - public V1DeleteResponse delete() { - return this.rawClient.delete().body(); - } - - public V1DeleteResponse delete(V1DeleteRequest request) { - return this.rawClient.delete(request).body(); - } - - public V1DeleteResponse delete(V1DeleteRequest request, RequestOptions requestOptions) { - return this.rawClient.delete(request, requestOptions).body(); - } - - public V1GetResponse get() { - return this.rawClient.get().body(); - } - - public V1GetResponse get(V1GetRequest request) { - return this.rawClient.get(request).body(); - } - - public V1GetResponse get(V1GetRequest request, RequestOptions requestOptions) { - return this.rawClient.get(request, requestOptions).body(); - } - - public V1InsertResponse insert() { - return this.rawClient.insert().body(); - } - - public V1InsertResponse insert(V1InsertRequest request) { - return this.rawClient.insert(request).body(); - } - - public V1InsertResponse insert(V1InsertRequest request, RequestOptions requestOptions) { - return this.rawClient.insert(request, requestOptions).body(); - } - - public V1UpdateResponse update() { - return this.rawClient.update().body(); - } - - public V1UpdateResponse update(V1UpdateRequest request) { - return this.rawClient.update(request).body(); - } - - public V1UpdateResponse update(V1UpdateRequest request, RequestOptions requestOptions) { - return this.rawClient.update(request, requestOptions).body(); - } - - public V1FlowDeleteTokenResponse deletetoken() { - return this.rawClient.deletetoken().body(); - } - - public V1FlowDeleteTokenResponse deletetoken(V1FlowDeleteTokenRequest request) { - return this.rawClient.deletetoken(request).body(); - } - - public V1FlowDeleteTokenResponse deletetoken(V1FlowDeleteTokenRequest request, RequestOptions requestOptions) { - return this.rawClient.deletetoken(request, requestOptions).body(); - } - - public V1FlowDetokenizeResponse detokenize() { - return this.rawClient.detokenize().body(); - } - - public V1FlowDetokenizeResponse detokenize(V1FlowDetokenizeRequest request) { - return this.rawClient.detokenize(request).body(); - } - - public V1FlowDetokenizeResponse detokenize(V1FlowDetokenizeRequest request, RequestOptions requestOptions) { - return this.rawClient.detokenize(request, requestOptions).body(); - } - - public V1FlowTokenizeResponse tokenize() { - return this.rawClient.tokenize().body(); - } - - public V1FlowTokenizeResponse tokenize(V1FlowTokenizeRequest request) { - return this.rawClient.tokenize(request).body(); - } - - public V1FlowTokenizeResponse tokenize(V1FlowTokenizeRequest request, RequestOptions requestOptions) { - return this.rawClient.tokenize(request, requestOptions).body(); - } - - public V1FlowVaultMetricsResponse flowvaultmetrics() { - return this.rawClient.flowvaultmetrics().body(); - } - - public V1FlowVaultMetricsResponse flowvaultmetrics(V1FlowVaultMetricsRequest request) { - return this.rawClient.flowvaultmetrics(request).body(); - } - - public V1FlowVaultMetricsResponse flowvaultmetrics( - V1FlowVaultMetricsRequest request, RequestOptions requestOptions) { - return this.rawClient.flowvaultmetrics(request, requestOptions).body(); - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/RawFlowserviceClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/RawFlowserviceClient.java deleted file mode 100644 index f1203085..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/RawFlowserviceClient.java +++ /dev/null @@ -1,412 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.resources.flowservice; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.*; -import com.skyflow.generated.rest.resources.flowservice.requests.*; -import com.skyflow.generated.rest.types.*; -import okhttp3.*; - -import java.io.IOException; - -public class RawFlowserviceClient { - protected final ClientOptions clientOptions; - - public RawFlowserviceClient(ClientOptions clientOptions) { - this.clientOptions = clientOptions; - } - - public ApiClientHttpResponse delete() { - return delete(V1DeleteRequest.builder().build()); - } - - public ApiClientHttpResponse delete(V1DeleteRequest request) { - return delete(request, null); - } - - public ApiClientHttpResponse delete(V1DeleteRequest request, RequestOptions requestOptions) { - HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) - .newBuilder() - .addPathSegments("v2/records/delete") - .build(); - RequestBody body; - try { - body = RequestBody.create( - ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); - } catch (JsonProcessingException e) { - throw new ApiClientException("Failed to serialize request", e); - } - Request okhttpRequest = new Request.Builder() - .url(httpUrl) - .method("POST", body) - .headers(Headers.of(clientOptions.headers(requestOptions))) - .addHeader("Content-Type", "application/json") - .addHeader("Accept", "application/json") - .build(); - OkHttpClient client = clientOptions.httpClient(); - if (requestOptions != null && requestOptions.getTimeout().isPresent()) { - client = clientOptions.httpClientWithTimeout(requestOptions); - } - try (Response response = client.newCall(okhttpRequest).execute()) { - ResponseBody responseBody = response.body(); - if (response.isSuccessful()) { - return new ApiClientHttpResponse<>( - ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1DeleteResponse.class), response); - } - String responseBodyString = responseBody != null ? responseBody.string() : "{}"; - throw new ApiClientApiException( - "Error with status code " + response.code(), - response.code(), - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), - response); - } catch (IOException e) { - throw new ApiClientException("Network error executing HTTP request", e); - } - } - - public ApiClientHttpResponse get() { - return get(V1GetRequest.builder().build()); - } - - public ApiClientHttpResponse get(V1GetRequest request) { - return get(request, null); - } - - public ApiClientHttpResponse get(V1GetRequest request, RequestOptions requestOptions) { - HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) - .newBuilder() - .addPathSegments("v2/records/get") - .build(); - RequestBody body; - try { - body = RequestBody.create( - ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); - } catch (JsonProcessingException e) { - throw new ApiClientException("Failed to serialize request", e); - } - Request okhttpRequest = new Request.Builder() - .url(httpUrl) - .method("POST", body) - .headers(Headers.of(clientOptions.headers(requestOptions))) - .addHeader("Content-Type", "application/json") - .addHeader("Accept", "application/json") - .build(); - OkHttpClient client = clientOptions.httpClient(); - if (requestOptions != null && requestOptions.getTimeout().isPresent()) { - client = clientOptions.httpClientWithTimeout(requestOptions); - } - try (Response response = client.newCall(okhttpRequest).execute()) { - ResponseBody responseBody = response.body(); - if (response.isSuccessful()) { - return new ApiClientHttpResponse<>( - ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1GetResponse.class), response); - } - String responseBodyString = responseBody != null ? responseBody.string() : "{}"; - throw new ApiClientApiException( - "Error with status code " + response.code(), - response.code(), - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), - response); - } catch (IOException e) { - throw new ApiClientException("Network error executing HTTP request", e); - } - } - - public ApiClientHttpResponse insert() { - return insert(V1InsertRequest.builder().build()); - } - - public ApiClientHttpResponse insert(V1InsertRequest request) { - return insert(request, null); - } - - public ApiClientHttpResponse insert(V1InsertRequest request, RequestOptions requestOptions) { - HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) - .newBuilder() - .addPathSegments("v2/records/insert") - .build(); - RequestBody body; - try { - body = RequestBody.create( - ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); - } catch (JsonProcessingException e) { - throw new ApiClientException("Failed to serialize request", e); - } - Request okhttpRequest = new Request.Builder() - .url(httpUrl) - .method("POST", body) - .headers(Headers.of(clientOptions.headers(requestOptions))) - .addHeader("Content-Type", "application/json") - .addHeader("Accept", "application/json") - .build(); - OkHttpClient client = clientOptions.httpClient(); - if (requestOptions != null && requestOptions.getTimeout().isPresent()) { - client = clientOptions.httpClientWithTimeout(requestOptions); - } - try (Response response = client.newCall(okhttpRequest).execute()) { - ResponseBody responseBody = response.body(); - if (response.isSuccessful()) { - return new ApiClientHttpResponse<>( - ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1InsertResponse.class), response); - } - String responseBodyString = responseBody != null ? responseBody.string() : "{}"; - throw new ApiClientApiException( - "Error with status code " + response.code(), - response.code(), - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), - response); - } catch (IOException e) { - throw new ApiClientException("Network error executing HTTP request", e); - } - } - - public ApiClientHttpResponse update() { - return update(V1UpdateRequest.builder().build()); - } - - public ApiClientHttpResponse update(V1UpdateRequest request) { - return update(request, null); - } - - public ApiClientHttpResponse update(V1UpdateRequest request, RequestOptions requestOptions) { - HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) - .newBuilder() - .addPathSegments("v2/records/update") - .build(); - RequestBody body; - try { - body = RequestBody.create( - ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); - } catch (JsonProcessingException e) { - throw new ApiClientException("Failed to serialize request", e); - } - Request okhttpRequest = new Request.Builder() - .url(httpUrl) - .method("POST", body) - .headers(Headers.of(clientOptions.headers(requestOptions))) - .addHeader("Content-Type", "application/json") - .addHeader("Accept", "application/json") - .build(); - OkHttpClient client = clientOptions.httpClient(); - if (requestOptions != null && requestOptions.getTimeout().isPresent()) { - client = clientOptions.httpClientWithTimeout(requestOptions); - } - try (Response response = client.newCall(okhttpRequest).execute()) { - ResponseBody responseBody = response.body(); - if (response.isSuccessful()) { - return new ApiClientHttpResponse<>( - ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1UpdateResponse.class), response); - } - String responseBodyString = responseBody != null ? responseBody.string() : "{}"; - throw new ApiClientApiException( - "Error with status code " + response.code(), - response.code(), - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), - response); - } catch (IOException e) { - throw new ApiClientException("Network error executing HTTP request", e); - } - } - - public ApiClientHttpResponse deletetoken() { - return deletetoken(V1FlowDeleteTokenRequest.builder().build()); - } - - public ApiClientHttpResponse deletetoken(V1FlowDeleteTokenRequest request) { - return deletetoken(request, null); - } - - public ApiClientHttpResponse deletetoken( - V1FlowDeleteTokenRequest request, RequestOptions requestOptions) { - HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) - .newBuilder() - .addPathSegments("v2/tokens/delete") - .build(); - RequestBody body; - try { - body = RequestBody.create( - ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); - } catch (JsonProcessingException e) { - throw new ApiClientException("Failed to serialize request", e); - } - Request okhttpRequest = new Request.Builder() - .url(httpUrl) - .method("POST", body) - .headers(Headers.of(clientOptions.headers(requestOptions))) - .addHeader("Content-Type", "application/json") - .addHeader("Accept", "application/json") - .build(); - OkHttpClient client = clientOptions.httpClient(); - if (requestOptions != null && requestOptions.getTimeout().isPresent()) { - client = clientOptions.httpClientWithTimeout(requestOptions); - } - try (Response response = client.newCall(okhttpRequest).execute()) { - ResponseBody responseBody = response.body(); - if (response.isSuccessful()) { - return new ApiClientHttpResponse<>( - ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1FlowDeleteTokenResponse.class), - response); - } - String responseBodyString = responseBody != null ? responseBody.string() : "{}"; - throw new ApiClientApiException( - "Error with status code " + response.code(), - response.code(), - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), - response); - } catch (IOException e) { - throw new ApiClientException("Network error executing HTTP request", e); - } - } - - public ApiClientHttpResponse detokenize() { - return detokenize(V1FlowDetokenizeRequest.builder().build()); - } - - public ApiClientHttpResponse detokenize(V1FlowDetokenizeRequest request) { - return detokenize(request, null); - } - - public ApiClientHttpResponse detokenize( - V1FlowDetokenizeRequest request, RequestOptions requestOptions) { - HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) - .newBuilder() - .addPathSegments("v2/tokens/detokenize") - .build(); - RequestBody body; - try { - body = RequestBody.create( - ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); - } catch (JsonProcessingException e) { - throw new ApiClientException("Failed to serialize request", e); - } - Request okhttpRequest = new Request.Builder() - .url(httpUrl) - .method("POST", body) - .headers(Headers.of(clientOptions.headers(requestOptions))) - .addHeader("Content-Type", "application/json") - .addHeader("Accept", "application/json") - .build(); - OkHttpClient client = clientOptions.httpClient(); - if (requestOptions != null && requestOptions.getTimeout().isPresent()) { - client = clientOptions.httpClientWithTimeout(requestOptions); - } - try (Response response = client.newCall(okhttpRequest).execute()) { - ResponseBody responseBody = response.body(); - if (response.isSuccessful()) { - return new ApiClientHttpResponse<>( - ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1FlowDetokenizeResponse.class), - response); - } - String responseBodyString = responseBody != null ? responseBody.string() : "{}"; - throw new ApiClientApiException( - "Error with status code " + response.code(), - response.code(), - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), - response); - } catch (IOException e) { - throw new ApiClientException("Network error executing HTTP request", e); - } - } - - public ApiClientHttpResponse tokenize() { - return tokenize(V1FlowTokenizeRequest.builder().build()); - } - - public ApiClientHttpResponse tokenize(V1FlowTokenizeRequest request) { - return tokenize(request, null); - } - - public ApiClientHttpResponse tokenize( - V1FlowTokenizeRequest request, RequestOptions requestOptions) { - HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) - .newBuilder() - .addPathSegments("v2/tokens/tokenize") - .build(); - RequestBody body; - try { - body = RequestBody.create( - ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); - } catch (JsonProcessingException e) { - throw new ApiClientException("Failed to serialize request", e); - } - Request okhttpRequest = new Request.Builder() - .url(httpUrl) - .method("POST", body) - .headers(Headers.of(clientOptions.headers(requestOptions))) - .addHeader("Content-Type", "application/json") - .addHeader("Accept", "application/json") - .build(); - OkHttpClient client = clientOptions.httpClient(); - if (requestOptions != null && requestOptions.getTimeout().isPresent()) { - client = clientOptions.httpClientWithTimeout(requestOptions); - } - try (Response response = client.newCall(okhttpRequest).execute()) { - ResponseBody responseBody = response.body(); - if (response.isSuccessful()) { - return new ApiClientHttpResponse<>( - ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1FlowTokenizeResponse.class), - response); - } - String responseBodyString = responseBody != null ? responseBody.string() : "{}"; - throw new ApiClientApiException( - "Error with status code " + response.code(), - response.code(), - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), - response); - } catch (IOException e) { - throw new ApiClientException("Network error executing HTTP request", e); - } - } - - public ApiClientHttpResponse flowvaultmetrics() { - return flowvaultmetrics(V1FlowVaultMetricsRequest.builder().build()); - } - - public ApiClientHttpResponse flowvaultmetrics(V1FlowVaultMetricsRequest request) { - return flowvaultmetrics(request, null); - } - - public ApiClientHttpResponse flowvaultmetrics( - V1FlowVaultMetricsRequest request, RequestOptions requestOptions) { - HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) - .newBuilder() - .addPathSegments("v2/vaults/metrics") - .build(); - RequestBody body; - try { - body = RequestBody.create( - ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); - } catch (JsonProcessingException e) { - throw new ApiClientException("Failed to serialize request", e); - } - Request okhttpRequest = new Request.Builder() - .url(httpUrl) - .method("POST", body) - .headers(Headers.of(clientOptions.headers(requestOptions))) - .addHeader("Content-Type", "application/json") - .addHeader("Accept", "application/json") - .build(); - OkHttpClient client = clientOptions.httpClient(); - if (requestOptions != null && requestOptions.getTimeout().isPresent()) { - client = clientOptions.httpClientWithTimeout(requestOptions); - } - try (Response response = client.newCall(okhttpRequest).execute()) { - ResponseBody responseBody = response.body(); - if (response.isSuccessful()) { - return new ApiClientHttpResponse<>( - ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1FlowVaultMetricsResponse.class), - response); - } - String responseBodyString = responseBody != null ? responseBody.string() : "{}"; - throw new ApiClientApiException( - "Error with status code " + response.code(), - response.code(), - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), - response); - } catch (IOException e) { - throw new ApiClientException("Network error executing HTTP request", e); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1DeleteRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1DeleteRequest.java deleted file mode 100644 index 27e22a8d..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1DeleteRequest.java +++ /dev/null @@ -1,186 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.resources.flowservice.requests; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.types.V1UniqueValue; - -import java.util.*; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1DeleteRequest.Builder.class) -public final class V1DeleteRequest { - private final Optional vaultId; - - private final Optional tableName; - - private final Optional> skyflowIDs; - - private final Optional> uniqueValues; - - private final Map additionalProperties; - - private V1DeleteRequest( - Optional vaultId, - Optional tableName, - Optional> skyflowIDs, - Optional> uniqueValues, - Map additionalProperties) { - this.vaultId = vaultId; - this.tableName = tableName; - this.skyflowIDs = skyflowIDs; - this.uniqueValues = uniqueValues; - this.additionalProperties = additionalProperties; - } - - /** - * @return ID of the vault where data is being deleted - */ - @JsonProperty("vaultID") - public Optional getVaultId() { - return vaultId; - } - - /** - * @return Name of the table where data is being deleted - */ - @JsonProperty("tableName") - public Optional getTableName() { - return tableName; - } - - /** - * @return Skyflow ID for the record to be deleted - */ - @JsonProperty("skyflowIDs") - public Optional> getSkyflowIDs() { - return skyflowIDs; - } - - /** - * @return List of unique constraint values to query records by data - */ - @JsonProperty("uniqueValues") - public Optional> getUniqueValues() { - return uniqueValues; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1DeleteRequest && equalTo((V1DeleteRequest) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1DeleteRequest other) { - return vaultId.equals(other.vaultId) - && tableName.equals(other.tableName) - && skyflowIDs.equals(other.skyflowIDs) - && uniqueValues.equals(other.uniqueValues); - } - - @Override - public int hashCode() { - return Objects.hash(this.vaultId, this.tableName, this.skyflowIDs, this.uniqueValues); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional vaultId = Optional.empty(); - - private Optional tableName = Optional.empty(); - - private Optional> skyflowIDs = Optional.empty(); - - private Optional> uniqueValues = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1DeleteRequest other) { - vaultId(other.getVaultId()); - tableName(other.getTableName()); - skyflowIDs(other.getSkyflowIDs()); - uniqueValues(other.getUniqueValues()); - return this; - } - - /** - *

ID of the vault where data is being deleted

- */ - @JsonSetter(value = "vaultID", nulls = Nulls.SKIP) - public Builder vaultId(Optional vaultId) { - this.vaultId = vaultId; - return this; - } - - public Builder vaultId(String vaultId) { - this.vaultId = Optional.ofNullable(vaultId); - return this; - } - - /** - *

Name of the table where data is being deleted

- */ - @JsonSetter(value = "tableName", nulls = Nulls.SKIP) - public Builder tableName(Optional tableName) { - this.tableName = tableName; - return this; - } - - public Builder tableName(String tableName) { - this.tableName = Optional.ofNullable(tableName); - return this; - } - - /** - *

Skyflow ID for the record to be deleted

- */ - @JsonSetter(value = "skyflowIDs", nulls = Nulls.SKIP) - public Builder skyflowIDs(Optional> skyflowIDs) { - this.skyflowIDs = skyflowIDs; - return this; - } - - public Builder skyflowIDs(List skyflowIDs) { - this.skyflowIDs = Optional.ofNullable(skyflowIDs); - return this; - } - - /** - *

List of unique constraint values to query records by data

- */ - @JsonSetter(value = "uniqueValues", nulls = Nulls.SKIP) - public Builder uniqueValues(Optional> uniqueValues) { - this.uniqueValues = uniqueValues; - return this; - } - - public Builder uniqueValues(List uniqueValues) { - this.uniqueValues = Optional.ofNullable(uniqueValues); - return this; - } - - public V1DeleteRequest build() { - return new V1DeleteRequest(vaultId, tableName, skyflowIDs, uniqueValues, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowDeleteTokenRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowDeleteTokenRequest.java deleted file mode 100644 index 6bc8a4e6..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowDeleteTokenRequest.java +++ /dev/null @@ -1,122 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.resources.flowservice.requests; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1FlowDeleteTokenRequest.Builder.class) -public final class V1FlowDeleteTokenRequest { - private final Optional vaultId; - - private final Optional> tokens; - - private final Map additionalProperties; - - private V1FlowDeleteTokenRequest( - Optional vaultId, Optional> tokens, Map additionalProperties) { - this.vaultId = vaultId; - this.tokens = tokens; - this.additionalProperties = additionalProperties; - } - - /** - * @return Vault ID - */ - @JsonProperty("vaultID") - public Optional getVaultId() { - return vaultId; - } - - /** - * @return Token value - */ - @JsonProperty("tokens") - public Optional> getTokens() { - return tokens; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1FlowDeleteTokenRequest && equalTo((V1FlowDeleteTokenRequest) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1FlowDeleteTokenRequest other) { - return vaultId.equals(other.vaultId) && tokens.equals(other.tokens); - } - - @Override - public int hashCode() { - return Objects.hash(this.vaultId, this.tokens); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional vaultId = Optional.empty(); - - private Optional> tokens = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1FlowDeleteTokenRequest other) { - vaultId(other.getVaultId()); - tokens(other.getTokens()); - return this; - } - - /** - *

Vault ID

- */ - @JsonSetter(value = "vaultID", nulls = Nulls.SKIP) - public Builder vaultId(Optional vaultId) { - this.vaultId = vaultId; - return this; - } - - public Builder vaultId(String vaultId) { - this.vaultId = Optional.ofNullable(vaultId); - return this; - } - - /** - *

Token value

- */ - @JsonSetter(value = "tokens", nulls = Nulls.SKIP) - public Builder tokens(Optional> tokens) { - this.tokens = tokens; - return this; - } - - public Builder tokens(List tokens) { - this.tokens = Optional.ofNullable(tokens); - return this; - } - - public V1FlowDeleteTokenRequest build() { - return new V1FlowDeleteTokenRequest(vaultId, tokens, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowDetokenizeRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowDetokenizeRequest.java deleted file mode 100644 index bdbe3bf2..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowDetokenizeRequest.java +++ /dev/null @@ -1,156 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.resources.flowservice.requests; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.types.V1TokenGroupRedactions; - -import java.util.*; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1FlowDetokenizeRequest.Builder.class) -public final class V1FlowDetokenizeRequest { - private final Optional vaultId; - - private final Optional> tokens; - - private final Optional> tokenGroupRedactions; - - private final Map additionalProperties; - - private V1FlowDetokenizeRequest( - Optional vaultId, - Optional> tokens, - Optional> tokenGroupRedactions, - Map additionalProperties) { - this.vaultId = vaultId; - this.tokens = tokens; - this.tokenGroupRedactions = tokenGroupRedactions; - this.additionalProperties = additionalProperties; - } - - /** - * @return ID of the vault where detokenizing - */ - @JsonProperty("vaultID") - public Optional getVaultId() { - return vaultId; - } - - /** - * @return Token to be detokenized - */ - @JsonProperty("tokens") - public Optional> getTokens() { - return tokens; - } - - /** - * @return List of token groups to be redacted. - */ - @JsonProperty("tokenGroupRedactions") - public Optional> getTokenGroupRedactions() { - return tokenGroupRedactions; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1FlowDetokenizeRequest && equalTo((V1FlowDetokenizeRequest) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1FlowDetokenizeRequest other) { - return vaultId.equals(other.vaultId) - && tokens.equals(other.tokens) - && tokenGroupRedactions.equals(other.tokenGroupRedactions); - } - - @Override - public int hashCode() { - return Objects.hash(this.vaultId, this.tokens, this.tokenGroupRedactions); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional vaultId = Optional.empty(); - - private Optional> tokens = Optional.empty(); - - private Optional> tokenGroupRedactions = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1FlowDetokenizeRequest other) { - vaultId(other.getVaultId()); - tokens(other.getTokens()); - tokenGroupRedactions(other.getTokenGroupRedactions()); - return this; - } - - /** - *

ID of the vault where detokenizing

- */ - @JsonSetter(value = "vaultID", nulls = Nulls.SKIP) - public Builder vaultId(Optional vaultId) { - this.vaultId = vaultId; - return this; - } - - public Builder vaultId(String vaultId) { - this.vaultId = Optional.ofNullable(vaultId); - return this; - } - - /** - *

Token to be detokenized

- */ - @JsonSetter(value = "tokens", nulls = Nulls.SKIP) - public Builder tokens(Optional> tokens) { - this.tokens = tokens; - return this; - } - - public Builder tokens(List tokens) { - this.tokens = Optional.ofNullable(tokens); - return this; - } - - /** - *

List of token groups to be redacted.

- */ - @JsonSetter(value = "tokenGroupRedactions", nulls = Nulls.SKIP) - public Builder tokenGroupRedactions(Optional> tokenGroupRedactions) { - this.tokenGroupRedactions = tokenGroupRedactions; - return this; - } - - public Builder tokenGroupRedactions(List tokenGroupRedactions) { - this.tokenGroupRedactions = Optional.ofNullable(tokenGroupRedactions); - return this; - } - - public V1FlowDetokenizeRequest build() { - return new V1FlowDetokenizeRequest(vaultId, tokens, tokenGroupRedactions, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowTokenizeRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowTokenizeRequest.java deleted file mode 100644 index a27d7b62..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowTokenizeRequest.java +++ /dev/null @@ -1,125 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.resources.flowservice.requests; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.types.V1FlowTokenizeRequestObject; - -import java.util.*; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1FlowTokenizeRequest.Builder.class) -public final class V1FlowTokenizeRequest { - private final Optional vaultId; - - private final Optional> data; - - private final Map additionalProperties; - - private V1FlowTokenizeRequest( - Optional vaultId, - Optional> data, - Map additionalProperties) { - this.vaultId = vaultId; - this.data = data; - this.additionalProperties = additionalProperties; - } - - /** - * @return Vault ID. - */ - @JsonProperty("vaultID") - public Optional getVaultId() { - return vaultId; - } - - /** - * @return Data to be tokenized - */ - @JsonProperty("data") - public Optional> getData() { - return data; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1FlowTokenizeRequest && equalTo((V1FlowTokenizeRequest) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1FlowTokenizeRequest other) { - return vaultId.equals(other.vaultId) && data.equals(other.data); - } - - @Override - public int hashCode() { - return Objects.hash(this.vaultId, this.data); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional vaultId = Optional.empty(); - - private Optional> data = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1FlowTokenizeRequest other) { - vaultId(other.getVaultId()); - data(other.getData()); - return this; - } - - /** - *

Vault ID.

- */ - @JsonSetter(value = "vaultID", nulls = Nulls.SKIP) - public Builder vaultId(Optional vaultId) { - this.vaultId = vaultId; - return this; - } - - public Builder vaultId(String vaultId) { - this.vaultId = Optional.ofNullable(vaultId); - return this; - } - - /** - *

Data to be tokenized

- */ - @JsonSetter(value = "data", nulls = Nulls.SKIP) - public Builder data(Optional> data) { - this.data = data; - return this; - } - - public Builder data(List data) { - this.data = Optional.ofNullable(data); - return this; - } - - public V1FlowTokenizeRequest build() { - return new V1FlowTokenizeRequest(vaultId, data, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowVaultMetricsRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowVaultMetricsRequest.java deleted file mode 100644 index 026d2d30..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1FlowVaultMetricsRequest.java +++ /dev/null @@ -1,96 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.resources.flowservice.requests; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1FlowVaultMetricsRequest.Builder.class) -public final class V1FlowVaultMetricsRequest { - private final Optional vaultId; - - private final Map additionalProperties; - - private V1FlowVaultMetricsRequest(Optional vaultId, Map additionalProperties) { - this.vaultId = vaultId; - this.additionalProperties = additionalProperties; - } - - /** - * @return ID of the vault to get metrics for - */ - @JsonProperty("vaultID") - public Optional getVaultId() { - return vaultId; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1FlowVaultMetricsRequest && equalTo((V1FlowVaultMetricsRequest) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1FlowVaultMetricsRequest other) { - return vaultId.equals(other.vaultId); - } - - @Override - public int hashCode() { - return Objects.hash(this.vaultId); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional vaultId = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1FlowVaultMetricsRequest other) { - vaultId(other.getVaultId()); - return this; - } - - /** - *

ID of the vault to get metrics for

- */ - @JsonSetter(value = "vaultID", nulls = Nulls.SKIP) - public Builder vaultId(Optional vaultId) { - this.vaultId = vaultId; - return this; - } - - public Builder vaultId(String vaultId) { - this.vaultId = Optional.ofNullable(vaultId); - return this; - } - - public V1FlowVaultMetricsRequest build() { - return new V1FlowVaultMetricsRequest(vaultId, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1GetRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1GetRequest.java deleted file mode 100644 index 415f5291..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1GetRequest.java +++ /dev/null @@ -1,357 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.resources.flowservice.requests; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.types.V1ColumnRedactions; -import com.skyflow.generated.rest.types.V1GetRequestData; -import com.skyflow.generated.rest.types.V1UniqueValue; - -import java.util.*; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1GetRequest.Builder.class) -public final class V1GetRequest { - private final Optional vaultId; - - private final Optional tableName; - - private final Optional> skyflowIDs; - - private final Optional> columnRedactions; - - private final Optional> columns; - - private final Optional limit; - - private final Optional offset; - - private final Optional> uniqueValues; - - private final Optional> records; - - private final Map additionalProperties; - - private V1GetRequest( - Optional vaultId, - Optional tableName, - Optional> skyflowIDs, - Optional> columnRedactions, - Optional> columns, - Optional limit, - Optional offset, - Optional> uniqueValues, - Optional> records, - Map additionalProperties) { - this.vaultId = vaultId; - this.tableName = tableName; - this.skyflowIDs = skyflowIDs; - this.columnRedactions = columnRedactions; - this.columns = columns; - this.limit = limit; - this.offset = offset; - this.uniqueValues = uniqueValues; - this.records = records; - this.additionalProperties = additionalProperties; - } - - /** - * @return ID of the vault where data is being fetched - */ - @JsonProperty("vaultID") - public Optional getVaultId() { - return vaultId; - } - - /** - * @return Name of the table where data is being fetched - */ - @JsonProperty("tableName") - public Optional getTableName() { - return tableName; - } - - /** - * @return Skyflow ID for the record to be fetched - */ - @JsonProperty("skyflowIDs") - public Optional> getSkyflowIDs() { - return skyflowIDs; - } - - /** - * @return List of columns to be redacted. - */ - @JsonProperty("columnRedactions") - public Optional> getColumnRedactions() { - return columnRedactions; - } - - /** - * @return List of columns to be fetched. - */ - @JsonProperty("columns") - public Optional> getColumns() { - return columns; - } - - /** - * @return Limit for the number of records to be fetched - */ - @JsonProperty("limit") - public Optional getLimit() { - return limit; - } - - /** - * @return Offset for the number of records to be fetched - */ - @JsonProperty("offset") - public Optional getOffset() { - return offset; - } - - /** - * @return List of unique constraint values to query records by data - */ - @JsonProperty("uniqueValues") - public Optional> getUniqueValues() { - return uniqueValues; - } - - /** - * @return List of records to be fetched. This field contains tableName and skyflowIDs belonging to the table. - */ - @JsonProperty("records") - public Optional> getRecords() { - return records; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1GetRequest && equalTo((V1GetRequest) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1GetRequest other) { - return vaultId.equals(other.vaultId) - && tableName.equals(other.tableName) - && skyflowIDs.equals(other.skyflowIDs) - && columnRedactions.equals(other.columnRedactions) - && columns.equals(other.columns) - && limit.equals(other.limit) - && offset.equals(other.offset) - && uniqueValues.equals(other.uniqueValues) - && records.equals(other.records); - } - - @Override - public int hashCode() { - return Objects.hash( - this.vaultId, - this.tableName, - this.skyflowIDs, - this.columnRedactions, - this.columns, - this.limit, - this.offset, - this.uniqueValues, - this.records); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional vaultId = Optional.empty(); - - private Optional tableName = Optional.empty(); - - private Optional> skyflowIDs = Optional.empty(); - - private Optional> columnRedactions = Optional.empty(); - - private Optional> columns = Optional.empty(); - - private Optional limit = Optional.empty(); - - private Optional offset = Optional.empty(); - - private Optional> uniqueValues = Optional.empty(); - - private Optional> records = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1GetRequest other) { - vaultId(other.getVaultId()); - tableName(other.getTableName()); - skyflowIDs(other.getSkyflowIDs()); - columnRedactions(other.getColumnRedactions()); - columns(other.getColumns()); - limit(other.getLimit()); - offset(other.getOffset()); - uniqueValues(other.getUniqueValues()); - records(other.getRecords()); - return this; - } - - /** - *

ID of the vault where data is being fetched

- */ - @JsonSetter(value = "vaultID", nulls = Nulls.SKIP) - public Builder vaultId(Optional vaultId) { - this.vaultId = vaultId; - return this; - } - - public Builder vaultId(String vaultId) { - this.vaultId = Optional.ofNullable(vaultId); - return this; - } - - /** - *

Name of the table where data is being fetched

- */ - @JsonSetter(value = "tableName", nulls = Nulls.SKIP) - public Builder tableName(Optional tableName) { - this.tableName = tableName; - return this; - } - - public Builder tableName(String tableName) { - this.tableName = Optional.ofNullable(tableName); - return this; - } - - /** - *

Skyflow ID for the record to be fetched

- */ - @JsonSetter(value = "skyflowIDs", nulls = Nulls.SKIP) - public Builder skyflowIDs(Optional> skyflowIDs) { - this.skyflowIDs = skyflowIDs; - return this; - } - - public Builder skyflowIDs(List skyflowIDs) { - this.skyflowIDs = Optional.ofNullable(skyflowIDs); - return this; - } - - /** - *

List of columns to be redacted.

- */ - @JsonSetter(value = "columnRedactions", nulls = Nulls.SKIP) - public Builder columnRedactions(Optional> columnRedactions) { - this.columnRedactions = columnRedactions; - return this; - } - - public Builder columnRedactions(List columnRedactions) { - this.columnRedactions = Optional.ofNullable(columnRedactions); - return this; - } - - /** - *

List of columns to be fetched.

- */ - @JsonSetter(value = "columns", nulls = Nulls.SKIP) - public Builder columns(Optional> columns) { - this.columns = columns; - return this; - } - - public Builder columns(List columns) { - this.columns = Optional.ofNullable(columns); - return this; - } - - /** - *

Limit for the number of records to be fetched

- */ - @JsonSetter(value = "limit", nulls = Nulls.SKIP) - public Builder limit(Optional limit) { - this.limit = limit; - return this; - } - - public Builder limit(Integer limit) { - this.limit = Optional.ofNullable(limit); - return this; - } - - /** - *

Offset for the number of records to be fetched

- */ - @JsonSetter(value = "offset", nulls = Nulls.SKIP) - public Builder offset(Optional offset) { - this.offset = offset; - return this; - } - - public Builder offset(Integer offset) { - this.offset = Optional.ofNullable(offset); - return this; - } - - /** - *

List of unique constraint values to query records by data

- */ - @JsonSetter(value = "uniqueValues", nulls = Nulls.SKIP) - public Builder uniqueValues(Optional> uniqueValues) { - this.uniqueValues = uniqueValues; - return this; - } - - public Builder uniqueValues(List uniqueValues) { - this.uniqueValues = Optional.ofNullable(uniqueValues); - return this; - } - - /** - *

List of records to be fetched. This field contains tableName and skyflowIDs belonging to the table.

- */ - @JsonSetter(value = "records", nulls = Nulls.SKIP) - public Builder records(Optional> records) { - this.records = records; - return this; - } - - public Builder records(List records) { - this.records = Optional.ofNullable(records); - return this; - } - - public V1GetRequest build() { - return new V1GetRequest( - vaultId, - tableName, - skyflowIDs, - columnRedactions, - columns, - limit, - offset, - uniqueValues, - records, - additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1InsertRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1InsertRequest.java deleted file mode 100644 index 47a58cb2..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1InsertRequest.java +++ /dev/null @@ -1,181 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.resources.flowservice.requests; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.types.V1InsertRecordData; -import com.skyflow.generated.rest.types.V1Upsert; - -import java.util.*; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1InsertRequest.Builder.class) -public final class V1InsertRequest { - private final Optional vaultId; - - private final Optional tableName; - - private final Optional> records; - - private final Optional upsert; - - private final Map additionalProperties; - - private V1InsertRequest( - Optional vaultId, - Optional tableName, - Optional> records, - Optional upsert, - Map additionalProperties) { - this.vaultId = vaultId; - this.tableName = tableName; - this.records = records; - this.upsert = upsert; - this.additionalProperties = additionalProperties; - } - - /** - * @return ID of the vault where data is being inserted - */ - @JsonProperty("vaultID") - public Optional getVaultId() { - return vaultId; - } - - /** - * @return Name of the table where data is being inserted - */ - @JsonProperty("tableName") - public Optional getTableName() { - return tableName; - } - - /** - * @return List of data row wise that is to be inserted in the vault - */ - @JsonProperty("records") - public Optional> getRecords() { - return records; - } - - @JsonProperty("upsert") - public Optional getUpsert() { - return upsert; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1InsertRequest && equalTo((V1InsertRequest) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1InsertRequest other) { - return vaultId.equals(other.vaultId) - && tableName.equals(other.tableName) - && records.equals(other.records) - && upsert.equals(other.upsert); - } - - @Override - public int hashCode() { - return Objects.hash(this.vaultId, this.tableName, this.records, this.upsert); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional vaultId = Optional.empty(); - - private Optional tableName = Optional.empty(); - - private Optional> records = Optional.empty(); - - private Optional upsert = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1InsertRequest other) { - vaultId(other.getVaultId()); - tableName(other.getTableName()); - records(other.getRecords()); - upsert(other.getUpsert()); - return this; - } - - /** - *

ID of the vault where data is being inserted

- */ - @JsonSetter(value = "vaultID", nulls = Nulls.SKIP) - public Builder vaultId(Optional vaultId) { - this.vaultId = vaultId; - return this; - } - - public Builder vaultId(String vaultId) { - this.vaultId = Optional.ofNullable(vaultId); - return this; - } - - /** - *

Name of the table where data is being inserted

- */ - @JsonSetter(value = "tableName", nulls = Nulls.SKIP) - public Builder tableName(Optional tableName) { - this.tableName = tableName; - return this; - } - - public Builder tableName(String tableName) { - this.tableName = Optional.ofNullable(tableName); - return this; - } - - /** - *

List of data row wise that is to be inserted in the vault

- */ - @JsonSetter(value = "records", nulls = Nulls.SKIP) - public Builder records(Optional> records) { - this.records = records; - return this; - } - - public Builder records(List records) { - this.records = Optional.ofNullable(records); - return this; - } - - @JsonSetter(value = "upsert", nulls = Nulls.SKIP) - public Builder upsert(Optional upsert) { - this.upsert = upsert; - return this; - } - - public Builder upsert(V1Upsert upsert) { - this.upsert = Optional.ofNullable(upsert); - return this; - } - - public V1InsertRequest build() { - return new V1InsertRequest(vaultId, tableName, records, upsert, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1UpdateRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1UpdateRequest.java deleted file mode 100644 index 6f8b303e..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/resources/flowservice/requests/V1UpdateRequest.java +++ /dev/null @@ -1,181 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.resources.flowservice.requests; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.types.FlowEnumUpdateType; -import com.skyflow.generated.rest.types.V1UpdateRecordData; - -import java.util.*; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1UpdateRequest.Builder.class) -public final class V1UpdateRequest { - private final Optional vaultId; - - private final Optional tableName; - - private final Optional> records; - - private final Optional updateType; - - private final Map additionalProperties; - - private V1UpdateRequest( - Optional vaultId, - Optional tableName, - Optional> records, - Optional updateType, - Map additionalProperties) { - this.vaultId = vaultId; - this.tableName = tableName; - this.records = records; - this.updateType = updateType; - this.additionalProperties = additionalProperties; - } - - /** - * @return ID of the vault where data is being updated - */ - @JsonProperty("vaultID") - public Optional getVaultId() { - return vaultId; - } - - /** - * @return Name of the table where data is being updated - */ - @JsonProperty("tableName") - public Optional getTableName() { - return tableName; - } - - /** - * @return List of data row wise that is to be updated in the vault - */ - @JsonProperty("records") - public Optional> getRecords() { - return records; - } - - @JsonProperty("updateType") - public Optional getUpdateType() { - return updateType; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1UpdateRequest && equalTo((V1UpdateRequest) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1UpdateRequest other) { - return vaultId.equals(other.vaultId) - && tableName.equals(other.tableName) - && records.equals(other.records) - && updateType.equals(other.updateType); - } - - @Override - public int hashCode() { - return Objects.hash(this.vaultId, this.tableName, this.records, this.updateType); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional vaultId = Optional.empty(); - - private Optional tableName = Optional.empty(); - - private Optional> records = Optional.empty(); - - private Optional updateType = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1UpdateRequest other) { - vaultId(other.getVaultId()); - tableName(other.getTableName()); - records(other.getRecords()); - updateType(other.getUpdateType()); - return this; - } - - /** - *

ID of the vault where data is being updated

- */ - @JsonSetter(value = "vaultID", nulls = Nulls.SKIP) - public Builder vaultId(Optional vaultId) { - this.vaultId = vaultId; - return this; - } - - public Builder vaultId(String vaultId) { - this.vaultId = Optional.ofNullable(vaultId); - return this; - } - - /** - *

Name of the table where data is being updated

- */ - @JsonSetter(value = "tableName", nulls = Nulls.SKIP) - public Builder tableName(Optional tableName) { - this.tableName = tableName; - return this; - } - - public Builder tableName(String tableName) { - this.tableName = Optional.ofNullable(tableName); - return this; - } - - /** - *

List of data row wise that is to be updated in the vault

- */ - @JsonSetter(value = "records", nulls = Nulls.SKIP) - public Builder records(Optional> records) { - this.records = records; - return this; - } - - public Builder records(List records) { - this.records = Optional.ofNullable(records); - return this; - } - - @JsonSetter(value = "updateType", nulls = Nulls.SKIP) - public Builder updateType(Optional updateType) { - this.updateType = updateType; - return this; - } - - public Builder updateType(FlowEnumUpdateType updateType) { - this.updateType = Optional.ofNullable(updateType); - return this; - } - - public V1UpdateRequest build() { - return new V1UpdateRequest(vaultId, tableName, records, updateType, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/query/AsyncQueryClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/query/AsyncQueryClient.java new file mode 100644 index 00000000..a3ad1481 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/query/AsyncQueryClient.java @@ -0,0 +1,59 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.query; + +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.resources.query.requests.ExecuteQueryRequest; +import com.skyflow.generated.rest.types.ExecuteQueryResponse; +import java.util.concurrent.CompletableFuture; + +public class AsyncQueryClient { + protected final ClientOptions clientOptions; + + private final AsyncRawQueryClient rawClient; + + public AsyncQueryClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.rawClient = new AsyncRawQueryClient(clientOptions); + } + + /** + * Get responses with HTTP metadata like headers + */ + public AsyncRawQueryClient withRawResponse() { + return this.rawClient; + } + + /** + * Returns records for a valid SQL query. This endpoint + *
    + *
  • Can return masked record values.
  • + *
  • Supports only the SELECT command.
  • + *
  • Returns a maximum of 25 records. To return additional records, perform another query using the OFFSET keyword.
  • + *
  • Can't modify the vault or perform transactions.
  • + *
  • Can't return tokens.
  • + *
  • Can't return file download or render URLs.
  • + *
+ */ + public CompletableFuture executeQuery(ExecuteQueryRequest request) { + return this.rawClient.executeQuery(request).thenApply(response -> response.body()); + } + + /** + * Returns records for a valid SQL query. This endpoint + *
    + *
  • Can return masked record values.
  • + *
  • Supports only the SELECT command.
  • + *
  • Returns a maximum of 25 records. To return additional records, perform another query using the OFFSET keyword.
  • + *
  • Can't modify the vault or perform transactions.
  • + *
  • Can't return tokens.
  • + *
  • Can't return file download or render URLs.
  • + *
+ */ + public CompletableFuture executeQuery( + ExecuteQueryRequest request, RequestOptions requestOptions) { + return this.rawClient.executeQuery(request, requestOptions).thenApply(response -> response.body()); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/query/AsyncRawQueryClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/query/AsyncRawQueryClient.java new file mode 100644 index 00000000..821744c8 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/query/AsyncRawQueryClient.java @@ -0,0 +1,162 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.query; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.RetryInterceptor; +import com.skyflow.generated.rest.errors.BadRequestError; +import com.skyflow.generated.rest.errors.InternalServerError; +import com.skyflow.generated.rest.errors.NotFoundError; +import com.skyflow.generated.rest.errors.UnauthorizedError; +import com.skyflow.generated.rest.resources.query.requests.ExecuteQueryRequest; +import com.skyflow.generated.rest.types.ErrorResponse; +import com.skyflow.generated.rest.types.ExecuteQueryResponse; +import java.io.IOException; +import java.util.concurrent.CompletableFuture; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.jetbrains.annotations.NotNull; + +public class AsyncRawQueryClient { + protected final ClientOptions clientOptions; + + public AsyncRawQueryClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + } + + /** + * Returns records for a valid SQL query. This endpoint + *
    + *
  • Can return masked record values.
  • + *
  • Supports only the SELECT command.
  • + *
  • Returns a maximum of 25 records. To return additional records, perform another query using the OFFSET keyword.
  • + *
  • Can't modify the vault or perform transactions.
  • + *
  • Can't return tokens.
  • + *
  • Can't return file download or render URLs.
  • + *
+ */ + public CompletableFuture> executeQuery(ExecuteQueryRequest request) { + return executeQuery(request, null); + } + + /** + * Returns records for a valid SQL query. This endpoint + *
    + *
  • Can return masked record values.
  • + *
  • Supports only the SELECT command.
  • + *
  • Returns a maximum of 25 records. To return additional records, perform another query using the OFFSET keyword.
  • + *
  • Can't modify the vault or perform transactions.
  • + *
  • Can't return tokens.
  • + *
  • Can't return file download or render URLs.
  • + *
+ */ + public CompletableFuture> executeQuery( + ExecuteQueryRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/query"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + future.complete(new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ExecuteQueryResponse.class), + response)); + return; + } + try { + switch (response.code()) { + case 400: + future.completeExceptionally(new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 401: + future.completeExceptionally(new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 404: + future.completeExceptionally(new NotFoundError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 500: + future.completeExceptionally(new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + future.completeExceptionally(new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response)); + return; + } catch (JsonProcessingException e) { + future.completeExceptionally( + new ApiClientException("Failed to deserialize response: " + e.getMessage(), e)); + } catch (IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + }); + return future; + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/query/QueryClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/query/QueryClient.java new file mode 100644 index 00000000..5bad1de7 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/query/QueryClient.java @@ -0,0 +1,57 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.query; + +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.resources.query.requests.ExecuteQueryRequest; +import com.skyflow.generated.rest.types.ExecuteQueryResponse; + +public class QueryClient { + protected final ClientOptions clientOptions; + + private final RawQueryClient rawClient; + + public QueryClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.rawClient = new RawQueryClient(clientOptions); + } + + /** + * Get responses with HTTP metadata like headers + */ + public RawQueryClient withRawResponse() { + return this.rawClient; + } + + /** + * Returns records for a valid SQL query. This endpoint + *
    + *
  • Can return masked record values.
  • + *
  • Supports only the SELECT command.
  • + *
  • Returns a maximum of 25 records. To return additional records, perform another query using the OFFSET keyword.
  • + *
  • Can't modify the vault or perform transactions.
  • + *
  • Can't return tokens.
  • + *
  • Can't return file download or render URLs.
  • + *
+ */ + public ExecuteQueryResponse executeQuery(ExecuteQueryRequest request) { + return this.rawClient.executeQuery(request).body(); + } + + /** + * Returns records for a valid SQL query. This endpoint + *
    + *
  • Can return masked record values.
  • + *
  • Supports only the SELECT command.
  • + *
  • Returns a maximum of 25 records. To return additional records, perform another query using the OFFSET keyword.
  • + *
  • Can't modify the vault or perform transactions.
  • + *
  • Can't return tokens.
  • + *
  • Can't return file download or render URLs.
  • + *
+ */ + public ExecuteQueryResponse executeQuery(ExecuteQueryRequest request, RequestOptions requestOptions) { + return this.rawClient.executeQuery(request, requestOptions).body(); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/query/RawQueryClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/query/RawQueryClient.java new file mode 100644 index 00000000..0f536ff4 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/query/RawQueryClient.java @@ -0,0 +1,135 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.query; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.RetryInterceptor; +import com.skyflow.generated.rest.errors.BadRequestError; +import com.skyflow.generated.rest.errors.InternalServerError; +import com.skyflow.generated.rest.errors.NotFoundError; +import com.skyflow.generated.rest.errors.UnauthorizedError; +import com.skyflow.generated.rest.resources.query.requests.ExecuteQueryRequest; +import com.skyflow.generated.rest.types.ErrorResponse; +import com.skyflow.generated.rest.types.ExecuteQueryResponse; +import java.io.IOException; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; + +public class RawQueryClient { + protected final ClientOptions clientOptions; + + public RawQueryClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + } + + /** + * Returns records for a valid SQL query. This endpoint + *
    + *
  • Can return masked record values.
  • + *
  • Supports only the SELECT command.
  • + *
  • Returns a maximum of 25 records. To return additional records, perform another query using the OFFSET keyword.
  • + *
  • Can't modify the vault or perform transactions.
  • + *
  • Can't return tokens.
  • + *
  • Can't return file download or render URLs.
  • + *
+ */ + public ApiClientHttpResponse executeQuery(ExecuteQueryRequest request) { + return executeQuery(request, null); + } + + /** + * Returns records for a valid SQL query. This endpoint + *
    + *
  • Can return masked record values.
  • + *
  • Supports only the SELECT command.
  • + *
  • Returns a maximum of 25 records. To return additional records, perform another query using the OFFSET keyword.
  • + *
  • Can't modify the vault or perform transactions.
  • + *
  • Can't return tokens.
  • + *
  • Can't return file download or render URLs.
  • + *
+ */ + public ApiClientHttpResponse executeQuery( + ExecuteQueryRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/query"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + return new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ExecuteQueryResponse.class), response); + } + try { + switch (response.code()) { + case 400: + throw new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 401: + throw new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 404: + throw new NotFoundError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 500: + throw new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + throw new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to deserialize response: " + e.getMessage(), e); + } catch (IOException e) { + throw new ApiClientException("Network error executing HTTP request", e); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/query/requests/ExecuteQueryRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/query/requests/ExecuteQueryRequest.java new file mode 100644 index 00000000..2d9c81c0 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/query/requests/ExecuteQueryRequest.java @@ -0,0 +1,160 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.query.requests; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = ExecuteQueryRequest.Builder.class) +public final class ExecuteQueryRequest { + private final String vaultId; + + private final String query; + + private final Map additionalProperties; + + private ExecuteQueryRequest(String vaultId, String query, Map additionalProperties) { + this.vaultId = vaultId; + this.query = query; + this.additionalProperties = additionalProperties; + } + + /** + * @return ID of the vault where the query is being performed. + */ + @JsonProperty("vaultID") + public String getVaultId() { + return vaultId; + } + + /** + * @return Query to perform. + */ + @JsonProperty("query") + public String getQuery() { + return query; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof ExecuteQueryRequest && equalTo((ExecuteQueryRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(ExecuteQueryRequest other) { + return vaultId.equals(other.vaultId) && query.equals(other.query); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.vaultId, this.query); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static VaultIdStage builder() { + return new Builder(); + } + + public interface VaultIdStage { + /** + *

ID of the vault where the query is being performed.

+ */ + QueryStage vaultId(@NotNull String vaultId); + + Builder from(ExecuteQueryRequest other); + } + + public interface QueryStage { + /** + *

Query to perform.

+ */ + _FinalStage query(@NotNull String query); + } + + public interface _FinalStage { + ExecuteQueryRequest build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements VaultIdStage, QueryStage, _FinalStage { + private String vaultId; + + private String query; + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(ExecuteQueryRequest other) { + vaultId(other.getVaultId()); + query(other.getQuery()); + return this; + } + + /** + *

ID of the vault where the query is being performed.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("vaultID") + public QueryStage vaultId(@NotNull String vaultId) { + this.vaultId = Objects.requireNonNull(vaultId, "vaultId must not be null"); + return this; + } + + /** + *

Query to perform.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("query") + public _FinalStage query(@NotNull String query) { + this.query = Objects.requireNonNull(query, "query must not be null"); + return this; + } + + @java.lang.Override + public ExecuteQueryRequest build() { + return new ExecuteQueryRequest(vaultId, query, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java index c91ad763..31e18651 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRawRecordsClient.java @@ -4,14 +4,39 @@ package com.skyflow.generated.rest.resources.records; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.*; -import com.skyflow.generated.rest.resources.records.requests.V1ExecuteQueryRequest; -import com.skyflow.generated.rest.types.V1ExecuteQueryResponse; -import okhttp3.*; -import org.jetbrains.annotations.NotNull; - +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.RetryInterceptor; +import com.skyflow.generated.rest.errors.BadRequestError; +import com.skyflow.generated.rest.errors.InternalServerError; +import com.skyflow.generated.rest.errors.NotFoundError; +import com.skyflow.generated.rest.errors.UnauthorizedError; +import com.skyflow.generated.rest.resources.records.requests.DeleteRequest; +import com.skyflow.generated.rest.resources.records.requests.GetRequest; +import com.skyflow.generated.rest.resources.records.requests.InsertRequest; +import com.skyflow.generated.rest.resources.records.requests.UpdateRequest; +import com.skyflow.generated.rest.types.DeleteResponse; +import com.skyflow.generated.rest.types.ErrorResponse; +import com.skyflow.generated.rest.types.GetResponse; +import com.skyflow.generated.rest.types.InsertResponse; +import com.skyflow.generated.rest.types.UpdateResponse; import java.io.IOException; import java.util.concurrent.CompletableFuture; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.jetbrains.annotations.NotNull; public class AsyncRawRecordsClient { protected final ClientOptions clientOptions; @@ -21,29 +46,234 @@ public AsyncRawRecordsClient(ClientOptions clientOptions) { } /** - * Executes a query on the specified vault. + * Deletes records from a vault. + */ + public CompletableFuture> deleteRecords(DeleteRequest request) { + return deleteRecords(request, null); + } + + /** + * Deletes records from a vault. */ - public CompletableFuture> flowServiceExecuteQuery() { - return flowServiceExecuteQuery(V1ExecuteQueryRequest.builder().build()); + public CompletableFuture> deleteRecords( + DeleteRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/records/delete"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + future.complete(new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, DeleteResponse.class), + response)); + return; + } + try { + switch (response.code()) { + case 400: + future.completeExceptionally(new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 401: + future.completeExceptionally(new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 404: + future.completeExceptionally(new NotFoundError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 500: + future.completeExceptionally(new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + future.completeExceptionally(new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response)); + return; + } catch (JsonProcessingException e) { + future.completeExceptionally( + new ApiClientException("Failed to deserialize response: " + e.getMessage(), e)); + } catch (IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + }); + return future; } /** - * Executes a query on the specified vault. + * Returns the specified records from a vault. */ - public CompletableFuture> flowServiceExecuteQuery( - V1ExecuteQueryRequest request) { - return flowServiceExecuteQuery(request, null); + public CompletableFuture> getRecords(GetRequest request) { + return getRecords(request, null); } /** - * Executes a query on the specified vault. + * Returns the specified records from a vault. */ - public CompletableFuture> flowServiceExecuteQuery( - V1ExecuteQueryRequest request, RequestOptions requestOptions) { - HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + public CompletableFuture> getRecords( + GetRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) .newBuilder() - .addPathSegments("v2/query") + .addPathSegments("v2/records/get"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + future.complete(new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, GetResponse.class), response)); + return; + } + try { + switch (response.code()) { + case 400: + future.completeExceptionally(new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 401: + future.completeExceptionally(new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 404: + future.completeExceptionally(new NotFoundError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 500: + future.completeExceptionally(new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + future.completeExceptionally(new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response)); + return; + } catch (JsonProcessingException e) { + future.completeExceptionally( + new ApiClientException("Failed to deserialize response: " + e.getMessage(), e)); + } catch (IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + }); + return future; + } + + /** + * Inserts new records into a vault. + */ + public CompletableFuture> insertRecords(InsertRequest request) { + return insertRecords(request, null); + } + + /** + * Inserts new records into a vault. + */ + public CompletableFuture> insertRecords( + InsertRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/records/insert"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } RequestBody body; try { body = RequestBody.create( @@ -52,7 +282,7 @@ public CompletableFuture> flowServ throw new ApiClientException("Failed to serialize request", e); } Request okhttpRequest = new Request.Builder() - .url(httpUrl) + .url(httpUrl.build()) .method("POST", body) .headers(Headers.of(clientOptions.headers(requestOptions))) .addHeader("Content-Type", "application/json") @@ -62,25 +292,160 @@ public CompletableFuture> flowServ if (requestOptions != null && requestOptions.getTimeout().isPresent()) { client = clientOptions.httpClientWithTimeout(requestOptions); } - CompletableFuture> future = new CompletableFuture<>(); + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + CompletableFuture> future = new CompletableFuture<>(); client.newCall(okhttpRequest).enqueue(new Callback() { @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { try (ResponseBody responseBody = response.body()) { + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; if (response.isSuccessful()) { future.complete(new ApiClientHttpResponse<>( - ObjectMappers.JSON_MAPPER.readValue( - responseBody.string(), V1ExecuteQueryResponse.class), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, InsertResponse.class), response)); return; } + try { + switch (response.code()) { + case 400: + future.completeExceptionally(new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 401: + future.completeExceptionally(new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 500: + future.completeExceptionally(new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + future.completeExceptionally(new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response)); + return; + } catch (JsonProcessingException e) { + future.completeExceptionally( + new ApiClientException("Failed to deserialize response: " + e.getMessage(), e)); + } catch (IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + }); + return future; + } + + /** + * Updates the specified records in a vault. + */ + public CompletableFuture> updateRecords(UpdateRequest request) { + return updateRecords(request, null); + } + + /** + * Updates the specified records in a vault. + */ + public CompletableFuture> updateRecords( + UpdateRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/records/update"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + future.complete(new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, UpdateResponse.class), + response)); + return; + } + try { + switch (response.code()) { + case 400: + future.completeExceptionally(new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 401: + future.completeExceptionally(new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 404: + future.completeExceptionally(new NotFoundError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 500: + future.completeExceptionally(new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); future.completeExceptionally(new ApiClientApiException( - "Error with status code " + response.code(), - response.code(), - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), - response)); + "Error with status code " + response.code(), response.code(), errorBody, response)); return; + } catch (JsonProcessingException e) { + future.completeExceptionally( + new ApiClientException("Failed to deserialize response: " + e.getMessage(), e)); } catch (IOException e) { future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); } diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java index 9af54869..9e1e18d5 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/AsyncRecordsClient.java @@ -5,9 +5,14 @@ import com.skyflow.generated.rest.core.ClientOptions; import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.records.requests.V1ExecuteQueryRequest; -import com.skyflow.generated.rest.types.V1ExecuteQueryResponse; - +import com.skyflow.generated.rest.resources.records.requests.DeleteRequest; +import com.skyflow.generated.rest.resources.records.requests.GetRequest; +import com.skyflow.generated.rest.resources.records.requests.InsertRequest; +import com.skyflow.generated.rest.resources.records.requests.UpdateRequest; +import com.skyflow.generated.rest.types.DeleteResponse; +import com.skyflow.generated.rest.types.GetResponse; +import com.skyflow.generated.rest.types.InsertResponse; +import com.skyflow.generated.rest.types.UpdateResponse; import java.util.concurrent.CompletableFuture; public class AsyncRecordsClient { @@ -28,24 +33,58 @@ public AsyncRawRecordsClient withRawResponse() { } /** - * Executes a query on the specified vault. + * Deletes records from a vault. + */ + public CompletableFuture deleteRecords(DeleteRequest request) { + return this.rawClient.deleteRecords(request).thenApply(response -> response.body()); + } + + /** + * Deletes records from a vault. + */ + public CompletableFuture deleteRecords(DeleteRequest request, RequestOptions requestOptions) { + return this.rawClient.deleteRecords(request, requestOptions).thenApply(response -> response.body()); + } + + /** + * Returns the specified records from a vault. + */ + public CompletableFuture getRecords(GetRequest request) { + return this.rawClient.getRecords(request).thenApply(response -> response.body()); + } + + /** + * Returns the specified records from a vault. + */ + public CompletableFuture getRecords(GetRequest request, RequestOptions requestOptions) { + return this.rawClient.getRecords(request, requestOptions).thenApply(response -> response.body()); + } + + /** + * Inserts new records into a vault. + */ + public CompletableFuture insertRecords(InsertRequest request) { + return this.rawClient.insertRecords(request).thenApply(response -> response.body()); + } + + /** + * Inserts new records into a vault. */ - public CompletableFuture flowServiceExecuteQuery() { - return this.rawClient.flowServiceExecuteQuery().thenApply(response -> response.body()); + public CompletableFuture insertRecords(InsertRequest request, RequestOptions requestOptions) { + return this.rawClient.insertRecords(request, requestOptions).thenApply(response -> response.body()); } /** - * Executes a query on the specified vault. + * Updates the specified records in a vault. */ - public CompletableFuture flowServiceExecuteQuery(V1ExecuteQueryRequest request) { - return this.rawClient.flowServiceExecuteQuery(request).thenApply(response -> response.body()); + public CompletableFuture updateRecords(UpdateRequest request) { + return this.rawClient.updateRecords(request).thenApply(response -> response.body()); } /** - * Executes a query on the specified vault. + * Updates the specified records in a vault. */ - public CompletableFuture flowServiceExecuteQuery( - V1ExecuteQueryRequest request, RequestOptions requestOptions) { - return this.rawClient.flowServiceExecuteQuery(request, requestOptions).thenApply(response -> response.body()); + public CompletableFuture updateRecords(UpdateRequest request, RequestOptions requestOptions) { + return this.rawClient.updateRecords(request, requestOptions).thenApply(response -> response.body()); } } diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java index cf9a1db1..7b2d702b 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/RawRecordsClient.java @@ -4,12 +4,35 @@ package com.skyflow.generated.rest.resources.records; import com.fasterxml.jackson.core.JsonProcessingException; -import com.skyflow.generated.rest.core.*; -import com.skyflow.generated.rest.resources.records.requests.V1ExecuteQueryRequest; -import com.skyflow.generated.rest.types.V1ExecuteQueryResponse; -import okhttp3.*; - +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.RetryInterceptor; +import com.skyflow.generated.rest.errors.BadRequestError; +import com.skyflow.generated.rest.errors.InternalServerError; +import com.skyflow.generated.rest.errors.NotFoundError; +import com.skyflow.generated.rest.errors.UnauthorizedError; +import com.skyflow.generated.rest.resources.records.requests.DeleteRequest; +import com.skyflow.generated.rest.resources.records.requests.GetRequest; +import com.skyflow.generated.rest.resources.records.requests.InsertRequest; +import com.skyflow.generated.rest.resources.records.requests.UpdateRequest; +import com.skyflow.generated.rest.types.DeleteResponse; +import com.skyflow.generated.rest.types.ErrorResponse; +import com.skyflow.generated.rest.types.GetResponse; +import com.skyflow.generated.rest.types.InsertResponse; +import com.skyflow.generated.rest.types.UpdateResponse; import java.io.IOException; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; public class RawRecordsClient { protected final ClientOptions clientOptions; @@ -19,28 +42,186 @@ public RawRecordsClient(ClientOptions clientOptions) { } /** - * Executes a query on the specified vault. + * Deletes records from a vault. + */ + public ApiClientHttpResponse deleteRecords(DeleteRequest request) { + return deleteRecords(request, null); + } + + /** + * Deletes records from a vault. */ - public ApiClientHttpResponse flowServiceExecuteQuery() { - return flowServiceExecuteQuery(V1ExecuteQueryRequest.builder().build()); + public ApiClientHttpResponse deleteRecords(DeleteRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/records/delete"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + return new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, DeleteResponse.class), response); + } + try { + switch (response.code()) { + case 400: + throw new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 401: + throw new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 404: + throw new NotFoundError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 500: + throw new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + throw new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to deserialize response: " + e.getMessage(), e); + } catch (IOException e) { + throw new ApiClientException("Network error executing HTTP request", e); + } } /** - * Executes a query on the specified vault. + * Returns the specified records from a vault. */ - public ApiClientHttpResponse flowServiceExecuteQuery(V1ExecuteQueryRequest request) { - return flowServiceExecuteQuery(request, null); + public ApiClientHttpResponse getRecords(GetRequest request) { + return getRecords(request, null); } /** - * Executes a query on the specified vault. + * Returns the specified records from a vault. */ - public ApiClientHttpResponse flowServiceExecuteQuery( - V1ExecuteQueryRequest request, RequestOptions requestOptions) { - HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + public ApiClientHttpResponse getRecords(GetRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) .newBuilder() - .addPathSegments("v2/query") + .addPathSegments("v2/records/get"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + return new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, GetResponse.class), response); + } + try { + switch (response.code()) { + case 400: + throw new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 401: + throw new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 404: + throw new NotFoundError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 500: + throw new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + throw new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to deserialize response: " + e.getMessage(), e); + } catch (IOException e) { + throw new ApiClientException("Network error executing HTTP request", e); + } + } + + /** + * Inserts new records into a vault. + */ + public ApiClientHttpResponse insertRecords(InsertRequest request) { + return insertRecords(request, null); + } + + /** + * Inserts new records into a vault. + */ + public ApiClientHttpResponse insertRecords(InsertRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/records/insert"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } RequestBody body; try { body = RequestBody.create( @@ -49,7 +230,7 @@ public ApiClientHttpResponse flowServiceExecuteQuery( throw new ApiClientException("Failed to serialize request", e); } Request okhttpRequest = new Request.Builder() - .url(httpUrl) + .url(httpUrl.build()) .method("POST", body) .headers(Headers.of(clientOptions.headers(requestOptions))) .addHeader("Content-Type", "application/json") @@ -59,19 +240,123 @@ public ApiClientHttpResponse flowServiceExecuteQuery( if (requestOptions != null && requestOptions.getTimeout().isPresent()) { client = clientOptions.httpClientWithTimeout(requestOptions); } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } try (Response response = client.newCall(okhttpRequest).execute()) { ResponseBody responseBody = response.body(); + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; if (response.isSuccessful()) { return new ApiClientHttpResponse<>( - ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), V1ExecuteQueryResponse.class), - response); + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, InsertResponse.class), response); } + try { + switch (response.code()) { + case 400: + throw new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 401: + throw new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 500: + throw new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + throw new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to deserialize response: " + e.getMessage(), e); + } catch (IOException e) { + throw new ApiClientException("Network error executing HTTP request", e); + } + } + + /** + * Updates the specified records in a vault. + */ + public ApiClientHttpResponse updateRecords(UpdateRequest request) { + return updateRecords(request, null); + } + + /** + * Updates the specified records in a vault. + */ + public ApiClientHttpResponse updateRecords(UpdateRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/records/update"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + return new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, UpdateResponse.class), response); + } + try { + switch (response.code()) { + case 400: + throw new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 401: + throw new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 404: + throw new NotFoundError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 500: + throw new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); throw new ApiClientApiException( - "Error with status code " + response.code(), - response.code(), - ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), - response); + "Error with status code " + response.code(), response.code(), errorBody, response); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to deserialize response: " + e.getMessage(), e); } catch (IOException e) { throw new ApiClientException("Network error executing HTTP request", e); } diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java index 332c0e1b..35c77aff 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/RecordsClient.java @@ -5,8 +5,14 @@ import com.skyflow.generated.rest.core.ClientOptions; import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.records.requests.V1ExecuteQueryRequest; -import com.skyflow.generated.rest.types.V1ExecuteQueryResponse; +import com.skyflow.generated.rest.resources.records.requests.DeleteRequest; +import com.skyflow.generated.rest.resources.records.requests.GetRequest; +import com.skyflow.generated.rest.resources.records.requests.InsertRequest; +import com.skyflow.generated.rest.resources.records.requests.UpdateRequest; +import com.skyflow.generated.rest.types.DeleteResponse; +import com.skyflow.generated.rest.types.GetResponse; +import com.skyflow.generated.rest.types.InsertResponse; +import com.skyflow.generated.rest.types.UpdateResponse; public class RecordsClient { protected final ClientOptions clientOptions; @@ -26,24 +32,58 @@ public RawRecordsClient withRawResponse() { } /** - * Executes a query on the specified vault. + * Deletes records from a vault. */ - public V1ExecuteQueryResponse flowServiceExecuteQuery() { - return this.rawClient.flowServiceExecuteQuery().body(); + public DeleteResponse deleteRecords(DeleteRequest request) { + return this.rawClient.deleteRecords(request).body(); } /** - * Executes a query on the specified vault. + * Deletes records from a vault. */ - public V1ExecuteQueryResponse flowServiceExecuteQuery(V1ExecuteQueryRequest request) { - return this.rawClient.flowServiceExecuteQuery(request).body(); + public DeleteResponse deleteRecords(DeleteRequest request, RequestOptions requestOptions) { + return this.rawClient.deleteRecords(request, requestOptions).body(); } /** - * Executes a query on the specified vault. + * Returns the specified records from a vault. */ - public V1ExecuteQueryResponse flowServiceExecuteQuery( - V1ExecuteQueryRequest request, RequestOptions requestOptions) { - return this.rawClient.flowServiceExecuteQuery(request, requestOptions).body(); + public GetResponse getRecords(GetRequest request) { + return this.rawClient.getRecords(request).body(); + } + + /** + * Returns the specified records from a vault. + */ + public GetResponse getRecords(GetRequest request, RequestOptions requestOptions) { + return this.rawClient.getRecords(request, requestOptions).body(); + } + + /** + * Inserts new records into a vault. + */ + public InsertResponse insertRecords(InsertRequest request) { + return this.rawClient.insertRecords(request).body(); + } + + /** + * Inserts new records into a vault. + */ + public InsertResponse insertRecords(InsertRequest request, RequestOptions requestOptions) { + return this.rawClient.insertRecords(request, requestOptions).body(); + } + + /** + * Updates the specified records in a vault. + */ + public UpdateResponse updateRecords(UpdateRequest request) { + return this.rawClient.updateRecords(request).body(); + } + + /** + * Updates the specified records in a vault. + */ + public UpdateResponse updateRecords(UpdateRequest request, RequestOptions requestOptions) { + return this.rawClient.updateRecords(request, requestOptions).body(); } } diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/requests/DeleteRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/requests/DeleteRequest.java new file mode 100644 index 00000000..3a620b09 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/requests/DeleteRequest.java @@ -0,0 +1,263 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.records.requests; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.types.UniqueValue; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = DeleteRequest.Builder.class) +public final class DeleteRequest { + private final String vaultId; + + private final Optional tableName; + + private final Optional> skyflowIDs; + + private final Optional> uniqueValues; + + private final Map additionalProperties; + + private DeleteRequest( + String vaultId, + Optional tableName, + Optional> skyflowIDs, + Optional> uniqueValues, + Map additionalProperties) { + this.vaultId = vaultId; + this.tableName = tableName; + this.skyflowIDs = skyflowIDs; + this.uniqueValues = uniqueValues; + this.additionalProperties = additionalProperties; + } + + /** + * @return ID of the vault. + */ + @JsonProperty("vaultID") + public String getVaultId() { + return vaultId; + } + + /** + * @return Name of the table. + */ + @JsonProperty("tableName") + public Optional getTableName() { + return tableName; + } + + /** + * @return Skyflow IDs of the records to delete. + */ + @JsonProperty("skyflowIDs") + public Optional> getSkyflowIDs() { + return skyflowIDs; + } + + /** + * @return List of unique constraint values to query records by data. + */ + @JsonProperty("uniqueValues") + public Optional> getUniqueValues() { + return uniqueValues; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof DeleteRequest && equalTo((DeleteRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(DeleteRequest other) { + return vaultId.equals(other.vaultId) + && tableName.equals(other.tableName) + && skyflowIDs.equals(other.skyflowIDs) + && uniqueValues.equals(other.uniqueValues); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.vaultId, this.tableName, this.skyflowIDs, this.uniqueValues); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static VaultIdStage builder() { + return new Builder(); + } + + public interface VaultIdStage { + /** + *

ID of the vault.

+ */ + _FinalStage vaultId(@NotNull String vaultId); + + Builder from(DeleteRequest other); + } + + public interface _FinalStage { + DeleteRequest build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + /** + *

Name of the table.

+ */ + _FinalStage tableName(Optional tableName); + + _FinalStage tableName(String tableName); + + /** + *

Skyflow IDs of the records to delete.

+ */ + _FinalStage skyflowIDs(Optional> skyflowIDs); + + _FinalStage skyflowIDs(List skyflowIDs); + + /** + *

List of unique constraint values to query records by data.

+ */ + _FinalStage uniqueValues(Optional> uniqueValues); + + _FinalStage uniqueValues(List uniqueValues); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements VaultIdStage, _FinalStage { + private String vaultId; + + private Optional> uniqueValues = Optional.empty(); + + private Optional> skyflowIDs = Optional.empty(); + + private Optional tableName = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(DeleteRequest other) { + vaultId(other.getVaultId()); + tableName(other.getTableName()); + skyflowIDs(other.getSkyflowIDs()); + uniqueValues(other.getUniqueValues()); + return this; + } + + /** + *

ID of the vault.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("vaultID") + public _FinalStage vaultId(@NotNull String vaultId) { + this.vaultId = Objects.requireNonNull(vaultId, "vaultId must not be null"); + return this; + } + + /** + *

List of unique constraint values to query records by data.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage uniqueValues(List uniqueValues) { + this.uniqueValues = Optional.ofNullable(uniqueValues); + return this; + } + + /** + *

List of unique constraint values to query records by data.

+ */ + @java.lang.Override + @JsonSetter(value = "uniqueValues", nulls = Nulls.SKIP) + public _FinalStage uniqueValues(Optional> uniqueValues) { + this.uniqueValues = uniqueValues; + return this; + } + + /** + *

Skyflow IDs of the records to delete.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage skyflowIDs(List skyflowIDs) { + this.skyflowIDs = Optional.ofNullable(skyflowIDs); + return this; + } + + /** + *

Skyflow IDs of the records to delete.

+ */ + @java.lang.Override + @JsonSetter(value = "skyflowIDs", nulls = Nulls.SKIP) + public _FinalStage skyflowIDs(Optional> skyflowIDs) { + this.skyflowIDs = skyflowIDs; + return this; + } + + /** + *

Name of the table.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage tableName(String tableName) { + this.tableName = Optional.ofNullable(tableName); + return this; + } + + /** + *

Name of the table.

+ */ + @java.lang.Override + @JsonSetter(value = "tableName", nulls = Nulls.SKIP) + public _FinalStage tableName(Optional tableName) { + this.tableName = tableName; + return this; + } + + @java.lang.Override + public DeleteRequest build() { + return new DeleteRequest(vaultId, tableName, skyflowIDs, uniqueValues, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/requests/GetRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/requests/GetRequest.java new file mode 100644 index 00000000..e6290a9d --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/requests/GetRequest.java @@ -0,0 +1,499 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.records.requests; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.types.ColumnRedactions; +import com.skyflow.generated.rest.types.GetRequestData; +import com.skyflow.generated.rest.types.UniqueValue; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = GetRequest.Builder.class) +public final class GetRequest { + private final String vaultId; + + private final Optional tableName; + + private final Optional> skyflowIDs; + + private final Optional> columnRedactions; + + private final Optional> columns; + + private final Optional limit; + + private final Optional offset; + + private final Optional> uniqueValues; + + private final Optional> records; + + private final Map additionalProperties; + + private GetRequest( + String vaultId, + Optional tableName, + Optional> skyflowIDs, + Optional> columnRedactions, + Optional> columns, + Optional limit, + Optional offset, + Optional> uniqueValues, + Optional> records, + Map additionalProperties) { + this.vaultId = vaultId; + this.tableName = tableName; + this.skyflowIDs = skyflowIDs; + this.columnRedactions = columnRedactions; + this.columns = columns; + this.limit = limit; + this.offset = offset; + this.uniqueValues = uniqueValues; + this.records = records; + this.additionalProperties = additionalProperties; + } + + /** + * @return ID of the vault. + */ + @JsonProperty("vaultID") + public String getVaultId() { + return vaultId; + } + + /** + * @return Name of the table to perform the operation on. + */ + @JsonProperty("tableName") + public Optional getTableName() { + return tableName; + } + + /** + * @return Skyflow IDs of the records to return. Either skyflowIDs or uniqueValues are required. If both are provided, the request fails. + */ + @JsonProperty("skyflowIDs") + public Optional> getSkyflowIDs() { + return skyflowIDs; + } + + /** + * @return List of columns to redact. + */ + @JsonProperty("columnRedactions") + public Optional> getColumnRedactions() { + return columnRedactions; + } + + /** + * @return List of columns to return. + */ + @JsonProperty("columns") + public Optional> getColumns() { + return columns; + } + + /** + * @return Limit for the number of records to be fetched. + */ + @JsonProperty("limit") + public Optional getLimit() { + return limit; + } + + /** + * @return Offset for the number of records to be fetched. + */ + @JsonProperty("offset") + public Optional getOffset() { + return offset; + } + + /** + * @return List of unique constraint values to query records by data. + */ + @JsonProperty("uniqueValues") + public Optional> getUniqueValues() { + return uniqueValues; + } + + /** + * @return List of records to be fetched. This field contains tableName and skyflowIDs belonging to the table. + */ + @JsonProperty("records") + public Optional> getRecords() { + return records; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof GetRequest && equalTo((GetRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(GetRequest other) { + return vaultId.equals(other.vaultId) + && tableName.equals(other.tableName) + && skyflowIDs.equals(other.skyflowIDs) + && columnRedactions.equals(other.columnRedactions) + && columns.equals(other.columns) + && limit.equals(other.limit) + && offset.equals(other.offset) + && uniqueValues.equals(other.uniqueValues) + && records.equals(other.records); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash( + this.vaultId, + this.tableName, + this.skyflowIDs, + this.columnRedactions, + this.columns, + this.limit, + this.offset, + this.uniqueValues, + this.records); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static VaultIdStage builder() { + return new Builder(); + } + + public interface VaultIdStage { + /** + *

ID of the vault.

+ */ + _FinalStage vaultId(@NotNull String vaultId); + + Builder from(GetRequest other); + } + + public interface _FinalStage { + GetRequest build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + /** + *

Name of the table to perform the operation on.

+ */ + _FinalStage tableName(Optional tableName); + + _FinalStage tableName(String tableName); + + /** + *

Skyflow IDs of the records to return. Either skyflowIDs or uniqueValues are required. If both are provided, the request fails.

+ */ + _FinalStage skyflowIDs(Optional> skyflowIDs); + + _FinalStage skyflowIDs(List skyflowIDs); + + /** + *

List of columns to redact.

+ */ + _FinalStage columnRedactions(Optional> columnRedactions); + + _FinalStage columnRedactions(List columnRedactions); + + /** + *

List of columns to return.

+ */ + _FinalStage columns(Optional> columns); + + _FinalStage columns(List columns); + + /** + *

Limit for the number of records to be fetched.

+ */ + _FinalStage limit(Optional limit); + + _FinalStage limit(Integer limit); + + /** + *

Offset for the number of records to be fetched.

+ */ + _FinalStage offset(Optional offset); + + _FinalStage offset(Integer offset); + + /** + *

List of unique constraint values to query records by data.

+ */ + _FinalStage uniqueValues(Optional> uniqueValues); + + _FinalStage uniqueValues(List uniqueValues); + + /** + *

List of records to be fetched. This field contains tableName and skyflowIDs belonging to the table.

+ */ + _FinalStage records(Optional> records); + + _FinalStage records(List records); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements VaultIdStage, _FinalStage { + private String vaultId; + + private Optional> records = Optional.empty(); + + private Optional> uniqueValues = Optional.empty(); + + private Optional offset = Optional.empty(); + + private Optional limit = Optional.empty(); + + private Optional> columns = Optional.empty(); + + private Optional> columnRedactions = Optional.empty(); + + private Optional> skyflowIDs = Optional.empty(); + + private Optional tableName = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(GetRequest other) { + vaultId(other.getVaultId()); + tableName(other.getTableName()); + skyflowIDs(other.getSkyflowIDs()); + columnRedactions(other.getColumnRedactions()); + columns(other.getColumns()); + limit(other.getLimit()); + offset(other.getOffset()); + uniqueValues(other.getUniqueValues()); + records(other.getRecords()); + return this; + } + + /** + *

ID of the vault.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("vaultID") + public _FinalStage vaultId(@NotNull String vaultId) { + this.vaultId = Objects.requireNonNull(vaultId, "vaultId must not be null"); + return this; + } + + /** + *

List of records to be fetched. This field contains tableName and skyflowIDs belonging to the table.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage records(List records) { + this.records = Optional.ofNullable(records); + return this; + } + + /** + *

List of records to be fetched. This field contains tableName and skyflowIDs belonging to the table.

+ */ + @java.lang.Override + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public _FinalStage records(Optional> records) { + this.records = records; + return this; + } + + /** + *

List of unique constraint values to query records by data.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage uniqueValues(List uniqueValues) { + this.uniqueValues = Optional.ofNullable(uniqueValues); + return this; + } + + /** + *

List of unique constraint values to query records by data.

+ */ + @java.lang.Override + @JsonSetter(value = "uniqueValues", nulls = Nulls.SKIP) + public _FinalStage uniqueValues(Optional> uniqueValues) { + this.uniqueValues = uniqueValues; + return this; + } + + /** + *

Offset for the number of records to be fetched.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage offset(Integer offset) { + this.offset = Optional.ofNullable(offset); + return this; + } + + /** + *

Offset for the number of records to be fetched.

+ */ + @java.lang.Override + @JsonSetter(value = "offset", nulls = Nulls.SKIP) + public _FinalStage offset(Optional offset) { + this.offset = offset; + return this; + } + + /** + *

Limit for the number of records to be fetched.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage limit(Integer limit) { + this.limit = Optional.ofNullable(limit); + return this; + } + + /** + *

Limit for the number of records to be fetched.

+ */ + @java.lang.Override + @JsonSetter(value = "limit", nulls = Nulls.SKIP) + public _FinalStage limit(Optional limit) { + this.limit = limit; + return this; + } + + /** + *

List of columns to return.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage columns(List columns) { + this.columns = Optional.ofNullable(columns); + return this; + } + + /** + *

List of columns to return.

+ */ + @java.lang.Override + @JsonSetter(value = "columns", nulls = Nulls.SKIP) + public _FinalStage columns(Optional> columns) { + this.columns = columns; + return this; + } + + /** + *

List of columns to redact.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage columnRedactions(List columnRedactions) { + this.columnRedactions = Optional.ofNullable(columnRedactions); + return this; + } + + /** + *

List of columns to redact.

+ */ + @java.lang.Override + @JsonSetter(value = "columnRedactions", nulls = Nulls.SKIP) + public _FinalStage columnRedactions(Optional> columnRedactions) { + this.columnRedactions = columnRedactions; + return this; + } + + /** + *

Skyflow IDs of the records to return. Either skyflowIDs or uniqueValues are required. If both are provided, the request fails.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage skyflowIDs(List skyflowIDs) { + this.skyflowIDs = Optional.ofNullable(skyflowIDs); + return this; + } + + /** + *

Skyflow IDs of the records to return. Either skyflowIDs or uniqueValues are required. If both are provided, the request fails.

+ */ + @java.lang.Override + @JsonSetter(value = "skyflowIDs", nulls = Nulls.SKIP) + public _FinalStage skyflowIDs(Optional> skyflowIDs) { + this.skyflowIDs = skyflowIDs; + return this; + } + + /** + *

Name of the table to perform the operation on.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage tableName(String tableName) { + this.tableName = Optional.ofNullable(tableName); + return this; + } + + /** + *

Name of the table to perform the operation on.

+ */ + @java.lang.Override + @JsonSetter(value = "tableName", nulls = Nulls.SKIP) + public _FinalStage tableName(Optional tableName) { + this.tableName = tableName; + return this; + } + + @java.lang.Override + public GetRequest build() { + return new GetRequest( + vaultId, + tableName, + skyflowIDs, + columnRedactions, + columns, + limit, + offset, + uniqueValues, + records, + additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/requests/InsertRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/requests/InsertRequest.java new file mode 100644 index 00000000..c4db785e --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/requests/InsertRequest.java @@ -0,0 +1,260 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.records.requests; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.types.InsertRecordData; +import com.skyflow.generated.rest.types.Upsert; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = InsertRequest.Builder.class) +public final class InsertRequest { + private final String vaultId; + + private final String tableName; + + private final List records; + + private final Optional upsert; + + private final Map additionalProperties; + + private InsertRequest( + String vaultId, + String tableName, + List records, + Optional upsert, + Map additionalProperties) { + this.vaultId = vaultId; + this.tableName = tableName; + this.records = records; + this.upsert = upsert; + this.additionalProperties = additionalProperties; + } + + /** + * @return ID of the vault. + */ + @JsonProperty("vaultID") + public String getVaultId() { + return vaultId; + } + + /** + * @return Name of the table to perform the operation on. Can be defined at both the request body level and individual record level. If provided at both levels, the record-level tableName takes precedence. + */ + @JsonProperty("tableName") + public String getTableName() { + return tableName; + } + + /** + * @return Data to insert as a list of records. + */ + @JsonProperty("records") + public List getRecords() { + return records; + } + + @JsonProperty("upsert") + public Optional getUpsert() { + return upsert; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof InsertRequest && equalTo((InsertRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(InsertRequest other) { + return vaultId.equals(other.vaultId) + && tableName.equals(other.tableName) + && records.equals(other.records) + && upsert.equals(other.upsert); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.vaultId, this.tableName, this.records, this.upsert); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static VaultIdStage builder() { + return new Builder(); + } + + public interface VaultIdStage { + /** + *

ID of the vault.

+ */ + TableNameStage vaultId(@NotNull String vaultId); + + Builder from(InsertRequest other); + } + + public interface TableNameStage { + /** + *

Name of the table to perform the operation on. Can be defined at both the request body level and individual record level. If provided at both levels, the record-level tableName takes precedence.

+ */ + _FinalStage tableName(@NotNull String tableName); + } + + public interface _FinalStage { + InsertRequest build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + /** + *

Data to insert as a list of records.

+ */ + _FinalStage records(List records); + + _FinalStage addRecords(InsertRecordData records); + + _FinalStage addAllRecords(List records); + + _FinalStage upsert(Optional upsert); + + _FinalStage upsert(Upsert upsert); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements VaultIdStage, TableNameStage, _FinalStage { + private String vaultId; + + private String tableName; + + private Optional upsert = Optional.empty(); + + private List records = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(InsertRequest other) { + vaultId(other.getVaultId()); + tableName(other.getTableName()); + records(other.getRecords()); + upsert(other.getUpsert()); + return this; + } + + /** + *

ID of the vault.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("vaultID") + public TableNameStage vaultId(@NotNull String vaultId) { + this.vaultId = Objects.requireNonNull(vaultId, "vaultId must not be null"); + return this; + } + + /** + *

Name of the table to perform the operation on. Can be defined at both the request body level and individual record level. If provided at both levels, the record-level tableName takes precedence.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("tableName") + public _FinalStage tableName(@NotNull String tableName) { + this.tableName = Objects.requireNonNull(tableName, "tableName must not be null"); + return this; + } + + @java.lang.Override + public _FinalStage upsert(Upsert upsert) { + this.upsert = Optional.ofNullable(upsert); + return this; + } + + @java.lang.Override + @JsonSetter(value = "upsert", nulls = Nulls.SKIP) + public _FinalStage upsert(Optional upsert) { + this.upsert = upsert; + return this; + } + + /** + *

Data to insert as a list of records.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addAllRecords(List records) { + if (records != null) { + this.records.addAll(records); + } + return this; + } + + /** + *

Data to insert as a list of records.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addRecords(InsertRecordData records) { + this.records.add(records); + return this; + } + + /** + *

Data to insert as a list of records.

+ */ + @java.lang.Override + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public _FinalStage records(List records) { + this.records.clear(); + if (records != null) { + this.records.addAll(records); + } + return this; + } + + @java.lang.Override + public InsertRequest build() { + return new InsertRequest(vaultId, tableName, records, upsert, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/requests/UpdateRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/requests/UpdateRequest.java new file mode 100644 index 00000000..6b7f32c7 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/requests/UpdateRequest.java @@ -0,0 +1,273 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.records.requests; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.resources.records.types.UpdateRequestUpdateType; +import com.skyflow.generated.rest.types.UpdateRecordData; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = UpdateRequest.Builder.class) +public final class UpdateRequest { + private final String vaultId; + + private final String tableName; + + private final List records; + + private final Optional updateType; + + private final Map additionalProperties; + + private UpdateRequest( + String vaultId, + String tableName, + List records, + Optional updateType, + Map additionalProperties) { + this.vaultId = vaultId; + this.tableName = tableName; + this.records = records; + this.updateType = updateType; + this.additionalProperties = additionalProperties; + } + + /** + * @return ID of the vault. + */ + @JsonProperty("vaultID") + public String getVaultId() { + return vaultId; + } + + /** + * @return Name of the table. + */ + @JsonProperty("tableName") + public String getTableName() { + return tableName; + } + + /** + * @return Data to update as a list of records. + */ + @JsonProperty("records") + public List getRecords() { + return records; + } + + /** + * @return Type of update operation to perform. + */ + @JsonProperty("updateType") + public Optional getUpdateType() { + return updateType; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof UpdateRequest && equalTo((UpdateRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(UpdateRequest other) { + return vaultId.equals(other.vaultId) + && tableName.equals(other.tableName) + && records.equals(other.records) + && updateType.equals(other.updateType); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.vaultId, this.tableName, this.records, this.updateType); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static VaultIdStage builder() { + return new Builder(); + } + + public interface VaultIdStage { + /** + *

ID of the vault.

+ */ + TableNameStage vaultId(@NotNull String vaultId); + + Builder from(UpdateRequest other); + } + + public interface TableNameStage { + /** + *

Name of the table.

+ */ + _FinalStage tableName(@NotNull String tableName); + } + + public interface _FinalStage { + UpdateRequest build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + /** + *

Data to update as a list of records.

+ */ + _FinalStage records(List records); + + _FinalStage addRecords(UpdateRecordData records); + + _FinalStage addAllRecords(List records); + + /** + *

Type of update operation to perform.

+ */ + _FinalStage updateType(Optional updateType); + + _FinalStage updateType(UpdateRequestUpdateType updateType); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements VaultIdStage, TableNameStage, _FinalStage { + private String vaultId; + + private String tableName; + + private Optional updateType = Optional.empty(); + + private List records = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(UpdateRequest other) { + vaultId(other.getVaultId()); + tableName(other.getTableName()); + records(other.getRecords()); + updateType(other.getUpdateType()); + return this; + } + + /** + *

ID of the vault.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("vaultID") + public TableNameStage vaultId(@NotNull String vaultId) { + this.vaultId = Objects.requireNonNull(vaultId, "vaultId must not be null"); + return this; + } + + /** + *

Name of the table.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("tableName") + public _FinalStage tableName(@NotNull String tableName) { + this.tableName = Objects.requireNonNull(tableName, "tableName must not be null"); + return this; + } + + /** + *

Type of update operation to perform.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage updateType(UpdateRequestUpdateType updateType) { + this.updateType = Optional.ofNullable(updateType); + return this; + } + + /** + *

Type of update operation to perform.

+ */ + @java.lang.Override + @JsonSetter(value = "updateType", nulls = Nulls.SKIP) + public _FinalStage updateType(Optional updateType) { + this.updateType = updateType; + return this; + } + + /** + *

Data to update as a list of records.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addAllRecords(List records) { + if (records != null) { + this.records.addAll(records); + } + return this; + } + + /** + *

Data to update as a list of records.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addRecords(UpdateRecordData records) { + this.records.add(records); + return this; + } + + /** + *

Data to update as a list of records.

+ */ + @java.lang.Override + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public _FinalStage records(List records) { + this.records.clear(); + if (records != null) { + this.records.addAll(records); + } + return this; + } + + @java.lang.Override + public UpdateRequest build() { + return new UpdateRequest(vaultId, tableName, records, updateType, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/requests/V1ExecuteQueryRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/requests/V1ExecuteQueryRequest.java deleted file mode 100644 index 2857faca..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/requests/V1ExecuteQueryRequest.java +++ /dev/null @@ -1,125 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.resources.records.requests; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1ExecuteQueryRequest.Builder.class) -public final class V1ExecuteQueryRequest { - private final Optional vaultId; - - private final Optional query; - - private final Map additionalProperties; - - private V1ExecuteQueryRequest( - Optional vaultId, Optional query, Map additionalProperties) { - this.vaultId = vaultId; - this.query = query; - this.additionalProperties = additionalProperties; - } - - /** - * @return ID of the vault where data is being inserted - */ - @JsonProperty("vaultID") - public Optional getVaultId() { - return vaultId; - } - - /** - * @return Query to execute. - */ - @JsonProperty("query") - public Optional getQuery() { - return query; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1ExecuteQueryRequest && equalTo((V1ExecuteQueryRequest) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1ExecuteQueryRequest other) { - return vaultId.equals(other.vaultId) && query.equals(other.query); - } - - @Override - public int hashCode() { - return Objects.hash(this.vaultId, this.query); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional vaultId = Optional.empty(); - - private Optional query = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1ExecuteQueryRequest other) { - vaultId(other.getVaultId()); - query(other.getQuery()); - return this; - } - - /** - *

ID of the vault where data is being inserted

- */ - @JsonSetter(value = "vaultID", nulls = Nulls.SKIP) - public Builder vaultId(Optional vaultId) { - this.vaultId = vaultId; - return this; - } - - public Builder vaultId(String vaultId) { - this.vaultId = Optional.ofNullable(vaultId); - return this; - } - - /** - *

Query to execute.

- */ - @JsonSetter(value = "query", nulls = Nulls.SKIP) - public Builder query(Optional query) { - this.query = query; - return this; - } - - public Builder query(String query) { - this.query = Optional.ofNullable(query); - return this; - } - - public V1ExecuteQueryRequest build() { - return new V1ExecuteQueryRequest(vaultId, query, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/types/UpdateRequestUpdateType.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/types/UpdateRequestUpdateType.java new file mode 100644 index 00000000..660067b8 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/records/types/UpdateRequestUpdateType.java @@ -0,0 +1,84 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.records.types; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public final class UpdateRequestUpdateType { + public static final UpdateRequestUpdateType REPLACE = new UpdateRequestUpdateType(Value.REPLACE, "REPLACE"); + + public static final UpdateRequestUpdateType UPDATE = new UpdateRequestUpdateType(Value.UPDATE, "UPDATE"); + + private final Value value; + + private final String string; + + UpdateRequestUpdateType(Value value, String string) { + this.value = value; + this.string = string; + } + + public Value getEnumValue() { + return value; + } + + @java.lang.Override + @JsonValue + public String toString() { + return this.string; + } + + @java.lang.Override + public boolean equals(Object other) { + return (this == other) + || (other instanceof UpdateRequestUpdateType + && this.string.equals(((UpdateRequestUpdateType) other).string)); + } + + @java.lang.Override + public int hashCode() { + return this.string.hashCode(); + } + + public T visit(Visitor visitor) { + switch (value) { + case REPLACE: + return visitor.visitReplace(); + case UPDATE: + return visitor.visitUpdate(); + case UNKNOWN: + default: + return visitor.visitUnknown(string); + } + } + + @JsonCreator(mode = JsonCreator.Mode.DELEGATING) + public static UpdateRequestUpdateType valueOf(String value) { + switch (value) { + case "REPLACE": + return REPLACE; + case "UPDATE": + return UPDATE; + default: + return new UpdateRequestUpdateType(Value.UNKNOWN, value); + } + } + + public enum Value { + UPDATE, + + REPLACE, + + UNKNOWN + } + + public interface Visitor { + T visitUpdate(); + + T visitReplace(); + + T visitUnknown(String unknownType); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncRawTokensClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncRawTokensClient.java new file mode 100644 index 00000000..17a85aee --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncRawTokensClient.java @@ -0,0 +1,481 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.tokens; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.RetryInterceptor; +import com.skyflow.generated.rest.errors.BadRequestError; +import com.skyflow.generated.rest.errors.ForbiddenError; +import com.skyflow.generated.rest.errors.InternalServerError; +import com.skyflow.generated.rest.errors.NotFoundError; +import com.skyflow.generated.rest.errors.TooManyRequestsError; +import com.skyflow.generated.rest.errors.UnauthorizedError; +import com.skyflow.generated.rest.resources.tokens.requests.DeleteTokenRequest; +import com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest; +import com.skyflow.generated.rest.resources.tokens.requests.GetTokensFromValuesRequest; +import com.skyflow.generated.rest.resources.tokens.requests.TokenizeRequest; +import com.skyflow.generated.rest.types.DeleteTokenResponse; +import com.skyflow.generated.rest.types.DetokenizeResponse; +import com.skyflow.generated.rest.types.ErrorResponse; +import com.skyflow.generated.rest.types.GetTokensFromValuesResponse; +import com.skyflow.generated.rest.types.TokenizeResponse; +import java.io.IOException; +import java.util.concurrent.CompletableFuture; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.jetbrains.annotations.NotNull; + +public class AsyncRawTokensClient { + protected final ClientOptions clientOptions; + + public AsyncRawTokensClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + } + + /** + * Returns the deterministic token previously issued for each supplied plaintext value within the specified token group. Only applicable to deterministic tokengroups. + */ + public CompletableFuture> getTokens( + GetTokensFromValuesRequest request) { + return getTokens(request, null); + } + + /** + * Returns the deterministic token previously issued for each supplied plaintext value within the specified token group. Only applicable to deterministic tokengroups. + */ + public CompletableFuture> getTokens( + GetTokensFromValuesRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/records/getTokens"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + future.complete(new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue( + responseBodyString, GetTokensFromValuesResponse.class), + response)); + return; + } + try { + switch (response.code()) { + case 400: + future.completeExceptionally(new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 401: + future.completeExceptionally(new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 403: + future.completeExceptionally(new ForbiddenError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 404: + future.completeExceptionally(new NotFoundError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 429: + future.completeExceptionally(new TooManyRequestsError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 500: + future.completeExceptionally(new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + future.completeExceptionally(new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response)); + return; + } catch (JsonProcessingException e) { + future.completeExceptionally( + new ApiClientException("Failed to deserialize response: " + e.getMessage(), e)); + } catch (IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + }); + return future; + } + + /** + * Deletes tokens from the vault. + */ + public CompletableFuture> deleteToken(DeleteTokenRequest request) { + return deleteToken(request, null); + } + + /** + * Deletes tokens from the vault. + */ + public CompletableFuture> deleteToken( + DeleteTokenRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/tokens/delete"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + future.complete(new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, DeleteTokenResponse.class), + response)); + return; + } + try { + switch (response.code()) { + case 400: + future.completeExceptionally(new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 401: + future.completeExceptionally(new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 404: + future.completeExceptionally(new NotFoundError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 500: + future.completeExceptionally(new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + future.completeExceptionally(new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response)); + return; + } catch (JsonProcessingException e) { + future.completeExceptionally( + new ApiClientException("Failed to deserialize response: " + e.getMessage(), e)); + } catch (IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + }); + return future; + } + + /** + * Returns values that correspond to the specified tokens. + */ + public CompletableFuture> detokenize(DetokenizeRequest request) { + return detokenize(request, null); + } + + /** + * Returns values that correspond to the specified tokens. + */ + public CompletableFuture> detokenize( + DetokenizeRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/tokens/detokenize"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + future.complete(new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, DetokenizeResponse.class), + response)); + return; + } + try { + switch (response.code()) { + case 400: + future.completeExceptionally(new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 401: + future.completeExceptionally(new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 404: + future.completeExceptionally(new NotFoundError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 500: + future.completeExceptionally(new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + future.completeExceptionally(new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response)); + return; + } catch (JsonProcessingException e) { + future.completeExceptionally( + new ApiClientException("Failed to deserialize response: " + e.getMessage(), e)); + } catch (IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + }); + return future; + } + + /** + * Returns tokens that correspond to the specified values. Only applicable to fields that use deterministic tokenization. + */ + public CompletableFuture> tokenize(TokenizeRequest request) { + return tokenize(request, null); + } + + /** + * Returns tokens that correspond to the specified values. Only applicable to fields that use deterministic tokenization. + */ + public CompletableFuture> tokenize( + TokenizeRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/tokens/tokenize"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + future.complete(new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, TokenizeResponse.class), + response)); + return; + } + try { + switch (response.code()) { + case 400: + future.completeExceptionally(new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 401: + future.completeExceptionally(new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 404: + future.completeExceptionally(new NotFoundError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + case 500: + future.completeExceptionally(new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), + response)); + return; + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + future.completeExceptionally(new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response)); + return; + } catch (JsonProcessingException e) { + future.completeExceptionally( + new ApiClientException("Failed to deserialize response: " + e.getMessage(), e)); + } catch (IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new ApiClientException("Network error executing HTTP request", e)); + } + }); + return future; + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncTokensClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncTokensClient.java new file mode 100644 index 00000000..e85ae3a1 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/AsyncTokensClient.java @@ -0,0 +1,92 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.tokens; + +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.resources.tokens.requests.DeleteTokenRequest; +import com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest; +import com.skyflow.generated.rest.resources.tokens.requests.GetTokensFromValuesRequest; +import com.skyflow.generated.rest.resources.tokens.requests.TokenizeRequest; +import com.skyflow.generated.rest.types.DeleteTokenResponse; +import com.skyflow.generated.rest.types.DetokenizeResponse; +import com.skyflow.generated.rest.types.GetTokensFromValuesResponse; +import com.skyflow.generated.rest.types.TokenizeResponse; +import java.util.concurrent.CompletableFuture; + +public class AsyncTokensClient { + protected final ClientOptions clientOptions; + + private final AsyncRawTokensClient rawClient; + + public AsyncTokensClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.rawClient = new AsyncRawTokensClient(clientOptions); + } + + /** + * Get responses with HTTP metadata like headers + */ + public AsyncRawTokensClient withRawResponse() { + return this.rawClient; + } + + /** + * Returns the deterministic token previously issued for each supplied plaintext value within the specified token group. Only applicable to deterministic tokengroups. + */ + public CompletableFuture getTokens(GetTokensFromValuesRequest request) { + return this.rawClient.getTokens(request).thenApply(response -> response.body()); + } + + /** + * Returns the deterministic token previously issued for each supplied plaintext value within the specified token group. Only applicable to deterministic tokengroups. + */ + public CompletableFuture getTokens( + GetTokensFromValuesRequest request, RequestOptions requestOptions) { + return this.rawClient.getTokens(request, requestOptions).thenApply(response -> response.body()); + } + + /** + * Deletes tokens from the vault. + */ + public CompletableFuture deleteToken(DeleteTokenRequest request) { + return this.rawClient.deleteToken(request).thenApply(response -> response.body()); + } + + /** + * Deletes tokens from the vault. + */ + public CompletableFuture deleteToken( + DeleteTokenRequest request, RequestOptions requestOptions) { + return this.rawClient.deleteToken(request, requestOptions).thenApply(response -> response.body()); + } + + /** + * Returns values that correspond to the specified tokens. + */ + public CompletableFuture detokenize(DetokenizeRequest request) { + return this.rawClient.detokenize(request).thenApply(response -> response.body()); + } + + /** + * Returns values that correspond to the specified tokens. + */ + public CompletableFuture detokenize(DetokenizeRequest request, RequestOptions requestOptions) { + return this.rawClient.detokenize(request, requestOptions).thenApply(response -> response.body()); + } + + /** + * Returns tokens that correspond to the specified values. Only applicable to fields that use deterministic tokenization. + */ + public CompletableFuture tokenize(TokenizeRequest request) { + return this.rawClient.tokenize(request).thenApply(response -> response.body()); + } + + /** + * Returns tokens that correspond to the specified values. Only applicable to fields that use deterministic tokenization. + */ + public CompletableFuture tokenize(TokenizeRequest request, RequestOptions requestOptions) { + return this.rawClient.tokenize(request, requestOptions).thenApply(response -> response.body()); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/RawTokensClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/RawTokensClient.java new file mode 100644 index 00000000..be94d051 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/RawTokensClient.java @@ -0,0 +1,379 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.tokens; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.MediaTypes; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.core.RetryInterceptor; +import com.skyflow.generated.rest.errors.BadRequestError; +import com.skyflow.generated.rest.errors.ForbiddenError; +import com.skyflow.generated.rest.errors.InternalServerError; +import com.skyflow.generated.rest.errors.NotFoundError; +import com.skyflow.generated.rest.errors.TooManyRequestsError; +import com.skyflow.generated.rest.errors.UnauthorizedError; +import com.skyflow.generated.rest.resources.tokens.requests.DeleteTokenRequest; +import com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest; +import com.skyflow.generated.rest.resources.tokens.requests.GetTokensFromValuesRequest; +import com.skyflow.generated.rest.resources.tokens.requests.TokenizeRequest; +import com.skyflow.generated.rest.types.DeleteTokenResponse; +import com.skyflow.generated.rest.types.DetokenizeResponse; +import com.skyflow.generated.rest.types.ErrorResponse; +import com.skyflow.generated.rest.types.GetTokensFromValuesResponse; +import com.skyflow.generated.rest.types.TokenizeResponse; +import java.io.IOException; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; + +public class RawTokensClient { + protected final ClientOptions clientOptions; + + public RawTokensClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + } + + /** + * Returns the deterministic token previously issued for each supplied plaintext value within the specified token group. Only applicable to deterministic tokengroups. + */ + public ApiClientHttpResponse getTokens(GetTokensFromValuesRequest request) { + return getTokens(request, null); + } + + /** + * Returns the deterministic token previously issued for each supplied plaintext value within the specified token group. Only applicable to deterministic tokengroups. + */ + public ApiClientHttpResponse getTokens( + GetTokensFromValuesRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/records/getTokens"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + return new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, GetTokensFromValuesResponse.class), + response); + } + try { + switch (response.code()) { + case 400: + throw new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 401: + throw new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 403: + throw new ForbiddenError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 404: + throw new NotFoundError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 429: + throw new TooManyRequestsError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 500: + throw new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + throw new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to deserialize response: " + e.getMessage(), e); + } catch (IOException e) { + throw new ApiClientException("Network error executing HTTP request", e); + } + } + + /** + * Deletes tokens from the vault. + */ + public ApiClientHttpResponse deleteToken(DeleteTokenRequest request) { + return deleteToken(request, null); + } + + /** + * Deletes tokens from the vault. + */ + public ApiClientHttpResponse deleteToken( + DeleteTokenRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/tokens/delete"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + return new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, DeleteTokenResponse.class), response); + } + try { + switch (response.code()) { + case 400: + throw new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 401: + throw new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 404: + throw new NotFoundError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 500: + throw new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + throw new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to deserialize response: " + e.getMessage(), e); + } catch (IOException e) { + throw new ApiClientException("Network error executing HTTP request", e); + } + } + + /** + * Returns values that correspond to the specified tokens. + */ + public ApiClientHttpResponse detokenize(DetokenizeRequest request) { + return detokenize(request, null); + } + + /** + * Returns values that correspond to the specified tokens. + */ + public ApiClientHttpResponse detokenize( + DetokenizeRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/tokens/detokenize"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + return new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, DetokenizeResponse.class), response); + } + try { + switch (response.code()) { + case 400: + throw new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 401: + throw new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 404: + throw new NotFoundError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 500: + throw new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + throw new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to deserialize response: " + e.getMessage(), e); + } catch (IOException e) { + throw new ApiClientException("Network error executing HTTP request", e); + } + } + + /** + * Returns tokens that correspond to the specified values. Only applicable to fields that use deterministic tokenization. + */ + public ApiClientHttpResponse tokenize(TokenizeRequest request) { + return tokenize(request, null); + } + + /** + * Returns tokens that correspond to the specified values. Only applicable to fields that use deterministic tokenization. + */ + public ApiClientHttpResponse tokenize(TokenizeRequest request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("v2/tokens/tokenize"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + if (requestOptions != null && requestOptions.getMaxRetries().isPresent()) { + okhttpRequest = okhttpRequest + .newBuilder() + .tag( + RetryInterceptor.MaxRetriesOverride.class, + new RetryInterceptor.MaxRetriesOverride( + requestOptions.getMaxRetries().get())) + .build(); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + return new ApiClientHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, TokenizeResponse.class), response); + } + try { + switch (response.code()) { + case 400: + throw new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 401: + throw new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 404: + throw new NotFoundError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + case 500: + throw new InternalServerError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, ErrorResponse.class), response); + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + throw new ApiClientApiException( + "Error with status code " + response.code(), response.code(), errorBody, response); + } catch (JsonProcessingException e) { + throw new ApiClientException("Failed to deserialize response: " + e.getMessage(), e); + } catch (IOException e) { + throw new ApiClientException("Network error executing HTTP request", e); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/TokensClient.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/TokensClient.java new file mode 100644 index 00000000..8fceb337 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/TokensClient.java @@ -0,0 +1,89 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.tokens; + +import com.skyflow.generated.rest.core.ClientOptions; +import com.skyflow.generated.rest.core.RequestOptions; +import com.skyflow.generated.rest.resources.tokens.requests.DeleteTokenRequest; +import com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest; +import com.skyflow.generated.rest.resources.tokens.requests.GetTokensFromValuesRequest; +import com.skyflow.generated.rest.resources.tokens.requests.TokenizeRequest; +import com.skyflow.generated.rest.types.DeleteTokenResponse; +import com.skyflow.generated.rest.types.DetokenizeResponse; +import com.skyflow.generated.rest.types.GetTokensFromValuesResponse; +import com.skyflow.generated.rest.types.TokenizeResponse; + +public class TokensClient { + protected final ClientOptions clientOptions; + + private final RawTokensClient rawClient; + + public TokensClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.rawClient = new RawTokensClient(clientOptions); + } + + /** + * Get responses with HTTP metadata like headers + */ + public RawTokensClient withRawResponse() { + return this.rawClient; + } + + /** + * Returns the deterministic token previously issued for each supplied plaintext value within the specified token group. Only applicable to deterministic tokengroups. + */ + public GetTokensFromValuesResponse getTokens(GetTokensFromValuesRequest request) { + return this.rawClient.getTokens(request).body(); + } + + /** + * Returns the deterministic token previously issued for each supplied plaintext value within the specified token group. Only applicable to deterministic tokengroups. + */ + public GetTokensFromValuesResponse getTokens(GetTokensFromValuesRequest request, RequestOptions requestOptions) { + return this.rawClient.getTokens(request, requestOptions).body(); + } + + /** + * Deletes tokens from the vault. + */ + public DeleteTokenResponse deleteToken(DeleteTokenRequest request) { + return this.rawClient.deleteToken(request).body(); + } + + /** + * Deletes tokens from the vault. + */ + public DeleteTokenResponse deleteToken(DeleteTokenRequest request, RequestOptions requestOptions) { + return this.rawClient.deleteToken(request, requestOptions).body(); + } + + /** + * Returns values that correspond to the specified tokens. + */ + public DetokenizeResponse detokenize(DetokenizeRequest request) { + return this.rawClient.detokenize(request).body(); + } + + /** + * Returns values that correspond to the specified tokens. + */ + public DetokenizeResponse detokenize(DetokenizeRequest request, RequestOptions requestOptions) { + return this.rawClient.detokenize(request, requestOptions).body(); + } + + /** + * Returns tokens that correspond to the specified values. Only applicable to fields that use deterministic tokenization. + */ + public TokenizeResponse tokenize(TokenizeRequest request) { + return this.rawClient.tokenize(request).body(); + } + + /** + * Returns tokens that correspond to the specified values. Only applicable to fields that use deterministic tokenization. + */ + public TokenizeResponse tokenize(TokenizeRequest request, RequestOptions requestOptions) { + return this.rawClient.tokenize(request, requestOptions).body(); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/DeleteTokenRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/DeleteTokenRequest.java new file mode 100644 index 00000000..61f59fa4 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/DeleteTokenRequest.java @@ -0,0 +1,189 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.tokens.requests; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = DeleteTokenRequest.Builder.class) +public final class DeleteTokenRequest { + private final String vaultId; + + private final List tokens; + + private final Map additionalProperties; + + private DeleteTokenRequest(String vaultId, List tokens, Map additionalProperties) { + this.vaultId = vaultId; + this.tokens = tokens; + this.additionalProperties = additionalProperties; + } + + /** + * @return ID of the vault. + */ + @JsonProperty("vaultID") + public String getVaultId() { + return vaultId; + } + + /** + * @return Tokens to delete. + */ + @JsonProperty("tokens") + public List getTokens() { + return tokens; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof DeleteTokenRequest && equalTo((DeleteTokenRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(DeleteTokenRequest other) { + return vaultId.equals(other.vaultId) && tokens.equals(other.tokens); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.vaultId, this.tokens); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static VaultIdStage builder() { + return new Builder(); + } + + public interface VaultIdStage { + /** + *

ID of the vault.

+ */ + _FinalStage vaultId(@NotNull String vaultId); + + Builder from(DeleteTokenRequest other); + } + + public interface _FinalStage { + DeleteTokenRequest build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + /** + *

Tokens to delete.

+ */ + _FinalStage tokens(List tokens); + + _FinalStage addTokens(String tokens); + + _FinalStage addAllTokens(List tokens); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements VaultIdStage, _FinalStage { + private String vaultId; + + private List tokens = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(DeleteTokenRequest other) { + vaultId(other.getVaultId()); + tokens(other.getTokens()); + return this; + } + + /** + *

ID of the vault.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("vaultID") + public _FinalStage vaultId(@NotNull String vaultId) { + this.vaultId = Objects.requireNonNull(vaultId, "vaultId must not be null"); + return this; + } + + /** + *

Tokens to delete.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addAllTokens(List tokens) { + if (tokens != null) { + this.tokens.addAll(tokens); + } + return this; + } + + /** + *

Tokens to delete.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addTokens(String tokens) { + this.tokens.add(tokens); + return this; + } + + /** + *

Tokens to delete.

+ */ + @java.lang.Override + @JsonSetter(value = "tokens", nulls = Nulls.SKIP) + public _FinalStage tokens(List tokens) { + this.tokens.clear(); + if (tokens != null) { + this.tokens.addAll(tokens); + } + return this; + } + + @java.lang.Override + public DeleteTokenRequest build() { + return new DeleteTokenRequest(vaultId, tokens, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/DetokenizeRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/DetokenizeRequest.java new file mode 100644 index 00000000..3424acdc --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/DetokenizeRequest.java @@ -0,0 +1,238 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.tokens.requests; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.types.TokenGroupRedactions; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = DetokenizeRequest.Builder.class) +public final class DetokenizeRequest { + private final String vaultId; + + private final List tokens; + + private final Optional> tokenGroupRedactions; + + private final Map additionalProperties; + + private DetokenizeRequest( + String vaultId, + List tokens, + Optional> tokenGroupRedactions, + Map additionalProperties) { + this.vaultId = vaultId; + this.tokens = tokens; + this.tokenGroupRedactions = tokenGroupRedactions; + this.additionalProperties = additionalProperties; + } + + /** + * @return ID of the vault. + */ + @JsonProperty("vaultID") + public String getVaultId() { + return vaultId; + } + + /** + * @return Token to be detokenized + */ + @JsonProperty("tokens") + public List getTokens() { + return tokens; + } + + /** + * @return List of token groups to redact. + */ + @JsonProperty("tokenGroupRedactions") + public Optional> getTokenGroupRedactions() { + return tokenGroupRedactions; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof DetokenizeRequest && equalTo((DetokenizeRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(DetokenizeRequest other) { + return vaultId.equals(other.vaultId) + && tokens.equals(other.tokens) + && tokenGroupRedactions.equals(other.tokenGroupRedactions); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.vaultId, this.tokens, this.tokenGroupRedactions); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static VaultIdStage builder() { + return new Builder(); + } + + public interface VaultIdStage { + /** + *

ID of the vault.

+ */ + _FinalStage vaultId(@NotNull String vaultId); + + Builder from(DetokenizeRequest other); + } + + public interface _FinalStage { + DetokenizeRequest build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + /** + *

Token to be detokenized

+ */ + _FinalStage tokens(List tokens); + + _FinalStage addTokens(String tokens); + + _FinalStage addAllTokens(List tokens); + + /** + *

List of token groups to redact.

+ */ + _FinalStage tokenGroupRedactions(Optional> tokenGroupRedactions); + + _FinalStage tokenGroupRedactions(List tokenGroupRedactions); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements VaultIdStage, _FinalStage { + private String vaultId; + + private Optional> tokenGroupRedactions = Optional.empty(); + + private List tokens = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(DetokenizeRequest other) { + vaultId(other.getVaultId()); + tokens(other.getTokens()); + tokenGroupRedactions(other.getTokenGroupRedactions()); + return this; + } + + /** + *

ID of the vault.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("vaultID") + public _FinalStage vaultId(@NotNull String vaultId) { + this.vaultId = Objects.requireNonNull(vaultId, "vaultId must not be null"); + return this; + } + + /** + *

List of token groups to redact.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage tokenGroupRedactions(List tokenGroupRedactions) { + this.tokenGroupRedactions = Optional.ofNullable(tokenGroupRedactions); + return this; + } + + /** + *

List of token groups to redact.

+ */ + @java.lang.Override + @JsonSetter(value = "tokenGroupRedactions", nulls = Nulls.SKIP) + public _FinalStage tokenGroupRedactions(Optional> tokenGroupRedactions) { + this.tokenGroupRedactions = tokenGroupRedactions; + return this; + } + + /** + *

Token to be detokenized

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addAllTokens(List tokens) { + if (tokens != null) { + this.tokens.addAll(tokens); + } + return this; + } + + /** + *

Token to be detokenized

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addTokens(String tokens) { + this.tokens.add(tokens); + return this; + } + + /** + *

Token to be detokenized

+ */ + @java.lang.Override + @JsonSetter(value = "tokens", nulls = Nulls.SKIP) + public _FinalStage tokens(List tokens) { + this.tokens.clear(); + if (tokens != null) { + this.tokens.addAll(tokens); + } + return this; + } + + @java.lang.Override + public DetokenizeRequest build() { + return new DetokenizeRequest(vaultId, tokens, tokenGroupRedactions, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/GetTokensFromValuesRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/GetTokensFromValuesRequest.java new file mode 100644 index 00000000..ffa9160b --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/GetTokensFromValuesRequest.java @@ -0,0 +1,191 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.tokens.requests; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.types.GetTokensFromValuesRequestObject; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = GetTokensFromValuesRequest.Builder.class) +public final class GetTokensFromValuesRequest { + private final String vaultId; + + private final List records; + + private final Map additionalProperties; + + private GetTokensFromValuesRequest( + String vaultId, List records, Map additionalProperties) { + this.vaultId = vaultId; + this.records = records; + this.additionalProperties = additionalProperties; + } + + /** + * @return ID of the vault. + */ + @JsonProperty("vaultID") + public String getVaultId() { + return vaultId; + } + + /** + * @return Array of value/token-group pairs to look up. + */ + @JsonProperty("records") + public List getRecords() { + return records; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof GetTokensFromValuesRequest && equalTo((GetTokensFromValuesRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(GetTokensFromValuesRequest other) { + return vaultId.equals(other.vaultId) && records.equals(other.records); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.vaultId, this.records); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static VaultIdStage builder() { + return new Builder(); + } + + public interface VaultIdStage { + /** + *

ID of the vault.

+ */ + _FinalStage vaultId(@NotNull String vaultId); + + Builder from(GetTokensFromValuesRequest other); + } + + public interface _FinalStage { + GetTokensFromValuesRequest build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + /** + *

Array of value/token-group pairs to look up.

+ */ + _FinalStage records(List records); + + _FinalStage addRecords(GetTokensFromValuesRequestObject records); + + _FinalStage addAllRecords(List records); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements VaultIdStage, _FinalStage { + private String vaultId; + + private List records = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(GetTokensFromValuesRequest other) { + vaultId(other.getVaultId()); + records(other.getRecords()); + return this; + } + + /** + *

ID of the vault.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("vaultID") + public _FinalStage vaultId(@NotNull String vaultId) { + this.vaultId = Objects.requireNonNull(vaultId, "vaultId must not be null"); + return this; + } + + /** + *

Array of value/token-group pairs to look up.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addAllRecords(List records) { + if (records != null) { + this.records.addAll(records); + } + return this; + } + + /** + *

Array of value/token-group pairs to look up.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addRecords(GetTokensFromValuesRequestObject records) { + this.records.add(records); + return this; + } + + /** + *

Array of value/token-group pairs to look up.

+ */ + @java.lang.Override + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public _FinalStage records(List records) { + this.records.clear(); + if (records != null) { + this.records.addAll(records); + } + return this; + } + + @java.lang.Override + public GetTokensFromValuesRequest build() { + return new GetTokensFromValuesRequest(vaultId, records, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/TokenizeRequest.java b/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/TokenizeRequest.java new file mode 100644 index 00000000..7aab1a72 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/resources/tokens/requests/TokenizeRequest.java @@ -0,0 +1,191 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.resources.tokens.requests; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.types.TokenizeRequestObject; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = TokenizeRequest.Builder.class) +public final class TokenizeRequest { + private final String vaultId; + + private final List data; + + private final Map additionalProperties; + + private TokenizeRequest( + String vaultId, List data, Map additionalProperties) { + this.vaultId = vaultId; + this.data = data; + this.additionalProperties = additionalProperties; + } + + /** + * @return ID of the vault. + */ + @JsonProperty("vaultID") + public String getVaultId() { + return vaultId; + } + + /** + * @return Data to tokenize. + */ + @JsonProperty("data") + public List getData() { + return data; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof TokenizeRequest && equalTo((TokenizeRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(TokenizeRequest other) { + return vaultId.equals(other.vaultId) && data.equals(other.data); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.vaultId, this.data); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static VaultIdStage builder() { + return new Builder(); + } + + public interface VaultIdStage { + /** + *

ID of the vault.

+ */ + _FinalStage vaultId(@NotNull String vaultId); + + Builder from(TokenizeRequest other); + } + + public interface _FinalStage { + TokenizeRequest build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + /** + *

Data to tokenize.

+ */ + _FinalStage data(List data); + + _FinalStage addData(TokenizeRequestObject data); + + _FinalStage addAllData(List data); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements VaultIdStage, _FinalStage { + private String vaultId; + + private List data = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(TokenizeRequest other) { + vaultId(other.getVaultId()); + data(other.getData()); + return this; + } + + /** + *

ID of the vault.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("vaultID") + public _FinalStage vaultId(@NotNull String vaultId) { + this.vaultId = Objects.requireNonNull(vaultId, "vaultId must not be null"); + return this; + } + + /** + *

Data to tokenize.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addAllData(List data) { + if (data != null) { + this.data.addAll(data); + } + return this; + } + + /** + *

Data to tokenize.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addData(TokenizeRequestObject data) { + this.data.add(data); + return this; + } + + /** + *

Data to tokenize.

+ */ + @java.lang.Override + @JsonSetter(value = "data", nulls = Nulls.SKIP) + public _FinalStage data(List data) { + this.data.clear(); + if (data != null) { + this.data.addAll(data); + } + return this; + } + + @java.lang.Override + public TokenizeRequest build() { + return new TokenizeRequest(vaultId, data, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/ColumnRedactions.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/ColumnRedactions.java new file mode 100644 index 00000000..d445af16 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/ColumnRedactions.java @@ -0,0 +1,160 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = ColumnRedactions.Builder.class) +public final class ColumnRedactions { + private final String columnName; + + private final String redaction; + + private final Map additionalProperties; + + private ColumnRedactions(String columnName, String redaction, Map additionalProperties) { + this.columnName = columnName; + this.redaction = redaction; + this.additionalProperties = additionalProperties; + } + + /** + * @return Name of the column to redact. + */ + @JsonProperty("columnName") + public String getColumnName() { + return columnName; + } + + /** + * @return Name of the redaction type. + */ + @JsonProperty("redaction") + public String getRedaction() { + return redaction; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof ColumnRedactions && equalTo((ColumnRedactions) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(ColumnRedactions other) { + return columnName.equals(other.columnName) && redaction.equals(other.redaction); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.columnName, this.redaction); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static ColumnNameStage builder() { + return new Builder(); + } + + public interface ColumnNameStage { + /** + *

Name of the column to redact.

+ */ + RedactionStage columnName(@NotNull String columnName); + + Builder from(ColumnRedactions other); + } + + public interface RedactionStage { + /** + *

Name of the redaction type.

+ */ + _FinalStage redaction(@NotNull String redaction); + } + + public interface _FinalStage { + ColumnRedactions build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements ColumnNameStage, RedactionStage, _FinalStage { + private String columnName; + + private String redaction; + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(ColumnRedactions other) { + columnName(other.getColumnName()); + redaction(other.getRedaction()); + return this; + } + + /** + *

Name of the column to redact.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("columnName") + public RedactionStage columnName(@NotNull String columnName) { + this.columnName = Objects.requireNonNull(columnName, "columnName must not be null"); + return this; + } + + /** + *

Name of the redaction type.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("redaction") + public _FinalStage redaction(@NotNull String redaction) { + this.redaction = Objects.requireNonNull(redaction, "redaction must not be null"); + return this; + } + + @java.lang.Override + public ColumnRedactions build() { + return new ColumnRedactions(columnName, redaction, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/DeleteResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/DeleteResponse.java new file mode 100644 index 00000000..8b2845c5 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/DeleteResponse.java @@ -0,0 +1,122 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = DeleteResponse.Builder.class) +public final class DeleteResponse { + private final List records; + + private final Map additionalProperties; + + private DeleteResponse(List records, Map additionalProperties) { + this.records = records; + this.additionalProperties = additionalProperties; + } + + /** + * @return List of deleted records with skyflow ID and any partial errors. + */ + @JsonProperty("records") + public List getRecords() { + return records; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof DeleteResponse && equalTo((DeleteResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(DeleteResponse other) { + return records.equals(other.records); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.records); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private List records = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(DeleteResponse other) { + records(other.getRecords()); + return this; + } + + /** + *

List of deleted records with skyflow ID and any partial errors.

+ */ + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public Builder records(List records) { + this.records.clear(); + if (records != null) { + this.records.addAll(records); + } + return this; + } + + public Builder addRecords(DeleteResponseObject records) { + this.records.add(records); + return this; + } + + public Builder addAllRecords(List records) { + if (records != null) { + this.records.addAll(records); + } + return this; + } + + public DeleteResponse build() { + return new DeleteResponse(records, additionalProperties); + } + + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/DeleteResponseObject.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/DeleteResponseObject.java new file mode 100644 index 00000000..2b743afa --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/DeleteResponseObject.java @@ -0,0 +1,204 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = DeleteResponseObject.Builder.class) +public final class DeleteResponseObject { + private final String skyflowId; + + private final Optional error; + + private final int httpCode; + + private final Map additionalProperties; + + private DeleteResponseObject( + String skyflowId, Optional error, int httpCode, Map additionalProperties) { + this.skyflowId = skyflowId; + this.error = error; + this.httpCode = httpCode; + this.additionalProperties = additionalProperties; + } + + /** + * @return Skyflow ID of the deleted record. + */ + @JsonProperty("skyflowID") + public String getSkyflowId() { + return skyflowId; + } + + /** + * @return Error message, if any. + */ + @JsonProperty("error") + public Optional getError() { + return error; + } + + /** + * @return HTTP status code of the response. + */ + @JsonProperty("httpCode") + public int getHttpCode() { + return httpCode; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof DeleteResponseObject && equalTo((DeleteResponseObject) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(DeleteResponseObject other) { + return skyflowId.equals(other.skyflowId) && error.equals(other.error) && httpCode == other.httpCode; + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.skyflowId, this.error, this.httpCode); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static SkyflowIdStage builder() { + return new Builder(); + } + + public interface SkyflowIdStage { + /** + *

Skyflow ID of the deleted record.

+ */ + HttpCodeStage skyflowId(@NotNull String skyflowId); + + Builder from(DeleteResponseObject other); + } + + public interface HttpCodeStage { + /** + *

HTTP status code of the response.

+ */ + _FinalStage httpCode(int httpCode); + } + + public interface _FinalStage { + DeleteResponseObject build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + /** + *

Error message, if any.

+ */ + _FinalStage error(Optional error); + + _FinalStage error(String error); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements SkyflowIdStage, HttpCodeStage, _FinalStage { + private String skyflowId; + + private int httpCode; + + private Optional error = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(DeleteResponseObject other) { + skyflowId(other.getSkyflowId()); + error(other.getError()); + httpCode(other.getHttpCode()); + return this; + } + + /** + *

Skyflow ID of the deleted record.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("skyflowID") + public HttpCodeStage skyflowId(@NotNull String skyflowId) { + this.skyflowId = Objects.requireNonNull(skyflowId, "skyflowId must not be null"); + return this; + } + + /** + *

HTTP status code of the response.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("httpCode") + public _FinalStage httpCode(int httpCode) { + this.httpCode = httpCode; + return this; + } + + /** + *

Error message, if any.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage error(String error) { + this.error = Optional.ofNullable(error); + return this; + } + + /** + *

Error message, if any.

+ */ + @java.lang.Override + @JsonSetter(value = "error", nulls = Nulls.SKIP) + public _FinalStage error(Optional error) { + this.error = error; + return this; + } + + @java.lang.Override + public DeleteResponseObject build() { + return new DeleteResponseObject(skyflowId, error, httpCode, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/DeleteTokenResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/DeleteTokenResponse.java new file mode 100644 index 00000000..d651c5d9 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/DeleteTokenResponse.java @@ -0,0 +1,122 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = DeleteTokenResponse.Builder.class) +public final class DeleteTokenResponse { + private final List tokens; + + private final Map additionalProperties; + + private DeleteTokenResponse(List tokens, Map additionalProperties) { + this.tokens = tokens; + this.additionalProperties = additionalProperties; + } + + /** + * @return Tokens data for Delete + */ + @JsonProperty("tokens") + public List getTokens() { + return tokens; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof DeleteTokenResponse && equalTo((DeleteTokenResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(DeleteTokenResponse other) { + return tokens.equals(other.tokens); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.tokens); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private List tokens = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(DeleteTokenResponse other) { + tokens(other.getTokens()); + return this; + } + + /** + *

Tokens data for Delete

+ */ + @JsonSetter(value = "tokens", nulls = Nulls.SKIP) + public Builder tokens(List tokens) { + this.tokens.clear(); + if (tokens != null) { + this.tokens.addAll(tokens); + } + return this; + } + + public Builder addTokens(DeleteTokenResponseObject tokens) { + this.tokens.add(tokens); + return this; + } + + public Builder addAllTokens(List tokens) { + if (tokens != null) { + this.tokens.addAll(tokens); + } + return this; + } + + public DeleteTokenResponse build() { + return new DeleteTokenResponse(tokens, additionalProperties); + } + + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteTokenResponseObject.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/DeleteTokenResponseObject.java similarity index 68% rename from flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteTokenResponseObject.java rename to flowvault/src/main/java/com/skyflow/generated/rest/types/DeleteTokenResponseObject.java index f2e1dacd..cd3c1698 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteTokenResponseObject.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/DeleteTokenResponseObject.java @@ -3,18 +3,23 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1DeleteTokenResponseObject.Builder.class) -public final class V1DeleteTokenResponseObject { +@JsonDeserialize(builder = DeleteTokenResponseObject.Builder.class) +public final class DeleteTokenResponseObject { private final Optional value; private final Optional error; @@ -23,7 +28,7 @@ public final class V1DeleteTokenResponseObject { private final Map additionalProperties; - private V1DeleteTokenResponseObject( + private DeleteTokenResponseObject( Optional value, Optional error, Optional httpCode, @@ -35,7 +40,7 @@ private V1DeleteTokenResponseObject( } /** - * @return Token value + * @return Token to be deleted. */ @JsonProperty("value") public Optional getValue() { @@ -43,7 +48,7 @@ public Optional getValue() { } /** - * @return Error if deletion failed + * @return Error message, if any. */ @JsonProperty("error") public Optional getError() { @@ -51,17 +56,17 @@ public Optional getError() { } /** - * @return HTTP status code of the response + * @return HTTP status code of the response. */ @JsonProperty("httpCode") public Optional getHttpCode() { return httpCode; } - @Override + @java.lang.Override public boolean equals(Object other) { if (this == other) return true; - return other instanceof V1DeleteTokenResponseObject && equalTo((V1DeleteTokenResponseObject) other); + return other instanceof DeleteTokenResponseObject && equalTo((DeleteTokenResponseObject) other); } @JsonAnyGetter @@ -69,16 +74,16 @@ public Map getAdditionalProperties() { return this.additionalProperties; } - private boolean equalTo(V1DeleteTokenResponseObject other) { + private boolean equalTo(DeleteTokenResponseObject other) { return value.equals(other.value) && error.equals(other.error) && httpCode.equals(other.httpCode); } - @Override + @java.lang.Override public int hashCode() { return Objects.hash(this.value, this.error, this.httpCode); } - @Override + @java.lang.Override public String toString() { return ObjectMappers.stringify(this); } @@ -100,7 +105,7 @@ public static final class Builder { private Builder() {} - public Builder from(V1DeleteTokenResponseObject other) { + public Builder from(DeleteTokenResponseObject other) { value(other.getValue()); error(other.getError()); httpCode(other.getHttpCode()); @@ -108,7 +113,7 @@ public Builder from(V1DeleteTokenResponseObject other) { } /** - *

Token value

+ *

Token to be deleted.

*/ @JsonSetter(value = "value", nulls = Nulls.SKIP) public Builder value(Optional value) { @@ -122,7 +127,7 @@ public Builder value(String value) { } /** - *

Error if deletion failed

+ *

Error message, if any.

*/ @JsonSetter(value = "error", nulls = Nulls.SKIP) public Builder error(Optional error) { @@ -136,7 +141,7 @@ public Builder error(String error) { } /** - *

HTTP status code of the response

+ *

HTTP status code of the response.

*/ @JsonSetter(value = "httpCode", nulls = Nulls.SKIP) public Builder httpCode(Optional httpCode) { @@ -149,8 +154,18 @@ public Builder httpCode(Integer httpCode) { return this; } - public V1DeleteTokenResponseObject build() { - return new V1DeleteTokenResponseObject(value, error, httpCode, additionalProperties); + public DeleteTokenResponseObject build() { + return new DeleteTokenResponseObject(value, error, httpCode, additionalProperties); + } + + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; } } } diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/DetokenizeResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/DetokenizeResponse.java new file mode 100644 index 00000000..65cfea4e --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/DetokenizeResponse.java @@ -0,0 +1,122 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = DetokenizeResponse.Builder.class) +public final class DetokenizeResponse { + private final List response; + + private final Map additionalProperties; + + private DetokenizeResponse(List response, Map additionalProperties) { + this.response = response; + this.additionalProperties = additionalProperties; + } + + /** + * @return Detokenized data + */ + @JsonProperty("response") + public List getResponse() { + return response; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof DetokenizeResponse && equalTo((DetokenizeResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(DetokenizeResponse other) { + return response.equals(other.response); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.response); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private List response = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(DetokenizeResponse other) { + response(other.getResponse()); + return this; + } + + /** + *

Detokenized data

+ */ + @JsonSetter(value = "response", nulls = Nulls.SKIP) + public Builder response(List response) { + this.response.clear(); + if (response != null) { + this.response.addAll(response); + } + return this; + } + + public Builder addResponse(DetokenizeResponseObject response) { + this.response.add(response); + return this; + } + + public Builder addAllResponse(List response) { + if (response != null) { + this.response.addAll(response); + } + return this; + } + + public DetokenizeResponse build() { + return new DetokenizeResponse(response, additionalProperties); + } + + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/DetokenizeResponseObject.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/DetokenizeResponseObject.java new file mode 100644 index 00000000..1848b425 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/DetokenizeResponseObject.java @@ -0,0 +1,335 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = DetokenizeResponseObject.Builder.class) +public final class DetokenizeResponseObject { + private final String token; + + private final Optional value; + + private final Optional tokenGroupName; + + private final Optional error; + + private final Optional httpCode; + + private final Optional> metadata; + + private final Map additionalProperties; + + private DetokenizeResponseObject( + String token, + Optional value, + Optional tokenGroupName, + Optional error, + Optional httpCode, + Optional> metadata, + Map additionalProperties) { + this.token = token; + this.value = value; + this.tokenGroupName = tokenGroupName; + this.error = error; + this.httpCode = httpCode; + this.metadata = metadata; + this.additionalProperties = additionalProperties; + } + + /** + * @return Token that was detokenized. + */ + @JsonProperty("token") + public String getToken() { + return token; + } + + @JsonProperty("value") + public Optional getValue() { + return value; + } + + /** + * @return Name of the token group. + */ + @JsonProperty("tokenGroupName") + public Optional getTokenGroupName() { + return tokenGroupName; + } + + /** + * @return Error message, if any. + */ + @JsonProperty("error") + public Optional getError() { + return error; + } + + /** + * @return HTTP status code of the response. + */ + @JsonProperty("httpCode") + public Optional getHttpCode() { + return httpCode; + } + + /** + * @return Additional metadata associated with the token, such as tableName or skyflowID. + */ + @JsonProperty("metadata") + public Optional> getMetadata() { + return metadata; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof DetokenizeResponseObject && equalTo((DetokenizeResponseObject) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(DetokenizeResponseObject other) { + return token.equals(other.token) + && value.equals(other.value) + && tokenGroupName.equals(other.tokenGroupName) + && error.equals(other.error) + && httpCode.equals(other.httpCode) + && metadata.equals(other.metadata); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.token, this.value, this.tokenGroupName, this.error, this.httpCode, this.metadata); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static TokenStage builder() { + return new Builder(); + } + + public interface TokenStage { + /** + *

Token that was detokenized.

+ */ + _FinalStage token(@NotNull String token); + + Builder from(DetokenizeResponseObject other); + } + + public interface _FinalStage { + DetokenizeResponseObject build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + _FinalStage value(Optional value); + + _FinalStage value(GoogleProtobufValue value); + + /** + *

Name of the token group.

+ */ + _FinalStage tokenGroupName(Optional tokenGroupName); + + _FinalStage tokenGroupName(String tokenGroupName); + + /** + *

Error message, if any.

+ */ + _FinalStage error(Optional error); + + _FinalStage error(String error); + + /** + *

HTTP status code of the response.

+ */ + _FinalStage httpCode(Optional httpCode); + + _FinalStage httpCode(Integer httpCode); + + /** + *

Additional metadata associated with the token, such as tableName or skyflowID.

+ */ + _FinalStage metadata(Optional> metadata); + + _FinalStage metadata(Map metadata); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements TokenStage, _FinalStage { + private String token; + + private Optional> metadata = Optional.empty(); + + private Optional httpCode = Optional.empty(); + + private Optional error = Optional.empty(); + + private Optional tokenGroupName = Optional.empty(); + + private Optional value = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(DetokenizeResponseObject other) { + token(other.getToken()); + value(other.getValue()); + tokenGroupName(other.getTokenGroupName()); + error(other.getError()); + httpCode(other.getHttpCode()); + metadata(other.getMetadata()); + return this; + } + + /** + *

Token that was detokenized.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("token") + public _FinalStage token(@NotNull String token) { + this.token = Objects.requireNonNull(token, "token must not be null"); + return this; + } + + /** + *

Additional metadata associated with the token, such as tableName or skyflowID.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage metadata(Map metadata) { + this.metadata = Optional.ofNullable(metadata); + return this; + } + + /** + *

Additional metadata associated with the token, such as tableName or skyflowID.

+ */ + @java.lang.Override + @JsonSetter(value = "metadata", nulls = Nulls.SKIP) + public _FinalStage metadata(Optional> metadata) { + this.metadata = metadata; + return this; + } + + /** + *

HTTP status code of the response.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage httpCode(Integer httpCode) { + this.httpCode = Optional.ofNullable(httpCode); + return this; + } + + /** + *

HTTP status code of the response.

+ */ + @java.lang.Override + @JsonSetter(value = "httpCode", nulls = Nulls.SKIP) + public _FinalStage httpCode(Optional httpCode) { + this.httpCode = httpCode; + return this; + } + + /** + *

Error message, if any.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage error(String error) { + this.error = Optional.ofNullable(error); + return this; + } + + /** + *

Error message, if any.

+ */ + @java.lang.Override + @JsonSetter(value = "error", nulls = Nulls.SKIP) + public _FinalStage error(Optional error) { + this.error = error; + return this; + } + + /** + *

Name of the token group.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage tokenGroupName(String tokenGroupName) { + this.tokenGroupName = Optional.ofNullable(tokenGroupName); + return this; + } + + /** + *

Name of the token group.

+ */ + @java.lang.Override + @JsonSetter(value = "tokenGroupName", nulls = Nulls.SKIP) + public _FinalStage tokenGroupName(Optional tokenGroupName) { + this.tokenGroupName = tokenGroupName; + return this; + } + + @java.lang.Override + public _FinalStage value(GoogleProtobufValue value) { + this.value = Optional.ofNullable(value); + return this; + } + + @java.lang.Override + @JsonSetter(value = "value", nulls = Nulls.SKIP) + public _FinalStage value(Optional value) { + this.value = value; + return this; + } + + @java.lang.Override + public DetokenizeResponseObject build() { + return new DetokenizeResponseObject( + token, value, tokenGroupName, error, httpCode, metadata, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/ErrorResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/ErrorResponse.java new file mode 100644 index 00000000..3becce63 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/ErrorResponse.java @@ -0,0 +1,118 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = ErrorResponse.Builder.class) +public final class ErrorResponse { + private final ErrorResponseError error; + + private final Map additionalProperties; + + private ErrorResponse(ErrorResponseError error, Map additionalProperties) { + this.error = error; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("error") + public ErrorResponseError getError() { + return error; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof ErrorResponse && equalTo((ErrorResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(ErrorResponse other) { + return error.equals(other.error); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.error); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static ErrorStage builder() { + return new Builder(); + } + + public interface ErrorStage { + _FinalStage error(@NotNull ErrorResponseError error); + + Builder from(ErrorResponse other); + } + + public interface _FinalStage { + ErrorResponse build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements ErrorStage, _FinalStage { + private ErrorResponseError error; + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(ErrorResponse other) { + error(other.getError()); + return this; + } + + @java.lang.Override + @JsonSetter("error") + public _FinalStage error(@NotNull ErrorResponseError error) { + this.error = Objects.requireNonNull(error, "error must not be null"); + return this; + } + + @java.lang.Override + public ErrorResponse build() { + return new ErrorResponse(error, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/ErrorResponseError.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/ErrorResponseError.java new file mode 100644 index 00000000..a10d36cc --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/ErrorResponseError.java @@ -0,0 +1,236 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = ErrorResponseError.Builder.class) +public final class ErrorResponseError { + private final int grpcCode; + + private final int httpCode; + + private final String httpStatus; + + private final String message; + + private final Optional>> details; + + private final Map additionalProperties; + + private ErrorResponseError( + int grpcCode, + int httpCode, + String httpStatus, + String message, + Optional>> details, + Map additionalProperties) { + this.grpcCode = grpcCode; + this.httpCode = httpCode; + this.httpStatus = httpStatus; + this.message = message; + this.details = details; + this.additionalProperties = additionalProperties; + } + + /** + * @return gRPC status codes. See https://grpc.io/docs/guides/status-codes. + */ + @JsonProperty("grpc_code") + public int getGrpcCode() { + return grpcCode; + } + + @JsonProperty("http_code") + public int getHttpCode() { + return httpCode; + } + + @JsonProperty("http_status") + public String getHttpStatus() { + return httpStatus; + } + + @JsonProperty("message") + public String getMessage() { + return message; + } + + @JsonProperty("details") + public Optional>> getDetails() { + return details; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof ErrorResponseError && equalTo((ErrorResponseError) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(ErrorResponseError other) { + return grpcCode == other.grpcCode + && httpCode == other.httpCode + && httpStatus.equals(other.httpStatus) + && message.equals(other.message) + && details.equals(other.details); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.grpcCode, this.httpCode, this.httpStatus, this.message, this.details); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static GrpcCodeStage builder() { + return new Builder(); + } + + public interface GrpcCodeStage { + /** + *

gRPC status codes. See https://grpc.io/docs/guides/status-codes.

+ */ + HttpCodeStage grpcCode(int grpcCode); + + Builder from(ErrorResponseError other); + } + + public interface HttpCodeStage { + HttpStatusStage httpCode(int httpCode); + } + + public interface HttpStatusStage { + MessageStage httpStatus(@NotNull String httpStatus); + } + + public interface MessageStage { + _FinalStage message(@NotNull String message); + } + + public interface _FinalStage { + ErrorResponseError build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + _FinalStage details(Optional>> details); + + _FinalStage details(List> details); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder + implements GrpcCodeStage, HttpCodeStage, HttpStatusStage, MessageStage, _FinalStage { + private int grpcCode; + + private int httpCode; + + private String httpStatus; + + private String message; + + private Optional>> details = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(ErrorResponseError other) { + grpcCode(other.getGrpcCode()); + httpCode(other.getHttpCode()); + httpStatus(other.getHttpStatus()); + message(other.getMessage()); + details(other.getDetails()); + return this; + } + + /** + *

gRPC status codes. See https://grpc.io/docs/guides/status-codes.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("grpc_code") + public HttpCodeStage grpcCode(int grpcCode) { + this.grpcCode = grpcCode; + return this; + } + + @java.lang.Override + @JsonSetter("http_code") + public HttpStatusStage httpCode(int httpCode) { + this.httpCode = httpCode; + return this; + } + + @java.lang.Override + @JsonSetter("http_status") + public MessageStage httpStatus(@NotNull String httpStatus) { + this.httpStatus = Objects.requireNonNull(httpStatus, "httpStatus must not be null"); + return this; + } + + @java.lang.Override + @JsonSetter("message") + public _FinalStage message(@NotNull String message) { + this.message = Objects.requireNonNull(message, "message must not be null"); + return this; + } + + @java.lang.Override + public _FinalStage details(List> details) { + this.details = Optional.ofNullable(details); + return this; + } + + @java.lang.Override + @JsonSetter(value = "details", nulls = Nulls.SKIP) + public _FinalStage details(Optional>> details) { + this.details = details; + return this; + } + + @java.lang.Override + public ErrorResponseError build() { + return new ErrorResponseError(grpcCode, httpCode, httpStatus, message, details, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1UniqueValue.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/ExecuteQueryRecordResponse.java similarity index 56% rename from flowvault/src/main/java/com/skyflow/generated/rest/types/V1UniqueValue.java rename to flowvault/src/main/java/com/skyflow/generated/rest/types/ExecuteQueryRecordResponse.java index 3b188c6d..5c3433f4 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1UniqueValue.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/ExecuteQueryRecordResponse.java @@ -3,39 +3,44 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1UniqueValue.Builder.class) -public final class V1UniqueValue { +@JsonDeserialize(builder = ExecuteQueryRecordResponse.Builder.class) +public final class ExecuteQueryRecordResponse { private final Optional> data; private final Map additionalProperties; - private V1UniqueValue(Optional> data, Map additionalProperties) { + private ExecuteQueryRecordResponse(Optional> data, Map additionalProperties) { this.data = data; this.additionalProperties = additionalProperties; } /** - * @return Columns names and values for unique value entry + * @return Fields and values for the record. */ @JsonProperty("data") public Optional> getData() { return data; } - @Override + @java.lang.Override public boolean equals(Object other) { if (this == other) return true; - return other instanceof V1UniqueValue && equalTo((V1UniqueValue) other); + return other instanceof ExecuteQueryRecordResponse && equalTo((ExecuteQueryRecordResponse) other); } @JsonAnyGetter @@ -43,16 +48,16 @@ public Map getAdditionalProperties() { return this.additionalProperties; } - private boolean equalTo(V1UniqueValue other) { + private boolean equalTo(ExecuteQueryRecordResponse other) { return data.equals(other.data); } - @Override + @java.lang.Override public int hashCode() { return Objects.hash(this.data); } - @Override + @java.lang.Override public String toString() { return ObjectMappers.stringify(this); } @@ -70,13 +75,13 @@ public static final class Builder { private Builder() {} - public Builder from(V1UniqueValue other) { + public Builder from(ExecuteQueryRecordResponse other) { data(other.getData()); return this; } /** - *

Columns names and values for unique value entry

+ *

Fields and values for the record.

*/ @JsonSetter(value = "data", nulls = Nulls.SKIP) public Builder data(Optional> data) { @@ -89,8 +94,18 @@ public Builder data(Map data) { return this; } - public V1UniqueValue build() { - return new V1UniqueValue(data, additionalProperties); + public ExecuteQueryRecordResponse build() { + return new ExecuteQueryRecordResponse(data, additionalProperties); + } + + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; } } } diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/ExecuteQueryResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/ExecuteQueryResponse.java new file mode 100644 index 00000000..98eceffa --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/ExecuteQueryResponse.java @@ -0,0 +1,137 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = ExecuteQueryResponse.Builder.class) +public final class ExecuteQueryResponse { + private final Optional> records; + + private final Optional metadata; + + private final Map additionalProperties; + + private ExecuteQueryResponse( + Optional> records, + Optional metadata, + Map additionalProperties) { + this.records = records; + this.metadata = metadata; + this.additionalProperties = additionalProperties; + } + + /** + * @return Records corresponding to the specified query. + */ + @JsonProperty("records") + public Optional> getRecords() { + return records; + } + + @JsonProperty("metadata") + public Optional getMetadata() { + return metadata; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof ExecuteQueryResponse && equalTo((ExecuteQueryResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(ExecuteQueryResponse other) { + return records.equals(other.records) && metadata.equals(other.metadata); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.records, this.metadata); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional> records = Optional.empty(); + + private Optional metadata = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(ExecuteQueryResponse other) { + records(other.getRecords()); + metadata(other.getMetadata()); + return this; + } + + /** + *

Records corresponding to the specified query.

+ */ + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public Builder records(Optional> records) { + this.records = records; + return this; + } + + public Builder records(List records) { + this.records = Optional.ofNullable(records); + return this; + } + + @JsonSetter(value = "metadata", nulls = Nulls.SKIP) + public Builder metadata(Optional metadata) { + this.metadata = metadata; + return this; + } + + public Builder metadata(ExecuteQueryResponseMetadata metadata) { + this.metadata = Optional.ofNullable(metadata); + return this; + } + + public ExecuteQueryResponse build() { + return new ExecuteQueryResponse(records, metadata, additionalProperties); + } + + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryResponseMetadata.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/ExecuteQueryResponseMetadata.java similarity index 53% rename from flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryResponseMetadata.java rename to flowvault/src/main/java/com/skyflow/generated/rest/types/ExecuteQueryResponseMetadata.java index c23da3bd..0c98eaee 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryResponseMetadata.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/ExecuteQueryResponseMetadata.java @@ -3,36 +3,45 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1ExecuteQueryResponseMetadata.Builder.class) -public final class V1ExecuteQueryResponseMetadata { +@JsonDeserialize(builder = ExecuteQueryResponseMetadata.Builder.class) +public final class ExecuteQueryResponseMetadata { private final Optional> columns; private final Map additionalProperties; - private V1ExecuteQueryResponseMetadata(Optional> columns, Map additionalProperties) { + private ExecuteQueryResponseMetadata(Optional> columns, Map additionalProperties) { this.columns = columns; this.additionalProperties = additionalProperties; } /** - * @return Return columns for the query + * @return Columns returned for the query. */ @JsonProperty("columns") public Optional> getColumns() { return columns; } - @Override + @java.lang.Override public boolean equals(Object other) { if (this == other) return true; - return other instanceof V1ExecuteQueryResponseMetadata && equalTo((V1ExecuteQueryResponseMetadata) other); + return other instanceof ExecuteQueryResponseMetadata && equalTo((ExecuteQueryResponseMetadata) other); } @JsonAnyGetter @@ -40,16 +49,16 @@ public Map getAdditionalProperties() { return this.additionalProperties; } - private boolean equalTo(V1ExecuteQueryResponseMetadata other) { + private boolean equalTo(ExecuteQueryResponseMetadata other) { return columns.equals(other.columns); } - @Override + @java.lang.Override public int hashCode() { return Objects.hash(this.columns); } - @Override + @java.lang.Override public String toString() { return ObjectMappers.stringify(this); } @@ -67,13 +76,13 @@ public static final class Builder { private Builder() {} - public Builder from(V1ExecuteQueryResponseMetadata other) { + public Builder from(ExecuteQueryResponseMetadata other) { columns(other.getColumns()); return this; } /** - *

Return columns for the query

+ *

Columns returned for the query.

*/ @JsonSetter(value = "columns", nulls = Nulls.SKIP) public Builder columns(Optional> columns) { @@ -86,8 +95,18 @@ public Builder columns(List columns) { return this; } - public V1ExecuteQueryResponseMetadata build() { - return new V1ExecuteQueryResponseMetadata(columns, additionalProperties); + public ExecuteQueryResponseMetadata build() { + return new ExecuteQueryResponseMetadata(columns, additionalProperties); + } + + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; } } } diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/FileDeleteRecord.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/FileDeleteRecord.java new file mode 100644 index 00000000..5d3aad52 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/FileDeleteRecord.java @@ -0,0 +1,280 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = FileDeleteRecord.Builder.class) +public final class FileDeleteRecord { + private final String tableName; + + private final Optional skyflowId; + + private final List columns; + + private final Optional> uniqueValues; + + private final Map additionalProperties; + + private FileDeleteRecord( + String tableName, + Optional skyflowId, + List columns, + Optional> uniqueValues, + Map additionalProperties) { + this.tableName = tableName; + this.skyflowId = skyflowId; + this.columns = columns; + this.uniqueValues = uniqueValues; + this.additionalProperties = additionalProperties; + } + + /** + * @return Name of the table. + */ + @JsonProperty("tableName") + public String getTableName() { + return tableName; + } + + /** + * @return Skyflow ID of the record containing the file column(s) to delete. Either skyflowID or uniqueValues must be specified, not both. + */ + @JsonProperty("skyflowID") + public Optional getSkyflowId() { + return skyflowId; + } + + /** + * @return Names of the file columns to delete on this record. If any listed column has no file present, the request fails for this record. + */ + @JsonProperty("columns") + public List getColumns() { + return columns; + } + + /** + * @return List of unique constraint values used to look up the record(s) to delete, in place of skyflowID. If more than one object is provided, each is resolved independently and the specified columns are deleted from every matching record. + */ + @JsonProperty("uniqueValues") + public Optional> getUniqueValues() { + return uniqueValues; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof FileDeleteRecord && equalTo((FileDeleteRecord) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(FileDeleteRecord other) { + return tableName.equals(other.tableName) + && skyflowId.equals(other.skyflowId) + && columns.equals(other.columns) + && uniqueValues.equals(other.uniqueValues); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.tableName, this.skyflowId, this.columns, this.uniqueValues); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static TableNameStage builder() { + return new Builder(); + } + + public interface TableNameStage { + /** + *

Name of the table.

+ */ + _FinalStage tableName(@NotNull String tableName); + + Builder from(FileDeleteRecord other); + } + + public interface _FinalStage { + FileDeleteRecord build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + /** + *

Skyflow ID of the record containing the file column(s) to delete. Either skyflowID or uniqueValues must be specified, not both.

+ */ + _FinalStage skyflowId(Optional skyflowId); + + _FinalStage skyflowId(String skyflowId); + + /** + *

Names of the file columns to delete on this record. If any listed column has no file present, the request fails for this record.

+ */ + _FinalStage columns(List columns); + + _FinalStage addColumns(String columns); + + _FinalStage addAllColumns(List columns); + + /** + *

List of unique constraint values used to look up the record(s) to delete, in place of skyflowID. If more than one object is provided, each is resolved independently and the specified columns are deleted from every matching record.

+ */ + _FinalStage uniqueValues(Optional> uniqueValues); + + _FinalStage uniqueValues(List uniqueValues); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements TableNameStage, _FinalStage { + private String tableName; + + private Optional> uniqueValues = Optional.empty(); + + private List columns = new ArrayList<>(); + + private Optional skyflowId = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(FileDeleteRecord other) { + tableName(other.getTableName()); + skyflowId(other.getSkyflowId()); + columns(other.getColumns()); + uniqueValues(other.getUniqueValues()); + return this; + } + + /** + *

Name of the table.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("tableName") + public _FinalStage tableName(@NotNull String tableName) { + this.tableName = Objects.requireNonNull(tableName, "tableName must not be null"); + return this; + } + + /** + *

List of unique constraint values used to look up the record(s) to delete, in place of skyflowID. If more than one object is provided, each is resolved independently and the specified columns are deleted from every matching record.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage uniqueValues(List uniqueValues) { + this.uniqueValues = Optional.ofNullable(uniqueValues); + return this; + } + + /** + *

List of unique constraint values used to look up the record(s) to delete, in place of skyflowID. If more than one object is provided, each is resolved independently and the specified columns are deleted from every matching record.

+ */ + @java.lang.Override + @JsonSetter(value = "uniqueValues", nulls = Nulls.SKIP) + public _FinalStage uniqueValues(Optional> uniqueValues) { + this.uniqueValues = uniqueValues; + return this; + } + + /** + *

Names of the file columns to delete on this record. If any listed column has no file present, the request fails for this record.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addAllColumns(List columns) { + if (columns != null) { + this.columns.addAll(columns); + } + return this; + } + + /** + *

Names of the file columns to delete on this record. If any listed column has no file present, the request fails for this record.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addColumns(String columns) { + this.columns.add(columns); + return this; + } + + /** + *

Names of the file columns to delete on this record. If any listed column has no file present, the request fails for this record.

+ */ + @java.lang.Override + @JsonSetter(value = "columns", nulls = Nulls.SKIP) + public _FinalStage columns(List columns) { + this.columns.clear(); + if (columns != null) { + this.columns.addAll(columns); + } + return this; + } + + /** + *

Skyflow ID of the record containing the file column(s) to delete. Either skyflowID or uniqueValues must be specified, not both.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage skyflowId(String skyflowId) { + this.skyflowId = Optional.ofNullable(skyflowId); + return this; + } + + /** + *

Skyflow ID of the record containing the file column(s) to delete. Either skyflowID or uniqueValues must be specified, not both.

+ */ + @java.lang.Override + @JsonSetter(value = "skyflowID", nulls = Nulls.SKIP) + public _FinalStage skyflowId(Optional skyflowId) { + this.skyflowId = skyflowId; + return this; + } + + @java.lang.Override + public FileDeleteRecord build() { + return new FileDeleteRecord(tableName, skyflowId, columns, uniqueValues, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/FileDeleteResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/FileDeleteResponse.java new file mode 100644 index 00000000..5062fdf2 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/FileDeleteResponse.java @@ -0,0 +1,122 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = FileDeleteResponse.Builder.class) +public final class FileDeleteResponse { + private final List records; + + private final Map additionalProperties; + + private FileDeleteResponse(List records, Map additionalProperties) { + this.records = records; + this.additionalProperties = additionalProperties; + } + + /** + * @return List of records (max 100) with the result of the delete operation. + */ + @JsonProperty("records") + public List getRecords() { + return records; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof FileDeleteResponse && equalTo((FileDeleteResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(FileDeleteResponse other) { + return records.equals(other.records); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.records); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private List records = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(FileDeleteResponse other) { + records(other.getRecords()); + return this; + } + + /** + *

List of records (max 100) with the result of the delete operation.

+ */ + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public Builder records(List records) { + this.records.clear(); + if (records != null) { + this.records.addAll(records); + } + return this; + } + + public Builder addRecords(FileDeleteResponseObject records) { + this.records.add(records); + return this; + } + + public Builder addAllRecords(List records) { + if (records != null) { + this.records.addAll(records); + } + return this; + } + + public FileDeleteResponse build() { + return new FileDeleteResponse(records, additionalProperties); + } + + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/FileDeleteResponseObject.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/FileDeleteResponseObject.java new file mode 100644 index 00000000..61427130 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/FileDeleteResponseObject.java @@ -0,0 +1,295 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = FileDeleteResponseObject.Builder.class) +public final class FileDeleteResponseObject { + private final Optional skyflowId; + + private final String tableName; + + private final Optional> data; + + private final Optional error; + + private final int httpCode; + + private final Map additionalProperties; + + private FileDeleteResponseObject( + Optional skyflowId, + String tableName, + Optional> data, + Optional error, + int httpCode, + Map additionalProperties) { + this.skyflowId = skyflowId; + this.tableName = tableName; + this.data = data; + this.error = error; + this.httpCode = httpCode; + this.additionalProperties = additionalProperties; + } + + /** + * @return Skyflow ID of the record that was targeted. When the request specifies uniqueValues, this is the skyflowID resolved from the matching record. Null if the record failed validation before a skyflowID could be resolved. + */ + @JsonProperty("skyflowID") + public Optional getSkyflowId() { + return skyflowId; + } + + /** + * @return Name of the table. + */ + @JsonProperty("tableName") + public String getTableName() { + return tableName; + } + + /** + * @return Map of column name to deletion result. Populated only when the record's delete succeeds, with one entry per requested column with status DELETED. Null if any requested column has no file present, in which case error is populated instead. + */ + @JsonProperty("data") + public Optional> getData() { + return data; + } + + /** + * @return Error message describing any issue with the specific record. Null if no error occurred. + */ + @JsonProperty("error") + public Optional getError() { + return error; + } + + /** + * @return HTTP status code representing the result of the API request for this record. + */ + @JsonProperty("httpCode") + public int getHttpCode() { + return httpCode; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof FileDeleteResponseObject && equalTo((FileDeleteResponseObject) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(FileDeleteResponseObject other) { + return skyflowId.equals(other.skyflowId) + && tableName.equals(other.tableName) + && data.equals(other.data) + && error.equals(other.error) + && httpCode == other.httpCode; + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.skyflowId, this.tableName, this.data, this.error, this.httpCode); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static TableNameStage builder() { + return new Builder(); + } + + public interface TableNameStage { + /** + *

Name of the table.

+ */ + HttpCodeStage tableName(@NotNull String tableName); + + Builder from(FileDeleteResponseObject other); + } + + public interface HttpCodeStage { + /** + *

HTTP status code representing the result of the API request for this record.

+ */ + _FinalStage httpCode(int httpCode); + } + + public interface _FinalStage { + FileDeleteResponseObject build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + /** + *

Skyflow ID of the record that was targeted. When the request specifies uniqueValues, this is the skyflowID resolved from the matching record. Null if the record failed validation before a skyflowID could be resolved.

+ */ + _FinalStage skyflowId(Optional skyflowId); + + _FinalStage skyflowId(String skyflowId); + + /** + *

Map of column name to deletion result. Populated only when the record's delete succeeds, with one entry per requested column with status DELETED. Null if any requested column has no file present, in which case error is populated instead.

+ */ + _FinalStage data(Optional> data); + + _FinalStage data(Map data); + + /** + *

Error message describing any issue with the specific record. Null if no error occurred.

+ */ + _FinalStage error(Optional error); + + _FinalStage error(String error); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements TableNameStage, HttpCodeStage, _FinalStage { + private String tableName; + + private int httpCode; + + private Optional error = Optional.empty(); + + private Optional> data = Optional.empty(); + + private Optional skyflowId = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(FileDeleteResponseObject other) { + skyflowId(other.getSkyflowId()); + tableName(other.getTableName()); + data(other.getData()); + error(other.getError()); + httpCode(other.getHttpCode()); + return this; + } + + /** + *

Name of the table.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("tableName") + public HttpCodeStage tableName(@NotNull String tableName) { + this.tableName = Objects.requireNonNull(tableName, "tableName must not be null"); + return this; + } + + /** + *

HTTP status code representing the result of the API request for this record.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("httpCode") + public _FinalStage httpCode(int httpCode) { + this.httpCode = httpCode; + return this; + } + + /** + *

Error message describing any issue with the specific record. Null if no error occurred.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage error(String error) { + this.error = Optional.ofNullable(error); + return this; + } + + /** + *

Error message describing any issue with the specific record. Null if no error occurred.

+ */ + @java.lang.Override + @JsonSetter(value = "error", nulls = Nulls.SKIP) + public _FinalStage error(Optional error) { + this.error = error; + return this; + } + + /** + *

Map of column name to deletion result. Populated only when the record's delete succeeds, with one entry per requested column with status DELETED. Null if any requested column has no file present, in which case error is populated instead.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage data(Map data) { + this.data = Optional.ofNullable(data); + return this; + } + + /** + *

Map of column name to deletion result. Populated only when the record's delete succeeds, with one entry per requested column with status DELETED. Null if any requested column has no file present, in which case error is populated instead.

+ */ + @java.lang.Override + @JsonSetter(value = "data", nulls = Nulls.SKIP) + public _FinalStage data(Optional> data) { + this.data = data; + return this; + } + + /** + *

Skyflow ID of the record that was targeted. When the request specifies uniqueValues, this is the skyflowID resolved from the matching record. Null if the record failed validation before a skyflowID could be resolved.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage skyflowId(String skyflowId) { + this.skyflowId = Optional.ofNullable(skyflowId); + return this; + } + + /** + *

Skyflow ID of the record that was targeted. When the request specifies uniqueValues, this is the skyflowID resolved from the matching record. Null if the record failed validation before a skyflowID could be resolved.

+ */ + @java.lang.Override + @JsonSetter(value = "skyflowID", nulls = Nulls.SKIP) + public _FinalStage skyflowId(Optional skyflowId) { + this.skyflowId = skyflowId; + return this; + } + + @java.lang.Override + public FileDeleteResponseObject build() { + return new FileDeleteResponseObject(skyflowId, tableName, data, error, httpCode, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/FileUploadColumn.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/FileUploadColumn.java new file mode 100644 index 00000000..73d3f27e --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/FileUploadColumn.java @@ -0,0 +1,171 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = FileUploadColumn.Builder.class) +public final class FileUploadColumn { + private final String column; + + private final Optional fileName; + + private final Map additionalProperties; + + private FileUploadColumn(String column, Optional fileName, Map additionalProperties) { + this.column = column; + this.fileName = fileName; + this.additionalProperties = additionalProperties; + } + + /** + * @return Name of the column where the file is being uploaded. + */ + @JsonProperty("column") + public String getColumn() { + return column; + } + + /** + * @return Name of the file being uploaded to the file column. If not provided, a random 16-byte UUID name is generated. + */ + @JsonProperty("fileName") + public Optional getFileName() { + return fileName; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof FileUploadColumn && equalTo((FileUploadColumn) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(FileUploadColumn other) { + return column.equals(other.column) && fileName.equals(other.fileName); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.column, this.fileName); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static ColumnStage builder() { + return new Builder(); + } + + public interface ColumnStage { + /** + *

Name of the column where the file is being uploaded.

+ */ + _FinalStage column(@NotNull String column); + + Builder from(FileUploadColumn other); + } + + public interface _FinalStage { + FileUploadColumn build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + /** + *

Name of the file being uploaded to the file column. If not provided, a random 16-byte UUID name is generated.

+ */ + _FinalStage fileName(Optional fileName); + + _FinalStage fileName(String fileName); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements ColumnStage, _FinalStage { + private String column; + + private Optional fileName = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(FileUploadColumn other) { + column(other.getColumn()); + fileName(other.getFileName()); + return this; + } + + /** + *

Name of the column where the file is being uploaded.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("column") + public _FinalStage column(@NotNull String column) { + this.column = Objects.requireNonNull(column, "column must not be null"); + return this; + } + + /** + *

Name of the file being uploaded to the file column. If not provided, a random 16-byte UUID name is generated.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage fileName(String fileName) { + this.fileName = Optional.ofNullable(fileName); + return this; + } + + /** + *

Name of the file being uploaded to the file column. If not provided, a random 16-byte UUID name is generated.

+ */ + @java.lang.Override + @JsonSetter(value = "fileName", nulls = Nulls.SKIP) + public _FinalStage fileName(Optional fileName) { + this.fileName = fileName; + return this; + } + + @java.lang.Override + public FileUploadColumn build() { + return new FileUploadColumn(column, fileName, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/FileUploadRecord.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/FileUploadRecord.java new file mode 100644 index 00000000..976b0bfb --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/FileUploadRecord.java @@ -0,0 +1,235 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = FileUploadRecord.Builder.class) +public final class FileUploadRecord { + private final String tableName; + + private final Optional skyflowId; + + private final List columns; + + private final Map additionalProperties; + + private FileUploadRecord( + String tableName, + Optional skyflowId, + List columns, + Map additionalProperties) { + this.tableName = tableName; + this.skyflowId = skyflowId; + this.columns = columns; + this.additionalProperties = additionalProperties; + } + + /** + * @return Name of the table. + */ + @JsonProperty("tableName") + public String getTableName() { + return tableName; + } + + /** + * @return Skyflow ID of the record. If not provided, a new record is created and its skyflowID is used for the file upload. + */ + @JsonProperty("skyflowID") + public Optional getSkyflowId() { + return skyflowId; + } + + /** + * @return List of file columns to generate signed upload URLs for. + */ + @JsonProperty("columns") + public List getColumns() { + return columns; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof FileUploadRecord && equalTo((FileUploadRecord) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(FileUploadRecord other) { + return tableName.equals(other.tableName) && skyflowId.equals(other.skyflowId) && columns.equals(other.columns); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.tableName, this.skyflowId, this.columns); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static TableNameStage builder() { + return new Builder(); + } + + public interface TableNameStage { + /** + *

Name of the table.

+ */ + _FinalStage tableName(@NotNull String tableName); + + Builder from(FileUploadRecord other); + } + + public interface _FinalStage { + FileUploadRecord build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + /** + *

Skyflow ID of the record. If not provided, a new record is created and its skyflowID is used for the file upload.

+ */ + _FinalStage skyflowId(Optional skyflowId); + + _FinalStage skyflowId(String skyflowId); + + /** + *

List of file columns to generate signed upload URLs for.

+ */ + _FinalStage columns(List columns); + + _FinalStage addColumns(FileUploadColumn columns); + + _FinalStage addAllColumns(List columns); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements TableNameStage, _FinalStage { + private String tableName; + + private List columns = new ArrayList<>(); + + private Optional skyflowId = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(FileUploadRecord other) { + tableName(other.getTableName()); + skyflowId(other.getSkyflowId()); + columns(other.getColumns()); + return this; + } + + /** + *

Name of the table.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("tableName") + public _FinalStage tableName(@NotNull String tableName) { + this.tableName = Objects.requireNonNull(tableName, "tableName must not be null"); + return this; + } + + /** + *

List of file columns to generate signed upload URLs for.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addAllColumns(List columns) { + if (columns != null) { + this.columns.addAll(columns); + } + return this; + } + + /** + *

List of file columns to generate signed upload URLs for.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addColumns(FileUploadColumn columns) { + this.columns.add(columns); + return this; + } + + /** + *

List of file columns to generate signed upload URLs for.

+ */ + @java.lang.Override + @JsonSetter(value = "columns", nulls = Nulls.SKIP) + public _FinalStage columns(List columns) { + this.columns.clear(); + if (columns != null) { + this.columns.addAll(columns); + } + return this; + } + + /** + *

Skyflow ID of the record. If not provided, a new record is created and its skyflowID is used for the file upload.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage skyflowId(String skyflowId) { + this.skyflowId = Optional.ofNullable(skyflowId); + return this; + } + + /** + *

Skyflow ID of the record. If not provided, a new record is created and its skyflowID is used for the file upload.

+ */ + @java.lang.Override + @JsonSetter(value = "skyflowID", nulls = Nulls.SKIP) + public _FinalStage skyflowId(Optional skyflowId) { + this.skyflowId = skyflowId; + return this; + } + + @java.lang.Override + public FileUploadRecord build() { + return new FileUploadRecord(tableName, skyflowId, columns, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/FileUploadResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/FileUploadResponse.java new file mode 100644 index 00000000..6ef52d52 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/FileUploadResponse.java @@ -0,0 +1,122 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = FileUploadResponse.Builder.class) +public final class FileUploadResponse { + private final List records; + + private final Map additionalProperties; + + private FileUploadResponse(List records, Map additionalProperties) { + this.records = records; + this.additionalProperties = additionalProperties; + } + + /** + * @return List of records with signed upload URLs. + */ + @JsonProperty("records") + public List getRecords() { + return records; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof FileUploadResponse && equalTo((FileUploadResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(FileUploadResponse other) { + return records.equals(other.records); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.records); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private List records = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(FileUploadResponse other) { + records(other.getRecords()); + return this; + } + + /** + *

List of records with signed upload URLs.

+ */ + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public Builder records(List records) { + this.records.clear(); + if (records != null) { + this.records.addAll(records); + } + return this; + } + + public Builder addRecords(FileUploadResponseObject records) { + this.records.add(records); + return this; + } + + public Builder addAllRecords(List records) { + if (records != null) { + this.records.addAll(records); + } + return this; + } + + public FileUploadResponse build() { + return new FileUploadResponse(records, additionalProperties); + } + + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/FileUploadResponseObject.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/FileUploadResponseObject.java new file mode 100644 index 00000000..5a2d674c --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/FileUploadResponseObject.java @@ -0,0 +1,286 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = FileUploadResponseObject.Builder.class) +public final class FileUploadResponseObject { + private final String skyflowId; + + private final String tableName; + + private final Optional> data; + + private final Optional error; + + private final int httpCode; + + private final Map additionalProperties; + + private FileUploadResponseObject( + String skyflowId, + String tableName, + Optional> data, + Optional error, + int httpCode, + Map additionalProperties) { + this.skyflowId = skyflowId; + this.tableName = tableName; + this.data = data; + this.error = error; + this.httpCode = httpCode; + this.additionalProperties = additionalProperties; + } + + /** + * @return Skyflow ID of the record. A new skyflowID is returned if one was not provided in the request. + */ + @JsonProperty("skyflowID") + public String getSkyflowId() { + return skyflowId; + } + + /** + * @return Name of the table. + */ + @JsonProperty("tableName") + public String getTableName() { + return tableName; + } + + /** + * @return Map of column names to signed upload URLs. Each signed URL expires after 15 minutes by default. + */ + @JsonProperty("data") + public Optional> getData() { + return data; + } + + /** + * @return Error message describing any issue with the specific record. Null if no error occurred. + */ + @JsonProperty("error") + public Optional getError() { + return error; + } + + /** + * @return HTTP status code representing the result of the API request for this record. + */ + @JsonProperty("httpCode") + public int getHttpCode() { + return httpCode; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof FileUploadResponseObject && equalTo((FileUploadResponseObject) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(FileUploadResponseObject other) { + return skyflowId.equals(other.skyflowId) + && tableName.equals(other.tableName) + && data.equals(other.data) + && error.equals(other.error) + && httpCode == other.httpCode; + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.skyflowId, this.tableName, this.data, this.error, this.httpCode); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static SkyflowIdStage builder() { + return new Builder(); + } + + public interface SkyflowIdStage { + /** + *

Skyflow ID of the record. A new skyflowID is returned if one was not provided in the request.

+ */ + TableNameStage skyflowId(@NotNull String skyflowId); + + Builder from(FileUploadResponseObject other); + } + + public interface TableNameStage { + /** + *

Name of the table.

+ */ + HttpCodeStage tableName(@NotNull String tableName); + } + + public interface HttpCodeStage { + /** + *

HTTP status code representing the result of the API request for this record.

+ */ + _FinalStage httpCode(int httpCode); + } + + public interface _FinalStage { + FileUploadResponseObject build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + /** + *

Map of column names to signed upload URLs. Each signed URL expires after 15 minutes by default.

+ */ + _FinalStage data(Optional> data); + + _FinalStage data(Map data); + + /** + *

Error message describing any issue with the specific record. Null if no error occurred.

+ */ + _FinalStage error(Optional error); + + _FinalStage error(String error); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements SkyflowIdStage, TableNameStage, HttpCodeStage, _FinalStage { + private String skyflowId; + + private String tableName; + + private int httpCode; + + private Optional error = Optional.empty(); + + private Optional> data = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(FileUploadResponseObject other) { + skyflowId(other.getSkyflowId()); + tableName(other.getTableName()); + data(other.getData()); + error(other.getError()); + httpCode(other.getHttpCode()); + return this; + } + + /** + *

Skyflow ID of the record. A new skyflowID is returned if one was not provided in the request.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("skyflowID") + public TableNameStage skyflowId(@NotNull String skyflowId) { + this.skyflowId = Objects.requireNonNull(skyflowId, "skyflowId must not be null"); + return this; + } + + /** + *

Name of the table.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("tableName") + public HttpCodeStage tableName(@NotNull String tableName) { + this.tableName = Objects.requireNonNull(tableName, "tableName must not be null"); + return this; + } + + /** + *

HTTP status code representing the result of the API request for this record.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("httpCode") + public _FinalStage httpCode(int httpCode) { + this.httpCode = httpCode; + return this; + } + + /** + *

Error message describing any issue with the specific record. Null if no error occurred.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage error(String error) { + this.error = Optional.ofNullable(error); + return this; + } + + /** + *

Error message describing any issue with the specific record. Null if no error occurred.

+ */ + @java.lang.Override + @JsonSetter(value = "error", nulls = Nulls.SKIP) + public _FinalStage error(Optional error) { + this.error = error; + return this; + } + + /** + *

Map of column names to signed upload URLs. Each signed URL expires after 15 minutes by default.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage data(Map data) { + this.data = Optional.ofNullable(data); + return this; + } + + /** + *

Map of column names to signed upload URLs. Each signed URL expires after 15 minutes by default.

+ */ + @java.lang.Override + @JsonSetter(value = "data", nulls = Nulls.SKIP) + public _FinalStage data(Optional> data) { + this.data = data; + return this; + } + + @java.lang.Override + public FileUploadResponseObject build() { + return new FileUploadResponseObject(skyflowId, tableName, data, error, httpCode, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/FlowEnumUpdateType.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/FlowEnumUpdateType.java deleted file mode 100644 index d3c1cea0..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/FlowEnumUpdateType.java +++ /dev/null @@ -1,24 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.JsonValue; - -public enum FlowEnumUpdateType { - UPDATE("UPDATE"), - - REPLACE("REPLACE"); - - private final String value; - - FlowEnumUpdateType(String value) { - this.value = value; - } - - @JsonValue - @Override - public String toString() { - return this.value; - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/GetRequestData.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/GetRequestData.java new file mode 100644 index 00000000..dbe46db3 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/GetRequestData.java @@ -0,0 +1,324 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = GetRequestData.Builder.class) +public final class GetRequestData { + private final String tableName; + + private final List skyflowIDs; + + private final Optional> columnRedactions; + + private final Optional> columns; + + private final Optional> uniqueValues; + + private final Map additionalProperties; + + private GetRequestData( + String tableName, + List skyflowIDs, + Optional> columnRedactions, + Optional> columns, + Optional> uniqueValues, + Map additionalProperties) { + this.tableName = tableName; + this.skyflowIDs = skyflowIDs; + this.columnRedactions = columnRedactions; + this.columns = columns; + this.uniqueValues = uniqueValues; + this.additionalProperties = additionalProperties; + } + + /** + * @return Name of the table. + */ + @JsonProperty("tableName") + public String getTableName() { + return tableName; + } + + /** + * @return Skyflow IDs of the records to return. + */ + @JsonProperty("skyflowIDs") + public List getSkyflowIDs() { + return skyflowIDs; + } + + /** + * @return List of columns to redact. + */ + @JsonProperty("columnRedactions") + public Optional> getColumnRedactions() { + return columnRedactions; + } + + /** + * @return List of columns to return. + */ + @JsonProperty("columns") + public Optional> getColumns() { + return columns; + } + + /** + * @return List of unique constraint values to query records by data. + */ + @JsonProperty("uniqueValues") + public Optional> getUniqueValues() { + return uniqueValues; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof GetRequestData && equalTo((GetRequestData) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(GetRequestData other) { + return tableName.equals(other.tableName) + && skyflowIDs.equals(other.skyflowIDs) + && columnRedactions.equals(other.columnRedactions) + && columns.equals(other.columns) + && uniqueValues.equals(other.uniqueValues); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.tableName, this.skyflowIDs, this.columnRedactions, this.columns, this.uniqueValues); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static TableNameStage builder() { + return new Builder(); + } + + public interface TableNameStage { + /** + *

Name of the table.

+ */ + _FinalStage tableName(@NotNull String tableName); + + Builder from(GetRequestData other); + } + + public interface _FinalStage { + GetRequestData build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + /** + *

Skyflow IDs of the records to return.

+ */ + _FinalStage skyflowIDs(List skyflowIDs); + + _FinalStage addSkyflowIDs(String skyflowIDs); + + _FinalStage addAllSkyflowIDs(List skyflowIDs); + + /** + *

List of columns to redact.

+ */ + _FinalStage columnRedactions(Optional> columnRedactions); + + _FinalStage columnRedactions(List columnRedactions); + + /** + *

List of columns to return.

+ */ + _FinalStage columns(Optional> columns); + + _FinalStage columns(List columns); + + /** + *

List of unique constraint values to query records by data.

+ */ + _FinalStage uniqueValues(Optional> uniqueValues); + + _FinalStage uniqueValues(List uniqueValues); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements TableNameStage, _FinalStage { + private String tableName; + + private Optional> uniqueValues = Optional.empty(); + + private Optional> columns = Optional.empty(); + + private Optional> columnRedactions = Optional.empty(); + + private List skyflowIDs = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(GetRequestData other) { + tableName(other.getTableName()); + skyflowIDs(other.getSkyflowIDs()); + columnRedactions(other.getColumnRedactions()); + columns(other.getColumns()); + uniqueValues(other.getUniqueValues()); + return this; + } + + /** + *

Name of the table.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("tableName") + public _FinalStage tableName(@NotNull String tableName) { + this.tableName = Objects.requireNonNull(tableName, "tableName must not be null"); + return this; + } + + /** + *

List of unique constraint values to query records by data.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage uniqueValues(List uniqueValues) { + this.uniqueValues = Optional.ofNullable(uniqueValues); + return this; + } + + /** + *

List of unique constraint values to query records by data.

+ */ + @java.lang.Override + @JsonSetter(value = "uniqueValues", nulls = Nulls.SKIP) + public _FinalStage uniqueValues(Optional> uniqueValues) { + this.uniqueValues = uniqueValues; + return this; + } + + /** + *

List of columns to return.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage columns(List columns) { + this.columns = Optional.ofNullable(columns); + return this; + } + + /** + *

List of columns to return.

+ */ + @java.lang.Override + @JsonSetter(value = "columns", nulls = Nulls.SKIP) + public _FinalStage columns(Optional> columns) { + this.columns = columns; + return this; + } + + /** + *

List of columns to redact.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage columnRedactions(List columnRedactions) { + this.columnRedactions = Optional.ofNullable(columnRedactions); + return this; + } + + /** + *

List of columns to redact.

+ */ + @java.lang.Override + @JsonSetter(value = "columnRedactions", nulls = Nulls.SKIP) + public _FinalStage columnRedactions(Optional> columnRedactions) { + this.columnRedactions = columnRedactions; + return this; + } + + /** + *

Skyflow IDs of the records to return.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addAllSkyflowIDs(List skyflowIDs) { + if (skyflowIDs != null) { + this.skyflowIDs.addAll(skyflowIDs); + } + return this; + } + + /** + *

Skyflow IDs of the records to return.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addSkyflowIDs(String skyflowIDs) { + this.skyflowIDs.add(skyflowIDs); + return this; + } + + /** + *

Skyflow IDs of the records to return.

+ */ + @java.lang.Override + @JsonSetter(value = "skyflowIDs", nulls = Nulls.SKIP) + public _FinalStage skyflowIDs(List skyflowIDs) { + this.skyflowIDs.clear(); + if (skyflowIDs != null) { + this.skyflowIDs.addAll(skyflowIDs); + } + return this; + } + + @java.lang.Override + public GetRequestData build() { + return new GetRequestData( + tableName, skyflowIDs, columnRedactions, columns, uniqueValues, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/GetResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/GetResponse.java new file mode 100644 index 00000000..fa49bbb4 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/GetResponse.java @@ -0,0 +1,122 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = GetResponse.Builder.class) +public final class GetResponse { + private final List records; + + private final Map additionalProperties; + + private GetResponse(List records, Map additionalProperties) { + this.records = records; + this.additionalProperties = additionalProperties; + } + + /** + * @return List of fetched records. For file columns, the value in the data map is an object containing: fileName, mimeType, sizeBytes, fileStatus (PENDING | READY | FAILED | SCAN_ERROR), fileFailureReason (non-null only when fileStatus is FAILED), url (pre-signed download URL, non-null only when fileStatus is READY), and urlExpiresAt (UTC expiry of the URL). + */ + @JsonProperty("records") + public List getRecords() { + return records; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof GetResponse && equalTo((GetResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(GetResponse other) { + return records.equals(other.records); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.records); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private List records = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(GetResponse other) { + records(other.getRecords()); + return this; + } + + /** + *

List of fetched records. For file columns, the value in the data map is an object containing: fileName, mimeType, sizeBytes, fileStatus (PENDING | READY | FAILED | SCAN_ERROR), fileFailureReason (non-null only when fileStatus is FAILED), url (pre-signed download URL, non-null only when fileStatus is READY), and urlExpiresAt (UTC expiry of the URL).

+ */ + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public Builder records(List records) { + this.records.clear(); + if (records != null) { + this.records.addAll(records); + } + return this; + } + + public Builder addRecords(RecordResponseObject records) { + this.records.add(records); + return this; + } + + public Builder addAllRecords(List records) { + if (records != null) { + this.records.addAll(records); + } + return this; + } + + public GetResponse build() { + return new GetResponse(records, additionalProperties); + } + + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/GetTokensFromValuesRequestObject.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/GetTokensFromValuesRequestObject.java new file mode 100644 index 00000000..c0fab010 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/GetTokensFromValuesRequestObject.java @@ -0,0 +1,151 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = GetTokensFromValuesRequestObject.Builder.class) +public final class GetTokensFromValuesRequestObject { + private final GoogleProtobufValue value; + + private final String tokenGroupName; + + private final Map additionalProperties; + + private GetTokensFromValuesRequestObject( + GoogleProtobufValue value, String tokenGroupName, Map additionalProperties) { + this.value = value; + this.tokenGroupName = tokenGroupName; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("value") + public GoogleProtobufValue getValue() { + return value; + } + + /** + * @return Name of the deterministic token group. + */ + @JsonProperty("tokenGroupName") + public String getTokenGroupName() { + return tokenGroupName; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof GetTokensFromValuesRequestObject && equalTo((GetTokensFromValuesRequestObject) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(GetTokensFromValuesRequestObject other) { + return value.equals(other.value) && tokenGroupName.equals(other.tokenGroupName); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.value, this.tokenGroupName); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static ValueStage builder() { + return new Builder(); + } + + public interface ValueStage { + TokenGroupNameStage value(@NotNull GoogleProtobufValue value); + + Builder from(GetTokensFromValuesRequestObject other); + } + + public interface TokenGroupNameStage { + /** + *

Name of the deterministic token group.

+ */ + _FinalStage tokenGroupName(@NotNull String tokenGroupName); + } + + public interface _FinalStage { + GetTokensFromValuesRequestObject build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements ValueStage, TokenGroupNameStage, _FinalStage { + private GoogleProtobufValue value; + + private String tokenGroupName; + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(GetTokensFromValuesRequestObject other) { + value(other.getValue()); + tokenGroupName(other.getTokenGroupName()); + return this; + } + + @java.lang.Override + @JsonSetter("value") + public TokenGroupNameStage value(@NotNull GoogleProtobufValue value) { + this.value = Objects.requireNonNull(value, "value must not be null"); + return this; + } + + /** + *

Name of the deterministic token group.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("tokenGroupName") + public _FinalStage tokenGroupName(@NotNull String tokenGroupName) { + this.tokenGroupName = Objects.requireNonNull(tokenGroupName, "tokenGroupName must not be null"); + return this; + } + + @java.lang.Override + public GetTokensFromValuesRequestObject build() { + return new GetTokensFromValuesRequestObject(value, tokenGroupName, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/GetTokensFromValuesResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/GetTokensFromValuesResponse.java new file mode 100644 index 00000000..de800b47 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/GetTokensFromValuesResponse.java @@ -0,0 +1,123 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = GetTokensFromValuesResponse.Builder.class) +public final class GetTokensFromValuesResponse { + private final List records; + + private final Map additionalProperties; + + private GetTokensFromValuesResponse( + List records, Map additionalProperties) { + this.records = records; + this.additionalProperties = additionalProperties; + } + + /** + * @return Array of token result objects, one per input entry, in the same order as the request. + */ + @JsonProperty("records") + public List getRecords() { + return records; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof GetTokensFromValuesResponse && equalTo((GetTokensFromValuesResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(GetTokensFromValuesResponse other) { + return records.equals(other.records); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.records); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private List records = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(GetTokensFromValuesResponse other) { + records(other.getRecords()); + return this; + } + + /** + *

Array of token result objects, one per input entry, in the same order as the request.

+ */ + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public Builder records(List records) { + this.records.clear(); + if (records != null) { + this.records.addAll(records); + } + return this; + } + + public Builder addRecords(TokenizeResponseObject records) { + this.records.add(records); + return this; + } + + public Builder addAllRecords(List records) { + if (records != null) { + this.records.addAll(records); + } + return this; + } + + public GetTokensFromValuesResponse build() { + return new GetTokensFromValuesResponse(records, additionalProperties); + } + + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/GoogleProtobufValue.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/GoogleProtobufValue.java new file mode 100644 index 00000000..0b0efc95 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/GoogleProtobufValue.java @@ -0,0 +1,42 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import com.skyflow.generated.rest.core.WrappedAlias; + +public final class GoogleProtobufValue implements WrappedAlias { + private final Object value; + + private GoogleProtobufValue(Object value) { + this.value = value; + } + + @JsonValue + public Object get() { + return this.value; + } + + @java.lang.Override + public boolean equals(Object other) { + return this == other + || (other instanceof GoogleProtobufValue && this.value.equals(((GoogleProtobufValue) other).value)); + } + + @java.lang.Override + public int hashCode() { + return value.hashCode(); + } + + @java.lang.Override + public String toString() { + return value.toString(); + } + + @JsonCreator(mode = JsonCreator.Mode.DELEGATING) + public static GoogleProtobufValue of(Object value) { + return new GoogleProtobufValue(value); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/GoogleprotobufAny.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/GoogleprotobufAny.java deleted file mode 100644 index 06205978..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/GoogleprotobufAny.java +++ /dev/null @@ -1,146 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = GoogleprotobufAny.Builder.class) -public final class GoogleprotobufAny { - private final Optional type; - - private final Map additionalProperties; - - private GoogleprotobufAny(Optional type, Map additionalProperties) { - this.type = type; - this.additionalProperties = additionalProperties; - } - - /** - * @return A URL/resource name that uniquely identifies the type of the serialized - * protocol buffer message. This string must contain at least - * one "/" character. The last segment of the URL's path must represent - * the fully qualified name of the type (as in - * path/google.protobuf.Duration). The name should be in a canonical form - * (e.g., leading "." is not accepted). - *

In practice, teams usually precompile into the binary all types that they - * expect it to use in the context of Any. However, for URLs which use the - * scheme http, https, or no scheme, one can optionally set up a type - * server that maps type URLs to message definitions as follows:

- *
    - *
  • If no scheme is provided, https is assumed.
  • - *
  • An HTTP GET on the URL must yield a [google.protobuf.Type][] - * value in binary format, or produce an error.
  • - *
  • Applications are allowed to cache lookup results based on the - * URL, or have them precompiled into a binary to avoid any - * lookup. Therefore, binary compatibility needs to be preserved - * on changes to types. (Use versioned type names to manage - * breaking changes.)
  • - *
- *

Note: this functionality is not currently available in the official - * protobuf release, and it is not used for type URLs beginning with - * type.googleapis.com. As of May 2023, there are no widely used type server - * implementations and no plans to implement one.

- *

Schemes other than http, https (or the empty scheme) might be - * used with implementation specific semantics.

- */ - @JsonProperty("@type") - public Optional getType() { - return type; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof GoogleprotobufAny && equalTo((GoogleprotobufAny) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(GoogleprotobufAny other) { - return type.equals(other.type); - } - - @Override - public int hashCode() { - return Objects.hash(this.type); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional type = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(GoogleprotobufAny other) { - type(other.getType()); - return this; - } - - /** - *

A URL/resource name that uniquely identifies the type of the serialized - * protocol buffer message. This string must contain at least - * one "/" character. The last segment of the URL's path must represent - * the fully qualified name of the type (as in - * path/google.protobuf.Duration). The name should be in a canonical form - * (e.g., leading "." is not accepted).

- *

In practice, teams usually precompile into the binary all types that they - * expect it to use in the context of Any. However, for URLs which use the - * scheme http, https, or no scheme, one can optionally set up a type - * server that maps type URLs to message definitions as follows:

- *
    - *
  • If no scheme is provided, https is assumed.
  • - *
  • An HTTP GET on the URL must yield a [google.protobuf.Type][] - * value in binary format, or produce an error.
  • - *
  • Applications are allowed to cache lookup results based on the - * URL, or have them precompiled into a binary to avoid any - * lookup. Therefore, binary compatibility needs to be preserved - * on changes to types. (Use versioned type names to manage - * breaking changes.)
  • - *
- *

Note: this functionality is not currently available in the official - * protobuf release, and it is not used for type URLs beginning with - * type.googleapis.com. As of May 2023, there are no widely used type server - * implementations and no plans to implement one.

- *

Schemes other than http, https (or the empty scheme) might be - * used with implementation specific semantics.

- */ - @JsonSetter(value = "@type", nulls = Nulls.SKIP) - public Builder type(Optional type) { - this.type = type; - return this; - } - - public Builder type(String type) { - this.type = Optional.ofNullable(type); - return this; - } - - public GoogleprotobufAny build() { - return new GoogleprotobufAny(type, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1InsertRecordData.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/InsertRecordData.java similarity index 52% rename from flowvault/src/main/java/com/skyflow/generated/rest/types/V1InsertRecordData.java rename to flowvault/src/main/java/com/skyflow/generated/rest/types/InsertRecordData.java index 7de162cc..0b0ea516 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1InsertRecordData.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/InsertRecordData.java @@ -3,59 +3,53 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1InsertRecordData.Builder.class) -public final class V1InsertRecordData { - private final Optional> data; - - private final Optional> tokens; +@JsonDeserialize(builder = InsertRecordData.Builder.class) +public final class InsertRecordData { + private final Map data; private final Optional tableName; - private final Optional upsert; + private final Optional upsert; private final Map additionalProperties; - private V1InsertRecordData( - Optional> data, - Optional> tokens, + private InsertRecordData( + Map data, Optional tableName, - Optional upsert, + Optional upsert, Map additionalProperties) { this.data = data; - this.tokens = tokens; this.tableName = tableName; this.upsert = upsert; this.additionalProperties = additionalProperties; } /** - * @return Columns names and values + * @return Columns and values for the record. */ @JsonProperty("data") - public Optional> getData() { + public Map getData() { return data; } /** - * @return undocumented_field; Tokens data for the columns if any - */ - @JsonProperty("tokens") - public Optional> getTokens() { - return tokens; - } - - /** - * @return Table name for the record + * @return Name of the table to insert data into. */ @JsonProperty("tableName") public Optional getTableName() { @@ -63,14 +57,14 @@ public Optional getTableName() { } @JsonProperty("upsert") - public Optional getUpsert() { + public Optional getUpsert() { return upsert; } - @Override + @java.lang.Override public boolean equals(Object other) { if (this == other) return true; - return other instanceof V1InsertRecordData && equalTo((V1InsertRecordData) other); + return other instanceof InsertRecordData && equalTo((InsertRecordData) other); } @JsonAnyGetter @@ -78,19 +72,16 @@ public Map getAdditionalProperties() { return this.additionalProperties; } - private boolean equalTo(V1InsertRecordData other) { - return data.equals(other.data) - && tokens.equals(other.tokens) - && tableName.equals(other.tableName) - && upsert.equals(other.upsert); + private boolean equalTo(InsertRecordData other) { + return data.equals(other.data) && tableName.equals(other.tableName) && upsert.equals(other.upsert); } - @Override + @java.lang.Override public int hashCode() { - return Objects.hash(this.data, this.tokens, this.tableName, this.upsert); + return Objects.hash(this.data, this.tableName, this.upsert); } - @Override + @java.lang.Override public String toString() { return ObjectMappers.stringify(this); } @@ -101,57 +92,50 @@ public static Builder builder() { @JsonIgnoreProperties(ignoreUnknown = true) public static final class Builder { - private Optional> data = Optional.empty(); - - private Optional> tokens = Optional.empty(); + private Map data = new LinkedHashMap<>(); private Optional tableName = Optional.empty(); - private Optional upsert = Optional.empty(); + private Optional upsert = Optional.empty(); @JsonAnySetter private Map additionalProperties = new HashMap<>(); private Builder() {} - public Builder from(V1InsertRecordData other) { + public Builder from(InsertRecordData other) { data(other.getData()); - tokens(other.getTokens()); tableName(other.getTableName()); upsert(other.getUpsert()); return this; } /** - *

Columns names and values

+ *

Columns and values for the record.

*/ @JsonSetter(value = "data", nulls = Nulls.SKIP) - public Builder data(Optional> data) { - this.data = data; - return this; - } - public Builder data(Map data) { - this.data = Optional.ofNullable(data); + this.data.clear(); + if (data != null) { + this.data.putAll(data); + } return this; } - /** - *

undocumented_field; Tokens data for the columns if any

- */ - @JsonSetter(value = "tokens", nulls = Nulls.SKIP) - public Builder tokens(Optional> tokens) { - this.tokens = tokens; + public Builder putAllData(Map data) { + if (data != null) { + this.data.putAll(data); + } return this; } - public Builder tokens(Map tokens) { - this.tokens = Optional.ofNullable(tokens); + public Builder data(String key, Object value) { + this.data.put(key, value); return this; } /** - *

Table name for the record

+ *

Name of the table to insert data into.

*/ @JsonSetter(value = "tableName", nulls = Nulls.SKIP) public Builder tableName(Optional tableName) { @@ -165,18 +149,28 @@ public Builder tableName(String tableName) { } @JsonSetter(value = "upsert", nulls = Nulls.SKIP) - public Builder upsert(Optional upsert) { + public Builder upsert(Optional upsert) { this.upsert = upsert; return this; } - public Builder upsert(V1Upsert upsert) { + public Builder upsert(Upsert upsert) { this.upsert = Optional.ofNullable(upsert); return this; } - public V1InsertRecordData build() { - return new V1InsertRecordData(data, tokens, tableName, upsert, additionalProperties); + public InsertRecordData build() { + return new InsertRecordData(data, tableName, upsert, additionalProperties); + } + + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; } } } diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/InsertResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/InsertResponse.java new file mode 100644 index 00000000..63814444 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/InsertResponse.java @@ -0,0 +1,122 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = InsertResponse.Builder.class) +public final class InsertResponse { + private final List records; + + private final Map additionalProperties; + + private InsertResponse(List records, Map additionalProperties) { + this.records = records; + this.additionalProperties = additionalProperties; + } + + /** + * @return List of inserted records. + */ + @JsonProperty("records") + public List getRecords() { + return records; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof InsertResponse && equalTo((InsertResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(InsertResponse other) { + return records.equals(other.records); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.records); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private List records = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(InsertResponse other) { + records(other.getRecords()); + return this; + } + + /** + *

List of inserted records.

+ */ + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public Builder records(List records) { + this.records.clear(); + if (records != null) { + this.records.addAll(records); + } + return this; + } + + public Builder addRecords(RecordResponseObject records) { + this.records.add(records); + return this; + } + + public Builder addAllRecords(List records) { + if (records != null) { + this.records.addAll(records); + } + return this; + } + + public InsertResponse build() { + return new InsertResponse(records, additionalProperties); + } + + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/RecordResponseObject.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/RecordResponseObject.java new file mode 100644 index 00000000..a00428e2 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/RecordResponseObject.java @@ -0,0 +1,448 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.Nullable; +import com.skyflow.generated.rest.core.NullableNonemptyFilter; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = RecordResponseObject.Builder.class) +public final class RecordResponseObject { + private final Optional skyflowId; + + private final Optional> tokens; + + private final Optional> data; + + private final Optional> hashedData; + + private final Optional error; + + private final int httpCode; + + private final Optional tableName; + + private final Map additionalProperties; + + private RecordResponseObject( + Optional skyflowId, + Optional> tokens, + Optional> data, + Optional> hashedData, + Optional error, + int httpCode, + Optional tableName, + Map additionalProperties) { + this.skyflowId = skyflowId; + this.tokens = tokens; + this.data = data; + this.hashedData = hashedData; + this.error = error; + this.httpCode = httpCode; + this.tableName = tableName; + this.additionalProperties = additionalProperties; + } + + /** + * @return Skyflow ID for the inserted record + */ + @JsonIgnore + public Optional getSkyflowId() { + if (skyflowId == null) { + return Optional.empty(); + } + return skyflowId; + } + + /** + * @return Columns and tokens for the record. + */ + @JsonProperty("tokens") + public Optional> getTokens() { + return tokens; + } + + /** + * @return Columns and values for the record. For file columns, the value is an object containing file metadata: fileName, mimeType, sizeBytes, fileStatus (PENDING | READY | FAILED | SCAN_ERROR), fileFailureReason (populated only when fileStatus is FAILED), url (pre-signed download URL, populated only when fileStatus is READY), and urlExpiresAt (UTC expiry of the URL). + */ + @JsonProperty("data") + public Optional> getData() { + return data; + } + + /** + * @return Columns and hashed values for the record. + */ + @JsonProperty("hashedData") + public Optional> getHashedData() { + return hashedData; + } + + /** + * @return Error message, if any. + */ + @JsonIgnore + public Optional getError() { + if (error == null) { + return Optional.empty(); + } + return error; + } + + /** + * @return HTTP status code of the response. + */ + @JsonProperty("httpCode") + public int getHttpCode() { + return httpCode; + } + + /** + * @return Name of the table that the record belongs to. + */ + @JsonProperty("tableName") + public Optional getTableName() { + return tableName; + } + + @JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = NullableNonemptyFilter.class) + @JsonProperty("skyflowID") + private Optional _getSkyflowId() { + return skyflowId; + } + + @JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = NullableNonemptyFilter.class) + @JsonProperty("error") + private Optional _getError() { + return error; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof RecordResponseObject && equalTo((RecordResponseObject) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(RecordResponseObject other) { + return skyflowId.equals(other.skyflowId) + && tokens.equals(other.tokens) + && data.equals(other.data) + && hashedData.equals(other.hashedData) + && error.equals(other.error) + && httpCode == other.httpCode + && tableName.equals(other.tableName); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash( + this.skyflowId, this.tokens, this.data, this.hashedData, this.error, this.httpCode, this.tableName); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static HttpCodeStage builder() { + return new Builder(); + } + + public interface HttpCodeStage { + /** + *

HTTP status code of the response.

+ */ + _FinalStage httpCode(int httpCode); + + Builder from(RecordResponseObject other); + } + + public interface _FinalStage { + RecordResponseObject build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + /** + *

Skyflow ID for the inserted record

+ */ + _FinalStage skyflowId(Optional skyflowId); + + _FinalStage skyflowId(String skyflowId); + + _FinalStage skyflowId(Nullable skyflowId); + + /** + *

Columns and tokens for the record.

+ */ + _FinalStage tokens(Optional> tokens); + + _FinalStage tokens(Map tokens); + + /** + *

Columns and values for the record. For file columns, the value is an object containing file metadata: fileName, mimeType, sizeBytes, fileStatus (PENDING | READY | FAILED | SCAN_ERROR), fileFailureReason (populated only when fileStatus is FAILED), url (pre-signed download URL, populated only when fileStatus is READY), and urlExpiresAt (UTC expiry of the URL).

+ */ + _FinalStage data(Optional> data); + + _FinalStage data(Map data); + + /** + *

Columns and hashed values for the record.

+ */ + _FinalStage hashedData(Optional> hashedData); + + _FinalStage hashedData(Map hashedData); + + /** + *

Error message, if any.

+ */ + _FinalStage error(Optional error); + + _FinalStage error(String error); + + _FinalStage error(Nullable error); + + /** + *

Name of the table that the record belongs to.

+ */ + _FinalStage tableName(Optional tableName); + + _FinalStage tableName(String tableName); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements HttpCodeStage, _FinalStage { + private int httpCode; + + private Optional tableName = Optional.empty(); + + private Optional error = Optional.empty(); + + private Optional> hashedData = Optional.empty(); + + private Optional> data = Optional.empty(); + + private Optional> tokens = Optional.empty(); + + private Optional skyflowId = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(RecordResponseObject other) { + skyflowId(other.getSkyflowId()); + tokens(other.getTokens()); + data(other.getData()); + hashedData(other.getHashedData()); + error(other.getError()); + httpCode(other.getHttpCode()); + tableName(other.getTableName()); + return this; + } + + /** + *

HTTP status code of the response.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("httpCode") + public _FinalStage httpCode(int httpCode) { + this.httpCode = httpCode; + return this; + } + + /** + *

Name of the table that the record belongs to.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage tableName(String tableName) { + this.tableName = Optional.ofNullable(tableName); + return this; + } + + /** + *

Name of the table that the record belongs to.

+ */ + @java.lang.Override + @JsonSetter(value = "tableName", nulls = Nulls.SKIP) + public _FinalStage tableName(Optional tableName) { + this.tableName = tableName; + return this; + } + + /** + *

Error message, if any.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage error(Nullable error) { + if (error.isNull()) { + this.error = null; + } else if (error.isEmpty()) { + this.error = Optional.empty(); + } else { + this.error = Optional.of(error.get()); + } + return this; + } + + /** + *

Error message, if any.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage error(String error) { + this.error = Optional.ofNullable(error); + return this; + } + + /** + *

Error message, if any.

+ */ + @java.lang.Override + @JsonSetter(value = "error", nulls = Nulls.SKIP) + public _FinalStage error(Optional error) { + this.error = error; + return this; + } + + /** + *

Columns and hashed values for the record.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage hashedData(Map hashedData) { + this.hashedData = Optional.ofNullable(hashedData); + return this; + } + + /** + *

Columns and hashed values for the record.

+ */ + @java.lang.Override + @JsonSetter(value = "hashedData", nulls = Nulls.SKIP) + public _FinalStage hashedData(Optional> hashedData) { + this.hashedData = hashedData; + return this; + } + + /** + *

Columns and values for the record. For file columns, the value is an object containing file metadata: fileName, mimeType, sizeBytes, fileStatus (PENDING | READY | FAILED | SCAN_ERROR), fileFailureReason (populated only when fileStatus is FAILED), url (pre-signed download URL, populated only when fileStatus is READY), and urlExpiresAt (UTC expiry of the URL).

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage data(Map data) { + this.data = Optional.ofNullable(data); + return this; + } + + /** + *

Columns and values for the record. For file columns, the value is an object containing file metadata: fileName, mimeType, sizeBytes, fileStatus (PENDING | READY | FAILED | SCAN_ERROR), fileFailureReason (populated only when fileStatus is FAILED), url (pre-signed download URL, populated only when fileStatus is READY), and urlExpiresAt (UTC expiry of the URL).

+ */ + @java.lang.Override + @JsonSetter(value = "data", nulls = Nulls.SKIP) + public _FinalStage data(Optional> data) { + this.data = data; + return this; + } + + /** + *

Columns and tokens for the record.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage tokens(Map tokens) { + this.tokens = Optional.ofNullable(tokens); + return this; + } + + /** + *

Columns and tokens for the record.

+ */ + @java.lang.Override + @JsonSetter(value = "tokens", nulls = Nulls.SKIP) + public _FinalStage tokens(Optional> tokens) { + this.tokens = tokens; + return this; + } + + /** + *

Skyflow ID for the inserted record

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage skyflowId(Nullable skyflowId) { + if (skyflowId.isNull()) { + this.skyflowId = null; + } else if (skyflowId.isEmpty()) { + this.skyflowId = Optional.empty(); + } else { + this.skyflowId = Optional.of(skyflowId.get()); + } + return this; + } + + /** + *

Skyflow ID for the inserted record

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage skyflowId(String skyflowId) { + this.skyflowId = Optional.ofNullable(skyflowId); + return this; + } + + /** + *

Skyflow ID for the inserted record

+ */ + @java.lang.Override + @JsonSetter(value = "skyflowID", nulls = Nulls.SKIP) + public _FinalStage skyflowId(Optional skyflowId) { + this.skyflowId = skyflowId; + return this; + } + + @java.lang.Override + public RecordResponseObject build() { + return new RecordResponseObject( + skyflowId, tokens, data, hashedData, error, httpCode, tableName, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/RpcStatus.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/RpcStatus.java deleted file mode 100644 index 347ce5c4..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/RpcStatus.java +++ /dev/null @@ -1,135 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = RpcStatus.Builder.class) -public final class RpcStatus { - private final Optional code; - - private final Optional message; - - private final Optional> details; - - private final Map additionalProperties; - - private RpcStatus( - Optional code, - Optional message, - Optional> details, - Map additionalProperties) { - this.code = code; - this.message = message; - this.details = details; - this.additionalProperties = additionalProperties; - } - - @JsonProperty("code") - public Optional getCode() { - return code; - } - - @JsonProperty("message") - public Optional getMessage() { - return message; - } - - @JsonProperty("details") - public Optional> getDetails() { - return details; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof RpcStatus && equalTo((RpcStatus) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(RpcStatus other) { - return code.equals(other.code) && message.equals(other.message) && details.equals(other.details); - } - - @Override - public int hashCode() { - return Objects.hash(this.code, this.message, this.details); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional code = Optional.empty(); - - private Optional message = Optional.empty(); - - private Optional> details = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(RpcStatus other) { - code(other.getCode()); - message(other.getMessage()); - details(other.getDetails()); - return this; - } - - @JsonSetter(value = "code", nulls = Nulls.SKIP) - public Builder code(Optional code) { - this.code = code; - return this; - } - - public Builder code(Integer code) { - this.code = Optional.ofNullable(code); - return this; - } - - @JsonSetter(value = "message", nulls = Nulls.SKIP) - public Builder message(Optional message) { - this.message = message; - return this; - } - - public Builder message(String message) { - this.message = Optional.ofNullable(message); - return this; - } - - @JsonSetter(value = "details", nulls = Nulls.SKIP) - public Builder details(Optional> details) { - this.details = details; - return this; - } - - public Builder details(List details) { - this.details = Optional.ofNullable(details); - return this; - } - - public RpcStatus build() { - return new RpcStatus(code, message, details, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1TokenGroupRedactions.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/TokenGroupRedactions.java similarity index 66% rename from flowvault/src/main/java/com/skyflow/generated/rest/types/V1TokenGroupRedactions.java rename to flowvault/src/main/java/com/skyflow/generated/rest/types/TokenGroupRedactions.java index 5d5fc97f..a05b6681 100644 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1TokenGroupRedactions.java +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/TokenGroupRedactions.java @@ -3,25 +3,30 @@ */ package com.skyflow.generated.rest.types; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.skyflow.generated.rest.core.ObjectMappers; - import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; @JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1TokenGroupRedactions.Builder.class) -public final class V1TokenGroupRedactions { +@JsonDeserialize(builder = TokenGroupRedactions.Builder.class) +public final class TokenGroupRedactions { private final Optional tokenGroupName; private final Optional redaction; private final Map additionalProperties; - private V1TokenGroupRedactions( + private TokenGroupRedactions( Optional tokenGroupName, Optional redaction, Map additionalProperties) { this.tokenGroupName = tokenGroupName; this.redaction = redaction; @@ -29,7 +34,7 @@ private V1TokenGroupRedactions( } /** - * @return Name of the token group to be redacted + * @return Name of the token group to redact. */ @JsonProperty("tokenGroupName") public Optional getTokenGroupName() { @@ -37,17 +42,17 @@ public Optional getTokenGroupName() { } /** - * @return Name of the redaction. Eg: plain_text, redacted, mask1 + * @return Name of the redaction to perform. */ @JsonProperty("redaction") public Optional getRedaction() { return redaction; } - @Override + @java.lang.Override public boolean equals(Object other) { if (this == other) return true; - return other instanceof V1TokenGroupRedactions && equalTo((V1TokenGroupRedactions) other); + return other instanceof TokenGroupRedactions && equalTo((TokenGroupRedactions) other); } @JsonAnyGetter @@ -55,16 +60,16 @@ public Map getAdditionalProperties() { return this.additionalProperties; } - private boolean equalTo(V1TokenGroupRedactions other) { + private boolean equalTo(TokenGroupRedactions other) { return tokenGroupName.equals(other.tokenGroupName) && redaction.equals(other.redaction); } - @Override + @java.lang.Override public int hashCode() { return Objects.hash(this.tokenGroupName, this.redaction); } - @Override + @java.lang.Override public String toString() { return ObjectMappers.stringify(this); } @@ -84,14 +89,14 @@ public static final class Builder { private Builder() {} - public Builder from(V1TokenGroupRedactions other) { + public Builder from(TokenGroupRedactions other) { tokenGroupName(other.getTokenGroupName()); redaction(other.getRedaction()); return this; } /** - *

Name of the token group to be redacted

+ *

Name of the token group to redact.

*/ @JsonSetter(value = "tokenGroupName", nulls = Nulls.SKIP) public Builder tokenGroupName(Optional tokenGroupName) { @@ -105,7 +110,7 @@ public Builder tokenGroupName(String tokenGroupName) { } /** - *

Name of the redaction. Eg: plain_text, redacted, mask1

+ *

Name of the redaction to perform.

*/ @JsonSetter(value = "redaction", nulls = Nulls.SKIP) public Builder redaction(Optional redaction) { @@ -118,8 +123,18 @@ public Builder redaction(String redaction) { return this; } - public V1TokenGroupRedactions build() { - return new V1TokenGroupRedactions(tokenGroupName, redaction, additionalProperties); + public TokenGroupRedactions build() { + return new TokenGroupRedactions(tokenGroupName, redaction, additionalProperties); + } + + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; } } } diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/TokenizeRequestObject.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/TokenizeRequestObject.java new file mode 100644 index 00000000..6cffce95 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/TokenizeRequestObject.java @@ -0,0 +1,212 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = TokenizeRequestObject.Builder.class) +public final class TokenizeRequestObject { + private final GoogleProtobufValue value; + + private final List tokenGroupNames; + + private final Optional token; + + private final Map additionalProperties; + + private TokenizeRequestObject( + GoogleProtobufValue value, + List tokenGroupNames, + Optional token, + Map additionalProperties) { + this.value = value; + this.tokenGroupNames = tokenGroupNames; + this.token = token; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("value") + public GoogleProtobufValue getValue() { + return value; + } + + /** + * @return Names of token groups the value might be present in. + */ + @JsonProperty("tokenGroupNames") + public List getTokenGroupNames() { + return tokenGroupNames; + } + + @JsonProperty("token") + public Optional getToken() { + return token; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof TokenizeRequestObject && equalTo((TokenizeRequestObject) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(TokenizeRequestObject other) { + return value.equals(other.value) && tokenGroupNames.equals(other.tokenGroupNames) && token.equals(other.token); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.value, this.tokenGroupNames, this.token); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static ValueStage builder() { + return new Builder(); + } + + public interface ValueStage { + _FinalStage value(@NotNull GoogleProtobufValue value); + + Builder from(TokenizeRequestObject other); + } + + public interface _FinalStage { + TokenizeRequestObject build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + /** + *

Names of token groups the value might be present in.

+ */ + _FinalStage tokenGroupNames(List tokenGroupNames); + + _FinalStage addTokenGroupNames(String tokenGroupNames); + + _FinalStage addAllTokenGroupNames(List tokenGroupNames); + + _FinalStage token(Optional token); + + _FinalStage token(GoogleProtobufValue token); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements ValueStage, _FinalStage { + private GoogleProtobufValue value; + + private Optional token = Optional.empty(); + + private List tokenGroupNames = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(TokenizeRequestObject other) { + value(other.getValue()); + tokenGroupNames(other.getTokenGroupNames()); + token(other.getToken()); + return this; + } + + @java.lang.Override + @JsonSetter("value") + public _FinalStage value(@NotNull GoogleProtobufValue value) { + this.value = Objects.requireNonNull(value, "value must not be null"); + return this; + } + + @java.lang.Override + public _FinalStage token(GoogleProtobufValue token) { + this.token = Optional.ofNullable(token); + return this; + } + + @java.lang.Override + @JsonSetter(value = "token", nulls = Nulls.SKIP) + public _FinalStage token(Optional token) { + this.token = token; + return this; + } + + /** + *

Names of token groups the value might be present in.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addAllTokenGroupNames(List tokenGroupNames) { + if (tokenGroupNames != null) { + this.tokenGroupNames.addAll(tokenGroupNames); + } + return this; + } + + /** + *

Names of token groups the value might be present in.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage addTokenGroupNames(String tokenGroupNames) { + this.tokenGroupNames.add(tokenGroupNames); + return this; + } + + /** + *

Names of token groups the value might be present in.

+ */ + @java.lang.Override + @JsonSetter(value = "tokenGroupNames", nulls = Nulls.SKIP) + public _FinalStage tokenGroupNames(List tokenGroupNames) { + this.tokenGroupNames.clear(); + if (tokenGroupNames != null) { + this.tokenGroupNames.addAll(tokenGroupNames); + } + return this; + } + + @java.lang.Override + public TokenizeRequestObject build() { + return new TokenizeRequestObject(value, tokenGroupNames, token, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/TokenizeResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/TokenizeResponse.java new file mode 100644 index 00000000..b7c28cfe --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/TokenizeResponse.java @@ -0,0 +1,122 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = TokenizeResponse.Builder.class) +public final class TokenizeResponse { + private final List response; + + private final Map additionalProperties; + + private TokenizeResponse(List response, Map additionalProperties) { + this.response = response; + this.additionalProperties = additionalProperties; + } + + /** + * @return Tokenized data + */ + @JsonProperty("response") + public List getResponse() { + return response; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof TokenizeResponse && equalTo((TokenizeResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(TokenizeResponse other) { + return response.equals(other.response); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.response); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private List response = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(TokenizeResponse other) { + response(other.getResponse()); + return this; + } + + /** + *

Tokenized data

+ */ + @JsonSetter(value = "response", nulls = Nulls.SKIP) + public Builder response(List response) { + this.response.clear(); + if (response != null) { + this.response.addAll(response); + } + return this; + } + + public Builder addResponse(TokenizeResponseObject response) { + this.response.add(response); + return this; + } + + public Builder addAllResponse(List response) { + if (response != null) { + this.response.addAll(response); + } + return this; + } + + public TokenizeResponse build() { + return new TokenizeResponse(response, additionalProperties); + } + + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/TokenizeResponseObject.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/TokenizeResponseObject.java new file mode 100644 index 00000000..70f9d9dc --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/TokenizeResponseObject.java @@ -0,0 +1,321 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.Nullable; +import com.skyflow.generated.rest.core.NullableNonemptyFilter; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = TokenizeResponseObject.Builder.class) +public final class TokenizeResponseObject { + private final String token; + + private final Optional value; + + private final Optional tokenGroupName; + + private final Optional error; + + private final Optional httpCode; + + private final Map additionalProperties; + + private TokenizeResponseObject( + String token, + Optional value, + Optional tokenGroupName, + Optional error, + Optional httpCode, + Map additionalProperties) { + this.token = token; + this.value = value; + this.tokenGroupName = tokenGroupName; + this.error = error; + this.httpCode = httpCode; + this.additionalProperties = additionalProperties; + } + + /** + * @return Token that was generated. + */ + @JsonProperty("token") + public String getToken() { + return token; + } + + @JsonProperty("value") + public Optional getValue() { + return value; + } + + /** + * @return Name of the token group. + */ + @JsonIgnore + public Optional getTokenGroupName() { + if (tokenGroupName == null) { + return Optional.empty(); + } + return tokenGroupName; + } + + /** + * @return Error message, if any. + */ + @JsonProperty("error") + public Optional getError() { + return error; + } + + /** + * @return HTTP status code of the response. + */ + @JsonProperty("httpCode") + public Optional getHttpCode() { + return httpCode; + } + + @JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = NullableNonemptyFilter.class) + @JsonProperty("tokenGroupName") + private Optional _getTokenGroupName() { + return tokenGroupName; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof TokenizeResponseObject && equalTo((TokenizeResponseObject) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(TokenizeResponseObject other) { + return token.equals(other.token) + && value.equals(other.value) + && tokenGroupName.equals(other.tokenGroupName) + && error.equals(other.error) + && httpCode.equals(other.httpCode); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.token, this.value, this.tokenGroupName, this.error, this.httpCode); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static TokenStage builder() { + return new Builder(); + } + + public interface TokenStage { + /** + *

Token that was generated.

+ */ + _FinalStage token(@NotNull String token); + + Builder from(TokenizeResponseObject other); + } + + public interface _FinalStage { + TokenizeResponseObject build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + _FinalStage value(Optional value); + + _FinalStage value(GoogleProtobufValue value); + + /** + *

Name of the token group.

+ */ + _FinalStage tokenGroupName(Optional tokenGroupName); + + _FinalStage tokenGroupName(String tokenGroupName); + + _FinalStage tokenGroupName(Nullable tokenGroupName); + + /** + *

Error message, if any.

+ */ + _FinalStage error(Optional error); + + _FinalStage error(String error); + + /** + *

HTTP status code of the response.

+ */ + _FinalStage httpCode(Optional httpCode); + + _FinalStage httpCode(Integer httpCode); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements TokenStage, _FinalStage { + private String token; + + private Optional httpCode = Optional.empty(); + + private Optional error = Optional.empty(); + + private Optional tokenGroupName = Optional.empty(); + + private Optional value = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(TokenizeResponseObject other) { + token(other.getToken()); + value(other.getValue()); + tokenGroupName(other.getTokenGroupName()); + error(other.getError()); + httpCode(other.getHttpCode()); + return this; + } + + /** + *

Token that was generated.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("token") + public _FinalStage token(@NotNull String token) { + this.token = Objects.requireNonNull(token, "token must not be null"); + return this; + } + + /** + *

HTTP status code of the response.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage httpCode(Integer httpCode) { + this.httpCode = Optional.ofNullable(httpCode); + return this; + } + + /** + *

HTTP status code of the response.

+ */ + @java.lang.Override + @JsonSetter(value = "httpCode", nulls = Nulls.SKIP) + public _FinalStage httpCode(Optional httpCode) { + this.httpCode = httpCode; + return this; + } + + /** + *

Error message, if any.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage error(String error) { + this.error = Optional.ofNullable(error); + return this; + } + + /** + *

Error message, if any.

+ */ + @java.lang.Override + @JsonSetter(value = "error", nulls = Nulls.SKIP) + public _FinalStage error(Optional error) { + this.error = error; + return this; + } + + /** + *

Name of the token group.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage tokenGroupName(Nullable tokenGroupName) { + if (tokenGroupName.isNull()) { + this.tokenGroupName = null; + } else if (tokenGroupName.isEmpty()) { + this.tokenGroupName = Optional.empty(); + } else { + this.tokenGroupName = Optional.of(tokenGroupName.get()); + } + return this; + } + + /** + *

Name of the token group.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage tokenGroupName(String tokenGroupName) { + this.tokenGroupName = Optional.ofNullable(tokenGroupName); + return this; + } + + /** + *

Name of the token group.

+ */ + @java.lang.Override + @JsonSetter(value = "tokenGroupName", nulls = Nulls.SKIP) + public _FinalStage tokenGroupName(Optional tokenGroupName) { + this.tokenGroupName = tokenGroupName; + return this; + } + + @java.lang.Override + public _FinalStage value(GoogleProtobufValue value) { + this.value = Optional.ofNullable(value); + return this; + } + + @java.lang.Override + @JsonSetter(value = "value", nulls = Nulls.SKIP) + public _FinalStage value(Optional value) { + this.value = value; + return this; + } + + @java.lang.Override + public TokenizeResponseObject build() { + return new TokenizeResponseObject(token, value, tokenGroupName, error, httpCode, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/UniqueValue.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/UniqueValue.java new file mode 100644 index 00000000..7c185437 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/UniqueValue.java @@ -0,0 +1,121 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = UniqueValue.Builder.class) +public final class UniqueValue { + private final Map data; + + private final Map additionalProperties; + + private UniqueValue(Map data, Map additionalProperties) { + this.data = data; + this.additionalProperties = additionalProperties; + } + + /** + * @return Columns names and values for the unique value entry. + */ + @JsonProperty("data") + public Map getData() { + return data; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof UniqueValue && equalTo((UniqueValue) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(UniqueValue other) { + return data.equals(other.data); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.data); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Map data = new LinkedHashMap<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(UniqueValue other) { + data(other.getData()); + return this; + } + + /** + *

Columns names and values for the unique value entry.

+ */ + @JsonSetter(value = "data", nulls = Nulls.SKIP) + public Builder data(Map data) { + this.data.clear(); + if (data != null) { + this.data.putAll(data); + } + return this; + } + + public Builder putAllData(Map data) { + if (data != null) { + this.data.putAll(data); + } + return this; + } + + public Builder data(String key, Object value) { + this.data.put(key, value); + return this; + } + + public UniqueValue build() { + return new UniqueValue(data, additionalProperties); + } + + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/UpdateRecordData.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/UpdateRecordData.java new file mode 100644 index 00000000..83a11ab0 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/UpdateRecordData.java @@ -0,0 +1,279 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = UpdateRecordData.Builder.class) +public final class UpdateRecordData { + private final String skyflowId; + + private final Map data; + + private final Optional tableName; + + private final Optional updateType; + + private final Map additionalProperties; + + private UpdateRecordData( + String skyflowId, + Map data, + Optional tableName, + Optional updateType, + Map additionalProperties) { + this.skyflowId = skyflowId; + this.data = data; + this.tableName = tableName; + this.updateType = updateType; + this.additionalProperties = additionalProperties; + } + + /** + * @return Skyflow ID of the record to update. + */ + @JsonProperty("skyflowID") + public String getSkyflowId() { + return skyflowId; + } + + /** + * @return Columns and values for the record. + */ + @JsonProperty("data") + public Map getData() { + return data; + } + + /** + * @return Name of the table to update data in. + */ + @JsonProperty("tableName") + public Optional getTableName() { + return tableName; + } + + /** + * @return Type of update operation to perform. + */ + @JsonProperty("updateType") + public Optional getUpdateType() { + return updateType; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof UpdateRecordData && equalTo((UpdateRecordData) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(UpdateRecordData other) { + return skyflowId.equals(other.skyflowId) + && data.equals(other.data) + && tableName.equals(other.tableName) + && updateType.equals(other.updateType); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.skyflowId, this.data, this.tableName, this.updateType); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static SkyflowIdStage builder() { + return new Builder(); + } + + public interface SkyflowIdStage { + /** + *

Skyflow ID of the record to update.

+ */ + _FinalStage skyflowId(@NotNull String skyflowId); + + Builder from(UpdateRecordData other); + } + + public interface _FinalStage { + UpdateRecordData build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + + /** + *

Columns and values for the record.

+ */ + _FinalStage data(Map data); + + _FinalStage putAllData(Map data); + + _FinalStage data(String key, Object value); + + /** + *

Name of the table to update data in.

+ */ + _FinalStage tableName(Optional tableName); + + _FinalStage tableName(String tableName); + + /** + *

Type of update operation to perform.

+ */ + _FinalStage updateType(Optional updateType); + + _FinalStage updateType(UpdateRecordDataUpdateType updateType); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements SkyflowIdStage, _FinalStage { + private String skyflowId; + + private Optional updateType = Optional.empty(); + + private Optional tableName = Optional.empty(); + + private Map data = new LinkedHashMap<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(UpdateRecordData other) { + skyflowId(other.getSkyflowId()); + data(other.getData()); + tableName(other.getTableName()); + updateType(other.getUpdateType()); + return this; + } + + /** + *

Skyflow ID of the record to update.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("skyflowID") + public _FinalStage skyflowId(@NotNull String skyflowId) { + this.skyflowId = Objects.requireNonNull(skyflowId, "skyflowId must not be null"); + return this; + } + + /** + *

Type of update operation to perform.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage updateType(UpdateRecordDataUpdateType updateType) { + this.updateType = Optional.ofNullable(updateType); + return this; + } + + /** + *

Type of update operation to perform.

+ */ + @java.lang.Override + @JsonSetter(value = "updateType", nulls = Nulls.SKIP) + public _FinalStage updateType(Optional updateType) { + this.updateType = updateType; + return this; + } + + /** + *

Name of the table to update data in.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage tableName(String tableName) { + this.tableName = Optional.ofNullable(tableName); + return this; + } + + /** + *

Name of the table to update data in.

+ */ + @java.lang.Override + @JsonSetter(value = "tableName", nulls = Nulls.SKIP) + public _FinalStage tableName(Optional tableName) { + this.tableName = tableName; + return this; + } + + /** + *

Columns and values for the record.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage data(String key, Object value) { + this.data.put(key, value); + return this; + } + + /** + *

Columns and values for the record.

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage putAllData(Map data) { + if (data != null) { + this.data.putAll(data); + } + return this; + } + + /** + *

Columns and values for the record.

+ */ + @java.lang.Override + @JsonSetter(value = "data", nulls = Nulls.SKIP) + public _FinalStage data(Map data) { + this.data.clear(); + if (data != null) { + this.data.putAll(data); + } + return this; + } + + @java.lang.Override + public UpdateRecordData build() { + return new UpdateRecordData(skyflowId, data, tableName, updateType, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/UpdateRecordDataUpdateType.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/UpdateRecordDataUpdateType.java new file mode 100644 index 00000000..2fe52e9d --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/UpdateRecordDataUpdateType.java @@ -0,0 +1,84 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public final class UpdateRecordDataUpdateType { + public static final UpdateRecordDataUpdateType REPLACE = new UpdateRecordDataUpdateType(Value.REPLACE, "REPLACE"); + + public static final UpdateRecordDataUpdateType UPDATE = new UpdateRecordDataUpdateType(Value.UPDATE, "UPDATE"); + + private final Value value; + + private final String string; + + UpdateRecordDataUpdateType(Value value, String string) { + this.value = value; + this.string = string; + } + + public Value getEnumValue() { + return value; + } + + @java.lang.Override + @JsonValue + public String toString() { + return this.string; + } + + @java.lang.Override + public boolean equals(Object other) { + return (this == other) + || (other instanceof UpdateRecordDataUpdateType + && this.string.equals(((UpdateRecordDataUpdateType) other).string)); + } + + @java.lang.Override + public int hashCode() { + return this.string.hashCode(); + } + + public T visit(Visitor visitor) { + switch (value) { + case REPLACE: + return visitor.visitReplace(); + case UPDATE: + return visitor.visitUpdate(); + case UNKNOWN: + default: + return visitor.visitUnknown(string); + } + } + + @JsonCreator(mode = JsonCreator.Mode.DELEGATING) + public static UpdateRecordDataUpdateType valueOf(String value) { + switch (value) { + case "REPLACE": + return REPLACE; + case "UPDATE": + return UPDATE; + default: + return new UpdateRecordDataUpdateType(Value.UNKNOWN, value); + } + } + + public enum Value { + UPDATE, + + REPLACE, + + UNKNOWN + } + + public interface Visitor { + T visitUpdate(); + + T visitReplace(); + + T visitUnknown(String unknownType); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/UpdateResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/UpdateResponse.java new file mode 100644 index 00000000..7f509065 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/UpdateResponse.java @@ -0,0 +1,122 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = UpdateResponse.Builder.class) +public final class UpdateResponse { + private final List records; + + private final Map additionalProperties; + + private UpdateResponse(List records, Map additionalProperties) { + this.records = records; + this.additionalProperties = additionalProperties; + } + + /** + * @return List of updated records. + */ + @JsonProperty("records") + public List getRecords() { + return records; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof UpdateResponse && equalTo((UpdateResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(UpdateResponse other) { + return records.equals(other.records); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.records); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private List records = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(UpdateResponse other) { + records(other.getRecords()); + return this; + } + + /** + *

List of updated records.

+ */ + @JsonSetter(value = "records", nulls = Nulls.SKIP) + public Builder records(List records) { + this.records.clear(); + if (records != null) { + this.records.addAll(records); + } + return this; + } + + public Builder addRecords(RecordResponseObject records) { + this.records.add(records); + return this; + } + + public Builder addAllRecords(List records) { + if (records != null) { + this.records.addAll(records); + } + return this; + } + + public UpdateResponse build() { + return new UpdateResponse(records, additionalProperties); + } + + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/Upsert.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/Upsert.java new file mode 100644 index 00000000..d413f637 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/Upsert.java @@ -0,0 +1,154 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.skyflow.generated.rest.core.ObjectMappers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = Upsert.Builder.class) +public final class Upsert { + private final Optional updateType; + + private final List uniqueColumns; + + private final Map additionalProperties; + + private Upsert( + Optional updateType, + List uniqueColumns, + Map additionalProperties) { + this.updateType = updateType; + this.uniqueColumns = uniqueColumns; + this.additionalProperties = additionalProperties; + } + + /** + * @return Type of update operation to perform. + */ + @JsonProperty("updateType") + public Optional getUpdateType() { + return updateType; + } + + /** + * @return List of unique columns in the table that upsert operations use to identify if a record with matching values exists. If a matching record exists, the record updates with the specified values. If a matching record doesn't exist, the upsert operation inserts a new record. + */ + @JsonProperty("uniqueColumns") + public List getUniqueColumns() { + return uniqueColumns; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof Upsert && equalTo((Upsert) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(Upsert other) { + return updateType.equals(other.updateType) && uniqueColumns.equals(other.uniqueColumns); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.updateType, this.uniqueColumns); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional updateType = Optional.empty(); + + private List uniqueColumns = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(Upsert other) { + updateType(other.getUpdateType()); + uniqueColumns(other.getUniqueColumns()); + return this; + } + + /** + *

Type of update operation to perform.

+ */ + @JsonSetter(value = "updateType", nulls = Nulls.SKIP) + public Builder updateType(Optional updateType) { + this.updateType = updateType; + return this; + } + + public Builder updateType(UpsertUpdateType updateType) { + this.updateType = Optional.ofNullable(updateType); + return this; + } + + /** + *

List of unique columns in the table that upsert operations use to identify if a record with matching values exists. If a matching record exists, the record updates with the specified values. If a matching record doesn't exist, the upsert operation inserts a new record.

+ */ + @JsonSetter(value = "uniqueColumns", nulls = Nulls.SKIP) + public Builder uniqueColumns(List uniqueColumns) { + this.uniqueColumns.clear(); + if (uniqueColumns != null) { + this.uniqueColumns.addAll(uniqueColumns); + } + return this; + } + + public Builder addUniqueColumns(String uniqueColumns) { + this.uniqueColumns.add(uniqueColumns); + return this; + } + + public Builder addAllUniqueColumns(List uniqueColumns) { + if (uniqueColumns != null) { + this.uniqueColumns.addAll(uniqueColumns); + } + return this; + } + + public Upsert build() { + return new Upsert(updateType, uniqueColumns, additionalProperties); + } + + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/UpsertUpdateType.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/UpsertUpdateType.java new file mode 100644 index 00000000..09196134 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/generated/rest/types/UpsertUpdateType.java @@ -0,0 +1,83 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.skyflow.generated.rest.types; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public final class UpsertUpdateType { + public static final UpsertUpdateType REPLACE = new UpsertUpdateType(Value.REPLACE, "REPLACE"); + + public static final UpsertUpdateType UPDATE = new UpsertUpdateType(Value.UPDATE, "UPDATE"); + + private final Value value; + + private final String string; + + UpsertUpdateType(Value value, String string) { + this.value = value; + this.string = string; + } + + public Value getEnumValue() { + return value; + } + + @java.lang.Override + @JsonValue + public String toString() { + return this.string; + } + + @java.lang.Override + public boolean equals(Object other) { + return (this == other) + || (other instanceof UpsertUpdateType && this.string.equals(((UpsertUpdateType) other).string)); + } + + @java.lang.Override + public int hashCode() { + return this.string.hashCode(); + } + + public T visit(Visitor visitor) { + switch (value) { + case REPLACE: + return visitor.visitReplace(); + case UPDATE: + return visitor.visitUpdate(); + case UNKNOWN: + default: + return visitor.visitUnknown(string); + } + } + + @JsonCreator(mode = JsonCreator.Mode.DELEGATING) + public static UpsertUpdateType valueOf(String value) { + switch (value) { + case "REPLACE": + return REPLACE; + case "UPDATE": + return UPDATE; + default: + return new UpsertUpdateType(Value.UNKNOWN, value); + } + } + + public enum Value { + UPDATE, + + REPLACE, + + UNKNOWN + } + + public interface Visitor { + T visitUpdate(); + + T visitReplace(); + + T visitUnknown(String unknownType); + } +} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ColumnRedactions.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ColumnRedactions.java deleted file mode 100644 index b467a8c0..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ColumnRedactions.java +++ /dev/null @@ -1,125 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1ColumnRedactions.Builder.class) -public final class V1ColumnRedactions { - private final Optional columnName; - - private final Optional redaction; - - private final Map additionalProperties; - - private V1ColumnRedactions( - Optional columnName, Optional redaction, Map additionalProperties) { - this.columnName = columnName; - this.redaction = redaction; - this.additionalProperties = additionalProperties; - } - - /** - * @return Name of the column to be redacted - */ - @JsonProperty("columnName") - public Optional getColumnName() { - return columnName; - } - - /** - * @return Name of the redaction. Eg: plain_text, redacted, mask1 - */ - @JsonProperty("redaction") - public Optional getRedaction() { - return redaction; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1ColumnRedactions && equalTo((V1ColumnRedactions) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1ColumnRedactions other) { - return columnName.equals(other.columnName) && redaction.equals(other.redaction); - } - - @Override - public int hashCode() { - return Objects.hash(this.columnName, this.redaction); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional columnName = Optional.empty(); - - private Optional redaction = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1ColumnRedactions other) { - columnName(other.getColumnName()); - redaction(other.getRedaction()); - return this; - } - - /** - *

Name of the column to be redacted

- */ - @JsonSetter(value = "columnName", nulls = Nulls.SKIP) - public Builder columnName(Optional columnName) { - this.columnName = columnName; - return this; - } - - public Builder columnName(String columnName) { - this.columnName = Optional.ofNullable(columnName); - return this; - } - - /** - *

Name of the redaction. Eg: plain_text, redacted, mask1

- */ - @JsonSetter(value = "redaction", nulls = Nulls.SKIP) - public Builder redaction(Optional redaction) { - this.redaction = redaction; - return this; - } - - public Builder redaction(String redaction) { - this.redaction = Optional.ofNullable(redaction); - return this; - } - - public V1ColumnRedactions build() { - return new V1ColumnRedactions(columnName, redaction, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteResponse.java deleted file mode 100644 index 24bd865d..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteResponse.java +++ /dev/null @@ -1,93 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1DeleteResponse.Builder.class) -public final class V1DeleteResponse { - private final Optional> records; - - private final Map additionalProperties; - - private V1DeleteResponse(Optional> records, Map additionalProperties) { - this.records = records; - this.additionalProperties = additionalProperties; - } - - /** - * @return List of deleted records with skyflow ID and any partial errors. - */ - @JsonProperty("records") - public Optional> getRecords() { - return records; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1DeleteResponse && equalTo((V1DeleteResponse) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1DeleteResponse other) { - return records.equals(other.records); - } - - @Override - public int hashCode() { - return Objects.hash(this.records); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional> records = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1DeleteResponse other) { - records(other.getRecords()); - return this; - } - - /** - *

List of deleted records with skyflow ID and any partial errors.

- */ - @JsonSetter(value = "records", nulls = Nulls.SKIP) - public Builder records(Optional> records) { - this.records = records; - return this; - } - - public Builder records(List records) { - this.records = Optional.ofNullable(records); - return this; - } - - public V1DeleteResponse build() { - return new V1DeleteResponse(records, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteResponseObject.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteResponseObject.java deleted file mode 100644 index 087ce4c7..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1DeleteResponseObject.java +++ /dev/null @@ -1,156 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1DeleteResponseObject.Builder.class) -public final class V1DeleteResponseObject { - private final Optional skyflowId; - - private final Optional error; - - private final Optional httpCode; - - private final Map additionalProperties; - - private V1DeleteResponseObject( - Optional skyflowId, - Optional error, - Optional httpCode, - Map additionalProperties) { - this.skyflowId = skyflowId; - this.error = error; - this.httpCode = httpCode; - this.additionalProperties = additionalProperties; - } - - /** - * @return Skyflow ID for the deleted record - */ - @JsonProperty("skyflowID") - public Optional getSkyflowId() { - return skyflowId; - } - - /** - * @return Partial Error message if any - */ - @JsonProperty("error") - public Optional getError() { - return error; - } - - /** - * @return HTTP status code of the response - */ - @JsonProperty("httpCode") - public Optional getHttpCode() { - return httpCode; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1DeleteResponseObject && equalTo((V1DeleteResponseObject) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1DeleteResponseObject other) { - return skyflowId.equals(other.skyflowId) && error.equals(other.error) && httpCode.equals(other.httpCode); - } - - @Override - public int hashCode() { - return Objects.hash(this.skyflowId, this.error, this.httpCode); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional skyflowId = Optional.empty(); - - private Optional error = Optional.empty(); - - private Optional httpCode = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1DeleteResponseObject other) { - skyflowId(other.getSkyflowId()); - error(other.getError()); - httpCode(other.getHttpCode()); - return this; - } - - /** - *

Skyflow ID for the deleted record

- */ - @JsonSetter(value = "skyflowID", nulls = Nulls.SKIP) - public Builder skyflowId(Optional skyflowId) { - this.skyflowId = skyflowId; - return this; - } - - public Builder skyflowId(String skyflowId) { - this.skyflowId = Optional.ofNullable(skyflowId); - return this; - } - - /** - *

Partial Error message if any

- */ - @JsonSetter(value = "error", nulls = Nulls.SKIP) - public Builder error(Optional error) { - this.error = error; - return this; - } - - public Builder error(String error) { - this.error = Optional.ofNullable(error); - return this; - } - - /** - *

HTTP status code of the response

- */ - @JsonSetter(value = "httpCode", nulls = Nulls.SKIP) - public Builder httpCode(Optional httpCode) { - this.httpCode = httpCode; - return this; - } - - public Builder httpCode(Integer httpCode) { - this.httpCode = Optional.ofNullable(httpCode); - return this; - } - - public V1DeleteResponseObject build() { - return new V1DeleteResponseObject(skyflowId, error, httpCode, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryRecordResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryRecordResponse.java deleted file mode 100644 index 9de3418b..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryRecordResponse.java +++ /dev/null @@ -1,96 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1ExecuteQueryRecordResponse.Builder.class) -public final class V1ExecuteQueryRecordResponse { - private final Optional> data; - - private final Map additionalProperties; - - private V1ExecuteQueryRecordResponse(Optional> data, Map additionalProperties) { - this.data = data; - this.additionalProperties = additionalProperties; - } - - /** - * @return Fields and values for the record. For example, {'field_1':'value_1', 'field_2':'value_2'}. - */ - @JsonProperty("data") - public Optional> getData() { - return data; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1ExecuteQueryRecordResponse && equalTo((V1ExecuteQueryRecordResponse) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1ExecuteQueryRecordResponse other) { - return data.equals(other.data); - } - - @Override - public int hashCode() { - return Objects.hash(this.data); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional> data = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1ExecuteQueryRecordResponse other) { - data(other.getData()); - return this; - } - - /** - *

Fields and values for the record. For example, {'field_1':'value_1', 'field_2':'value_2'}.

- */ - @JsonSetter(value = "data", nulls = Nulls.SKIP) - public Builder data(Optional> data) { - this.data = data; - return this; - } - - public Builder data(Map data) { - this.data = Optional.ofNullable(data); - return this; - } - - public V1ExecuteQueryRecordResponse build() { - return new V1ExecuteQueryRecordResponse(data, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryResponse.java deleted file mode 100644 index f80b54e0..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1ExecuteQueryResponse.java +++ /dev/null @@ -1,118 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1ExecuteQueryResponse.Builder.class) -public final class V1ExecuteQueryResponse { - private final Optional> records; - - private final Optional metadata; - - private final Map additionalProperties; - - private V1ExecuteQueryResponse( - Optional> records, - Optional metadata, - Map additionalProperties) { - this.records = records; - this.metadata = metadata; - this.additionalProperties = additionalProperties; - } - - /** - * @return Records corresponding to the specified query. - */ - @JsonProperty("records") - public Optional> getRecords() { - return records; - } - - @JsonProperty("metadata") - public Optional getMetadata() { - return metadata; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1ExecuteQueryResponse && equalTo((V1ExecuteQueryResponse) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1ExecuteQueryResponse other) { - return records.equals(other.records) && metadata.equals(other.metadata); - } - - @Override - public int hashCode() { - return Objects.hash(this.records, this.metadata); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional> records = Optional.empty(); - - private Optional metadata = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1ExecuteQueryResponse other) { - records(other.getRecords()); - metadata(other.getMetadata()); - return this; - } - - /** - *

Records corresponding to the specified query.

- */ - @JsonSetter(value = "records", nulls = Nulls.SKIP) - public Builder records(Optional> records) { - this.records = records; - return this; - } - - public Builder records(List records) { - this.records = Optional.ofNullable(records); - return this; - } - - @JsonSetter(value = "metadata", nulls = Nulls.SKIP) - public Builder metadata(Optional metadata) { - this.metadata = metadata; - return this; - } - - public Builder metadata(V1ExecuteQueryResponseMetadata metadata) { - this.metadata = Optional.ofNullable(metadata); - return this; - } - - public V1ExecuteQueryResponse build() { - return new V1ExecuteQueryResponse(records, metadata, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDeleteTokenResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDeleteTokenResponse.java deleted file mode 100644 index 34ca245c..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDeleteTokenResponse.java +++ /dev/null @@ -1,94 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1FlowDeleteTokenResponse.Builder.class) -public final class V1FlowDeleteTokenResponse { - private final Optional> tokens; - - private final Map additionalProperties; - - private V1FlowDeleteTokenResponse( - Optional> tokens, Map additionalProperties) { - this.tokens = tokens; - this.additionalProperties = additionalProperties; - } - - /** - * @return Tokens data for Delete - */ - @JsonProperty("tokens") - public Optional> getTokens() { - return tokens; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1FlowDeleteTokenResponse && equalTo((V1FlowDeleteTokenResponse) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1FlowDeleteTokenResponse other) { - return tokens.equals(other.tokens); - } - - @Override - public int hashCode() { - return Objects.hash(this.tokens); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional> tokens = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1FlowDeleteTokenResponse other) { - tokens(other.getTokens()); - return this; - } - - /** - *

Tokens data for Delete

- */ - @JsonSetter(value = "tokens", nulls = Nulls.SKIP) - public Builder tokens(Optional> tokens) { - this.tokens = tokens; - return this; - } - - public Builder tokens(List tokens) { - this.tokens = Optional.ofNullable(tokens); - return this; - } - - public V1FlowDeleteTokenResponse build() { - return new V1FlowDeleteTokenResponse(tokens, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDetokenizeResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDetokenizeResponse.java deleted file mode 100644 index defe1dad..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDetokenizeResponse.java +++ /dev/null @@ -1,94 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1FlowDetokenizeResponse.Builder.class) -public final class V1FlowDetokenizeResponse { - private final Optional> response; - - private final Map additionalProperties; - - private V1FlowDetokenizeResponse( - Optional> response, Map additionalProperties) { - this.response = response; - this.additionalProperties = additionalProperties; - } - - /** - * @return Detokenized data - */ - @JsonProperty("response") - public Optional> getResponse() { - return response; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1FlowDetokenizeResponse && equalTo((V1FlowDetokenizeResponse) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1FlowDetokenizeResponse other) { - return response.equals(other.response); - } - - @Override - public int hashCode() { - return Objects.hash(this.response); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional> response = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1FlowDetokenizeResponse other) { - response(other.getResponse()); - return this; - } - - /** - *

Detokenized data

- */ - @JsonSetter(value = "response", nulls = Nulls.SKIP) - public Builder response(Optional> response) { - this.response = response; - return this; - } - - public Builder response(List response) { - this.response = Optional.ofNullable(response); - return this; - } - - public V1FlowDetokenizeResponse build() { - return new V1FlowDetokenizeResponse(response, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDetokenizeResponseObject.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDetokenizeResponseObject.java deleted file mode 100644 index f0cf909d..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowDetokenizeResponseObject.java +++ /dev/null @@ -1,249 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1FlowDetokenizeResponseObject.Builder.class) -public final class V1FlowDetokenizeResponseObject { - private final Optional token; - - private final Optional value; - - private final Optional tokenGroupName; - - private final Optional error; - - private final Optional httpCode; - - private final Optional> metadata; - - private final Map additionalProperties; - - private V1FlowDetokenizeResponseObject( - Optional token, - Optional value, - Optional tokenGroupName, - Optional error, - Optional httpCode, - Optional> metadata, - Map additionalProperties) { - this.token = token; - this.value = value; - this.tokenGroupName = tokenGroupName; - this.error = error; - this.httpCode = httpCode; - this.metadata = metadata; - this.additionalProperties = additionalProperties; - } - - /** - * @return Token to be detokenized - */ - @JsonProperty("token") - public Optional getToken() { - return token; - } - - /** - * @return Detokenized value for the token - */ - @JsonProperty("value") - public Optional getValue() { - return value; - } - - /** - * @return Token group name - */ - @JsonProperty("tokenGroupName") - public Optional getTokenGroupName() { - return tokenGroupName; - } - - /** - * @return Error if detokenization failed - */ - @JsonProperty("error") - public Optional getError() { - return error; - } - - /** - * @return HTTP status code of the response - */ - @JsonProperty("httpCode") - public Optional getHttpCode() { - return httpCode; - } - - /** - * @return Additional metadata associated with the token, such as tableName or skyflowID - */ - @JsonProperty("metadata") - public Optional> getMetadata() { - return metadata; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1FlowDetokenizeResponseObject && equalTo((V1FlowDetokenizeResponseObject) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1FlowDetokenizeResponseObject other) { - return token.equals(other.token) - && value.equals(other.value) - && tokenGroupName.equals(other.tokenGroupName) - && error.equals(other.error) - && httpCode.equals(other.httpCode) - && metadata.equals(other.metadata); - } - - @Override - public int hashCode() { - return Objects.hash(this.token, this.value, this.tokenGroupName, this.error, this.httpCode, this.metadata); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional token = Optional.empty(); - - private Optional value = Optional.empty(); - - private Optional tokenGroupName = Optional.empty(); - - private Optional error = Optional.empty(); - - private Optional httpCode = Optional.empty(); - - private Optional> metadata = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1FlowDetokenizeResponseObject other) { - token(other.getToken()); - value(other.getValue()); - tokenGroupName(other.getTokenGroupName()); - error(other.getError()); - httpCode(other.getHttpCode()); - metadata(other.getMetadata()); - return this; - } - - /** - *

Token to be detokenized

- */ - @JsonSetter(value = "token", nulls = Nulls.SKIP) - public Builder token(Optional token) { - this.token = token; - return this; - } - - public Builder token(String token) { - this.token = Optional.ofNullable(token); - return this; - } - - /** - *

Detokenized value for the token

- */ - @JsonSetter(value = "value", nulls = Nulls.SKIP) - public Builder value(Optional value) { - this.value = value; - return this; - } - - public Builder value(Object value) { - this.value = Optional.ofNullable(value); - return this; - } - - /** - *

Token group name

- */ - @JsonSetter(value = "tokenGroupName", nulls = Nulls.SKIP) - public Builder tokenGroupName(Optional tokenGroupName) { - this.tokenGroupName = tokenGroupName; - return this; - } - - public Builder tokenGroupName(String tokenGroupName) { - this.tokenGroupName = Optional.ofNullable(tokenGroupName); - return this; - } - - /** - *

Error if detokenization failed

- */ - @JsonSetter(value = "error", nulls = Nulls.SKIP) - public Builder error(Optional error) { - this.error = error; - return this; - } - - public Builder error(String error) { - this.error = Optional.ofNullable(error); - return this; - } - - /** - *

HTTP status code of the response

- */ - @JsonSetter(value = "httpCode", nulls = Nulls.SKIP) - public Builder httpCode(Optional httpCode) { - this.httpCode = httpCode; - return this; - } - - public Builder httpCode(Integer httpCode) { - this.httpCode = Optional.ofNullable(httpCode); - return this; - } - - /** - *

Additional metadata associated with the token, such as tableName or skyflowID

- */ - @JsonSetter(value = "metadata", nulls = Nulls.SKIP) - public Builder metadata(Optional> metadata) { - this.metadata = metadata; - return this; - } - - public Builder metadata(Map metadata) { - this.metadata = Optional.ofNullable(metadata); - return this; - } - - public V1FlowDetokenizeResponseObject build() { - return new V1FlowDetokenizeResponseObject( - token, value, tokenGroupName, error, httpCode, metadata, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeRequestObject.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeRequestObject.java deleted file mode 100644 index adefcaed..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeRequestObject.java +++ /dev/null @@ -1,153 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1FlowTokenizeRequestObject.Builder.class) -public final class V1FlowTokenizeRequestObject { - private final Optional value; - - private final Optional> tokenGroupNames; - - private final Optional token; - - private final Map additionalProperties; - - private V1FlowTokenizeRequestObject( - Optional value, - Optional> tokenGroupNames, - Optional token, - Map additionalProperties) { - this.value = value; - this.tokenGroupNames = tokenGroupNames; - this.token = token; - this.additionalProperties = additionalProperties; - } - - /** - * @return Token Value - */ - @JsonProperty("value") - public Optional getValue() { - return value; - } - - /** - * @return List of token group names - */ - @JsonProperty("tokenGroupNames") - public Optional> getTokenGroupNames() { - return tokenGroupNames; - } - - /** - * @return Token for the value, in case of BYOT. - */ - @JsonProperty("token") - public Optional getToken() { - return token; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1FlowTokenizeRequestObject && equalTo((V1FlowTokenizeRequestObject) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1FlowTokenizeRequestObject other) { - return value.equals(other.value) && tokenGroupNames.equals(other.tokenGroupNames) && token.equals(other.token); - } - - @Override - public int hashCode() { - return Objects.hash(this.value, this.tokenGroupNames, this.token); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional value = Optional.empty(); - - private Optional> tokenGroupNames = Optional.empty(); - - private Optional token = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1FlowTokenizeRequestObject other) { - value(other.getValue()); - tokenGroupNames(other.getTokenGroupNames()); - token(other.getToken()); - return this; - } - - /** - *

Token Value

- */ - @JsonSetter(value = "value", nulls = Nulls.SKIP) - public Builder value(Optional value) { - this.value = value; - return this; - } - - public Builder value(Object value) { - this.value = Optional.ofNullable(value); - return this; - } - - /** - *

List of token group names

- */ - @JsonSetter(value = "tokenGroupNames", nulls = Nulls.SKIP) - public Builder tokenGroupNames(Optional> tokenGroupNames) { - this.tokenGroupNames = tokenGroupNames; - return this; - } - - public Builder tokenGroupNames(List tokenGroupNames) { - this.tokenGroupNames = Optional.ofNullable(tokenGroupNames); - return this; - } - - /** - *

Token for the value, in case of BYOT.

- */ - @JsonSetter(value = "token", nulls = Nulls.SKIP) - public Builder token(Optional token) { - this.token = token; - return this; - } - - public Builder token(Object token) { - this.token = Optional.ofNullable(token); - return this; - } - - public V1FlowTokenizeRequestObject build() { - return new V1FlowTokenizeRequestObject(value, tokenGroupNames, token, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeResponse.java deleted file mode 100644 index cf071b86..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeResponse.java +++ /dev/null @@ -1,94 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1FlowTokenizeResponse.Builder.class) -public final class V1FlowTokenizeResponse { - private final Optional> response; - - private final Map additionalProperties; - - private V1FlowTokenizeResponse( - Optional> response, Map additionalProperties) { - this.response = response; - this.additionalProperties = additionalProperties; - } - - /** - * @return Tokenized data - */ - @JsonProperty("response") - public Optional> getResponse() { - return response; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1FlowTokenizeResponse && equalTo((V1FlowTokenizeResponse) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1FlowTokenizeResponse other) { - return response.equals(other.response); - } - - @Override - public int hashCode() { - return Objects.hash(this.response); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional> response = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1FlowTokenizeResponse other) { - response(other.getResponse()); - return this; - } - - /** - *

Tokenized data

- */ - @JsonSetter(value = "response", nulls = Nulls.SKIP) - public Builder response(Optional> response) { - this.response = response; - return this; - } - - public Builder response(List response) { - this.response = Optional.ofNullable(response); - return this; - } - - public V1FlowTokenizeResponse build() { - return new V1FlowTokenizeResponse(response, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeResponseObject.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeResponseObject.java deleted file mode 100644 index badc525e..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowTokenizeResponseObject.java +++ /dev/null @@ -1,218 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1FlowTokenizeResponseObject.Builder.class) -public final class V1FlowTokenizeResponseObject { - private final Optional token; - - private final Optional value; - - private final Optional tokenGroupName; - - private final Optional error; - - private final Optional httpCode; - - private final Map additionalProperties; - - private V1FlowTokenizeResponseObject( - Optional token, - Optional value, - Optional tokenGroupName, - Optional error, - Optional httpCode, - Map additionalProperties) { - this.token = token; - this.value = value; - this.tokenGroupName = tokenGroupName; - this.error = error; - this.httpCode = httpCode; - this.additionalProperties = additionalProperties; - } - - /** - * @return Token that was generated - */ - @JsonProperty("token") - public Optional getToken() { - return token; - } - - /** - * @return Value that was tokenized - */ - @JsonProperty("value") - public Optional getValue() { - return value; - } - - /** - * @return Name of the token group - */ - @JsonProperty("tokenGroupName") - public Optional getTokenGroupName() { - return tokenGroupName; - } - - /** - * @return Error if tokenization failed - */ - @JsonProperty("error") - public Optional getError() { - return error; - } - - /** - * @return HTTP status code of the response - */ - @JsonProperty("httpCode") - public Optional getHttpCode() { - return httpCode; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1FlowTokenizeResponseObject && equalTo((V1FlowTokenizeResponseObject) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1FlowTokenizeResponseObject other) { - return token.equals(other.token) - && value.equals(other.value) - && tokenGroupName.equals(other.tokenGroupName) - && error.equals(other.error) - && httpCode.equals(other.httpCode); - } - - @Override - public int hashCode() { - return Objects.hash(this.token, this.value, this.tokenGroupName, this.error, this.httpCode); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional token = Optional.empty(); - - private Optional value = Optional.empty(); - - private Optional tokenGroupName = Optional.empty(); - - private Optional error = Optional.empty(); - - private Optional httpCode = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1FlowTokenizeResponseObject other) { - token(other.getToken()); - value(other.getValue()); - tokenGroupName(other.getTokenGroupName()); - error(other.getError()); - httpCode(other.getHttpCode()); - return this; - } - - /** - *

Token that was generated

- */ - @JsonSetter(value = "token", nulls = Nulls.SKIP) - public Builder token(Optional token) { - this.token = token; - return this; - } - - public Builder token(String token) { - this.token = Optional.ofNullable(token); - return this; - } - - /** - *

Value that was tokenized

- */ - @JsonSetter(value = "value", nulls = Nulls.SKIP) - public Builder value(Optional value) { - this.value = value; - return this; - } - - public Builder value(Object value) { - this.value = Optional.ofNullable(value); - return this; - } - - /** - *

Name of the token group

- */ - @JsonSetter(value = "tokenGroupName", nulls = Nulls.SKIP) - public Builder tokenGroupName(Optional tokenGroupName) { - this.tokenGroupName = tokenGroupName; - return this; - } - - public Builder tokenGroupName(String tokenGroupName) { - this.tokenGroupName = Optional.ofNullable(tokenGroupName); - return this; - } - - /** - *

Error if tokenization failed

- */ - @JsonSetter(value = "error", nulls = Nulls.SKIP) - public Builder error(Optional error) { - this.error = error; - return this; - } - - public Builder error(String error) { - this.error = Optional.ofNullable(error); - return this; - } - - /** - *

HTTP status code of the response

- */ - @JsonSetter(value = "httpCode", nulls = Nulls.SKIP) - public Builder httpCode(Optional httpCode) { - this.httpCode = httpCode; - return this; - } - - public Builder httpCode(Integer httpCode) { - this.httpCode = Optional.ofNullable(httpCode); - return this; - } - - public V1FlowTokenizeResponseObject build() { - return new V1FlowTokenizeResponseObject(token, value, tokenGroupName, error, httpCode, additionalProperties); - } - } -} \ No newline at end of file diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowVaultMetricsData.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowVaultMetricsData.java deleted file mode 100644 index 5345de38..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowVaultMetricsData.java +++ /dev/null @@ -1,96 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1FlowVaultMetricsData.Builder.class) -public final class V1FlowVaultMetricsData { - private final Optional> tables; - - private final Map additionalProperties; - - private V1FlowVaultMetricsData(Optional> tables, Map additionalProperties) { - this.tables = tables; - this.additionalProperties = additionalProperties; - } - - /** - * @return Map of table names to their metrics - */ - @JsonProperty("tables") - public Optional> getTables() { - return tables; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1FlowVaultMetricsData && equalTo((V1FlowVaultMetricsData) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1FlowVaultMetricsData other) { - return tables.equals(other.tables); - } - - @Override - public int hashCode() { - return Objects.hash(this.tables); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional> tables = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1FlowVaultMetricsData other) { - tables(other.getTables()); - return this; - } - - /** - *

Map of table names to their metrics

- */ - @JsonSetter(value = "tables", nulls = Nulls.SKIP) - public Builder tables(Optional> tables) { - this.tables = tables; - return this; - } - - public Builder tables(Map tables) { - this.tables = Optional.ofNullable(tables); - return this; - } - - public V1FlowVaultMetricsData build() { - return new V1FlowVaultMetricsData(tables, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowVaultMetricsResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowVaultMetricsResponse.java deleted file mode 100644 index f933bce5..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1FlowVaultMetricsResponse.java +++ /dev/null @@ -1,121 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1FlowVaultMetricsResponse.Builder.class) -public final class V1FlowVaultMetricsResponse { - private final Optional data; - - private final Optional> error; - - private final Map additionalProperties; - - private V1FlowVaultMetricsResponse( - Optional data, - Optional> error, - Map additionalProperties) { - this.data = data; - this.error = error; - this.additionalProperties = additionalProperties; - } - - @JsonProperty("data") - public Optional getData() { - return data; - } - - /** - * @return Error information, if any - */ - @JsonProperty("error") - public Optional> getError() { - return error; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1FlowVaultMetricsResponse && equalTo((V1FlowVaultMetricsResponse) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1FlowVaultMetricsResponse other) { - return data.equals(other.data) && error.equals(other.error); - } - - @Override - public int hashCode() { - return Objects.hash(this.data, this.error); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional data = Optional.empty(); - - private Optional> error = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1FlowVaultMetricsResponse other) { - data(other.getData()); - error(other.getError()); - return this; - } - - @JsonSetter(value = "data", nulls = Nulls.SKIP) - public Builder data(Optional data) { - this.data = data; - return this; - } - - public Builder data(V1FlowVaultMetricsData data) { - this.data = Optional.ofNullable(data); - return this; - } - - /** - *

Error information, if any

- */ - @JsonSetter(value = "error", nulls = Nulls.SKIP) - public Builder error(Optional> error) { - this.error = error; - return this; - } - - public Builder error(Map error) { - this.error = Optional.ofNullable(error); - return this; - } - - public V1FlowVaultMetricsResponse build() { - return new V1FlowVaultMetricsResponse(data, error, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1GetRequestData.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1GetRequestData.java deleted file mode 100644 index 0c0cfab9..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1GetRequestData.java +++ /dev/null @@ -1,216 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1GetRequestData.Builder.class) -public final class V1GetRequestData { - private final Optional tableName; - - private final Optional> skyflowIDs; - - private final Optional> columnRedactions; - - private final Optional> columns; - - private final Optional> uniqueValues; - - private final Map additionalProperties; - - private V1GetRequestData( - Optional tableName, - Optional> skyflowIDs, - Optional> columnRedactions, - Optional> columns, - Optional> uniqueValues, - Map additionalProperties) { - this.tableName = tableName; - this.skyflowIDs = skyflowIDs; - this.columnRedactions = columnRedactions; - this.columns = columns; - this.uniqueValues = uniqueValues; - this.additionalProperties = additionalProperties; - } - - /** - * @return Name of the table where data is being fetched - */ - @JsonProperty("tableName") - public Optional getTableName() { - return tableName; - } - - /** - * @return Skyflow ID for the record to be fetched - */ - @JsonProperty("skyflowIDs") - public Optional> getSkyflowIDs() { - return skyflowIDs; - } - - /** - * @return List of columns to be redacted. - */ - @JsonProperty("columnRedactions") - public Optional> getColumnRedactions() { - return columnRedactions; - } - - /** - * @return List of columns to be fetched. - */ - @JsonProperty("columns") - public Optional> getColumns() { - return columns; - } - - /** - * @return List of unique constraint values to query records by data - */ - @JsonProperty("uniqueValues") - public Optional> getUniqueValues() { - return uniqueValues; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1GetRequestData && equalTo((V1GetRequestData) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1GetRequestData other) { - return tableName.equals(other.tableName) - && skyflowIDs.equals(other.skyflowIDs) - && columnRedactions.equals(other.columnRedactions) - && columns.equals(other.columns) - && uniqueValues.equals(other.uniqueValues); - } - - @Override - public int hashCode() { - return Objects.hash(this.tableName, this.skyflowIDs, this.columnRedactions, this.columns, this.uniqueValues); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional tableName = Optional.empty(); - - private Optional> skyflowIDs = Optional.empty(); - - private Optional> columnRedactions = Optional.empty(); - - private Optional> columns = Optional.empty(); - - private Optional> uniqueValues = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1GetRequestData other) { - tableName(other.getTableName()); - skyflowIDs(other.getSkyflowIDs()); - columnRedactions(other.getColumnRedactions()); - columns(other.getColumns()); - uniqueValues(other.getUniqueValues()); - return this; - } - - /** - *

Name of the table where data is being fetched

- */ - @JsonSetter(value = "tableName", nulls = Nulls.SKIP) - public Builder tableName(Optional tableName) { - this.tableName = tableName; - return this; - } - - public Builder tableName(String tableName) { - this.tableName = Optional.ofNullable(tableName); - return this; - } - - /** - *

Skyflow ID for the record to be fetched

- */ - @JsonSetter(value = "skyflowIDs", nulls = Nulls.SKIP) - public Builder skyflowIDs(Optional> skyflowIDs) { - this.skyflowIDs = skyflowIDs; - return this; - } - - public Builder skyflowIDs(List skyflowIDs) { - this.skyflowIDs = Optional.ofNullable(skyflowIDs); - return this; - } - - /** - *

List of columns to be redacted.

- */ - @JsonSetter(value = "columnRedactions", nulls = Nulls.SKIP) - public Builder columnRedactions(Optional> columnRedactions) { - this.columnRedactions = columnRedactions; - return this; - } - - public Builder columnRedactions(List columnRedactions) { - this.columnRedactions = Optional.ofNullable(columnRedactions); - return this; - } - - /** - *

List of columns to be fetched.

- */ - @JsonSetter(value = "columns", nulls = Nulls.SKIP) - public Builder columns(Optional> columns) { - this.columns = columns; - return this; - } - - public Builder columns(List columns) { - this.columns = Optional.ofNullable(columns); - return this; - } - - /** - *

List of unique constraint values to query records by data

- */ - @JsonSetter(value = "uniqueValues", nulls = Nulls.SKIP) - public Builder uniqueValues(Optional> uniqueValues) { - this.uniqueValues = uniqueValues; - return this; - } - - public Builder uniqueValues(List uniqueValues) { - this.uniqueValues = Optional.ofNullable(uniqueValues); - return this; - } - - public V1GetRequestData build() { - return new V1GetRequestData( - tableName, skyflowIDs, columnRedactions, columns, uniqueValues, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1GetResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1GetResponse.java deleted file mode 100644 index a64a7588..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1GetResponse.java +++ /dev/null @@ -1,93 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1GetResponse.Builder.class) -public final class V1GetResponse { - private final Optional> records; - - private final Map additionalProperties; - - private V1GetResponse(Optional> records, Map additionalProperties) { - this.records = records; - this.additionalProperties = additionalProperties; - } - - /** - * @return List of fetched records with skyflow ID, tokens, data, and any partial errors - */ - @JsonProperty("records") - public Optional> getRecords() { - return records; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1GetResponse && equalTo((V1GetResponse) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1GetResponse other) { - return records.equals(other.records); - } - - @Override - public int hashCode() { - return Objects.hash(this.records); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional> records = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1GetResponse other) { - records(other.getRecords()); - return this; - } - - /** - *

List of fetched records with skyflow ID, tokens, data, and any partial errors

- */ - @JsonSetter(value = "records", nulls = Nulls.SKIP) - public Builder records(Optional> records) { - this.records = records; - return this; - } - - public Builder records(List records) { - this.records = Optional.ofNullable(records); - return this; - } - - public V1GetResponse build() { - return new V1GetResponse(records, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1InsertResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1InsertResponse.java deleted file mode 100644 index 4ff3ff2d..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1InsertResponse.java +++ /dev/null @@ -1,93 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1InsertResponse.Builder.class) -public final class V1InsertResponse { - private final Optional> records; - - private final Map additionalProperties; - - private V1InsertResponse(Optional> records, Map additionalProperties) { - this.records = records; - this.additionalProperties = additionalProperties; - } - - /** - * @return List of inserted records with skyflow ID, tokens, data, and any partial errors. - */ - @JsonProperty("records") - public Optional> getRecords() { - return records; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1InsertResponse && equalTo((V1InsertResponse) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1InsertResponse other) { - return records.equals(other.records); - } - - @Override - public int hashCode() { - return Objects.hash(this.records); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional> records = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1InsertResponse other) { - records(other.getRecords()); - return this; - } - - /** - *

List of inserted records with skyflow ID, tokens, data, and any partial errors.

- */ - @JsonSetter(value = "records", nulls = Nulls.SKIP) - public Builder records(Optional> records) { - this.records = records; - return this; - } - - public Builder records(List records) { - this.records = Optional.ofNullable(records); - return this; - } - - public V1InsertResponse build() { - return new V1InsertResponse(records, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1RecordResponseObject.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1RecordResponseObject.java deleted file mode 100644 index b6c2467c..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1RecordResponseObject.java +++ /dev/null @@ -1,280 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1RecordResponseObject.Builder.class) -public final class V1RecordResponseObject { - private final Optional skyflowId; - - private final Optional> tokens; - - private final Optional> data; - - private final Optional> hashedData; - - private final Optional error; - - private final Optional httpCode; - - private final Optional tableName; - - private final Map additionalProperties; - - private V1RecordResponseObject( - Optional skyflowId, - Optional> tokens, - Optional> data, - Optional> hashedData, - Optional error, - Optional httpCode, - Optional tableName, - Map additionalProperties) { - this.skyflowId = skyflowId; - this.tokens = tokens; - this.data = data; - this.hashedData = hashedData; - this.error = error; - this.httpCode = httpCode; - this.tableName = tableName; - this.additionalProperties = additionalProperties; - } - - /** - * @return Skyflow ID for the inserted record - */ - @JsonProperty("skyflowID") - public Optional getSkyflowId() { - return skyflowId; - } - - /** - * @return Tokens data for the columns if any - */ - @JsonProperty("tokens") - public Optional> getTokens() { - return tokens; - } - - /** - * @return Columns names and values - */ - @JsonProperty("data") - public Optional> getData() { - return data; - } - - /** - * @return Hashed Data for the columns if any - */ - @JsonProperty("hashedData") - public Optional> getHashedData() { - return hashedData; - } - - /** - * @return Partial Error message if any - */ - @JsonProperty("error") - public Optional getError() { - return error; - } - - /** - * @return HTTP status code of the response - */ - @JsonProperty("httpCode") - public Optional getHttpCode() { - return httpCode; - } - - /** - * @return Name of the table record belongs to - */ - @JsonProperty("tableName") - public Optional getTableName() { - return tableName; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1RecordResponseObject && equalTo((V1RecordResponseObject) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1RecordResponseObject other) { - return skyflowId.equals(other.skyflowId) - && tokens.equals(other.tokens) - && data.equals(other.data) - && hashedData.equals(other.hashedData) - && error.equals(other.error) - && httpCode.equals(other.httpCode) - && tableName.equals(other.tableName); - } - - @Override - public int hashCode() { - return Objects.hash( - this.skyflowId, this.tokens, this.data, this.hashedData, this.error, this.httpCode, this.tableName); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional skyflowId = Optional.empty(); - - private Optional> tokens = Optional.empty(); - - private Optional> data = Optional.empty(); - - private Optional> hashedData = Optional.empty(); - - private Optional error = Optional.empty(); - - private Optional httpCode = Optional.empty(); - - private Optional tableName = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1RecordResponseObject other) { - skyflowId(other.getSkyflowId()); - tokens(other.getTokens()); - data(other.getData()); - hashedData(other.getHashedData()); - error(other.getError()); - httpCode(other.getHttpCode()); - tableName(other.getTableName()); - return this; - } - - /** - *

Skyflow ID for the inserted record

- */ - @JsonSetter(value = "skyflowID", nulls = Nulls.SKIP) - public Builder skyflowId(Optional skyflowId) { - this.skyflowId = skyflowId; - return this; - } - - public Builder skyflowId(String skyflowId) { - this.skyflowId = Optional.ofNullable(skyflowId); - return this; - } - - /** - *

Tokens data for the columns if any

- */ - @JsonSetter(value = "tokens", nulls = Nulls.SKIP) - public Builder tokens(Optional> tokens) { - this.tokens = tokens; - return this; - } - - public Builder tokens(Map tokens) { - this.tokens = Optional.ofNullable(tokens); - return this; - } - - /** - *

Columns names and values

- */ - @JsonSetter(value = "data", nulls = Nulls.SKIP) - public Builder data(Optional> data) { - this.data = data; - return this; - } - - public Builder data(Map data) { - this.data = Optional.ofNullable(data); - return this; - } - - /** - *

Hashed Data for the columns if any

- */ - @JsonSetter(value = "hashedData", nulls = Nulls.SKIP) - public Builder hashedData(Optional> hashedData) { - this.hashedData = hashedData; - return this; - } - - public Builder hashedData(Map hashedData) { - this.hashedData = Optional.ofNullable(hashedData); - return this; - } - - /** - *

Partial Error message if any

- */ - @JsonSetter(value = "error", nulls = Nulls.SKIP) - public Builder error(Optional error) { - this.error = error; - return this; - } - - public Builder error(String error) { - this.error = Optional.ofNullable(error); - return this; - } - - /** - *

HTTP status code of the response

- */ - @JsonSetter(value = "httpCode", nulls = Nulls.SKIP) - public Builder httpCode(Optional httpCode) { - this.httpCode = httpCode; - return this; - } - - public Builder httpCode(Integer httpCode) { - this.httpCode = Optional.ofNullable(httpCode); - return this; - } - - /** - *

Name of the table record belongs to

- */ - @JsonSetter(value = "tableName", nulls = Nulls.SKIP) - public Builder tableName(Optional tableName) { - this.tableName = tableName; - return this; - } - - public Builder tableName(String tableName) { - this.tableName = Optional.ofNullable(tableName); - return this; - } - - public V1RecordResponseObject build() { - return new V1RecordResponseObject( - skyflowId, tokens, data, hashedData, error, httpCode, tableName, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordData.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordData.java deleted file mode 100644 index 5a904005..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1UpdateRecordData.java +++ /dev/null @@ -1,188 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1UpdateRecordData.Builder.class) -public final class V1UpdateRecordData { - private final Optional skyflowId; - - private final Optional> data; - - private final Optional> tokens; - - private final Optional tableName; - - private final Map additionalProperties; - - private V1UpdateRecordData( - Optional skyflowId, - Optional> data, - Optional> tokens, - Optional tableName, - Map additionalProperties) { - this.skyflowId = skyflowId; - this.data = data; - this.tokens = tokens; - this.tableName = tableName; - this.additionalProperties = additionalProperties; - } - - /** - * @return Skyflow ID for the record to be updated - */ - @JsonProperty("skyflowID") - public Optional getSkyflowId() { - return skyflowId; - } - - /** - * @return List of data row wise that is to be updated in the vault - */ - @JsonProperty("data") - public Optional> getData() { - return data; - } - - /** - * @return undocumented_field; Tokens data for the columns if any - */ - @JsonProperty("tokens") - public Optional> getTokens() { - return tokens; - } - - /** - * @return Table name for the record - */ - @JsonProperty("tableName") - public Optional getTableName() { - return tableName; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1UpdateRecordData && equalTo((V1UpdateRecordData) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1UpdateRecordData other) { - return skyflowId.equals(other.skyflowId) - && data.equals(other.data) - && tokens.equals(other.tokens) - && tableName.equals(other.tableName); - } - - @Override - public int hashCode() { - return Objects.hash(this.skyflowId, this.data, this.tokens, this.tableName); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional skyflowId = Optional.empty(); - - private Optional> data = Optional.empty(); - - private Optional> tokens = Optional.empty(); - - private Optional tableName = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1UpdateRecordData other) { - skyflowId(other.getSkyflowId()); - data(other.getData()); - tokens(other.getTokens()); - tableName(other.getTableName()); - return this; - } - - /** - *

Skyflow ID for the record to be updated

- */ - @JsonSetter(value = "skyflowID", nulls = Nulls.SKIP) - public Builder skyflowId(Optional skyflowId) { - this.skyflowId = skyflowId; - return this; - } - - public Builder skyflowId(String skyflowId) { - this.skyflowId = Optional.ofNullable(skyflowId); - return this; - } - - /** - *

List of data row wise that is to be updated in the vault

- */ - @JsonSetter(value = "data", nulls = Nulls.SKIP) - public Builder data(Optional> data) { - this.data = data; - return this; - } - - public Builder data(Map data) { - this.data = Optional.ofNullable(data); - return this; - } - - /** - *

undocumented_field; Tokens data for the columns if any

- */ - @JsonSetter(value = "tokens", nulls = Nulls.SKIP) - public Builder tokens(Optional> tokens) { - this.tokens = tokens; - return this; - } - - public Builder tokens(Map tokens) { - this.tokens = Optional.ofNullable(tokens); - return this; - } - - /** - *

Table name for the record

- */ - @JsonSetter(value = "tableName", nulls = Nulls.SKIP) - public Builder tableName(Optional tableName) { - this.tableName = tableName; - return this; - } - - public Builder tableName(String tableName) { - this.tableName = Optional.ofNullable(tableName); - return this; - } - - public V1UpdateRecordData build() { - return new V1UpdateRecordData(skyflowId, data, tokens, tableName, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1UpdateResponse.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1UpdateResponse.java deleted file mode 100644 index 38dfe0ab..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1UpdateResponse.java +++ /dev/null @@ -1,93 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1UpdateResponse.Builder.class) -public final class V1UpdateResponse { - private final Optional> records; - - private final Map additionalProperties; - - private V1UpdateResponse(Optional> records, Map additionalProperties) { - this.records = records; - this.additionalProperties = additionalProperties; - } - - /** - * @return List of updated records with skyflow ID, tokens, data, and any partial errors - */ - @JsonProperty("records") - public Optional> getRecords() { - return records; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1UpdateResponse && equalTo((V1UpdateResponse) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1UpdateResponse other) { - return records.equals(other.records); - } - - @Override - public int hashCode() { - return Objects.hash(this.records); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional> records = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1UpdateResponse other) { - records(other.getRecords()); - return this; - } - - /** - *

List of updated records with skyflow ID, tokens, data, and any partial errors

- */ - @JsonSetter(value = "records", nulls = Nulls.SKIP) - public Builder records(Optional> records) { - this.records = records; - return this; - } - - public Builder records(List records) { - this.records = Optional.ofNullable(records); - return this; - } - - public V1UpdateResponse build() { - return new V1UpdateResponse(records, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1Upsert.java b/flowvault/src/main/java/com/skyflow/generated/rest/types/V1Upsert.java deleted file mode 100644 index a0c27b0e..00000000 --- a/flowvault/src/main/java/com/skyflow/generated/rest/types/V1Upsert.java +++ /dev/null @@ -1,118 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ -package com.skyflow.generated.rest.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.skyflow.generated.rest.core.ObjectMappers; - -import java.util.*; - -@JsonInclude(JsonInclude.Include.NON_ABSENT) -@JsonDeserialize(builder = V1Upsert.Builder.class) -public final class V1Upsert { - private final Optional updateType; - - private final Optional> uniqueColumns; - - private final Map additionalProperties; - - private V1Upsert( - Optional updateType, - Optional> uniqueColumns, - Map additionalProperties) { - this.updateType = updateType; - this.uniqueColumns = uniqueColumns; - this.additionalProperties = additionalProperties; - } - - @JsonProperty("updateType") - public Optional getUpdateType() { - return updateType; - } - - /** - * @return Name of a unique columns in the table. Uses upsert operations to check if a record exists based on the unique column's value. If a matching record exists, the record updates with the values you provide. If a matching record doesn't exist, the upsert operation inserts a new record. - */ - @JsonProperty("uniqueColumns") - public Optional> getUniqueColumns() { - return uniqueColumns; - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - return other instanceof V1Upsert && equalTo((V1Upsert) other); - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - private boolean equalTo(V1Upsert other) { - return updateType.equals(other.updateType) && uniqueColumns.equals(other.uniqueColumns); - } - - @Override - public int hashCode() { - return Objects.hash(this.updateType, this.uniqueColumns); - } - - @Override - public String toString() { - return ObjectMappers.stringify(this); - } - - public static Builder builder() { - return new Builder(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static final class Builder { - private Optional updateType = Optional.empty(); - - private Optional> uniqueColumns = Optional.empty(); - - @JsonAnySetter - private Map additionalProperties = new HashMap<>(); - - private Builder() {} - - public Builder from(V1Upsert other) { - updateType(other.getUpdateType()); - uniqueColumns(other.getUniqueColumns()); - return this; - } - - @JsonSetter(value = "updateType", nulls = Nulls.SKIP) - public Builder updateType(Optional updateType) { - this.updateType = updateType; - return this; - } - - public Builder updateType(FlowEnumUpdateType updateType) { - this.updateType = Optional.ofNullable(updateType); - return this; - } - - /** - *

Name of a unique columns in the table. Uses upsert operations to check if a record exists based on the unique column's value. If a matching record exists, the record updates with the values you provide. If a matching record doesn't exist, the upsert operation inserts a new record.

- */ - @JsonSetter(value = "uniqueColumns", nulls = Nulls.SKIP) - public Builder uniqueColumns(Optional> uniqueColumns) { - this.uniqueColumns = uniqueColumns; - return this; - } - - public Builder uniqueColumns(List uniqueColumns) { - this.uniqueColumns = Optional.ofNullable(uniqueColumns); - return this; - } - - public V1Upsert build() { - return new V1Upsert(updateType, uniqueColumns, additionalProperties); - } - } -} diff --git a/flowvault/src/main/java/com/skyflow/utils/Constants.java b/flowvault/src/main/java/com/skyflow/utils/Constants.java index 3c82cc4b..2afcd4ea 100644 --- a/flowvault/src/main/java/com/skyflow/utils/Constants.java +++ b/flowvault/src/main/java/com/skyflow/utils/Constants.java @@ -25,6 +25,8 @@ public final class Constants extends BaseConstants { public static final Integer MAX_DELETE_TOKENS_CONCURRENCY_LIMIT = 100; public static final Integer TOKENIZE_BATCH_SIZE = 50; public static final Integer TOKENIZE_CONCURRENCY_LIMIT = 1; + // Fixed, not a caller option: uploads to signed URLs are I/O-bound and must finish before the URLs expire. + public static final Integer UPLOAD_FILES_CONCURRENCY_LIMIT = 5; public static final Integer MAX_TOKENIZE_BATCH_SIZE = 1000; public static final Integer MAX_TOKENIZE_CONCURRENCY_LIMIT = 100; public static final String DEFAULT_SDK_VERSION = "1.0.0"; diff --git a/flowvault/src/main/java/com/skyflow/utils/Utils.java b/flowvault/src/main/java/com/skyflow/utils/Utils.java index 61072231..bc082fbf 100644 --- a/flowvault/src/main/java/com/skyflow/utils/Utils.java +++ b/flowvault/src/main/java/com/skyflow/utils/Utils.java @@ -1,9 +1,16 @@ package com.skyflow.utils; +import java.io.File; import java.net.MalformedURLException; import java.net.URL; +import java.net.URLConnection; import java.util.ArrayList; +import java.util.Base64; +import java.util.HashMap; import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -12,38 +19,44 @@ import com.google.gson.JsonObject; import com.skyflow.config.VaultConfig; import com.skyflow.enums.Env; +import com.skyflow.enums.InterfaceName; import com.skyflow.enums.UpdateType; import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; import com.skyflow.generated.rest.core.ApiClientApiException; import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.resources.flowservice.requests.V1DeleteRequest; -import com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest; -import com.skyflow.generated.rest.resources.flowservice.requests.V1GetRequest; -import com.skyflow.generated.rest.resources.flowservice.requests.V1InsertRequest; -import com.skyflow.generated.rest.resources.flowservice.requests.V1UpdateRequest; -import com.skyflow.generated.rest.types.FlowEnumUpdateType; -import com.skyflow.generated.rest.types.V1ColumnRedactions; -import com.skyflow.generated.rest.types.V1DeleteResponse; -import com.skyflow.generated.rest.types.V1DeleteResponseObject; -import com.skyflow.generated.rest.types.V1DeleteTokenResponseObject; -import com.skyflow.generated.rest.types.V1FlowDeleteTokenResponse; -import com.skyflow.generated.rest.types.V1FlowDetokenizeResponse; -import com.skyflow.generated.rest.types.V1FlowDetokenizeResponseObject; -import com.skyflow.generated.rest.types.V1FlowTokenizeRequestObject; -import com.skyflow.generated.rest.types.V1FlowTokenizeResponse; -import com.skyflow.generated.rest.types.V1FlowTokenizeResponseObject; -import com.skyflow.generated.rest.types.V1GetRequestData; -import com.skyflow.generated.rest.types.V1GetResponse; -import com.skyflow.generated.rest.types.V1InsertRecordData; -import com.skyflow.generated.rest.types.V1InsertResponse; -import com.skyflow.generated.rest.types.V1RecordResponseObject; -import com.skyflow.generated.rest.types.V1TokenGroupRedactions; -import com.skyflow.generated.rest.types.V1UniqueValue; -import com.skyflow.generated.rest.types.V1UpdateRecordData; -import com.skyflow.generated.rest.types.V1UpdateResponse; -import com.skyflow.generated.rest.types.V1Upsert; +import com.skyflow.generated.rest.resources.files.requests.FileDeleteRequest; +import com.skyflow.generated.rest.resources.files.requests.FileUploadRequest; +import com.skyflow.generated.rest.resources.query.requests.ExecuteQueryRequest; +import com.skyflow.generated.rest.resources.records.types.UpdateRequestUpdateType; +import com.skyflow.generated.rest.resources.tokens.requests.DeleteTokenRequest; +import com.skyflow.generated.rest.resources.tokens.requests.GetTokensFromValuesRequest; +import com.skyflow.generated.rest.resources.tokens.requests.TokenizeRequest; +import com.skyflow.generated.rest.types.DeleteResponseObject; +import com.skyflow.generated.rest.types.DeleteTokenResponse; +import com.skyflow.generated.rest.types.DeleteTokenResponseObject; +import com.skyflow.generated.rest.types.DetokenizeResponseObject; +import com.skyflow.generated.rest.types.ExecuteQueryRecordResponse; +import com.skyflow.generated.rest.types.ExecuteQueryResponse; +import com.skyflow.generated.rest.types.FileDeleteRecord; +import com.skyflow.generated.rest.types.FileDeleteResponse; +import com.skyflow.generated.rest.types.FileDeleteResponseObject; +import com.skyflow.generated.rest.types.FileUploadColumn; +import com.skyflow.generated.rest.types.FileUploadRecord; +import com.skyflow.generated.rest.types.GetRequestData; +import com.skyflow.generated.rest.types.GetTokensFromValuesRequestObject; +import com.skyflow.generated.rest.types.GetTokensFromValuesResponse; +import com.skyflow.generated.rest.types.GoogleProtobufValue; +import com.skyflow.generated.rest.types.InsertRecordData; +import com.skyflow.generated.rest.types.RecordResponseObject; +import com.skyflow.generated.rest.types.TokenizeRequestObject; +import com.skyflow.generated.rest.types.TokenizeResponse; +import com.skyflow.generated.rest.types.TokenizeResponseObject; +import com.skyflow.generated.rest.types.UniqueValue; +import com.skyflow.generated.rest.types.UpdateRecordData; +import com.skyflow.generated.rest.types.Upsert; +import com.skyflow.generated.rest.types.UpsertUpdateType; import com.skyflow.logs.ErrorLogs; import com.skyflow.utils.logger.LogUtil; import com.skyflow.vault.data.BulkDeleteTokensRequest; @@ -59,6 +72,9 @@ import com.skyflow.vault.data.BulkTokenizeResponse; import com.skyflow.vault.data.BulkTokenizeResponseRecord; import com.skyflow.vault.data.ColumnRedactions; +import com.skyflow.vault.data.DeleteFilesRequest; +import com.skyflow.vault.data.DeleteFilesRequestRecord; +import com.skyflow.vault.data.DeleteFilesResponse; import com.skyflow.vault.data.DeleteRequest; import com.skyflow.vault.data.DeleteResponse; import com.skyflow.vault.data.DeleteResponseRecord; @@ -71,10 +87,16 @@ import com.skyflow.vault.data.GetRequestRecord; import com.skyflow.vault.data.GetResponse; import com.skyflow.vault.data.GetResponseRecord; +import com.skyflow.vault.data.GetTokensRequest; +import com.skyflow.vault.data.GetTokensRequestRecord; +import com.skyflow.vault.data.GetTokensResponse; import com.skyflow.vault.data.InsertRequest; import com.skyflow.vault.data.InsertRequestRecord; import com.skyflow.vault.data.InsertResponse; import com.skyflow.vault.data.InsertResponseRecord; +import com.skyflow.vault.data.QueryRequest; +import com.skyflow.vault.data.QueryResponse; +import com.skyflow.vault.data.QueryResponseMetadata; import com.skyflow.vault.data.Token; import com.skyflow.vault.data.TokenGroupRedactions; import com.skyflow.vault.data.TokenizeRequestRecord; @@ -82,9 +104,15 @@ import com.skyflow.vault.data.UpdateRequestRecord; import com.skyflow.vault.data.UpdateResponse; import com.skyflow.vault.data.UpdateResponseRecord; +import com.skyflow.vault.data.UploadFilesRequest; +import com.skyflow.vault.data.UploadFilesRequestColumn; +import com.skyflow.vault.data.UploadFilesRequestRecord; +import com.skyflow.vault.data.UploadFilesResponse; import com.skyflow.vault.data.UpsertOptions; import io.github.cdimascio.dotenv.Dotenv; +import okhttp3.MediaType; +import okhttp3.RequestBody; import io.github.cdimascio.dotenv.DotenvException; public final class Utils extends BaseUtils { @@ -145,74 +173,97 @@ private static boolean hasText(String value) { return value != null && !value.trim().isEmpty(); } - private static V1Upsert toV1Upsert(UpsertOptions upsert) { - V1Upsert.Builder builder = V1Upsert.builder().uniqueColumns(upsert.getUniqueColumns()); + private static Upsert toUpsert(UpsertOptions upsert) { + Upsert.Builder builder = Upsert.builder().uniqueColumns(upsert.getUniqueColumns()); // updateType is a String on the request; the legal values come from the wire enum itself // so there is a single source of truth. Validations rejects anything that does not match. - String updateType = upsert.getUpdateType(); - for (FlowEnumUpdateType type : FlowEnumUpdateType.values()) { - if (type.toString().equalsIgnoreCase(updateType)) { - builder.updateType(type); - break; - } + UpsertUpdateType updateType = toUpsertUpdateType(upsert.getUpdateType()); + if (updateType != null) { + builder.updateType(updateType); } return builder.build(); } - public static V1InsertRequest getInsertRequestBody(InsertRequest request, VaultConfig config) { + /** The wire enum value for {@code updateType} (any case), or null when it names no known value. */ + public static UpsertUpdateType toUpsertUpdateType(String updateType) { + if (updateType == null) { + return null; + } + UpsertUpdateType type = UpsertUpdateType.valueOf(updateType.toUpperCase()); + return type.getEnumValue() == UpsertUpdateType.Value.UNKNOWN ? null : type; + } + + /** + * The generated InsertRequest/UpdateRequest builders make the request-level tableName a required + * stage, yet the API takes the table per record too and rejects it at both levels. Binding through + * the type's own Jackson mapping lets an absent request-level table simply be omitted from the body. + */ + private static T bindRequest(Map fields, Class type) { + return ObjectMappers.JSON_MAPPER.convertValue(fields, type); + } + + public static com.skyflow.generated.rest.resources.records.requests.InsertRequest getInsertRequestBody(InsertRequest request, VaultConfig config) { List records = request.getRecords(); - List insertRecordDataList = new ArrayList<>(); + List insertRecordDataList = new ArrayList<>(); // tableName and upsert must reach the wire at exactly one level: the vault rejects a body // that carries either at both the request and the record level. validateTableAndUpsertPlacement // has already forced the caller to pick one, so mirror that choice here rather than copying // the request-level value down onto every record. for (InsertRequestRecord record : records) { - V1InsertRecordData.Builder data = V1InsertRecordData.builder() + InsertRecordData.Builder data = InsertRecordData.builder() .data(record.getData()); // A blank record-level table name counts as absent, matching validateInsertRequest. if (hasText(record.getTableName())) { data.tableName(record.getTableName()); } + // The generated InsertRecordData has no tokens field, but the API still accepts one. if (record.getTokens() != null && !record.getTokens().isEmpty()) { - data.tokens(record.getTokens()); + data.additionalProperty("tokens", record.getTokens()); } UpsertOptions recordUpsert = record.getUpsert(); if (recordUpsert != null && recordUpsert.getUniqueColumns() != null && !recordUpsert.getUniqueColumns().isEmpty()) { - data.upsert(toV1Upsert(recordUpsert)); + data.upsert(toUpsert(recordUpsert)); } insertRecordDataList.add(data.build()); } - V1InsertRequest.Builder builder = V1InsertRequest.builder() - .vaultId(config.getVaultId()) - .records(insertRecordDataList); - if (hasText(request.getTableName())) { - builder.tableName(request.getTableName()); - } UpsertOptions requestUpsert = request.getUpsert(); - if (requestUpsert != null && requestUpsert.getUniqueColumns() != null - && !requestUpsert.getUniqueColumns().isEmpty()) { - builder.upsert(toV1Upsert(requestUpsert)); + Upsert upsert = requestUpsert != null && requestUpsert.getUniqueColumns() != null + && !requestUpsert.getUniqueColumns().isEmpty() ? toUpsert(requestUpsert) : null; + return buildInsertRequest(config.getVaultId(), request.getTableName(), insertRecordDataList, upsert); + } + + /** Assembles the wire insert body; a blank tableName and a null upsert are left off. */ + public static com.skyflow.generated.rest.resources.records.requests.InsertRequest buildInsertRequest( + String vaultId, String tableName, List records, Upsert upsert) { + Map fields = new LinkedHashMap<>(); + fields.put("vaultID", vaultId); + if (hasText(tableName)) { + fields.put("tableName", tableName); } - return builder.build(); + fields.put("records", records); + if (upsert != null) { + fields.put("upsert", upsert); + } + return bindRequest(fields, com.skyflow.generated.rest.resources.records.requests.InsertRequest.class); } - private static String extractRequestId(Map> headers) { + public static String extractRequestId(Map> headers) { if (headers == null) return null; List ids = headers.get(BaseConstants.REQUEST_ID_HEADER_KEY); return (ids == null || ids.isEmpty()) ? null : ids.get(0); } - public static V1GetRequest getGetRequestBody(GetRequest request, VaultConfig config) { - V1GetRequest.Builder builder = V1GetRequest.builder().vaultId(config.getVaultId()); + public static com.skyflow.generated.rest.resources.records.requests.GetRequest getGetRequestBody(GetRequest request, VaultConfig config) { + com.skyflow.generated.rest.resources.records.requests.GetRequest._FinalStage builder = com.skyflow.generated.rest.resources.records.requests.GetRequest.builder().vaultId(config.getVaultId()); // Multi-table mode: Validations has already rejected the case where both this and the // single-table fields below are set, so their presence/absence is mutually exclusive. if (request.getRecords() != null && !request.getRecords().isEmpty()) { - List recordDataList = new ArrayList<>(); + List recordDataList = new ArrayList<>(); for (GetRequestRecord record : request.getRecords()) { - recordDataList.add(toV1GetRequestData(record)); + recordDataList.add(toGetRequestData(record)); } return builder.records(recordDataList).build(); } @@ -227,10 +278,10 @@ public static V1GetRequest getGetRequestBody(GetRequest request, VaultConfig con builder.columns(request.getColumns()); } if (request.getColumnRedactions() != null && !request.getColumnRedactions().isEmpty()) { - builder.columnRedactions(toV1ColumnRedactionsList(request.getColumnRedactions())); + builder.columnRedactions(toColumnRedactionsList(request.getColumnRedactions())); } if (request.getUniqueValues() != null && !request.getUniqueValues().isEmpty()) { - builder.uniqueValues(toV1UniqueValueList(request.getUniqueValues())); + builder.uniqueValues(toUniqueValueList(request.getUniqueValues())); } if (request.getLimit() != null) { builder.limit(request.getLimit()); @@ -241,8 +292,8 @@ public static V1GetRequest getGetRequestBody(GetRequest request, VaultConfig con return builder.build(); } - private static V1GetRequestData toV1GetRequestData(GetRequestRecord record) { - V1GetRequestData.Builder data = V1GetRequestData.builder().tableName(record.getTableName()); + private static GetRequestData toGetRequestData(GetRequestRecord record) { + GetRequestData._FinalStage data = GetRequestData.builder().tableName(record.getTableName()); if (record.getSkyflowIds() != null && !record.getSkyflowIds().isEmpty()) { data.skyflowIDs(record.getSkyflowIds()); } @@ -250,18 +301,18 @@ private static V1GetRequestData toV1GetRequestData(GetRequestRecord record) { data.columns(record.getColumns()); } if (record.getColumnRedactions() != null && !record.getColumnRedactions().isEmpty()) { - data.columnRedactions(toV1ColumnRedactionsList(record.getColumnRedactions())); + data.columnRedactions(toColumnRedactionsList(record.getColumnRedactions())); } if (record.getUniqueValues() != null && !record.getUniqueValues().isEmpty()) { - data.uniqueValues(toV1UniqueValueList(record.getUniqueValues())); + data.uniqueValues(toUniqueValueList(record.getUniqueValues())); } return data.build(); } - private static List toV1ColumnRedactionsList(List columnRedactions) { - List list = new ArrayList<>(); + private static List toColumnRedactionsList(List columnRedactions) { + List list = new ArrayList<>(); for (ColumnRedactions columnRedaction : columnRedactions) { - list.add(V1ColumnRedactions.builder() + list.add(com.skyflow.generated.rest.types.ColumnRedactions.builder() .columnName(columnRedaction.getColumnName()) .redaction(columnRedaction.getRedaction()) .build()); @@ -269,35 +320,36 @@ private static List toV1ColumnRedactionsList(List toV1UniqueValueList(List> uniqueValues) { - List list = new ArrayList<>(); + private static List toUniqueValueList(List> uniqueValues) { + List list = new ArrayList<>(); for (Map uniqueValue : uniqueValues) { - list.add(V1UniqueValue.builder().data(uniqueValue).build()); + list.add(UniqueValue.builder().data(uniqueValue).build()); } return list; } - public static V1DeleteRequest getDeleteRequestBody(DeleteRequest request, VaultConfig config) { - V1DeleteRequest.Builder builder = V1DeleteRequest.builder() + public static com.skyflow.generated.rest.resources.records.requests.DeleteRequest getDeleteRequestBody(DeleteRequest request, VaultConfig config) { + com.skyflow.generated.rest.resources.records.requests.DeleteRequest._FinalStage builder = com.skyflow.generated.rest.resources.records.requests.DeleteRequest.builder() .vaultId(config.getVaultId()) .tableName(request.getTableName()); if (request.getSkyflowIds() != null && !request.getSkyflowIds().isEmpty()) { builder.skyflowIDs(request.getSkyflowIds()); } if (request.getUniqueValues() != null && !request.getUniqueValues().isEmpty()) { - builder.uniqueValues(toV1UniqueValueList(request.getUniqueValues())); + builder.uniqueValues(toUniqueValueList(request.getUniqueValues())); } return builder.build(); } - public static V1UpdateRequest getUpdateRequestBody(UpdateRequest request, VaultConfig config) { - List updateRecordDataList = new ArrayList<>(); + public static com.skyflow.generated.rest.resources.records.requests.UpdateRequest getUpdateRequestBody(UpdateRequest request, VaultConfig config) { + List updateRecordDataList = new ArrayList<>(); for (UpdateRequestRecord record : request.getRecords()) { - V1UpdateRecordData.Builder data = V1UpdateRecordData.builder() + UpdateRecordData._FinalStage data = UpdateRecordData.builder() .skyflowId(record.getSkyflowId()) .data(record.getData()); + // The generated UpdateRecordData has no tokens field, but the API still accepts one. if (record.getTokens() != null && !record.getTokens().isEmpty()) { - data.tokens(record.getTokens()); + data.additionalProperty("tokens", record.getTokens()); } // A blank record-level table name counts as absent, matching validateInsertRequest's // handling of the same table/record split. @@ -307,35 +359,34 @@ public static V1UpdateRequest getUpdateRequestBody(UpdateRequest request, VaultC updateRecordDataList.add(data.build()); } - V1UpdateRequest.Builder builder = V1UpdateRequest.builder() - .vaultId(config.getVaultId()) - .tableName(request.getTableName()) - .records(updateRecordDataList); - - // Record-level updateType isn't wired here: the generated V1UpdateRecordData has no - // updateType setter yet even though the proto declares one (needs a client regeneration). + Map fields = new LinkedHashMap<>(); + fields.put("vaultID", config.getVaultId()); + if (hasText(request.getTableName())) { + fields.put("tableName", request.getTableName()); + } + fields.put("records", updateRecordDataList); UpdateType requestUpdateType = request.getUpdateType(); if (requestUpdateType != null) { - builder.updateType(FlowEnumUpdateType.valueOf(requestUpdateType.name())); + fields.put("updateType", UpdateRequestUpdateType.valueOf(requestUpdateType.name())); } - return builder.build(); + return bindRequest(fields, com.skyflow.generated.rest.resources.records.requests.UpdateRequest.class); } // ── Bulk (batched/concurrent) request-body builders ────────────────────── // BulkInsertRequest is an InsertRequest, so the bulk body is built exactly the same way. - public static com.skyflow.generated.rest.resources.flowservice.requests.V1InsertRequest getBulkInsertRequestBody(BulkInsertRequest request, VaultConfig config) { + public static com.skyflow.generated.rest.resources.records.requests.InsertRequest getBulkInsertRequestBody(BulkInsertRequest request, VaultConfig config) { return getInsertRequestBody(request, config); } - public static V1FlowDetokenizeRequest getDetokenizeRequestBody(DetokenizeRequest request, String vaultId) { - V1FlowDetokenizeRequest.Builder builder = V1FlowDetokenizeRequest.builder() + public static com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest getDetokenizeRequestBody(DetokenizeRequest request, String vaultId) { + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest._FinalStage builder = com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest.builder() .vaultId(vaultId) .tokens(request.getTokens()); if (request.getTokenGroupRedactions() != null && !request.getTokenGroupRedactions().isEmpty()) { - List tokenGroupRedactionsList = new ArrayList<>(); + List tokenGroupRedactionsList = new ArrayList<>(); for (TokenGroupRedactions tokenGroupRedactions : request.getTokenGroupRedactions()) { - tokenGroupRedactionsList.add(V1TokenGroupRedactions.builder() + tokenGroupRedactionsList.add(com.skyflow.generated.rest.types.TokenGroupRedactions.builder() .tokenGroupName(tokenGroupRedactions.getTokenGroupName()) .redaction(tokenGroupRedactions.getRedaction()) .build()); @@ -345,24 +396,45 @@ public static V1FlowDetokenizeRequest getDetokenizeRequestBody(DetokenizeRequest return builder.build(); } - public static V1FlowDetokenizeRequest getBulkDetokenizeRequestBody(BulkDetokenizeRequest request, String vaultId) { + public static com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest getBulkDetokenizeRequestBody(BulkDetokenizeRequest request, String vaultId) { return getDetokenizeRequestBody(request, vaultId); } - public static com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest getBulkDeleteTokensRequestBody(BulkDeleteTokensRequest request, String vaultId) { - return com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest.builder() + public static DeleteTokenRequest getBulkDeleteTokensRequestBody(BulkDeleteTokensRequest request, String vaultId) { + return DeleteTokenRequest.builder() .vaultId(vaultId) .tokens(request.getTokens()) .build(); } - public static com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest getBulkTokenizeRequestBody( + public static ExecuteQueryRequest getQueryRequestBody(QueryRequest request, String vaultId) { + return ExecuteQueryRequest.builder() + .vaultId(vaultId) + .query(request.getQuery()) + .build(); + } + + public static GetTokensFromValuesRequest getGetTokensRequestBody(GetTokensRequest request, String vaultId) { + List records = new ArrayList<>(); + for (GetTokensRequestRecord record : request.getRecords()) { + records.add(GetTokensFromValuesRequestObject.builder() + .value(GoogleProtobufValue.of(record.getValue())) + .tokenGroupName(record.getTokenGroupName()) + .build()); + } + return GetTokensFromValuesRequest.builder() + .vaultId(vaultId) + .records(records) + .build(); + } + + public static TokenizeRequest getBulkTokenizeRequestBody( List records, String vaultId) { - List dataList = new ArrayList<>(); + List dataList = new ArrayList<>(); for (BulkTokenizeRequestRecord record : records) { dataList.add(buildTokenizeRequestObject(record)); } - return com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest.builder() + return TokenizeRequest.builder() .vaultId(vaultId) .data(dataList) .build(); @@ -370,44 +442,40 @@ public static com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTo // ── Bulk batching, exception-handling and response-formatting helpers ──── - public static List> createBulkInsertBatches(List records, int batchSize) { - List> batches = new ArrayList<>(); + public static List> createBulkInsertBatches(List records, int batchSize) { + List> batches = new ArrayList<>(); for (int i = 0; i < records.size(); i += batchSize) { batches.add(records.subList(i, Math.min(i + batchSize, records.size()))); } return batches; } - public static List createBulkDetokenizeBatches(V1FlowDetokenizeRequest request, int batchSize) { - List detokenizeRequests = new ArrayList<>(); - List tokens = request.getTokens().get(); + public static List createBulkDetokenizeBatches(com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest request, int batchSize) { + List detokenizeRequests = new ArrayList<>(); + List tokens = request.getTokens(); for (int i = 0; i < tokens.size(); i += batchSize) { List batchTokens = tokens.subList(i, Math.min(i + batchSize, tokens.size())); - List tokenGroupRedactions = null; + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest._FinalStage batchRequest = com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest.builder() + .vaultId(request.getVaultId()) + .tokens(new ArrayList<>(batchTokens)); if (request.getTokenGroupRedactions().isPresent() && !request.getTokenGroupRedactions().get().isEmpty()) { - tokenGroupRedactions = request.getTokenGroupRedactions().get(); + batchRequest.tokenGroupRedactions(request.getTokenGroupRedactions().get()); } - V1FlowDetokenizeRequest batchRequest = V1FlowDetokenizeRequest.builder() - .vaultId(request.getVaultId()) - .tokens(new ArrayList<>(batchTokens)) - .tokenGroupRedactions(tokenGroupRedactions) - .build(); - detokenizeRequests.add(batchRequest); + detokenizeRequests.add(batchRequest.build()); } return detokenizeRequests; } - public static List createBulkDeleteTokensBatches( - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest request, int batchSize) { - List batches = new ArrayList<>(); - List tokens = request.getTokens().get(); + public static List createBulkDeleteTokensBatches(DeleteTokenRequest request, int batchSize) { + List batches = new ArrayList<>(); + List tokens = request.getTokens(); for (int i = 0; i < tokens.size(); i += batchSize) { List batchTokens = tokens.subList(i, Math.min(i + batchSize, tokens.size())); - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest batchRequest = - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest.builder() + DeleteTokenRequest batchRequest = + DeleteTokenRequest.builder() .vaultId(request.getVaultId()) .tokens(new ArrayList<>(batchTokens)) .build(); @@ -536,13 +604,73 @@ public static ErrorRecord createErrorRecord(Map recordMap, int i // exception. Each handler below returns null when the body doesn't match that shape, so the // caller falls back to throwing a SkyflowException as before. + /** + * The exception body as a JSON object, or null when it is not one. + * + *

For the statuses the API documents (400, 401, 403, 404, 429, 500) the generated client + * throws a typed error whose body is an {@code ErrorResponse} rather than the parsed map. That + * type keeps every field it does not model (for example a per-record {@code "records"} array) + * as an additional property, so converting it back yields the body the server sent. + */ + @SuppressWarnings("unchecked") + public static Map errorBodyAsMap(ApiClientApiException apiException) { + Object rawBody = apiException.body(); + if (rawBody instanceof Map) { + return (Map) rawBody; + } + if (rawBody == null || rawBody instanceof String) { + return null; + } + try { + Object converted = ObjectMappers.JSON_MAPPER.convertValue(rawBody, Object.class); + return converted instanceof Map ? (Map) converted : null; + } catch (IllegalArgumentException e) { + return null; + } + } + + /** The exception body in the form SkyflowException parses: the JSON object when there is one. */ + public static Object errorBody(ApiClientApiException apiException) { + Map body = errorBodyAsMap(apiException); + return body != null ? body : apiException.body(); + } + + /** + * The uploadFiles error body in the form SkyflowException parses. The vault can reject the call + * with a records-shaped body ({@code {"records":[{"error": ...}]}}) instead of + * {@code {"error": {...}}}, which left the thrown exception's message null; lift the record + * errors into {@code error.message} so callers see why the call failed. + */ + public static Object uploadFilesErrorBody(ApiClientApiException apiException) { + List> records = extractExceptionRecords(apiException, "records"); + if (records == null) { + return errorBody(apiException); + } + Set messages = new LinkedHashSet<>(); + for (Map record : records) { + String error = readString(record, "error"); + if (error != null && !error.isEmpty()) { + messages.add(error); + } + } + if (messages.isEmpty()) { + return errorBody(apiException); + } + Map error = new LinkedHashMap<>(); + error.put("http_code", apiException.statusCode()); + error.put("message", String.join("; ", messages)); + Map body = new LinkedHashMap<>(); + body.put("error", error); + return body; + } + /** Record maps under {@code key} in an exception body, or null if the shape doesn't match. */ private static List> extractExceptionRecords(ApiClientApiException apiException, String key) { - Object rawBody = apiException.body(); - if (!(rawBody instanceof Map)) { + Map body = errorBodyAsMap(apiException); + if (body == null) { return null; } - Object recordsField = ((Map) rawBody).get(key); + Object recordsField = body.get(key); if (!(recordsField instanceof List)) { return null; } @@ -650,18 +778,36 @@ public static DetokenizeResponse handleDetokenizeRequestException(ApiClientApiEx return new DetokenizeResponse(records); } + public static GetTokensResponse handleGetTokensRequestException(ApiClientApiException apiException) { + List> recordMaps = extractExceptionRecords(apiException, "records"); + if (recordMaps == null) { + return null; + } + String requestId = extractRequestId(apiException.headers()); + ArrayList> records = new ArrayList<>(); + for (Map recordMap : recordMaps) { + records.add(getTokensRow( + recordMap.get("value"), + readString(recordMap, "tokenGroupName"), + getTokensToken(recordMap.get("token")), + readHttpCode(recordMap, apiException.statusCode()), + readErrorMessage(recordMap), + requestId)); + } + return new GetTokensResponse(records); + } + // Errors are parsed into ErrorRecord (shared with the other bulk ops), then projected onto // the unified BulkInsertResponseRecord shape that bulk insert now returns. public static List handleBulkInsertBatchException( - Throwable ex, List batch, int batchNumber, int batchSize + Throwable ex, List batch, int batchNumber, int batchSize ) { List allRecords = new ArrayList<>(); Throwable cause = ex.getCause(); if (cause instanceof ApiClientApiException) { ApiClientApiException apiException = (ApiClientApiException) cause; String requestId = extractRequestId(apiException.headers()); - Object rawBody = apiException.body(); - Map responseBody = (rawBody instanceof Map) ? (Map) rawBody : null; + Map responseBody = errorBodyAsMap(apiException); int indexNumber = batchNumber > 0 ? batchNumber * batchSize : 0; if (responseBody != null) { if (responseBody.containsKey("records")) { @@ -734,17 +880,16 @@ public static List handleBulkInsertBatchException( // Errors are parsed into ErrorRecord (shared with the other bulk ops), then projected onto // the unified BulkDetokenizeResponseRecord shape that bulk detokenize now returns. public static List handleBulkDetokenizeBatchException( - Throwable ex, V1FlowDetokenizeRequest batch, int batchNumber, int batchSize + Throwable ex, com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest batch, int batchNumber, int batchSize ) { List allRecords = new ArrayList<>(); Throwable cause = ex.getCause(); if (cause instanceof ApiClientApiException) { ApiClientApiException apiException = (ApiClientApiException) cause; String requestId = extractRequestId(apiException.headers()); - Object rawBody = apiException.body(); - Map responseBody = (rawBody instanceof Map) ? (Map) rawBody : null; + Map responseBody = errorBodyAsMap(apiException); int indexNumber = batchNumber * batchSize; - int tokenCount = batch.getTokens().isPresent() ? batch.getTokens().get().size() : 0; + int tokenCount = batch.getTokens() != null ? batch.getTokens().size() : 0; if (responseBody != null) { if (responseBody.containsKey("response")) { Object recordss = responseBody.get("response"); @@ -803,7 +948,7 @@ public static List handleBulkDetokenizeBatchExcept if (message == null || message.isEmpty() || message.trim().isEmpty()){ message = ex.getMessage(); } - for (int j = 0; j < batch.getTokens().get().size(); j++) { + for (int j = 0; j < batch.getTokens().size(); j++) { BulkDetokenizeResponseRecord err = new BulkDetokenizeResponseRecord(indexNumber, null, null, null, null, 500, message, null); allRecords.add(err); indexNumber++; @@ -840,19 +985,18 @@ private static String describeTransportFailure(Throwable ex, Throwable cause) { public static List handleBulkDeleteTokensBatchException( Throwable ex, - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest batch, + DeleteTokenRequest batch, int batchNumber, int batchSize ) { List errorRecords = new ArrayList<>(); - List batchTokens = (batch != null && batch.getTokens().isPresent()) - ? batch.getTokens().get() : new ArrayList<>(); + List batchTokens = (batch != null && batch.getTokens() != null) + ? batch.getTokens() : new ArrayList<>(); int startIndex = batchNumber * batchSize; Throwable cause = ex.getCause(); if (cause instanceof ApiClientApiException) { ApiClientApiException apiException = (ApiClientApiException) cause; String requestId = extractRequestId(apiException.headers()); - Object rawBody = apiException.body(); - Map responseBody = (rawBody instanceof Map) ? (Map) rawBody : null; + Map responseBody = errorBodyAsMap(apiException); if (responseBody != null) { if (responseBody.containsKey("tokens")) { Object tokensList = responseBody.get("tokens"); @@ -977,17 +1121,16 @@ private static List tokenizeRecordsFromErrorBody( ApiClientApiException apiException, List batchRecords, int startIndex) { - Object rawBody = apiException.body(); - if (!(rawBody instanceof Map) || !((Map) rawBody).containsKey("response")) { + Map body = errorBodyAsMap(apiException); + if (body == null || !body.containsKey("response")) { return null; } try { - V1FlowTokenizeResponse parsed = - ObjectMappers.JSON_MAPPER.convertValue(rawBody, V1FlowTokenizeResponse.class); - if (!parsed.getResponse().isPresent() || parsed.getResponse().get().isEmpty()) { + TokenizeResponse parsed = ObjectMappers.JSON_MAPPER.convertValue(body, TokenizeResponse.class); + if (parsed.getResponse() == null || parsed.getResponse().isEmpty()) { return null; } - return groupTokenizeRows(parsed.getResponse().get(), batchRecords, startIndex, + return groupTokenizeRows(parsed.getResponse(), batchRecords, startIndex, extractRequestId(apiException.headers())); } catch (RuntimeException ignored) { // body did not deserialise into the shape we know; let the caller summarise instead @@ -997,9 +1140,9 @@ private static List tokenizeRecordsFromErrorBody( /** Pulls the most specific message available from a failed batch response body. */ private static String extractBatchErrorMessage(ApiClientApiException apiException) { - Object rawBody = apiException.body(); - if (rawBody instanceof Map) { - Object errField = ((Map) rawBody).get("error"); + Map body = errorBodyAsMap(apiException); + if (body != null) { + Object errField = body.get("error"); if (errField instanceof String) { return (String) errField; } @@ -1017,10 +1160,11 @@ private static String extractBatchErrorMessage(ApiClientApiException apiExceptio // Unary counterpart of formatBulkInsertResponse: a single, unbatched call has no batch // index to attach, but the call's own requestId is still populated on error records, // matching bulk's error != null ? requestId : null convention. - public static InsertResponse formatInsertResponse(V1InsertResponse response, Map> headers) { + public static InsertResponse formatInsertResponse( + com.skyflow.generated.rest.types.InsertResponse response, Map> headers) { List records = new ArrayList<>(); - if (response != null && response.getRecords().isPresent()) { - for (V1RecordResponseObject current : response.getRecords().get()) { + if (response != null && response.getRecords() != null) { + for (RecordResponseObject current : response.getRecords()) { String reqID = current.getError().isPresent() ? extractRequestId(headers) : null; records.add(new InsertResponseRecord( current.getTableName().orElse(null), @@ -1028,7 +1172,7 @@ public static InsertResponse formatInsertResponse(V1InsertResponse response, Map Token.parseTokens(current.getTokens().orElse(null)), current.getData().orElse(null), current.getHashedData().orElse(null), - current.getHttpCode().orElse(current.getError().isPresent() ? 500 : 200), + recordHttpCode(current.getHttpCode(), current.getError().isPresent()), current.getError().orElse(null), reqID)); } @@ -1038,16 +1182,17 @@ public static InsertResponse formatInsertResponse(V1InsertResponse response, Map // Update has no bulk/batched counterpart, so there is no index to attach here, but the call's // own requestId is still populated on error records. The wire response reuses - // V1RecordResponseObject (the same shape as insert's), so the per-record mapping mirrors + // RecordResponseObject (the same shape as insert's), so the per-record mapping mirrors // formatInsertResponse. // Get has no bulk/batched counterpart, so there is no index to attach here, but the call's own // requestId is still populated on error records. The wire response reuses - // V1RecordResponseObject (the same shape as insert's/update's), so the per-record mapping + // RecordResponseObject (the same shape as insert's/update's), so the per-record mapping // mirrors formatInsertResponse. - public static GetResponse formatGetResponse(V1GetResponse response, Map> headers) { + public static GetResponse formatGetResponse( + com.skyflow.generated.rest.types.GetResponse response, Map> headers) { List records = new ArrayList<>(); - if (response != null && response.getRecords().isPresent()) { - for (V1RecordResponseObject current : response.getRecords().get()) { + if (response != null && response.getRecords() != null) { + for (RecordResponseObject current : response.getRecords()) { String reqID = current.getError().isPresent() ? extractRequestId(headers) : null; records.add(new GetResponseRecord( current.getTableName().orElse(null), @@ -1055,7 +1200,7 @@ public static GetResponse formatGetResponse(V1GetResponse response, Map> headers) { + // response (DeleteResponseObject) carries no data/tokens. + public static DeleteResponse formatDeleteResponse( + com.skyflow.generated.rest.types.DeleteResponse response, Map> headers) { List records = new ArrayList<>(); - if (response != null && response.getRecords().isPresent()) { - for (V1DeleteResponseObject current : response.getRecords().get()) { + if (response != null && response.getRecords() != null) { + for (DeleteResponseObject current : response.getRecords()) { String reqID = current.getError().isPresent() ? extractRequestId(headers) : null; records.add(new DeleteResponseRecord( - current.getSkyflowId().orElse(null), - current.getHttpCode().orElse(current.getError().isPresent() ? 500 : 200), + current.getSkyflowId(), + recordHttpCode(current.getHttpCode(), current.getError().isPresent()), current.getError().orElse(null), reqID)); } @@ -1081,10 +1227,11 @@ public static DeleteResponse formatDeleteResponse(V1DeleteResponse response, Map return new DeleteResponse(records); } - public static UpdateResponse formatUpdateResponse(V1UpdateResponse response, Map> headers) { + public static UpdateResponse formatUpdateResponse( + com.skyflow.generated.rest.types.UpdateResponse response, Map> headers) { List records = new ArrayList<>(); - if (response != null && response.getRecords().isPresent()) { - for (V1RecordResponseObject current : response.getRecords().get()) { + if (response != null && response.getRecords() != null) { + for (RecordResponseObject current : response.getRecords()) { String reqID = current.getError().isPresent() ? extractRequestId(headers) : null; records.add(new UpdateResponseRecord( current.getTableName().orElse(null), @@ -1092,7 +1239,7 @@ public static UpdateResponse formatUpdateResponse(V1UpdateResponse response, Map Token.parseTokens(current.getTokens().orElse(null)), current.getData().orElse(null), current.getHashedData().orElse(null), - current.getHttpCode().orElse(current.getError().isPresent() ? 500 : 200), + recordHttpCode(current.getHttpCode(), current.getError().isPresent()), current.getError().orElse(null), reqID)); } @@ -1100,15 +1247,16 @@ public static UpdateResponse formatUpdateResponse(V1UpdateResponse response, Map return new UpdateResponse(records); } - public static BulkInsertResponse formatBulkInsertResponse(V1InsertResponse response, int batch, int batchSize, Map> headers) { + public static BulkInsertResponse formatBulkInsertResponse( + com.skyflow.generated.rest.types.InsertResponse response, int batch, int batchSize, Map> headers) { BulkInsertResponse formattedResponse = null; List records = new ArrayList<>(); - if (response != null && response.getRecords().isPresent()) { - List record = response.getRecords().get(); + if (response != null && response.getRecords() != null) { + List record = response.getRecords(); int indexNumber = batch * batchSize; int recordsSize = record.size(); for (int index = 0; index < recordsSize; index++) { - V1RecordResponseObject current = record.get(index); + RecordResponseObject current = record.get(index); String reqID = null; if(current.getError().isPresent()){ reqID = extractRequestId(headers); @@ -1120,7 +1268,7 @@ public static BulkInsertResponse formatBulkInsertResponse(V1InsertResponse respo Token.parseTokens(current.getTokens().orElse(null)), current.getData().orElse(null), current.getHashedData().orElse(null), - current.getHttpCode().orElse(current.getError().isPresent() ? 500 : 200), + recordHttpCode(current.getHttpCode(), current.getError().isPresent()), current.getError().orElse(null), reqID)); indexNumber++; @@ -1133,15 +1281,16 @@ public static BulkInsertResponse formatBulkInsertResponse(V1InsertResponse respo // Unary counterpart of formatBulkDetokenizeResponse: a single, unbatched call has no batch // index to attach, but the call's own requestId is still populated on error records, // matching bulk's error != null ? requestId : null convention. - public static DetokenizeResponse formatDetokenizeResponse(V1FlowDetokenizeResponse response, Map> headers) { + public static DetokenizeResponse formatDetokenizeResponse( + com.skyflow.generated.rest.types.DetokenizeResponse response, Map> headers) { List records = new ArrayList<>(); - if (response != null && response.getResponse().isPresent()) { - for (V1FlowDetokenizeResponseObject current : response.getResponse().get()) { + if (response != null && response.getResponse() != null) { + for (DetokenizeResponseObject current : response.getResponse()) { DetokenizeResponseRecordMetadata metadata = DetokenizeResponseRecordMetadata.parseMetadata(current.getMetadata().orElse(null)); String reqID = current.getError().isPresent() ? extractRequestId(headers) : null; records.add(new DetokenizeResponseRecord( - current.getToken().orElse(null), - current.getValue().orElse(null), + current.getToken(), + unwrap(current.getValue().orElse(null)), current.getTokenGroupName().orElse(null), metadata, current.getHttpCode().orElse(current.getError().isPresent() ? 500 : 200), @@ -1152,14 +1301,15 @@ public static DetokenizeResponse formatDetokenizeResponse(V1FlowDetokenizeRespon return new DetokenizeResponse(records); } - public static BulkDetokenizeResponse formatBulkDetokenizeResponse(V1FlowDetokenizeResponse response, int batch, int batchSize, Map> headers) { - if (response != null && response.getResponse().isPresent()) { - List record = response.getResponse().get(); + public static BulkDetokenizeResponse formatBulkDetokenizeResponse( + com.skyflow.generated.rest.types.DetokenizeResponse response, int batch, int batchSize, Map> headers) { + if (response != null && response.getResponse() != null) { + List record = response.getResponse(); List records = new ArrayList<>(); int indexNumber = batch * batchSize; int recordsSize = record.size(); for (int index = 0; index < recordsSize; index++) { - V1FlowDetokenizeResponseObject current = record.get(index); + DetokenizeResponseObject current = record.get(index); DetokenizeResponseRecordMetadata metadata = DetokenizeResponseRecordMetadata.parseMetadata(current.getMetadata().orElse(null)); String reqID = null; if(current.getError().isPresent()){ @@ -1167,8 +1317,8 @@ public static BulkDetokenizeResponse formatBulkDetokenizeResponse(V1FlowDetokeni } records.add(new BulkDetokenizeResponseRecord( indexNumber, - current.getToken().orElse(null), - current.getValue().orElse(null), + current.getToken(), + unwrap(current.getValue().orElse(null)), current.getTokenGroupName().orElse(null), metadata, current.getHttpCode().orElse(current.getError().isPresent() ? 500 : 200), @@ -1182,19 +1332,18 @@ public static BulkDetokenizeResponse formatBulkDetokenizeResponse(V1FlowDetokeni } public static BulkDeleteTokensResponse formatBulkDeleteTokensResponse( - V1FlowDeleteTokenResponse response, - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest batchRequest, + DeleteTokenResponse response, + DeleteTokenRequest batchRequest, int batch, int batchSize, Map> headers) { - if (response != null && response.getTokens().isPresent()) { - List records = response.getTokens().get(); - List requestedTokens = batchRequest != null && batchRequest.getTokens().isPresent() - ? batchRequest.getTokens().get() : null; + if (response != null && response.getTokens() != null) { + List records = response.getTokens(); + List requestedTokens = batchRequest != null ? batchRequest.getTokens() : null; List responseRecords = new ArrayList<>(); int indexNumber = batch * batchSize; // one id per API call, so every error this batch reports carries the same one String requestId = extractRequestId(headers); for (int position = 0; position < records.size(); position++) { - V1DeleteTokenResponseObject record = records.get(position); + DeleteTokenResponseObject record = records.get(position); boolean failed = isFailedRecord(record); // The API echoes the token back on both paths, but fall back to the token we sent at // this position so an error record is never missing its token. @@ -1217,32 +1366,103 @@ public static BulkDeleteTokensResponse formatBulkDeleteTokensResponse( /** Converts one wire record into the unified success/error record shape. */ /** Maps one SDK request record to the wire object, carrying the BYOT token when supplied. */ - private static V1FlowTokenizeRequestObject buildTokenizeRequestObject(TokenizeRequestRecord record) { - V1FlowTokenizeRequestObject.Builder builder = V1FlowTokenizeRequestObject.builder() - .value(record.getValue()) + // Query has no per-record status: a failure is thrown rather than returned, so each row is just + // the record's data. The requestId is call-level and set on every response, not only on errors. + public static QueryResponse formatQueryResponse(ExecuteQueryResponse response, Map> headers) { + ArrayList> fields = new ArrayList<>(); + List columns = null; + if (response != null) { + if (response.getRecords().isPresent()) { + for (ExecuteQueryRecordResponse record : response.getRecords().get()) { + // LinkedHashMap keeps the column order the vault returned + fields.add(new LinkedHashMap<>(record.getData().orElse(new HashMap<>()))); + } + } + if (response.getMetadata().isPresent()) { + columns = response.getMetadata().get().getColumns().orElse(null); + } + } + return new QueryResponse(fields, new QueryResponseMetadata(columns), extractRequestId(headers)); + } + + // Unary, unbatched: one row per input entry in request order, with the call's requestId set + // only on rows that carry an error, matching the other unary operations. + public static GetTokensResponse formatGetTokensResponse(GetTokensFromValuesResponse response, Map> headers) { + ArrayList> records = new ArrayList<>(); + if (response != null && response.getRecords() != null) { + for (TokenizeResponseObject current : response.getRecords()) { + String error = asNonEmptyString(current.getError().orElse(null)); + records.add(getTokensRow( + unwrap(current.getValue().orElse(null)), + asNonEmptyString(current.getTokenGroupName().orElse(null)), + getTokensToken(current.getToken()), + current.getHttpCode().orElse(error != null ? 500 : 200), + error, + error != null ? extractRequestId(headers) : null)); + } + } + return new GetTokensResponse(records); + } + + private static HashMap getTokensRow( + Object value, String tokenGroupName, String token, int httpCode, String error, String requestId) { + HashMap row = new LinkedHashMap<>(); + row.put("value", value); + row.put("tokenGroupName", tokenGroupName); + row.put("token", token); + row.put("httpCode", httpCode); + row.put("error", error); + row.put("requestId", requestId); + return row; + } + + private static TokenizeRequestObject buildTokenizeRequestObject(TokenizeRequestRecord record) { + TokenizeRequestObject._FinalStage builder = TokenizeRequestObject.builder() + .value(GoogleProtobufValue.of(record.getValue())) .tokenGroupNames(record.getTokenGroupNames()); if (record.getToken() != null) { - builder = builder.token(record.getToken()); + builder.token(GoogleProtobufValue.of(record.getToken())); } return builder.build(); } private static BulkTokenizeResponseRecord buildTokenizeResponseRecord( - int index, V1FlowTokenizeResponseObject record, String requestId) { + int index, TokenizeResponseObject record, String requestId) { boolean failed = record.getError().isPresent() && record.getError().get() != null && !record.getError().get().isEmpty(); return new BulkTokenizeResponseRecord( index, - record.getValue().orElse(null), + unwrap(record.getValue().orElse(null)), asNonEmptyString(record.getTokenGroupName().orElse(null)), - asNonEmptyString(record.getToken().orElse(null)), + asNonEmptyString(record.getToken()), record.getHttpCode().orElse(failed ? 500 : 200), failed ? record.getError().get() : null, requestId ); } + /** The plain JSON value inside a wire {@code google.protobuf.Value}, or null when absent. */ + private static Object unwrap(GoogleProtobufValue value) { + return value == null ? null : value.get(); + } + + /** + * The record's HTTP status. The wire field is a plain int, so an omitted status reads as 0; + * fall back to the status the record's error implies, as when the field was optional. + */ + private static int recordHttpCode(int httpCode, boolean failed) { + return httpCode != 0 ? httpCode : (failed ? 500 : 200); + } + + /** + * A getTokens record's token, passed through as the vault sent it so a value with no token reads + * {@code ""} rather than null — matching the python SDK. A missing token also reads {@code ""}. + */ + private static String getTokensToken(Object token) { + return token == null ? "" : token.toString(); + } + /** The API sends "" for a token or error that does not apply; normalise both to null. */ private static String asNonEmptyString(Object value) { if (!(value instanceof String)) { @@ -1256,7 +1476,7 @@ private static String asNonEmptyString(Object value) { * A record counts as failed only when the API returned a non-empty error message together with * a non-2xx status, mirroring the check the bulk path has always used. */ - private static boolean isFailedRecord(V1DeleteTokenResponseObject record) { + private static boolean isFailedRecord(DeleteTokenResponseObject record) { return record.getError().isPresent() && record.getError().get() != null && !record.getError().get().isEmpty() @@ -1264,12 +1484,12 @@ private static boolean isFailedRecord(V1DeleteTokenResponseObject record) { } public static BulkTokenizeResponse formatBulkTokenizeResponse( - V1FlowTokenizeResponse response, + TokenizeResponse response, List batchRecords, int startIndex, Map> headers) { - if (response != null && response.getResponse().isPresent()) { - List rows = response.getResponse().get(); + if (response != null && response.getResponse() != null) { + List rows = response.getResponse(); // one id per API call, so every error this batch reports carries the same one String requestId = extractRequestId(headers); return new BulkTokenizeResponse(groupTokenizeRows(rows, batchRecords, startIndex, requestId)); @@ -1289,7 +1509,7 @@ public static BulkTokenizeResponse formatBulkTokenizeResponse( * {@link #createBulkTokenizeBatches}), so the value comparison never straddles two records. */ private static List groupTokenizeRows( - List rows, + List rows, List batchRecords, int startIndex, String requestId) { @@ -1304,8 +1524,8 @@ private static List groupTokenizeRows( int recordPosition = 0; int rowsTakenByRecord = 0; - for (V1FlowTokenizeResponseObject row : rows) { - Object rowValue = row.getValue().orElse(null); + for (TokenizeResponseObject row : rows) { + Object rowValue = unwrap(row.getValue().orElse(null)); while (recordPosition < batchRecords.size() && !acceptsRow(batchRecords.get(recordPosition), rowValue, rowsTakenByRecord)) { rowsTakenByRecord = 0; @@ -1348,4 +1568,270 @@ private static boolean valuesMatch(Object requested, Object echoed) { return String.valueOf(requested).equals(String.valueOf(echoed)); } + // ── Upload / delete files ──────────────────────────────────────────────── + + public static final String UPLOAD_STATUS_UPLOADED = "UPLOADED"; + public static final String UPLOAD_STATUS_FAILED = "FAILED"; + public static final String UPLOAD_STATUS_SKIPPED = "SKIPPED"; + private static final String DEFAULT_UPLOAD_CONTENT_TYPE = "application/octet-stream"; + + /** Phase A body: the file columns of each record, with the name each file will be stored under. */ + public static FileUploadRequest getUploadFilesRequestBody(UploadFilesRequest request, String vaultId) { + List records = new ArrayList<>(); + for (UploadFilesRequestRecord record : request.getRecords()) { + List columns = new ArrayList<>(); + for (UploadFilesRequestColumn column : record.getColumns()) { + FileUploadColumn._FinalStage wireColumn = FileUploadColumn.builder().column(column.getColumn()); + String fileName = resolveUploadFileName(column); + if (fileName != null) { + wireColumn.fileName(fileName); + } + columns.add(wireColumn.build()); + } + FileUploadRecord._FinalStage wireRecord = FileUploadRecord.builder() + .tableName(record.getTableName()) + .columns(columns); + if (record.getSkyflowId() != null) { + wireRecord.skyflowId(record.getSkyflowId()); + } + records.add(wireRecord.build()); + } + return FileUploadRequest.builder().vaultId(vaultId).records(records).build(); + } + + /** + * The name the file is stored under: the explicit fileName, else the name of the column's file + * source (filePath or fileObject; base64 always carries an explicit fileName). + * Null leaves it to the server, which generates a random 16-byte UUID name. + */ + public static String resolveUploadFileName(UploadFilesRequestColumn column) { + if (hasText(column.getFileName())) { + return column.getFileName(); + } + if (hasText(column.getFilePath())) { + return new File(column.getFilePath()).getName(); + } + if (!hasText(column.getBase64()) && column.getFileObject() != null) { + return column.getFileObject().getName(); + } + return null; + } + + /** + * MIME types for common file extensions. The JDK's own table differs between releases — Java 8 + * knows none of the Office formats, csv, json, mp3 or mp4 — so the SDK keeps its own list and + * the same file gets the same type on every JDK. Anything not listed falls back to the JDK. + */ + private static final Map UPLOAD_CONTENT_TYPES = new HashMap<>(); + + static { + String[][] types = { + {"pdf", "application/pdf"}, + {"jpg", "image/jpeg"}, {"jpeg", "image/jpeg"}, {"png", "image/png"}, {"gif", "image/gif"}, + {"bmp", "image/bmp"}, {"tif", "image/tiff"}, {"tiff", "image/tiff"}, {"webp", "image/webp"}, + {"heic", "image/heic"}, {"heif", "image/heif"}, {"svg", "image/svg+xml"}, + {"txt", "text/plain"}, {"csv", "text/csv"}, {"tsv", "text/tab-separated-values"}, + {"json", "application/json"}, {"xml", "application/xml"}, {"html", "text/html"}, + {"htm", "text/html"}, {"rtf", "application/rtf"}, + {"doc", "application/msword"}, + {"docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, + {"xls", "application/vnd.ms-excel"}, + {"xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}, + {"ppt", "application/vnd.ms-powerpoint"}, + {"pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"}, + {"odt", "application/vnd.oasis.opendocument.text"}, + {"ods", "application/vnd.oasis.opendocument.spreadsheet"}, + {"odp", "application/vnd.oasis.opendocument.presentation"}, + {"zip", "application/zip"}, {"gz", "application/gzip"}, {"tar", "application/x-tar"}, + {"7z", "application/x-7z-compressed"}, + {"mp3", "audio/mpeg"}, {"wav", "audio/wav"}, {"m4a", "audio/mp4"}, {"ogg", "audio/ogg"}, + {"flac", "audio/flac"}, + {"mp4", "video/mp4"}, {"mov", "video/quicktime"}, {"avi", "video/x-msvideo"}, + {"webm", "video/webm"}, {"mkv", "video/x-matroska"}, + }; + for (String[] type : types) { + UPLOAD_CONTENT_TYPES.put(type[0], type[1]); + } + } + + /** + * The type for the file name's extension (case-insensitive), else the JDK's guess, else + * application/octet-stream. + */ + public static String resolveUploadContentType(String fileName) { + if (fileName == null) { + return DEFAULT_UPLOAD_CONTENT_TYPE; + } + int dot = fileName.lastIndexOf('.'); + if (dot >= 0) { + String known = UPLOAD_CONTENT_TYPES.get(fileName.substring(dot + 1).toLowerCase(java.util.Locale.ROOT)); + if (known != null) { + return known; + } + } + String guessed = URLConnection.guessContentTypeFromName(fileName); + return guessed != null ? guessed : DEFAULT_UPLOAD_CONTENT_TYPE; + } + + /** + * Decodes each base64 column once, before Phase A, so an invalid value fails the call before + * anything is sent. The decoded bytes are reused for the Phase B upload. + */ + public static Map decodeBase64Columns(UploadFilesRequest request) + throws SkyflowException { + Map decoded = new IdentityHashMap<>(); + List records = request.getRecords(); + for (int i = 0; i < records.size(); i++) { + for (UploadFilesRequestColumn column : records.get(i).getColumns()) { + if (!hasText(column.getBase64())) { + continue; + } + try { + decoded.put(column, Base64.getDecoder().decode(column.getBase64())); + } catch (IllegalArgumentException e) { + LogUtil.printErrorLog(parameterizedString(ErrorLogs.INVALID_BASE64_IN_UPLOAD_FILES_COLUMN.getLog(), + InterfaceName.UPLOAD_FILES.getName(), String.valueOf(i))); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), + ErrorMessage.InvalidBase64InUploadFilesColumn.getMessage()); + } + } + } + return decoded; + } + + /** + * Phase B body: the bytes of the column's one file source. Files are streamed from disk rather + * than read into memory; base64 content arrives already decoded. + */ + public static RequestBody buildUploadFileBody(UploadFilesRequestColumn column, byte[] decodedBase64, + String contentType) { + MediaType mediaType = MediaType.parse(contentType); + if (hasText(column.getFilePath())) { + return RequestBody.create(new File(column.getFilePath()), mediaType); + } + if (decodedBase64 != null) { + return RequestBody.create(decodedBase64, mediaType); + } + return RequestBody.create(column.getFileObject(), mediaType); + } + + public static HashMap uploadFilesColumnRow( + String column, String fileName, String uploadStatus, String error) { + HashMap row = new LinkedHashMap<>(); + row.put("column", column); + row.put("fileName", fileName); + row.put("uploadStatus", uploadStatus); + row.put("error", error); + return row; + } + + public static HashMap uploadFilesRecordRow(String skyflowId, String tableName, + List> columns, int httpCode, String error, String requestId) { + HashMap row = new LinkedHashMap<>(); + row.put("skyflowId", skyflowId); + row.put("tableName", tableName); + row.put("columns", columns); + row.put("httpCode", httpCode); + row.put("error", error); + row.put("requestId", requestId); + return row; + } + + /** Every requested column of a record that failed in Phase A: nothing was uploaded. */ + public static List> skippedUploadColumns(UploadFilesRequestRecord record, String error) { + List> columns = new ArrayList<>(); + if (record != null && record.getColumns() != null) { + for (UploadFilesRequestColumn column : record.getColumns()) { + columns.add(uploadFilesColumnRow(column.getColumn(), resolveUploadFileName(column), + UPLOAD_STATUS_SKIPPED, error)); + } + } + return columns; + } + + public static FileDeleteRequest getDeleteFilesRequestBody(DeleteFilesRequest request, String vaultId) { + List records = new ArrayList<>(); + for (DeleteFilesRequestRecord record : request.getRecords()) { + FileDeleteRecord._FinalStage wireRecord = FileDeleteRecord.builder() + .tableName(record.getTableName()) + .columns(record.getColumns()); + // validation guarantees exactly one of skyflowId / uniqueValues is set + if (record.getSkyflowId() != null) { + wireRecord.skyflowId(record.getSkyflowId()); + } + if (record.getUniqueValues() != null && !record.getUniqueValues().isEmpty()) { + wireRecord.uniqueValues(toUniqueValueList(record.getUniqueValues())); + } + records.add(wireRecord.build()); + } + return FileDeleteRequest.builder().vaultId(vaultId).records(records).build(); + } + + // One entry per resolved record (uniqueValues may resolve to several), with the call's + // requestId set only on entries that carry an error, matching the other unary operations. + public static DeleteFilesResponse formatDeleteFilesResponse( + FileDeleteResponse response, Map> headers) { + ArrayList> records = new ArrayList<>(); + if (response != null && response.getRecords() != null) { + for (FileDeleteResponseObject current : response.getRecords()) { + String error = asNonEmptyString(current.getError().orElse(null)); + records.add(deleteFilesRecordRow( + current.getSkyflowId().orElse(null), + current.getTableName(), + deletedColumns(current.getData().orElse(null)), + recordHttpCode(current.getHttpCode(), error != null), + error, + error != null ? extractRequestId(headers) : null)); + } + } + return new DeleteFilesResponse(records); + } + + public static DeleteFilesResponse handleDeleteFilesRequestException(ApiClientApiException apiException) { + List> recordMaps = extractExceptionRecords(apiException, "records"); + if (recordMaps == null) { + return null; + } + String requestId = extractRequestId(apiException.headers()); + ArrayList> records = new ArrayList<>(); + for (Map recordMap : recordMaps) { + records.add(deleteFilesRecordRow( + readString(recordMap, "skyflowID"), + readString(recordMap, "tableName"), + null, + readHttpCode(recordMap, apiException.statusCode()), + readErrorMessage(recordMap), + requestId)); + } + return new DeleteFilesResponse(records); + } + + /** The deleted columns from the wire "data" map, or null when the record failed. */ + private static List> deletedColumns(Map data) { + if (data == null) { + return null; + } + List> columns = new ArrayList<>(); + for (Map.Entry entry : data.entrySet()) { + Object result = entry.getValue(); + Object status = result instanceof Map ? ((Map) result).get("status") : result; + HashMap column = new LinkedHashMap<>(); + column.put("column", entry.getKey()); + column.put("status", status == null ? null : status.toString()); + columns.add(column); + } + return columns; + } + + private static HashMap deleteFilesRecordRow(String skyflowId, String tableName, + List> columns, int httpCode, String error, String requestId) { + HashMap row = new LinkedHashMap<>(); + row.put("skyflowId", skyflowId); + row.put("tableName", tableName); + row.put("columns", columns); + row.put("httpCode", httpCode); + row.put("error", error); + row.put("requestId", requestId); + return row; + } } diff --git a/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java b/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java index 084b01d7..be0cf6ea 100644 --- a/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java +++ b/flowvault/src/main/java/com/skyflow/utils/validations/Validations.java @@ -3,7 +3,6 @@ import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; import com.skyflow.enums.InterfaceName; -import com.skyflow.generated.rest.types.FlowEnumUpdateType; import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; @@ -13,7 +12,9 @@ import com.skyflow.utils.logger.LogUtil; import com.skyflow.vault.data.*; +import java.io.File; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -319,12 +320,7 @@ private static void validateUpsertOptions(UpsertOptions upsert) throws SkyflowEx } private static boolean isKnownUpdateType(String updateType) { - for (FlowEnumUpdateType type : FlowEnumUpdateType.values()) { - if (type.toString().equalsIgnoreCase(updateType)) { - return true; - } - } - return false; + return Utils.toUpsertUpdateType(updateType) != null; } public static void validateDetokenizeRequest(DetokenizeRequest request) throws SkyflowException { @@ -765,4 +761,203 @@ record = records.get(i); } } + public static void validateQueryRequest(QueryRequest queryRequest) throws SkyflowException { + if (queryRequest == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.QUERY_REQUEST_NULL.getLog(), InterfaceName.QUERY.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.QueryRequestNull.getMessage()); + } + String query = queryRequest.getQuery(); + if (query == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.QUERY_IS_REQUIRED.getLog(), InterfaceName.QUERY.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.QueryKeyError.getMessage()); + } else if (query.trim().isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_QUERY.getLog(), InterfaceName.QUERY.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyQuery.getMessage()); + } + } + + public static void validateGetTokensRequest(GetTokensRequest request) throws SkyflowException { + if (request == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.GET_TOKENS_REQUEST_NULL.getLog(), InterfaceName.GET_TOKENS.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.GetTokensRequestNull.getMessage()); + } + List records = request.getRecords(); + if (records == null || records.isEmpty()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_GET_TOKENS_RECORDS.getLog(), InterfaceName.GET_TOKENS.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyGetTokensRecords.getMessage()); + } + for (int i = 0; i < records.size(); i++) { + GetTokensRequestRecord record = records.get(i); + if (record == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.GET_TOKENS_RECORD_NULL.getLog(), InterfaceName.GET_TOKENS.getName(), String.valueOf(i) + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.GetTokensRecordNull.getMessage()); + } + Object value = record.getValue(); + if (value == null || (value instanceof String && ((String) value).trim().isEmpty())) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_VALUE_IN_GET_TOKENS_RECORD.getLog(), InterfaceName.GET_TOKENS.getName(), String.valueOf(i) + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyValueInGetTokensRecord.getMessage()); + } + if (!hasText(record.getTokenGroupName())) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_TOKEN_GROUP_NAME_IN_GET_TOKENS_RECORD.getLog(), InterfaceName.GET_TOKENS.getName(), String.valueOf(i) + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyTokenGroupNameInGetTokensRecord.getMessage()); + } + } + } + + public static void validateUploadFilesRequest(UploadFilesRequest request) throws SkyflowException { + InterfaceName upload = InterfaceName.UPLOAD_FILES; + if (request == null) { + throw invalid(ErrorLogs.UPLOAD_FILES_REQUEST_NULL, ErrorMessage.UploadFilesRequestNull, upload, null); + } + List records = request.getRecords(); + if (records == null || records.isEmpty()) { + throw invalid(ErrorLogs.EMPTY_UPLOAD_FILES_RECORDS, ErrorMessage.EmptyUploadFilesRecords, upload, null); + } + for (int i = 0; i < records.size(); i++) { + UploadFilesRequestRecord record = records.get(i); + if (record == null) { + throw invalid(ErrorLogs.UPLOAD_FILES_RECORD_NULL, ErrorMessage.UploadFilesRecordNull, upload, i); + } + if (!hasText(record.getTableName())) { + throw invalid(ErrorLogs.EMPTY_TABLE_NAME_IN_UPLOAD_FILES_RECORD, + ErrorMessage.EmptyTableNameInUploadFilesRecord, upload, i); + } + // Omitting skyflowId creates a new record, so a blank one is rejected rather than + // silently treated as absent. + if (record.getSkyflowId() != null && !hasText(record.getSkyflowId())) { + throw invalid(ErrorLogs.EMPTY_SKYFLOW_ID_IN_UPLOAD_FILES_RECORD, + ErrorMessage.EmptySkyflowIdInUploadFilesRecord, upload, i); + } + List columns = record.getColumns(); + if (columns == null || columns.isEmpty()) { + throw invalid(ErrorLogs.EMPTY_UPLOAD_FILES_COLUMNS, ErrorMessage.EmptyUploadFilesColumns, upload, i); + } + // Signed URLs come back keyed by column name, so a repeated column would overwrite + // the other file under the same URL. + Set seen = new HashSet<>(); + for (UploadFilesRequestColumn column : columns) { + validateUploadFilesColumn(column, i); + if (!seen.add(column.getColumn())) { + throw invalid(ErrorLogs.DUPLICATE_COLUMN_IN_UPLOAD_FILES_RECORD, + ErrorMessage.DuplicateColumnInUploadFilesRecord, upload, i); + } + } + } + } + + // Exactly one file source per column (filePath, base64 or fileObject), and it must be usable. + private static void validateUploadFilesColumn(UploadFilesRequestColumn column, int recordIndex) + throws SkyflowException { + InterfaceName upload = InterfaceName.UPLOAD_FILES; + if (column == null) { + throw invalid(ErrorLogs.UPLOAD_FILES_COLUMN_NULL, ErrorMessage.UploadFilesColumnNull, upload, recordIndex); + } + if (!hasText(column.getColumn())) { + throw invalid(ErrorLogs.EMPTY_COLUMN_IN_UPLOAD_FILES_COLUMN, + ErrorMessage.EmptyColumnInUploadFilesColumn, upload, recordIndex); + } + int sources = (hasText(column.getFilePath()) ? 1 : 0) + (hasText(column.getBase64()) ? 1 : 0) + + (column.getFileObject() != null ? 1 : 0); + if (sources == 0) { + throw invalid(ErrorLogs.MISSING_FILE_SOURCE_IN_UPLOAD_FILES_COLUMN, + ErrorMessage.MissingFileSourceInUploadFilesColumn, upload, recordIndex); + } + if (sources > 1) { + throw invalid(ErrorLogs.MULTIPLE_FILE_SOURCES_IN_UPLOAD_FILES_COLUMN, + ErrorMessage.MultipleFileSourcesInUploadFilesColumn, upload, recordIndex); + } + if (hasText(column.getFilePath())) { + File file = new File(column.getFilePath()); + if (!file.isFile() || !file.canRead()) { + throw invalid(ErrorLogs.INVALID_FILE_PATH_IN_UPLOAD_FILES_COLUMN, + ErrorMessage.InvalidFilePathInUploadFilesColumn, upload, recordIndex); + } + } else if (hasText(column.getBase64())) { + if (!hasText(column.getFileName())) { + throw invalid(ErrorLogs.FILE_NAME_REQUIRED_WITH_BASE64_IN_UPLOAD_FILES_COLUMN, + ErrorMessage.FileNameRequiredWithBase64InUploadFilesColumn, upload, recordIndex); + } + } else if (!column.getFileObject().isFile() || !column.getFileObject().canRead()) { + throw invalid(ErrorLogs.INVALID_FILE_OBJECT_IN_UPLOAD_FILES_COLUMN, + ErrorMessage.InvalidFileObjectInUploadFilesColumn, upload, recordIndex); + } + } + + public static void validateDeleteFilesRequest(DeleteFilesRequest request) throws SkyflowException { + InterfaceName delete = InterfaceName.DELETE_FILES; + if (request == null) { + throw invalid(ErrorLogs.DELETE_FILES_REQUEST_NULL, ErrorMessage.DeleteFilesRequestNull, delete, null); + } + List records = request.getRecords(); + if (records == null || records.isEmpty()) { + throw invalid(ErrorLogs.EMPTY_DELETE_FILES_RECORDS, ErrorMessage.EmptyDeleteFilesRecords, delete, null); + } + for (int i = 0; i < records.size(); i++) { + DeleteFilesRequestRecord record = records.get(i); + if (record == null) { + throw invalid(ErrorLogs.DELETE_FILES_RECORD_NULL, ErrorMessage.DeleteFilesRecordNull, delete, i); + } + if (!hasText(record.getTableName())) { + throw invalid(ErrorLogs.EMPTY_TABLE_NAME_IN_DELETE_FILES_RECORD, + ErrorMessage.EmptyTableNameInDeleteFilesRecord, delete, i); + } + List columns = record.getColumns(); + if (columns == null || columns.isEmpty()) { + throw invalid(ErrorLogs.EMPTY_DELETE_FILES_COLUMNS, ErrorMessage.EmptyDeleteFilesColumns, delete, i); + } + Set seen = new HashSet<>(); + for (String column : columns) { + if (!hasText(column)) { + throw invalid(ErrorLogs.EMPTY_COLUMN_IN_DELETE_FILES_COLUMNS, + ErrorMessage.EmptyColumnInDeleteFilesColumns, delete, i); + } + if (!seen.add(column)) { + throw invalid(ErrorLogs.DUPLICATE_COLUMN_IN_DELETE_FILES_COLUMNS, + ErrorMessage.DuplicateColumnInDeleteFilesColumns, delete, i); + } + } + List> uniqueValues = record.getUniqueValues(); + boolean hasSkyflowId = hasText(record.getSkyflowId()); + boolean hasUniqueValues = uniqueValues != null && !uniqueValues.isEmpty(); + if (hasSkyflowId == hasUniqueValues) { + throw invalid(ErrorLogs.INVALID_ID_OR_UNIQUE_VALUES_IN_DELETE_FILES_RECORD, + ErrorMessage.InvalidIdOrUniqueValuesInDeleteFilesRecord, delete, i); + } + // Same per-entry rule as Get and Delete records. + if (hasUniqueValues) { + for (int index = 0; index < uniqueValues.size(); index++) { + Map uniqueValue = uniqueValues.get(index); + if (uniqueValue == null || uniqueValue.isEmpty()) { + throw invalid(ErrorLogs.EMPTY_OR_NULL_UNIQUE_VALUE_IN_UNIQUE_VALUES, + ErrorMessage.EmptyUniqueValueInUniqueValues, delete, index); + } + } + } + } + } + + /** Logs a validation failure and builds the exception to throw for it. */ + private static SkyflowException invalid(ErrorLogs log, ErrorMessage message, InterfaceName interfaceName, + Integer index) { + LogUtil.printErrorLog(index == null + ? Utils.parameterizedString(log.getLog(), interfaceName.getName()) + : Utils.parameterizedString(log.getLog(), interfaceName.getName(), String.valueOf(index))); + return new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), message.getMessage()); + } } diff --git a/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java b/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java index 0a4f544e..1c5d7d14 100644 --- a/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java +++ b/flowvault/src/main/java/com/skyflow/vault/controller/VaultController.java @@ -1,9 +1,12 @@ package com.skyflow.vault.controller; +import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -21,18 +24,21 @@ import com.skyflow.generated.rest.core.ApiClientException; import com.skyflow.generated.rest.core.ApiClientHttpResponse; import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.flowservice.requests.V1InsertRequest; -import com.skyflow.generated.rest.resources.flowservice.requests.V1DeleteRequest; -import com.skyflow.generated.rest.resources.flowservice.requests.V1GetRequest; -import com.skyflow.generated.rest.resources.flowservice.requests.V1UpdateRequest; -import com.skyflow.generated.rest.types.V1FlowDeleteTokenResponse; -import com.skyflow.generated.rest.types.V1FlowTokenizeResponse; -import com.skyflow.generated.rest.types.V1InsertRecordData; -import com.skyflow.generated.rest.types.V1InsertResponse; -import com.skyflow.generated.rest.types.V1DeleteResponse; -import com.skyflow.generated.rest.types.V1GetResponse; -import com.skyflow.generated.rest.types.V1UpdateResponse; -import com.skyflow.generated.rest.types.V1Upsert; +import com.skyflow.generated.rest.resources.files.requests.FileDeleteRequest; +import com.skyflow.generated.rest.resources.files.requests.FileUploadRequest; +import com.skyflow.generated.rest.resources.query.requests.ExecuteQueryRequest; +import com.skyflow.generated.rest.resources.tokens.requests.DeleteTokenRequest; +import com.skyflow.generated.rest.resources.tokens.requests.GetTokensFromValuesRequest; +import com.skyflow.generated.rest.resources.tokens.requests.TokenizeRequest; +import com.skyflow.generated.rest.types.DeleteTokenResponse; +import com.skyflow.generated.rest.types.ExecuteQueryResponse; +import com.skyflow.generated.rest.types.FileDeleteResponse; +import com.skyflow.generated.rest.types.FileUploadResponse; +import com.skyflow.generated.rest.types.FileUploadResponseObject; +import com.skyflow.generated.rest.types.GetTokensFromValuesResponse; +import com.skyflow.generated.rest.types.InsertRecordData; +import com.skyflow.generated.rest.types.TokenizeResponse; +import com.skyflow.generated.rest.types.Upsert; import com.skyflow.logs.ErrorLogs; import com.skyflow.logs.InfoLogs; import com.skyflow.logs.WarningLogs; @@ -68,16 +74,33 @@ import com.skyflow.vault.data.UpdateOptions; import com.skyflow.vault.data.UpdateRequest; import com.skyflow.vault.data.UpdateResponse; +import com.skyflow.vault.data.DeleteFilesOptions; +import com.skyflow.vault.data.DeleteFilesRequest; +import com.skyflow.vault.data.DeleteFilesResponse; import com.skyflow.vault.data.DeleteOptions; import com.skyflow.vault.data.DeleteRequest; import com.skyflow.vault.data.DeleteResponse; import com.skyflow.vault.data.GetOptions; import com.skyflow.vault.data.GetRequest; import com.skyflow.vault.data.GetResponse; +import com.skyflow.vault.data.GetTokensOptions; +import com.skyflow.vault.data.GetTokensRequest; +import com.skyflow.vault.data.GetTokensResponse; +import com.skyflow.vault.data.QueryOptions; +import com.skyflow.vault.data.QueryRequest; +import com.skyflow.vault.data.QueryResponse; import com.skyflow.vault.data.RequestInterceptor; +import com.skyflow.vault.data.UploadFilesOptions; +import com.skyflow.vault.data.UploadFilesRequest; +import com.skyflow.vault.data.UploadFilesRequestColumn; +import com.skyflow.vault.data.UploadFilesRequestRecord; +import com.skyflow.vault.data.UploadFilesResponse; import io.github.cdimascio.dotenv.Dotenv; import io.github.cdimascio.dotenv.DotenvException; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; public final class VaultController extends VaultClient { private static final Gson gson = new GsonBuilder().serializeNulls().create(); @@ -125,13 +148,13 @@ public InsertResponse insert(InsertRequest insertRequest, InsertOptions options) Validations.validateInsertRequest(insertRequest); setBearerToken(); - V1InsertRequest request = Utils.getInsertRequestBody(insertRequest, this.getVaultConfig()); + com.skyflow.generated.rest.resources.records.requests.InsertRequest request = Utils.getInsertRequestBody(insertRequest, this.getVaultConfig()); RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; RequestContext ctx = new RequestContext("INSERT", 0, 1); if (interceptor != null) interceptor.intercept(ctx); - ApiClientHttpResponse response = - this.getRecordsApi().withRawResponse().insert(request, buildRequestOptions(ctx)); + ApiClientHttpResponse response = + this.getRecordsApi().withRawResponse().insertRecords(request, buildRequestOptions(ctx)); InsertResponse formattedResponse = Utils.formatInsertResponse(response.body(), response.headers()); LogUtil.printInfoLog(InfoLogs.INSERT_REQUEST_RESOLVED.getLog()); @@ -144,7 +167,7 @@ public InsertResponse insert(InsertRequest insertRequest, InsertOptions options) if (fallback != null) { return fallback; } - String bodyString = gson.toJson(e.body()); + String bodyString = gson.toJson(Utils.errorBody(e)); LogUtil.printErrorLog(ErrorLogs.INSERT_RECORDS_REJECTED.getLog()); throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); } catch (ApiClientException e) { @@ -168,11 +191,11 @@ public BulkInsertResponse bulkInsert(BulkInsertRequest insertRequest, BulkInsert BatchConfig cfg = configureInsertConcurrencyAndBatchSize(insertRequest.getRecords().size()); setBearerToken(); - V1InsertRequest request = Utils.getBulkInsertRequestBody(insertRequest, this.getVaultConfig()); + com.skyflow.generated.rest.resources.records.requests.InsertRequest request = Utils.getBulkInsertRequestBody(insertRequest, this.getVaultConfig()); RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; return this.processBulkInsertSync(request, insertRequest.getRecords(), interceptor, cfg); } catch (ApiClientApiException e) { - String bodyString = gson.toJson(e.body()); + String bodyString = gson.toJson(Utils.errorBody(e)); LogUtil.printErrorLog(ErrorLogs.INSERT_RECORDS_REJECTED.getLog()); throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); } catch (ApiClientException e) { @@ -200,7 +223,7 @@ public CompletableFuture bulkInsertAsync(BulkInsertRequest i BatchConfig cfg = configureInsertConcurrencyAndBatchSize(insertRequest.getRecords().size()); setBearerToken(); - V1InsertRequest request = Utils.getBulkInsertRequestBody(insertRequest, this.getVaultConfig()); + com.skyflow.generated.rest.resources.records.requests.InsertRequest request = Utils.getBulkInsertRequestBody(insertRequest, this.getVaultConfig()); RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; List> futures = this.insertBatchFutures(request, interceptor, cfg); @@ -218,7 +241,7 @@ public CompletableFuture bulkInsertAsync(BulkInsertRequest i return new BulkInsertResponse(records, insertRequest.getRecords()); }); } catch (ApiClientApiException e) { - String bodyString = gson.toJson(e.body()); + String bodyString = gson.toJson(Utils.errorBody(e)); LogUtil.printErrorLog(ErrorLogs.INSERT_RECORDS_REJECTED.getLog()); throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); } catch (SkyflowException e) { @@ -245,14 +268,14 @@ public DetokenizeResponse detokenize(DetokenizeRequest detokenizeRequest, Detoke Validations.validateDetokenizeRequest(detokenizeRequest); setBearerToken(); - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest request = + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest request = Utils.getDetokenizeRequestBody(detokenizeRequest, this.getVaultConfig().getVaultId()); RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; RequestContext ctx = new RequestContext("DETOKENIZE", 0, 1); if (interceptor != null) interceptor.intercept(ctx); - ApiClientHttpResponse response = - this.getRecordsApi().withRawResponse().detokenize(request, buildRequestOptions(ctx)); + ApiClientHttpResponse response = + this.getTokensApi().withRawResponse().detokenize(request, buildRequestOptions(ctx)); DetokenizeResponse formattedResponse = Utils.formatDetokenizeResponse(response.body(), response.headers()); LogUtil.printInfoLog(InfoLogs.DETOKENIZE_REQUEST_RESOLVED.getLog()); @@ -265,7 +288,7 @@ public DetokenizeResponse detokenize(DetokenizeRequest detokenizeRequest, Detoke if (fallback != null) { return fallback; } - String bodyString = gson.toJson(e.body()); + String bodyString = gson.toJson(Utils.errorBody(e)); LogUtil.printErrorLog(ErrorLogs.DETOKENIZE_REQUEST_REJECTED.getLog()); throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); } catch (ApiClientException e) { @@ -287,12 +310,12 @@ public BulkDetokenizeResponse bulkDetokenize(BulkDetokenizeRequest detokenizeReq Validations.validateBulkDetokenizeRequest(detokenizeRequest); BatchConfig cfg = configureDetokenizeConcurrencyAndBatchSize(detokenizeRequest.getTokens().size()); setBearerToken(); - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest request = + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest request = Utils.getBulkDetokenizeRequestBody(detokenizeRequest, this.getVaultConfig().getVaultId()); RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; return this.processBulkDetokenizeSync(request, detokenizeRequest.getTokens(), interceptor, cfg); } catch (ApiClientApiException e) { - String bodyString = gson.toJson(e.body()); + String bodyString = gson.toJson(Utils.errorBody(e)); LogUtil.printErrorLog(ErrorLogs.DETOKENIZE_REQUEST_REJECTED.getLog()); throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); } catch (ApiClientException e) { @@ -317,7 +340,7 @@ public CompletableFuture bulkDetokenizeAsync(BulkDetoken Validations.validateBulkDetokenizeRequest(detokenizeRequest); BatchConfig cfg = configureDetokenizeConcurrencyAndBatchSize(detokenizeRequest.getTokens().size()); setBearerToken(); - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest request = + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest request = Utils.getBulkDetokenizeRequestBody(detokenizeRequest, this.getVaultConfig().getVaultId()); RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; @@ -325,7 +348,7 @@ public CompletableFuture bulkDetokenizeAsync(BulkDetoken List records = new ArrayList<>(); - List batches = + List batches = Utils.createBulkDetokenizeBatches(request, cfg.batchSize); executor = Executors.newFixedThreadPool(cfg.concurrencyLimit); @@ -342,7 +365,7 @@ public CompletableFuture bulkDetokenizeAsync(BulkDetoken return new BulkDetokenizeResponse(records, detokenizeRequest.getTokens()); }); } catch (ApiClientApiException e) { - String bodyString = gson.toJson(e.body()); + String bodyString = gson.toJson(Utils.errorBody(e)); LogUtil.printErrorLog(ErrorLogs.DETOKENIZE_REQUEST_REJECTED.getLog()); throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); } catch (SkyflowException e) { @@ -372,13 +395,13 @@ public DeleteResponse delete(DeleteRequest deleteRequest, DeleteOptions options) Validations.validateDeleteRequest(deleteRequest); setBearerToken(); - V1DeleteRequest request = Utils.getDeleteRequestBody(deleteRequest, this.getVaultConfig()); + com.skyflow.generated.rest.resources.records.requests.DeleteRequest request = Utils.getDeleteRequestBody(deleteRequest, this.getVaultConfig()); RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; RequestContext ctx = new RequestContext("DELETE", 0, 1); if (interceptor != null) interceptor.intercept(ctx); - ApiClientHttpResponse response = - this.getRecordsApi().withRawResponse().delete(request, buildRequestOptions(ctx)); + ApiClientHttpResponse response = + this.getRecordsApi().withRawResponse().deleteRecords(request, buildRequestOptions(ctx)); DeleteResponse formattedResponse = Utils.formatDeleteResponse(response.body(), response.headers()); LogUtil.printInfoLog(InfoLogs.DELETE_REQUEST_RESOLVED.getLog()); @@ -391,7 +414,7 @@ public DeleteResponse delete(DeleteRequest deleteRequest, DeleteOptions options) if (fallback != null) { return fallback; } - String bodyString = gson.toJson(e.body()); + String bodyString = gson.toJson(Utils.errorBody(e)); LogUtil.printErrorLog(ErrorLogs.DELETE_REQUEST_REJECTED.getLog()); throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); } catch (ApiClientException e) { @@ -413,12 +436,12 @@ public BulkDeleteTokensResponse bulkDeleteTokens(BulkDeleteTokensRequest deleteT Validations.validateBulkDeleteTokensRequest(deleteTokensRequest); BatchConfig cfg = configureDeleteTokensConcurrencyAndBatchSize(deleteTokensRequest.getTokens().size()); setBearerToken(); - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest request = + DeleteTokenRequest request = Utils.getBulkDeleteTokensRequestBody(deleteTokensRequest, this.getVaultConfig().getVaultId()); RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; return this.processBulkDeleteTokensSync(request, deleteTokensRequest.getTokens(), interceptor, cfg); } catch (ApiClientApiException e) { - String bodyString = gson.toJson(e.body()); + String bodyString = gson.toJson(Utils.errorBody(e)); LogUtil.printErrorLog(ErrorLogs.DELETE_REQUEST_REJECTED.getLog()); throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); } catch (ApiClientException e) { @@ -441,7 +464,7 @@ public CompletableFuture bulkDeleteTokensAsync(BulkDel Validations.validateBulkDeleteTokensRequest(deleteTokensRequest); BatchConfig cfg = configureDeleteTokensConcurrencyAndBatchSize(deleteTokensRequest.getTokens().size()); setBearerToken(); - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest request = + DeleteTokenRequest request = Utils.getBulkDeleteTokensRequestBody(deleteTokensRequest, this.getVaultConfig().getVaultId()); RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; @@ -449,7 +472,7 @@ public CompletableFuture bulkDeleteTokensAsync(BulkDel List responseRecords = Collections.synchronizedList(new ArrayList<>()); - List batches = + List batches = Utils.createBulkDeleteTokensBatches(request, cfg.batchSize); executor = Executors.newFixedThreadPool(cfg.concurrencyLimit); @@ -469,7 +492,7 @@ public CompletableFuture bulkDeleteTokensAsync(BulkDel sortByIndex(responseRecords), deleteTokensRequest.getTokens()); }); } catch (ApiClientApiException e) { - String bodyString = gson.toJson(e.body()); + String bodyString = gson.toJson(Utils.errorBody(e)); LogUtil.printErrorLog(ErrorLogs.DELETE_REQUEST_REJECTED.getLog()); throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); } catch (SkyflowException e) { @@ -499,7 +522,7 @@ public BulkTokenizeResponse bulkTokenize(BulkTokenizeRequest tokenizeRequest, Bu RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; return this.processBulkTokenizeSync(tokenizeRequest.getRecords(), interceptor, cfg); } catch (ApiClientApiException e) { - String bodyString = gson.toJson(e.body()); + String bodyString = gson.toJson(Utils.errorBody(e)); LogUtil.printErrorLog(ErrorLogs.TOKENIZE_REQUEST_REJECTED.getLog()); throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); } catch (SkyflowException e) { @@ -551,7 +574,7 @@ public CompletableFuture bulkTokenizeAsync(BulkTokenizeReq sortTokenizeByIndex(responseRecords), tokenizeRequest.getRecords()); }); } catch (ApiClientApiException e) { - String bodyString = gson.toJson(e.body()); + String bodyString = gson.toJson(Utils.errorBody(e)); LogUtil.printErrorLog(ErrorLogs.TOKENIZE_REQUEST_REJECTED.getLog()); throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); } catch (SkyflowException e) { @@ -579,13 +602,13 @@ public UpdateResponse update(UpdateRequest updateRequest, UpdateOptions options) Validations.validateUpdateRequest(updateRequest); setBearerToken(); - V1UpdateRequest request = Utils.getUpdateRequestBody(updateRequest, this.getVaultConfig()); + com.skyflow.generated.rest.resources.records.requests.UpdateRequest request = Utils.getUpdateRequestBody(updateRequest, this.getVaultConfig()); RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; RequestContext ctx = new RequestContext("UPDATE", 0, 1); if (interceptor != null) interceptor.intercept(ctx); - ApiClientHttpResponse response = - this.getRecordsApi().withRawResponse().update(request, buildRequestOptions(ctx)); + ApiClientHttpResponse response = + this.getRecordsApi().withRawResponse().updateRecords(request, buildRequestOptions(ctx)); UpdateResponse formattedResponse = Utils.formatUpdateResponse(response.body(), response.headers()); LogUtil.printInfoLog(InfoLogs.UPDATE_REQUEST_RESOLVED.getLog()); @@ -598,7 +621,7 @@ public UpdateResponse update(UpdateRequest updateRequest, UpdateOptions options) if (fallback != null) { return fallback; } - String bodyString = gson.toJson(e.body()); + String bodyString = gson.toJson(Utils.errorBody(e)); LogUtil.printErrorLog(ErrorLogs.UPDATE_REQUEST_REJECTED.getLog()); throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); } catch (ApiClientException e) { @@ -621,13 +644,13 @@ public GetResponse get(GetRequest getRequest, GetOptions options) throws Skyflow Validations.validateGetRequest(getRequest); setBearerToken(); - V1GetRequest request = Utils.getGetRequestBody(getRequest, this.getVaultConfig()); + com.skyflow.generated.rest.resources.records.requests.GetRequest request = Utils.getGetRequestBody(getRequest, this.getVaultConfig()); RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; RequestContext ctx = new RequestContext("GET", 0, 1); if (interceptor != null) interceptor.intercept(ctx); - ApiClientHttpResponse response = - this.getRecordsApi().withRawResponse().get(request, buildRequestOptions(ctx)); + ApiClientHttpResponse response = + this.getRecordsApi().withRawResponse().getRecords(request, buildRequestOptions(ctx)); GetResponse formattedResponse = Utils.formatGetResponse(response.body(), response.headers()); LogUtil.printInfoLog(InfoLogs.GET_REQUEST_RESOLVED.getLog()); @@ -640,7 +663,7 @@ public GetResponse get(GetRequest getRequest, GetOptions options) throws Skyflow if (fallback != null) { return fallback; } - String bodyString = gson.toJson(e.body()); + String bodyString = gson.toJson(Utils.errorBody(e)); LogUtil.printErrorLog(ErrorLogs.GET_REQUEST_REJECTED.getLog()); throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); } catch (ApiClientException e) { @@ -649,10 +672,289 @@ public GetResponse get(GetRequest getRequest, GetOptions options) throws Skyflow } } + // ── Query ───────────────────────────────────────────────────────────────── + // Runs a SQL SELECT in a single API call. There is no per-record status, so any failure is + // thrown rather than returned on the response. + + public QueryResponse query(QueryRequest queryRequest) throws SkyflowException { + return query(queryRequest, null); + } + + public QueryResponse query(QueryRequest queryRequest, QueryOptions options) throws SkyflowException { + LogUtil.printInfoLog(InfoLogs.QUERY_TRIGGERED.getLog()); + try { + LogUtil.printInfoLog(InfoLogs.VALIDATING_QUERY_REQUEST.getLog()); + Validations.validateQueryRequest(queryRequest); + + setBearerToken(); + ExecuteQueryRequest request = Utils.getQueryRequestBody(queryRequest, this.getVaultConfig().getVaultId()); + RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; + RequestContext ctx = new RequestContext("QUERY", 0, 1); + if (interceptor != null) interceptor.intercept(ctx); + + ApiClientHttpResponse response = + this.getQueryApi().withRawResponse().executeQuery(request, buildRequestOptions(ctx)); + + QueryResponse formattedResponse = Utils.formatQueryResponse(response.body(), response.headers()); + LogUtil.printInfoLog(InfoLogs.QUERY_REQUEST_RESOLVED.getLog()); + return formattedResponse; + } catch (ApiClientApiException e) { + String bodyString = gson.toJson(Utils.errorBody(e)); + LogUtil.printErrorLog(ErrorLogs.QUERY_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + } catch (ApiClientException e) { + LogUtil.printErrorLog(ErrorLogs.QUERY_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e); + } + } + + // ── Get Tokens ──────────────────────────────────────────────────────────── + // Looks up the existing deterministic token for each value in a single API call. Record-level + // failures come back on the response (200/207); whole-call failures are thrown. + + public GetTokensResponse getTokens(GetTokensRequest getTokensRequest) throws SkyflowException { + return getTokens(getTokensRequest, null); + } + + public GetTokensResponse getTokens(GetTokensRequest getTokensRequest, GetTokensOptions options) throws SkyflowException { + LogUtil.printInfoLog(InfoLogs.GET_TOKENS_TRIGGERED.getLog()); + try { + LogUtil.printInfoLog(InfoLogs.VALIDATING_GET_TOKENS_REQUEST.getLog()); + Validations.validateGetTokensRequest(getTokensRequest); + + setBearerToken(); + GetTokensFromValuesRequest request = Utils.getGetTokensRequestBody(getTokensRequest, this.getVaultConfig().getVaultId()); + RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; + RequestContext ctx = new RequestContext("GET_TOKENS", 0, 1); + if (interceptor != null) interceptor.intercept(ctx); + + ApiClientHttpResponse response = + this.getTokensApi().withRawResponse().getTokens(request, buildRequestOptions(ctx)); + + GetTokensResponse formattedResponse = Utils.formatGetTokensResponse(response.body(), response.headers()); + LogUtil.printInfoLog(InfoLogs.GET_TOKENS_REQUEST_RESOLVED.getLog()); + return formattedResponse; + } catch (ApiClientApiException e) { + // The lone record in a unary request can fail outright, which the vault reflects as + // the overall HTTP status. If the body still carries the usual per-record shape, + // surface it on the response like a 200 partial success would, not as an exception. + GetTokensResponse fallback = Utils.handleGetTokensRequestException(e); + if (fallback != null) { + return fallback; + } + String bodyString = gson.toJson(Utils.errorBody(e)); + LogUtil.printErrorLog(ErrorLogs.GET_TOKENS_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + } catch (ApiClientException e) { + LogUtil.printErrorLog(ErrorLogs.GET_TOKENS_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e); + } + } + + // ── Upload Files ────────────────────────────────────────────────────────── + // Two steps inside one unary call. Phase A asks the vault for a signed upload URL per column; + // Phase B PUTs each file's bytes to its URL, a few at a time. Any Phase A error is thrown; a + // record that fails in Phase A has its columns SKIPPED; a column whose PUT fails is FAILED and + // leaves every other column and record unaffected. Signed URLs never reach the caller. + + public UploadFilesResponse uploadFiles(UploadFilesRequest uploadFilesRequest) throws SkyflowException { + return uploadFiles(uploadFilesRequest, null); + } + + public UploadFilesResponse uploadFiles(UploadFilesRequest uploadFilesRequest, UploadFilesOptions options) + throws SkyflowException { + LogUtil.printInfoLog(InfoLogs.UPLOAD_FILES_TRIGGERED.getLog()); + ApiClientHttpResponse response; + Map decodedBase64; + try { + LogUtil.printInfoLog(InfoLogs.VALIDATING_UPLOAD_FILES_REQUEST.getLog()); + Validations.validateUploadFilesRequest(uploadFilesRequest); + decodedBase64 = Utils.decodeBase64Columns(uploadFilesRequest); + + setBearerToken(); + FileUploadRequest request = Utils.getUploadFilesRequestBody(uploadFilesRequest, this.getVaultConfig().getVaultId()); + RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; + RequestContext ctx = new RequestContext("UPLOAD_FILES", 0, 1); + if (interceptor != null) interceptor.intercept(ctx); + + response = this.getFilesApi().withRawResponse().uploadFiles(request, buildRequestOptions(ctx)); + } catch (ApiClientApiException e) { + String bodyString = gson.toJson(Utils.uploadFilesErrorBody(e)); + LogUtil.printErrorLog(ErrorLogs.UPLOAD_FILES_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + } catch (ApiClientException e) { + LogUtil.printErrorLog(ErrorLogs.UPLOAD_FILES_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e); + } + + LogUtil.printInfoLog(InfoLogs.UPLOADING_FILES_TO_SIGNED_URLS.getLog()); + UploadFilesResponse formattedResponse = uploadToSignedUrls( + uploadFilesRequest.getRecords(), decodedBase64, response.body(), response.headers()); + LogUtil.printInfoLog(InfoLogs.UPLOAD_FILES_REQUEST_RESOLVED.getLog()); + return formattedResponse; + } + + private UploadFilesResponse uploadToSignedUrls(List requested, + Map decodedBase64, + FileUploadResponse body, Map> headers) { + List returned = body != null && body.getRecords() != null + ? body.getRecords() : Collections.emptyList(); + // All signed URLs are issued together and expire together, so the PUTs run on a small pool + // rather than one after another. Each record keeps its column futures in request order, so + // the response does not depend on which upload finishes first. + int fileCount = 0; + for (UploadFilesRequestRecord requestRecord : requested) { + fileCount += requestRecord.getColumns().size(); + } + ExecutorService executor = Executors.newFixedThreadPool( + Math.min(fileCount, Constants.UPLOAD_FILES_CONCURRENCY_LIMIT)); + try { + String[] errors = new String[returned.size()]; + List>>> uploads = new ArrayList<>(); + for (int i = 0; i < returned.size(); i++) { + FileUploadResponseObject record = returned.get(i); + errors[i] = record.getError().filter(e -> !e.isEmpty()).orElse(null); + if (errors[i] == null) { + uploads.add(uploadColumns(i < requested.size() ? requested.get(i) : null, decodedBase64, + record.getData().orElse(Collections.emptyMap()), executor)); + } else { + uploads.add(Collections.emptyList()); + } + } + + ArrayList> records = new ArrayList<>(); + for (int i = 0; i < returned.size(); i++) { + FileUploadResponseObject record = returned.get(i); + String error = errors[i]; + int httpCode = record.getHttpCode() != 0 ? record.getHttpCode() : (error != null ? 500 : 200); + List> columns; + if (error != null) { + columns = Utils.skippedUploadColumns(i < requested.size() ? requested.get(i) : null, error); + } else { + columns = new ArrayList<>(); + for (CompletableFuture> column : uploads.get(i)) { + columns.add(column.join()); + } + } + records.add(Utils.uploadFilesRecordRow(record.getSkyflowId(), record.getTableName(), columns, + httpCode, error, error != null ? Utils.extractRequestId(headers) : null)); + } + return new UploadFilesResponse(records); + } finally { + executor.shutdown(); + } + } + + private List>> uploadColumns(UploadFilesRequestRecord requestRecord, + Map decodedBase64, + Map signedUrls, + ExecutorService executor) { + List>> columns = new ArrayList<>(); + if (requestRecord == null) { + return columns; + } + for (UploadFilesRequestColumn column : requestRecord.getColumns()) { + Object signedUrl = signedUrls.get(column.getColumn()); + if (signedUrl == null) { + columns.add(CompletableFuture.completedFuture(Utils.uploadFilesColumnRow( + column.getColumn(), Utils.resolveUploadFileName(column), Utils.UPLOAD_STATUS_SKIPPED, null))); + continue; + } + columns.add(CompletableFuture.supplyAsync( + () -> uploadColumn(column, decodedBase64.get(column), signedUrl.toString()), executor)); + } + return columns; + } + + /** PUTs one column's file; a failure is reported on that column only. */ + private HashMap uploadColumn(UploadFilesRequestColumn column, byte[] decodedBase64, + String signedUrl) { + String fileName = Utils.resolveUploadFileName(column); + String error = null; + try { + RequestBody fileBody = Utils.buildUploadFileBody( + column, decodedBase64, Utils.resolveUploadContentType(fileName)); + int status = signedUrlUploader.upload(signedUrl, fileBody); + if (status < 200 || status >= 300) { + error = "PUT failed: " + status; + } + } catch (IOException | RuntimeException e) { + error = "PUT failed: " + (e.getMessage() != null ? e.getMessage() : e.toString()); + } + if (error != null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.SIGNED_URL_UPLOAD_FAILED.getLog(), column.getColumn())); + } + return Utils.uploadFilesColumnRow(column.getColumn(), fileName, + error == null ? Utils.UPLOAD_STATUS_UPLOADED : Utils.UPLOAD_STATUS_FAILED, error); + } + + /** Sends one file to its signed URL and returns the HTTP status. */ + interface SignedUrlUploader { + int upload(String signedUrl, RequestBody fileBody) throws IOException; + } + + /** + * Package-private and swappable purely so tests can stand in for the storage endpoint, like + * {@link #settingResolver}; deliberately not public. + */ + SignedUrlUploader signedUrlUploader = this::putToSignedUrl; + + private int putToSignedUrl(String signedUrl, RequestBody fileBody) throws IOException { + Request request = new Request.Builder().url(signedUrl).put(fileBody).build(); + try (Response response = getSignedUrlHttpClient().newCall(request).execute()) { + return response.code(); + } + } + + // ── Delete Files ────────────────────────────────────────────────────────── + // Deletes the files in file columns of existing records, in a single API call. Record-level + // failures come back on the response; whole-call failures are thrown. + + public DeleteFilesResponse deleteFiles(DeleteFilesRequest deleteFilesRequest) throws SkyflowException { + return deleteFiles(deleteFilesRequest, null); + } + + public DeleteFilesResponse deleteFiles(DeleteFilesRequest deleteFilesRequest, DeleteFilesOptions options) + throws SkyflowException { + LogUtil.printInfoLog(InfoLogs.DELETE_FILES_TRIGGERED.getLog()); + try { + LogUtil.printInfoLog(InfoLogs.VALIDATING_DELETE_FILES_REQUEST.getLog()); + Validations.validateDeleteFilesRequest(deleteFilesRequest); + + setBearerToken(); + FileDeleteRequest request = Utils.getDeleteFilesRequestBody(deleteFilesRequest, this.getVaultConfig().getVaultId()); + RequestInterceptor interceptor = options != null ? options.getInterceptor() : null; + RequestContext ctx = new RequestContext("DELETE_FILES", 0, 1); + if (interceptor != null) interceptor.intercept(ctx); + + ApiClientHttpResponse response = + this.getFilesApi().withRawResponse().deleteFiles(request, buildRequestOptions(ctx)); + + DeleteFilesResponse formattedResponse = Utils.formatDeleteFilesResponse(response.body(), response.headers()); + LogUtil.printInfoLog(InfoLogs.DELETE_FILES_REQUEST_RESOLVED.getLog()); + return formattedResponse; + } catch (ApiClientApiException e) { + // The lone record in a unary request can fail outright, which the vault reflects as + // the overall HTTP status. If the body still carries the usual per-record shape, + // surface it on the response like a 200 partial success would, not as an exception. + DeleteFilesResponse fallback = Utils.handleDeleteFilesRequestException(e); + if (fallback != null) { + return fallback; + } + String bodyString = gson.toJson(Utils.errorBody(e)); + LogUtil.printErrorLog(ErrorLogs.DELETE_FILES_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), bodyString); + } catch (ApiClientException e) { + LogUtil.printErrorLog(ErrorLogs.DELETE_FILES_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e); + } + } + // ── Bulk private helpers ────────────────────────────────────────────────── private BulkDeleteTokensResponse processBulkDeleteTokensSync( - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest deleteTokensRequest, + DeleteTokenRequest deleteTokensRequest, List originalTokens, RequestInterceptor interceptor, BatchConfig cfg @@ -660,7 +962,7 @@ private BulkDeleteTokensResponse processBulkDeleteTokensSync( LogUtil.printInfoLog(InfoLogs.PROCESSING_BATCHES.getLog()); List responseRecords = new ArrayList<>(); ExecutorService executor = Executors.newFixedThreadPool(cfg.concurrencyLimit); - List batches = + List batches = Utils.createBulkDeleteTokensBatches(deleteTokensRequest, cfg.batchSize); try { List> futures = @@ -700,14 +1002,14 @@ private static List sortByIndex(List> deleteTokensBatchFutures( ExecutorService executor, - List batches, + List batches, RequestInterceptor interceptor, int batchSize) { List> futures = new ArrayList<>(); if (batches == null) return futures; for (int batchIndex = 0; batchIndex < batches.size(); batchIndex++) { final int index = batchIndex; - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest batch = batches.get(index); + DeleteTokenRequest batch = batches.get(index); RequestContext ctx = new RequestContext("DELETE_TOKENS", batchIndex, batches.size()); if (interceptor != null) interceptor.intercept(ctx); CompletableFuture future = CompletableFuture @@ -726,10 +1028,10 @@ private List> deleteTokensBatchFutur return futures; } - private ApiClientHttpResponse processDeleteTokensBatch( - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest batch, + private ApiClientHttpResponse processDeleteTokensBatch( + DeleteTokenRequest batch, RequestContext ctx) { - return this.getRecordsApi().withRawResponse().deletetoken(batch, buildRequestOptions(ctx)); + return this.getTokensApi().withRawResponse().deleteToken(batch, buildRequestOptions(ctx)); } /** @@ -865,7 +1167,7 @@ private List> tokenizeBatchFutures( final int startIndex = nextStartIndex; nextStartIndex += batchRecords.size(); final int batchIndex = batchPosition++; - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest batch = + TokenizeRequest batch = Utils.getBulkTokenizeRequestBody(batchRecords, this.getVaultConfig().getVaultId()); RequestContext ctx = new RequestContext("TOKENIZE", batchIndex, batches.size()); if (interceptor != null) interceptor.intercept(ctx); @@ -884,10 +1186,10 @@ private List> tokenizeBatchFutures( return futures; } - private ApiClientHttpResponse processTokenizeBatch( - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest batch, + private ApiClientHttpResponse processTokenizeBatch( + TokenizeRequest batch, RequestContext ctx) { - return this.getRecordsApi().withRawResponse().tokenize(batch, buildRequestOptions(ctx)); + return this.getTokensApi().withRawResponse().tokenize(batch, buildRequestOptions(ctx)); } private BatchConfig configureTokenizeConcurrencyAndBatchSize(int totalRequests) { @@ -1004,7 +1306,7 @@ private BatchConfig configureDetokenizeConcurrencyAndBatchSize(int totalRequests } private BulkInsertResponse processBulkInsertSync( - V1InsertRequest insertRequest, + com.skyflow.generated.rest.resources.records.requests.InsertRequest insertRequest, List originalPayload, RequestInterceptor interceptor, BatchConfig cfg @@ -1036,7 +1338,7 @@ private BulkInsertResponse processBulkInsertSync( } private BulkDetokenizeResponse processBulkDetokenizeSync( - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest detokenizeRequest, + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest detokenizeRequest, List originalTokens, RequestInterceptor interceptor, BatchConfig cfg @@ -1044,7 +1346,7 @@ private BulkDetokenizeResponse processBulkDetokenizeSync( LogUtil.printInfoLog(InfoLogs.PROCESSING_BATCHES.getLog()); List records = new ArrayList<>(); ExecutorService executor = Executors.newFixedThreadPool(cfg.concurrencyLimit); - List batches = + List batches = Utils.createBulkDetokenizeBatches(detokenizeRequest, cfg.batchSize); try { List> futures = this.detokenizeBatchFutures(executor, batches, interceptor, cfg.batchSize); @@ -1073,12 +1375,12 @@ private BulkDetokenizeResponse processBulkDetokenizeSync( private List> detokenizeBatchFutures( ExecutorService executor, - List batches, + List batches, RequestInterceptor interceptor, int batchSize) { List> futures = new ArrayList<>(); for (int batchIndex = 0; batchIndex < batches.size(); batchIndex++) { - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest batch = batches.get(batchIndex); + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest batch = batches.get(batchIndex); int batchNumber = batchIndex; RequestContext ctx = new RequestContext("DETOKENIZE", batchIndex, batches.size()); if (interceptor != null) interceptor.intercept(ctx); @@ -1092,32 +1394,32 @@ private List> detokenizeBatchFutures( return futures; } - private ApiClientHttpResponse processDetokenizeBatch( - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest batch, + private ApiClientHttpResponse processDetokenizeBatch( + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest batch, RequestContext ctx) { - return this.getRecordsApi().withRawResponse().detokenize(batch, buildRequestOptions(ctx)); + return this.getTokensApi().withRawResponse().detokenize(batch, buildRequestOptions(ctx)); } private List> insertBatchFutures( - V1InsertRequest insertRequest, + com.skyflow.generated.rest.resources.records.requests.InsertRequest insertRequest, RequestInterceptor interceptor, BatchConfig cfg) { - List records = insertRequest.getRecords().get(); + List records = insertRequest.getRecords(); ExecutorService executor = Executors.newFixedThreadPool(cfg.concurrencyLimit); - List> batches = Utils.createBulkInsertBatches(records, cfg.batchSize); + List> batches = Utils.createBulkInsertBatches(records, cfg.batchSize); List> futures = new ArrayList<>(); try { for (int batchIndex = 0; batchIndex < batches.size(); batchIndex++) { - List batch = batches.get(batchIndex); + List batch = batches.get(batchIndex); int batchNumber = batchIndex; RequestContext ctx = new RequestContext("INSERT", batchIndex, batches.size()); if (interceptor != null) interceptor.intercept(ctx); CompletableFuture future = CompletableFuture .supplyAsync(() -> insertBatch( batch, - insertRequest.getTableName().isPresent() ? insertRequest.getTableName().get() : null, + insertRequest.getTableName(), insertRequest.getUpsert().isPresent() ? insertRequest.getUpsert().get() : null, ctx), executor) .thenApply(response -> Utils.formatBulkInsertResponse(response.body(), batchNumber, cfg.batchSize, response.headers())) @@ -1134,19 +1436,11 @@ private List> insertBatchFutures( // tableName and upsert live on the envelope when the caller set them at the request level, and // batching rebuilds the envelope per batch — so both have to be re-applied here or they are // silently dropped for every batch after the body was built. - private ApiClientHttpResponse insertBatch(List batch, String tableName, - V1Upsert upsert, RequestContext ctx) { - V1InsertRequest.Builder req = V1InsertRequest.builder() - .vaultId(this.getVaultConfig().getVaultId()) - .records(batch); - if (tableName != null && !tableName.isEmpty()) { - req.tableName(tableName); - } - if (upsert != null) { - req.upsert(upsert); - } - V1InsertRequest request = req.build(); - return this.getRecordsApi().withRawResponse().insert(request, buildRequestOptions(ctx)); + private ApiClientHttpResponse insertBatch(List batch, String tableName, + Upsert upsert, RequestContext ctx) { + com.skyflow.generated.rest.resources.records.requests.InsertRequest request = + Utils.buildInsertRequest(this.getVaultConfig().getVaultId(), tableName, batch, upsert); + return this.getRecordsApi().withRawResponse().insertRecords(request, buildRequestOptions(ctx)); } private BatchConfig configureInsertConcurrencyAndBatchSize(int totalRequests) { diff --git a/flowvault/src/main/java/com/skyflow/vault/data/DeleteFilesOptions.java b/flowvault/src/main/java/com/skyflow/vault/data/DeleteFilesOptions.java new file mode 100644 index 00000000..2499a14b --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/DeleteFilesOptions.java @@ -0,0 +1,33 @@ +package com.skyflow.vault.data; + +public final class DeleteFilesOptions { + private final RequestInterceptor interceptor; + + private DeleteFilesOptions(Builder builder) { + this.interceptor = builder.interceptor; + } + + public RequestInterceptor getInterceptor() { + return interceptor; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private RequestInterceptor interceptor; + + private Builder() { + } + + public Builder interceptor(RequestInterceptor interceptor) { + this.interceptor = interceptor; + return this; + } + + public DeleteFilesOptions build() { + return new DeleteFilesOptions(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/DeleteFilesRequest.java b/flowvault/src/main/java/com/skyflow/vault/data/DeleteFilesRequest.java new file mode 100644 index 00000000..930f3798 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/DeleteFilesRequest.java @@ -0,0 +1,37 @@ +package com.skyflow.vault.data; + +import java.util.List; + +public class DeleteFilesRequest extends BaseDeleteFilesRequest { + private final DeleteFilesRequestBuilder builder; + + private DeleteFilesRequest(DeleteFilesRequestBuilder builder) { + super(builder); + this.builder = builder; + } + + /** Records whose file columns to delete. */ + public List getRecords() { + return this.builder.records; + } + + public static DeleteFilesRequestBuilder builder() { + return new DeleteFilesRequestBuilder(); + } + + public static final class DeleteFilesRequestBuilder extends BaseDeleteFilesRequestBuilder { + private List records; + + private DeleteFilesRequestBuilder() { + } + + public DeleteFilesRequestBuilder records(List records) { + this.records = records; + return this; + } + + public DeleteFilesRequest build() { + return new DeleteFilesRequest(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/DeleteFilesRequestRecord.java b/flowvault/src/main/java/com/skyflow/vault/data/DeleteFilesRequestRecord.java new file mode 100644 index 00000000..ea0111f6 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/DeleteFilesRequestRecord.java @@ -0,0 +1,80 @@ +package com.skyflow.vault.data; + +import java.util.List; +import java.util.Map; + +/** + * One record whose file columns to delete. Set exactly one of {@code skyflowId} or + * {@code uniqueValues}; a record that sets both or neither fails validation. + */ +public class DeleteFilesRequestRecord { + private final String tableName; + private final List columns; + private final String skyflowId; + private final List> uniqueValues; + + protected DeleteFilesRequestRecord(DeleteFilesRequestRecordBuilder builder) { + this.tableName = builder.tableName; + this.columns = builder.columns; + this.skyflowId = builder.skyflowId; + this.uniqueValues = builder.uniqueValues; + } + + public static DeleteFilesRequestRecordBuilder builder() { + return new DeleteFilesRequestRecordBuilder(); + } + + public String getTableName() { + return this.tableName; + } + + /** File column names to delete. */ + public List getColumns() { + return this.columns; + } + + public String getSkyflowId() { + return this.skyflowId; + } + + /** + * Unique-column maps, e.g. {@code [{"email": "a@b.com"}]}. Each resolves independently and may + * match more than one record, giving one response entry per resolved skyflowId. + */ + public List> getUniqueValues() { + return this.uniqueValues; + } + + public static class DeleteFilesRequestRecordBuilder { + protected String tableName; + protected List columns; + protected String skyflowId; + protected List> uniqueValues; + + protected DeleteFilesRequestRecordBuilder() {} + + public DeleteFilesRequestRecordBuilder tableName(String tableName) { + this.tableName = tableName; + return this; + } + + public DeleteFilesRequestRecordBuilder columns(List columns) { + this.columns = columns; + return this; + } + + public DeleteFilesRequestRecordBuilder skyflowId(String skyflowId) { + this.skyflowId = skyflowId; + return this; + } + + public DeleteFilesRequestRecordBuilder uniqueValues(List> uniqueValues) { + this.uniqueValues = uniqueValues; + return this; + } + + public DeleteFilesRequestRecord build() { + return new DeleteFilesRequestRecord(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/DeleteFilesResponse.java b/flowvault/src/main/java/com/skyflow/vault/data/DeleteFilesResponse.java new file mode 100644 index 00000000..c5f89b65 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/DeleteFilesResponse.java @@ -0,0 +1,16 @@ +package com.skyflow.vault.data; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * Record map keys: {@code skyflowId}, {@code tableName}, {@code columns}, {@code httpCode}, + * {@code error}, {@code requestId} (set only when {@code error} is non-null). + * {@code columns} is a list of maps with keys {@code column} and {@code status} ({@code "DELETED"}), + * or null on a failed record. + */ +public class DeleteFilesResponse extends BaseDeleteFilesResponse { + public DeleteFilesResponse(ArrayList> records) { + super(records); + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/GetTokensOptions.java b/flowvault/src/main/java/com/skyflow/vault/data/GetTokensOptions.java new file mode 100644 index 00000000..df14acd9 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/GetTokensOptions.java @@ -0,0 +1,33 @@ +package com.skyflow.vault.data; + +public final class GetTokensOptions { + private final RequestInterceptor interceptor; + + private GetTokensOptions(Builder builder) { + this.interceptor = builder.interceptor; + } + + public RequestInterceptor getInterceptor() { + return interceptor; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private RequestInterceptor interceptor; + + private Builder() { + } + + public Builder interceptor(RequestInterceptor interceptor) { + this.interceptor = interceptor; + return this; + } + + public GetTokensOptions build() { + return new GetTokensOptions(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/GetTokensRequest.java b/flowvault/src/main/java/com/skyflow/vault/data/GetTokensRequest.java new file mode 100644 index 00000000..29e3a0a7 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/GetTokensRequest.java @@ -0,0 +1,37 @@ +package com.skyflow.vault.data; + +import java.util.List; + +public class GetTokensRequest extends BaseGetTokensRequest { + private final GetTokensRequestBuilder builder; + + private GetTokensRequest(GetTokensRequestBuilder builder) { + super(builder); + this.builder = builder; + } + + /** Value/token-group pairs to look up. One response record is returned per entry, in order. */ + public List getRecords() { + return this.builder.records; + } + + public static GetTokensRequestBuilder builder() { + return new GetTokensRequestBuilder(); + } + + public static final class GetTokensRequestBuilder extends BaseGetTokensRequestBuilder { + private List records; + + private GetTokensRequestBuilder() { + } + + public GetTokensRequestBuilder records(List records) { + this.records = records; + return this; + } + + public GetTokensRequest build() { + return new GetTokensRequest(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/GetTokensRequestRecord.java b/flowvault/src/main/java/com/skyflow/vault/data/GetTokensRequestRecord.java new file mode 100644 index 00000000..7bce5bac --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/GetTokensRequestRecord.java @@ -0,0 +1,45 @@ +package com.skyflow.vault.data; + +public class GetTokensRequestRecord { + private final Object value; + private final String tokenGroupName; + + protected GetTokensRequestRecord(GetTokensRequestRecordBuilder builder) { + this.value = builder.value; + this.tokenGroupName = builder.tokenGroupName; + } + + public static GetTokensRequestRecordBuilder builder() { + return new GetTokensRequestRecordBuilder(); + } + + public Object getValue() { + return this.value; + } + + /** Name of a deterministic token group; non-deterministic groups are not supported. */ + public String getTokenGroupName() { + return this.tokenGroupName; + } + + public static class GetTokensRequestRecordBuilder { + protected Object value; + protected String tokenGroupName; + + protected GetTokensRequestRecordBuilder() {} + + public GetTokensRequestRecordBuilder value(Object value) { + this.value = value; + return this; + } + + public GetTokensRequestRecordBuilder tokenGroupName(String tokenGroupName) { + this.tokenGroupName = tokenGroupName; + return this; + } + + public GetTokensRequestRecord build() { + return new GetTokensRequestRecord(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/GetTokensResponse.java b/flowvault/src/main/java/com/skyflow/vault/data/GetTokensResponse.java new file mode 100644 index 00000000..93ebfaf1 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/GetTokensResponse.java @@ -0,0 +1,15 @@ +package com.skyflow.vault.data; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * Record map keys: {@code value}, {@code tokenGroupName}, {@code token}, {@code httpCode}, + * {@code error}, {@code requestId} (set only when {@code error} is non-null). + * {@code token} is {@code ""} (never null) on a record that has no token. + */ +public class GetTokensResponse extends BaseGetTokensResponse { + public GetTokensResponse(ArrayList> records) { + super(records); + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/QueryOptions.java b/flowvault/src/main/java/com/skyflow/vault/data/QueryOptions.java new file mode 100644 index 00000000..63bd9749 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/QueryOptions.java @@ -0,0 +1,33 @@ +package com.skyflow.vault.data; + +public final class QueryOptions { + private final RequestInterceptor interceptor; + + private QueryOptions(Builder builder) { + this.interceptor = builder.interceptor; + } + + public RequestInterceptor getInterceptor() { + return interceptor; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private RequestInterceptor interceptor; + + private Builder() { + } + + public Builder interceptor(RequestInterceptor interceptor) { + this.interceptor = interceptor; + return this; + } + + public QueryOptions build() { + return new QueryOptions(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/QueryRequest.java b/flowvault/src/main/java/com/skyflow/vault/data/QueryRequest.java new file mode 100644 index 00000000..990d9670 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/QueryRequest.java @@ -0,0 +1,27 @@ +package com.skyflow.vault.data; + +public class QueryRequest extends BaseQueryRequest { + private QueryRequest(QueryRequestBuilder builder) { + super(builder); + } + + public static QueryRequestBuilder builder() { + return new QueryRequestBuilder(); + } + + public static final class QueryRequestBuilder extends BaseQueryRequestBuilder { + private QueryRequestBuilder() { + } + + /** SQL {@code SELECT} statement to run. At most 25 records are returned; page with {@code OFFSET}. */ + @Override + public QueryRequestBuilder query(String query) { + super.query(query); + return this; + } + + public QueryRequest build() { + return new QueryRequest(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/QueryResponse.java b/flowvault/src/main/java/com/skyflow/vault/data/QueryResponse.java new file mode 100644 index 00000000..b9f9bfe2 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/QueryResponse.java @@ -0,0 +1,28 @@ +package com.skyflow.vault.data; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * Rows returned by a query. Values may be masked, but are never tokens or file URLs. Query has no + * per-record status — any failure is thrown — so {@link #getErrors()} is always null. + */ +public class QueryResponse extends BaseQueryResponse { + private final QueryResponseMetadata metadata; + private final String requestId; + + public QueryResponse(ArrayList> fields, QueryResponseMetadata metadata, String requestId) { + super(fields); + this.metadata = metadata; + this.requestId = requestId; + } + + public QueryResponseMetadata getMetadata() { + return metadata; + } + + /** Call-level request id, populated on every response. */ + public String getRequestId() { + return requestId; + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/QueryResponseMetadata.java b/flowvault/src/main/java/com/skyflow/vault/data/QueryResponseMetadata.java new file mode 100644 index 00000000..8f19376d --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/QueryResponseMetadata.java @@ -0,0 +1,16 @@ +package com.skyflow.vault.data; + +import java.util.List; + +public class QueryResponseMetadata { + private final List columns; + + public QueryResponseMetadata(List columns) { + this.columns = columns; + } + + /** Column names returned by the query, in select order. */ + public List getColumns() { + return columns; + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/UploadFilesOptions.java b/flowvault/src/main/java/com/skyflow/vault/data/UploadFilesOptions.java new file mode 100644 index 00000000..7e15df38 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/UploadFilesOptions.java @@ -0,0 +1,33 @@ +package com.skyflow.vault.data; + +public final class UploadFilesOptions { + private final RequestInterceptor interceptor; + + private UploadFilesOptions(Builder builder) { + this.interceptor = builder.interceptor; + } + + public RequestInterceptor getInterceptor() { + return interceptor; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private RequestInterceptor interceptor; + + private Builder() { + } + + public Builder interceptor(RequestInterceptor interceptor) { + this.interceptor = interceptor; + return this; + } + + public UploadFilesOptions build() { + return new UploadFilesOptions(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/UploadFilesRequest.java b/flowvault/src/main/java/com/skyflow/vault/data/UploadFilesRequest.java new file mode 100644 index 00000000..a1357881 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/UploadFilesRequest.java @@ -0,0 +1,37 @@ +package com.skyflow.vault.data; + +import java.util.List; + +public class UploadFilesRequest extends BaseUploadFilesRequest { + private final UploadFilesRequestBuilder builder; + + private UploadFilesRequest(UploadFilesRequestBuilder builder) { + super(builder); + this.builder = builder; + } + + /** Records whose file columns to upload. One response record is returned per entry, in order. */ + public List getRecords() { + return this.builder.records; + } + + public static UploadFilesRequestBuilder builder() { + return new UploadFilesRequestBuilder(); + } + + public static final class UploadFilesRequestBuilder extends BaseUploadFilesRequestBuilder { + private List records; + + private UploadFilesRequestBuilder() { + } + + public UploadFilesRequestBuilder records(List records) { + this.records = records; + return this; + } + + public UploadFilesRequest build() { + return new UploadFilesRequest(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/UploadFilesRequestColumn.java b/flowvault/src/main/java/com/skyflow/vault/data/UploadFilesRequestColumn.java new file mode 100644 index 00000000..826ebdd6 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/UploadFilesRequestColumn.java @@ -0,0 +1,92 @@ +package com.skyflow.vault.data; + +import java.io.File; + +/** + * One file column to upload. Provide exactly one of {@code filePath}, {@code base64} or + * {@code fileObject}; a column that sets none, or more than one, fails validation. + */ +public class UploadFilesRequestColumn { + private final String column; + private final String filePath; + private final String base64; + private final File fileObject; + private final String fileName; + + protected UploadFilesRequestColumn(UploadFilesRequestColumnBuilder builder) { + this.column = builder.column; + this.filePath = builder.filePath; + this.base64 = builder.base64; + this.fileObject = builder.fileObject; + this.fileName = builder.fileName; + } + + public static UploadFilesRequestColumnBuilder builder() { + return new UploadFilesRequestColumnBuilder(); + } + + public String getColumn() { + return this.column; + } + + /** Local path of the file; it must exist. */ + public String getFilePath() { + return this.filePath; + } + + /** Base64-encoded file content; requires {@code fileName}. */ + public String getBase64() { + return this.base64; + } + + public File getFileObject() { + return this.fileObject; + } + + /** + * Name to store the file under. Derived from {@code filePath} or {@code fileObject} when + * omitted; if there is still none, the server generates a random 16-byte UUID name. + */ + public String getFileName() { + return this.fileName; + } + + public static class UploadFilesRequestColumnBuilder { + protected String column; + protected String filePath; + protected String base64; + protected File fileObject; + protected String fileName; + + protected UploadFilesRequestColumnBuilder() {} + + public UploadFilesRequestColumnBuilder column(String column) { + this.column = column; + return this; + } + + public UploadFilesRequestColumnBuilder filePath(String filePath) { + this.filePath = filePath; + return this; + } + + public UploadFilesRequestColumnBuilder base64(String base64) { + this.base64 = base64; + return this; + } + + public UploadFilesRequestColumnBuilder fileObject(File fileObject) { + this.fileObject = fileObject; + return this; + } + + public UploadFilesRequestColumnBuilder fileName(String fileName) { + this.fileName = fileName; + return this; + } + + public UploadFilesRequestColumn build() { + return new UploadFilesRequestColumn(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/UploadFilesRequestRecord.java b/flowvault/src/main/java/com/skyflow/vault/data/UploadFilesRequestRecord.java new file mode 100644 index 00000000..8a94cbbe --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/UploadFilesRequestRecord.java @@ -0,0 +1,59 @@ +package com.skyflow.vault.data; + +import java.util.List; + +public class UploadFilesRequestRecord { + private final String tableName; + private final String skyflowId; + private final List columns; + + protected UploadFilesRequestRecord(UploadFilesRequestRecordBuilder builder) { + this.tableName = builder.tableName; + this.skyflowId = builder.skyflowId; + this.columns = builder.columns; + } + + public static UploadFilesRequestRecordBuilder builder() { + return new UploadFilesRequestRecordBuilder(); + } + + public String getTableName() { + return this.tableName; + } + + /** Record to upload into. Omit to create a new record (CREATE permission); set to update one (UPDATE permission). */ + public String getSkyflowId() { + return this.skyflowId; + } + + public List getColumns() { + return this.columns; + } + + public static class UploadFilesRequestRecordBuilder { + protected String tableName; + protected String skyflowId; + protected List columns; + + protected UploadFilesRequestRecordBuilder() {} + + public UploadFilesRequestRecordBuilder tableName(String tableName) { + this.tableName = tableName; + return this; + } + + public UploadFilesRequestRecordBuilder skyflowId(String skyflowId) { + this.skyflowId = skyflowId; + return this; + } + + public UploadFilesRequestRecordBuilder columns(List columns) { + this.columns = columns; + return this; + } + + public UploadFilesRequestRecord build() { + return new UploadFilesRequestRecord(this); + } + } +} diff --git a/flowvault/src/main/java/com/skyflow/vault/data/UploadFilesResponse.java b/flowvault/src/main/java/com/skyflow/vault/data/UploadFilesResponse.java new file mode 100644 index 00000000..9ad3eaa8 --- /dev/null +++ b/flowvault/src/main/java/com/skyflow/vault/data/UploadFilesResponse.java @@ -0,0 +1,16 @@ +package com.skyflow.vault.data; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * Record map keys: {@code skyflowId}, {@code tableName}, {@code columns}, {@code httpCode}, + * {@code error}, {@code requestId} (set only when {@code error} is non-null). + * Each entry of {@code columns} is a map with keys {@code column}, {@code fileName}, + * {@code uploadStatus} ({@code "UPLOADED"}, {@code "FAILED"} or {@code "SKIPPED"}) and {@code error}. + */ +public class UploadFilesResponse extends BaseUploadFilesResponse { + public UploadFilesResponse(ArrayList> records) { + super(records); + } +} diff --git a/flowvault/src/test/java/com/skyflow/VaultClientTests.java b/flowvault/src/test/java/com/skyflow/VaultClientTests.java index 68f026fb..b16269a4 100644 --- a/flowvault/src/test/java/com/skyflow/VaultClientTests.java +++ b/flowvault/src/test/java/com/skyflow/VaultClientTests.java @@ -127,4 +127,39 @@ public void testSetCommonCredentials_usedWhenNoVaultSpecificCredentials() throws Assert.assertEquals("common-token", client.token); } + + // ── getSignedUrlHttpClient ──────────────────────────────────────────────── + + @Test + public void testSignedUrlHttpClient_liftsCallTimeoutButKeepsTheOtherLimits() throws SkyflowException { + VaultConfig config = buildConfig("vault1", "cluster1", null); + config.setTimeout(30); + config.setConnectTimeout(5); + config.setReadTimeout(7); + config.setWriteTimeout(9); + VaultClient client = new VaultClient(config, null); + client.updateExecutorInHTTP(); + + okhttp3.OkHttpClient upload = client.getSignedUrlHttpClient(); + + // vault calls keep their overall ceiling; the upload client has none + Assert.assertEquals(30_000, client.sharedHttpClient.callTimeoutMillis()); + Assert.assertEquals(0, upload.callTimeoutMillis()); + Assert.assertEquals(5_000, upload.connectTimeoutMillis()); + Assert.assertEquals(7_000, upload.readTimeoutMillis()); + Assert.assertEquals(9_000, upload.writeTimeoutMillis()); + Assert.assertTrue(upload.interceptors().isEmpty()); + Assert.assertTrue(upload.networkInterceptors().isEmpty()); + Assert.assertSame(client.sharedHttpClient.connectionPool(), upload.connectionPool()); + } + + @Test + public void testSignedUrlHttpClient_beforeTheVaultClientIsBuiltHasNoCallTimeout() throws SkyflowException { + VaultClient client = new VaultClient(buildConfig("vault1", "cluster1", null), null); + + okhttp3.OkHttpClient upload = client.getSignedUrlHttpClient(); + + Assert.assertEquals(0, upload.callTimeoutMillis()); + Assert.assertTrue(upload.interceptors().isEmpty()); + } } diff --git a/flowvault/src/test/java/com/skyflow/utils/FlatTokenizeResponseTests.java b/flowvault/src/test/java/com/skyflow/utils/FlatTokenizeResponseTests.java index 4d069d05..f29c048b 100644 --- a/flowvault/src/test/java/com/skyflow/utils/FlatTokenizeResponseTests.java +++ b/flowvault/src/test/java/com/skyflow/utils/FlatTokenizeResponseTests.java @@ -2,7 +2,6 @@ import com.skyflow.generated.rest.core.ApiClientApiException; import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.types.V1FlowTokenizeResponse; import com.skyflow.vault.data.BulkTokenizeRequestRecord; import com.skyflow.vault.data.BulkTokenizeResponse; import com.skyflow.vault.data.BulkTokenizeResponseRecord; @@ -25,9 +24,9 @@ */ public class FlatTokenizeResponseTests { - private static V1FlowTokenizeResponse parse(String json) { + private static com.skyflow.generated.rest.types.TokenizeResponse parse(String json) { try { - return ObjectMappers.JSON_MAPPER.readValue(json, V1FlowTokenizeResponse.class); + return ObjectMappers.JSON_MAPPER.readValue(json, com.skyflow.generated.rest.types.TokenizeResponse.class); } catch (Exception e) { throw new IllegalStateException(e); } diff --git a/flowvault/src/test/java/com/skyflow/utils/RequestFidelityTests.java b/flowvault/src/test/java/com/skyflow/utils/RequestFidelityTests.java index 42b3dac9..1cb3a11c 100644 --- a/flowvault/src/test/java/com/skyflow/utils/RequestFidelityTests.java +++ b/flowvault/src/test/java/com/skyflow/utils/RequestFidelityTests.java @@ -1,20 +1,18 @@ package com.skyflow.utils; +import com.skyflow.generated.rest.resources.query.requests.ExecuteQueryRequest; +import com.skyflow.generated.rest.resources.tokens.requests.DeleteTokenRequest; +import com.skyflow.generated.rest.resources.tokens.requests.GetTokensFromValuesRequest; +import com.skyflow.generated.rest.types.DeleteTokenResponse; +import com.skyflow.generated.rest.types.DeleteTokenResponseObject; +import com.skyflow.generated.rest.types.DetokenizeResponseObject; +import com.skyflow.generated.rest.types.ExecuteQueryResponse; +import com.skyflow.generated.rest.types.GetTokensFromValuesResponse; +import com.skyflow.generated.rest.types.InsertRecordData; +import com.skyflow.generated.rest.types.RecordResponseObject; +import com.skyflow.generated.rest.types.TokenizeRequestObject; import com.skyflow.config.VaultConfig; -import com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest; -import com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest; -import com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest; -import com.skyflow.generated.rest.resources.flowservice.requests.V1InsertRequest; -import com.skyflow.generated.rest.types.FlowEnumUpdateType; -import com.skyflow.generated.rest.types.V1DeleteTokenResponseObject; -import com.skyflow.generated.rest.types.V1FlowDeleteTokenResponse; -import com.skyflow.generated.rest.types.V1FlowDetokenizeResponse; -import com.skyflow.generated.rest.types.V1FlowDetokenizeResponseObject; -import com.skyflow.generated.rest.types.V1FlowTokenizeRequestObject; -import com.skyflow.generated.rest.types.V1InsertRecordData; -import com.skyflow.generated.rest.types.V1InsertResponse; -import com.skyflow.generated.rest.types.V1RecordResponseObject; -import com.skyflow.generated.rest.types.V1TokenGroupRedactions; +import com.skyflow.generated.rest.core.ObjectMappers; import com.skyflow.vault.data.BulkDeleteTokensRequest; import com.skyflow.vault.data.BulkDeleteTokensResponse; import com.skyflow.vault.data.BulkDetokenizeRequest; @@ -24,9 +22,15 @@ import com.skyflow.vault.data.BulkInsertResponse; import com.skyflow.vault.data.BulkTokenizeRequestRecord; import com.skyflow.vault.data.BulkTokenizeRequest; +import com.skyflow.vault.data.GetTokensRequest; +import com.skyflow.vault.data.GetTokensRequestRecord; +import com.skyflow.vault.data.GetTokensResponse; import com.skyflow.vault.data.InsertRequestRecord; +import com.skyflow.vault.data.QueryRequest; +import com.skyflow.vault.data.QueryResponse; import com.skyflow.vault.data.TokenGroupRedactions; import com.skyflow.vault.data.UpsertOptions; +import com.skyflow.generated.rest.types.UpsertUpdateType; import org.junit.Assert; import org.junit.Test; @@ -45,7 +49,9 @@ * * These tests deliberately assert on the real mapping code in {@link Utils} rather than on any * hand-rolled copy of it, and use {@code assertSame} where the SDK should be passing the user's - * own object through untouched (maps, lists, arbitrary tokenize values). + * own object through untouched (arbitrary tokenize values). The generated builders, and the + * Jackson binding of the insert/update bodies, copy the maps and lists they are given, so those + * are compared by value. */ public class RequestFidelityTests { @@ -92,17 +98,17 @@ public void testBulkInsert_everyRecordFieldReachesWire() { .records(recordList(record)) .build(); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); - Assert.assertEquals(VAULT_ID, body.getVaultId().get()); - Assert.assertEquals("cards", body.getTableName().get()); - V1InsertRecordData wire = body.getRecords().get().get(0); + Assert.assertEquals(VAULT_ID, body.getVaultId()); + Assert.assertEquals("cards", body.getTableName()); + InsertRecordData wire = body.getRecords().get(0); Assert.assertEquals("cards", wire.getTableName().get()); // The user's own map instances must be handed to the wire object untouched. - Assert.assertSame(data, wire.getData().get()); - Assert.assertSame(tokens, wire.getTokens().get()); - Assert.assertEquals(FlowEnumUpdateType.UPDATE, wire.getUpsert().get().getUpdateType().get()); - Assert.assertEquals(Arrays.asList("email", "phone"), wire.getUpsert().get().getUniqueColumns().get()); + Assert.assertEquals(data, wire.getData()); + Assert.assertEquals(tokens, wire.getAdditionalProperties().get("tokens")); + Assert.assertEquals(UpsertUpdateType.UPDATE, wire.getUpsert().get().getUpdateType().get()); + Assert.assertEquals(Arrays.asList("email", "phone"), wire.getUpsert().get().getUniqueColumns()); } @Test @@ -123,14 +129,14 @@ public void testBulkInsert_nonAsciiAndSpacedValues_userValueReachesWire() { .records(recordList(record)) .build(); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); - Assert.assertEquals(SPACED_TABLE, body.getTableName().get()); - V1InsertRecordData wire = body.getRecords().get().get(0); + Assert.assertEquals(SPACED_TABLE, body.getTableName()); + InsertRecordData wire = body.getRecords().get(0); Assert.assertEquals(NON_ASCII_TABLE, wire.getTableName().get()); - Assert.assertEquals(NON_ASCII_NAME, wire.getData().get().get("name")); - Assert.assertEquals("12 東京都 千代田区", wire.getData().get().get("street address")); - Assert.assertEquals("tök-ábc 123", wire.getTokens().get().get("name")); + Assert.assertEquals(NON_ASCII_NAME, wire.getData().get("name")); + Assert.assertEquals("12 東京都 千代田区", wire.getData().get("street address")); + Assert.assertEquals("tök-ábc 123", ((Map) wire.getAdditionalProperties().get("tokens")).get("name")); } @Test @@ -154,17 +160,17 @@ public void testBulkInsert_nonStringDataValues_userValueReachesWire() { .build(); BulkInsertRequest request = BulkInsertRequest.builder().records(recordList(record)).build(); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); - Map wireData = body.getRecords().get().get(0).getData().get(); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); + Map wireData = body.getRecords().get(0).getData(); - Assert.assertSame(data, wireData); + Assert.assertEquals(data, wireData); // Object identity/type of every value survives — no toString()-ing, no boxing changes. Assert.assertEquals(Integer.valueOf(42), wireData.get("age")); Assert.assertEquals(Double.valueOf(1234.56d), wireData.get("balance")); Assert.assertEquals(Long.valueOf(9007199254740993L), wireData.get("longValue")); Assert.assertSame(Boolean.TRUE, wireData.get("active")); - Assert.assertSame(nested, wireData.get("address")); - Assert.assertSame(list, wireData.get("tags")); + Assert.assertEquals(nested, wireData.get("address")); + Assert.assertEquals(list, wireData.get("tags")); Assert.assertEquals(Integer.valueOf(75001), ((Map) wireData.get("address")).get("zip")); } @@ -178,12 +184,12 @@ public void testBulkInsert_recordOrderPreserved() { } BulkInsertRequest request = BulkInsertRequest.builder().records(records).build(); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); - List wireRecords = body.getRecords().get(); + List wireRecords = body.getRecords(); Assert.assertEquals(7, wireRecords.size()); for (int i = 0; i < 7; i++) { - Assert.assertEquals(Integer.valueOf(i), wireRecords.get(i).getData().get().get("pos")); + Assert.assertEquals(Integer.valueOf(i), wireRecords.get(i).getData().get("pos")); } } @@ -199,14 +205,14 @@ public void testBulkInsert_recordOrderPreservedAcrossBatches() { } BulkInsertRequest request = BulkInsertRequest.builder().tableName("cards").records(records).build(); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); - List> batches = Utils.createBulkInsertBatches(body.getRecords().get(), batchSize); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); + List> batches = Utils.createBulkInsertBatches(body.getRecords(), batchSize); Assert.assertEquals(3, batches.size()); int expected = 0; - for (List batch : batches) { - for (V1InsertRecordData wire : batch) { - Assert.assertEquals(Integer.valueOf(expected), wire.getData().get().get("pos")); + for (List batch : batches) { + for (InsertRecordData wire : batch) { + Assert.assertEquals(Integer.valueOf(expected), wire.getData().get("pos")); // Non-batched per-record fields survive batching on every batch. Assert.assertEquals("cards", wire.getTableName().get()); expected++; @@ -227,21 +233,21 @@ public void testBulkInsert_responseIndexMapsToOriginalInputPosition_acrossBatche } BulkInsertRequest request = BulkInsertRequest.builder().tableName("cards").records(records).build(); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); - List> batches = Utils.createBulkInsertBatches(body.getRecords().get(), batchSize); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); + List> batches = Utils.createBulkInsertBatches(body.getRecords(), batchSize); // Simulate the server echoing one response record per request record in each batch, then // assert the SDK-assigned index equals the record's position in the ORIGINAL user list. List indices = new ArrayList<>(); List skyflowIds = new ArrayList<>(); for (int batchNumber = 0; batchNumber < batches.size(); batchNumber++) { - List responseRecords = new ArrayList<>(); - for (V1InsertRecordData wire : batches.get(batchNumber)) { - responseRecords.add(V1RecordResponseObject.builder() - .skyflowId("sky-" + wire.getData().get().get("pos")) + List responseRecords = new ArrayList<>(); + for (InsertRecordData wire : batches.get(batchNumber)) { + responseRecords.add(RecordResponseObject.builder().httpCode(200) + .skyflowId("sky-" + wire.getData().get("pos")) .build()); } - V1InsertResponse response = V1InsertResponse.builder().records(responseRecords).build(); + com.skyflow.generated.rest.types.InsertResponse response = com.skyflow.generated.rest.types.InsertResponse.builder().records(responseRecords).build(); BulkInsertResponse formatted = Utils.formatBulkInsertResponse(response, batchNumber, batchSize, new HashMap<>()); formatted.getRecords().forEach(r -> { indices.add(r.getIndex()); @@ -273,10 +279,10 @@ public void testBulkInsert_blankRecordTableNameStaysAtRequestLevel() { .records(recordList(record)) .build(); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); - Assert.assertFalse(body.getRecords().get().get(0).getTableName().isPresent()); - Assert.assertEquals("cards", body.getTableName().get()); + Assert.assertFalse(body.getRecords().get(0).getTableName().isPresent()); + Assert.assertEquals("cards", body.getTableName()); } @Test @@ -289,10 +295,10 @@ public void testBulkInsert_nullRecordTableNameStaysAtRequestLevel() { .records(recordList(record)) .build(); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); - Assert.assertFalse(body.getRecords().get().get(0).getTableName().isPresent()); - Assert.assertEquals("cards", body.getTableName().get()); + Assert.assertFalse(body.getRecords().get(0).getTableName().isPresent()); + Assert.assertEquals("cards", body.getTableName()); } @Test @@ -305,10 +311,10 @@ public void testBulkInsert_emptyStringRecordTableNameStaysAtRequestLevel() { .records(recordList(record)) .build(); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); - Assert.assertFalse(body.getRecords().get().get(0).getTableName().isPresent()); - Assert.assertEquals("cards", body.getTableName().get()); + Assert.assertFalse(body.getRecords().get(0).getTableName().isPresent()); + Assert.assertEquals("cards", body.getTableName()); } @Test @@ -324,11 +330,11 @@ public void testBulkInsert_recordTableNameOverridesRequestLevel() { .records(recordList(record)) .build(); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); - Assert.assertEquals("record_table", body.getRecords().get().get(0).getTableName().get()); + Assert.assertEquals("record_table", body.getRecords().get(0).getTableName().get()); // The request-level name still goes out on the envelope, untouched. - Assert.assertEquals("request_table", body.getTableName().get()); + Assert.assertEquals("request_table", body.getTableName()); } @Test @@ -343,14 +349,14 @@ public void testBulkInsert_perRecordTableNamesResolveIndependently() { .records(recordList(withOwn, blank, missing)) .build(); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); // Only a record that names its own table carries one on the wire; the others rely on the // envelope. Nothing is copied down, so the name is never duplicated across both levels. - Assert.assertEquals("own", body.getRecords().get().get(0).getTableName().get()); - Assert.assertFalse(body.getRecords().get().get(1).getTableName().isPresent()); - Assert.assertFalse(body.getRecords().get().get(2).getTableName().isPresent()); - Assert.assertEquals("fallback", body.getTableName().get()); + Assert.assertEquals("own", body.getRecords().get(0).getTableName().get()); + Assert.assertFalse(body.getRecords().get(1).getTableName().isPresent()); + Assert.assertFalse(body.getRecords().get(2).getTableName().isPresent()); + Assert.assertEquals("fallback", body.getTableName()); } @Test @@ -363,26 +369,26 @@ public void testBulkInsert_blankRequestLevelTableNameIsOmittedFromEnvelope() { .records(recordList(record)) .build(); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); - Assert.assertFalse(body.getTableName().isPresent()); - Assert.assertEquals("cards", body.getRecords().get().get(0).getTableName().get()); + Assert.assertNull(body.getTableName()); + Assert.assertEquals("cards", body.getRecords().get(0).getTableName().get()); } // ── insert: upsert mapping ─────────────────────────────────────────────── @Test public void testUpsert_updateTypeUpdateAndReplace_userValueReachesWire() { - Assert.assertEquals(FlowEnumUpdateType.UPDATE, upsertWire("UPDATE").getUpdateType().get()); - Assert.assertEquals(FlowEnumUpdateType.REPLACE, upsertWire("REPLACE").getUpdateType().get()); + Assert.assertEquals(UpsertUpdateType.UPDATE, upsertWire("UPDATE").getUpdateType().get()); + Assert.assertEquals(UpsertUpdateType.REPLACE, upsertWire("REPLACE").getUpdateType().get()); } @Test public void testUpsert_updateTypeIsMatchedCaseInsensitively() { - Assert.assertEquals(FlowEnumUpdateType.UPDATE, upsertWire("update").getUpdateType().get()); - Assert.assertEquals(FlowEnumUpdateType.UPDATE, upsertWire("UpDaTe").getUpdateType().get()); - Assert.assertEquals(FlowEnumUpdateType.REPLACE, upsertWire("replace").getUpdateType().get()); - Assert.assertEquals(FlowEnumUpdateType.REPLACE, upsertWire("Replace").getUpdateType().get()); + Assert.assertEquals(UpsertUpdateType.UPDATE, upsertWire("update").getUpdateType().get()); + Assert.assertEquals(UpsertUpdateType.UPDATE, upsertWire("UpDaTe").getUpdateType().get()); + Assert.assertEquals(UpsertUpdateType.REPLACE, upsertWire("replace").getUpdateType().get()); + Assert.assertEquals(UpsertUpdateType.REPLACE, upsertWire("Replace").getUpdateType().get()); } @Test @@ -390,9 +396,9 @@ public void testUpsert_unrecognizedUpdateTypeIsRejectedBeforeMapping() { // Validations.validateUpsertOptions now rejects anything that is not UPDATE/REPLACE, so // the mapper can no longer be reached with a value it would silently drop. A null // updateType stays legal and simply omits the field. - com.skyflow.generated.rest.types.V1Upsert nullType = upsertWire(null); + com.skyflow.generated.rest.types.Upsert nullType = upsertWire(null); Assert.assertFalse(nullType.getUpdateType().isPresent()); - Assert.assertEquals(Collections.singletonList("email"), nullType.getUniqueColumns().get()); + Assert.assertEquals(Collections.singletonList("email"), nullType.getUniqueColumns()); } @Test @@ -407,10 +413,10 @@ public void testUpsert_uniqueColumnsValuesAndOrderReachWire() { .build(); BulkInsertRequest request = BulkInsertRequest.builder().records(recordList(record)).build(); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); - List wireColumns = body.getRecords().get().get(0).getUpsert().get().getUniqueColumns().get(); - Assert.assertSame(uniqueColumns, wireColumns); + List wireColumns = body.getRecords().get(0).getUpsert().get().getUniqueColumns(); + Assert.assertEquals(uniqueColumns, wireColumns); Assert.assertEquals(Arrays.asList("email", "phone number", NON_ASCII_NAME), wireColumns); } @@ -434,11 +440,11 @@ public void testUpsert_recordLevelOverridesRequestLevel() { .build()) .build(); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); - com.skyflow.generated.rest.types.V1Upsert wire = body.getRecords().get().get(0).getUpsert().get(); - Assert.assertEquals(FlowEnumUpdateType.REPLACE, wire.getUpdateType().get()); - Assert.assertEquals(Collections.singletonList("record_col"), wire.getUniqueColumns().get()); + com.skyflow.generated.rest.types.Upsert wire = body.getRecords().get(0).getUpsert().get(); + Assert.assertEquals(UpsertUpdateType.REPLACE, wire.getUpdateType().get()); + Assert.assertEquals(Collections.singletonList("record_col"), wire.getUniqueColumns()); } @Test @@ -457,21 +463,21 @@ public void testUpsert_requestLevelStaysOnEnvelopeAndIsNotCopiedOntoRecords() { .build()) .build(); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); // upsert must travel at the same single level as the table name — here, the envelope. - for (V1InsertRecordData wire : body.getRecords().get()) { + for (InsertRecordData wire : body.getRecords()) { Assert.assertFalse(wire.getUpsert().isPresent()); } Assert.assertTrue(body.getUpsert().isPresent()); - Assert.assertEquals(FlowEnumUpdateType.UPDATE, body.getUpsert().get().getUpdateType().get()); - Assert.assertEquals(Collections.singletonList("email"), body.getUpsert().get().getUniqueColumns().get()); + Assert.assertEquals(UpsertUpdateType.UPDATE, body.getUpsert().get().getUpdateType().get()); + Assert.assertEquals(Collections.singletonList("email"), body.getUpsert().get().getUniqueColumns()); } @Test public void testUpsert_requestLevelUpsertReachesEnvelope() { // Regression: the request-level upsert used to be projected onto every record and never set - // on the V1InsertRequest envelope, so VaultController#insertBatchFutures — which reads + // on the com.skyflow.generated.rest.resources.records.requests.InsertRequest envelope, so VaultController#insertBatchFutures — which reads // insertRequest.getUpsert() to re-apply it per batch — always read empty. Map data = new HashMap<>(); data.put("name", "john"); @@ -484,10 +490,10 @@ public void testUpsert_requestLevelUpsertReachesEnvelope() { .build()) .build(); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); Assert.assertTrue(body.getUpsert().isPresent()); - Assert.assertFalse(body.getRecords().get().get(0).getUpsert().isPresent()); + Assert.assertFalse(body.getRecords().get(0).getUpsert().isPresent()); } @Test @@ -504,12 +510,12 @@ public void testUpsert_emptyUniqueColumnsMeansNoUpsertOnWire() { .build(); BulkInsertRequest request = BulkInsertRequest.builder().records(recordList(record)).build(); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); - Assert.assertFalse(body.getRecords().get().get(0).getUpsert().isPresent()); + Assert.assertFalse(body.getRecords().get(0).getUpsert().isPresent()); } - private static com.skyflow.generated.rest.types.V1Upsert upsertWire(String updateType) { + private static com.skyflow.generated.rest.types.Upsert upsertWire(String updateType) { Map data = new HashMap<>(); data.put("name", "john"); BulkInsertRequestRecord record = BulkInsertRequestRecord.builder() @@ -522,7 +528,7 @@ private static com.skyflow.generated.rest.types.V1Upsert upsertWire(String updat .build(); BulkInsertRequest request = BulkInsertRequest.builder().records(recordList(record)).build(); return Utils.getBulkInsertRequestBody(request, vaultConfig()) - .getRecords().get().get(0).getUpsert().get(); + .getRecords().get(0).getUpsert().get(); } // ── insert: tokens map ─────────────────────────────────────────────────── @@ -540,9 +546,9 @@ public void testBulkInsert_emptyTokensMapIsOmittedFromWire() { .build(); BulkInsertRequest request = BulkInsertRequest.builder().records(recordList(record)).build(); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); - Assert.assertFalse(body.getRecords().get().get(0).getTokens().isPresent()); + Assert.assertFalse(body.getRecords().get(0).getAdditionalProperties().containsKey("tokens")); } @Test @@ -555,9 +561,9 @@ public void testBulkInsert_nullTokensMapIsOmittedFromWire() { .build(); BulkInsertRequest request = BulkInsertRequest.builder().records(recordList(record)).build(); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); - Assert.assertFalse(body.getRecords().get().get(0).getTokens().isPresent()); + Assert.assertFalse(body.getRecords().get(0).getAdditionalProperties().containsKey("tokens")); } @Test @@ -575,10 +581,11 @@ public void testBulkInsert_multiValueTokensMapReachesWireVerbatim() { .build(); BulkInsertRequest request = BulkInsertRequest.builder().records(recordList(record)).build(); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, vaultConfig()); - Map wireTokens = body.getRecords().get().get(0).getTokens().get(); - Assert.assertSame(tokens, wireTokens); + @SuppressWarnings("unchecked") + Map wireTokens = (Map) body.getRecords().get(0).getAdditionalProperties().get("tokens"); + Assert.assertEquals(tokens, wireTokens); Assert.assertEquals("tok-1", wireTokens.get("name")); Assert.assertEquals("tok-2", wireTokens.get("ssn")); Assert.assertEquals(Collections.singletonMap("group", "tok-3"), wireTokens.get("nested")); @@ -604,13 +611,13 @@ public void testBulkDetokenize_everyFieldReachesWire() { .tokenGroupRedactions(Arrays.asList(groupA, groupB)) .build(); - V1FlowDetokenizeRequest body = Utils.getBulkDetokenizeRequestBody(request, VAULT_ID); + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest body = Utils.getBulkDetokenizeRequestBody(request, VAULT_ID); - Assert.assertEquals(VAULT_ID, body.getVaultId().get()); - Assert.assertSame(tokens, body.getTokens().get()); - Assert.assertEquals(Arrays.asList("token-1", "token 2", "トークン-3"), body.getTokens().get()); + Assert.assertEquals(VAULT_ID, body.getVaultId()); + Assert.assertEquals(tokens, body.getTokens()); + Assert.assertEquals(Arrays.asList("token-1", "token 2", "トークン-3"), body.getTokens()); - List wireGroups = body.getTokenGroupRedactions().get(); + List wireGroups = body.getTokenGroupRedactions().get(); Assert.assertEquals(2, wireGroups.size()); Assert.assertEquals("group one", wireGroups.get(0).getTokenGroupName().get()); Assert.assertEquals("MASKED", wireGroups.get(0).getRedaction().get()); @@ -625,7 +632,7 @@ public void testBulkDetokenize_emptyTokenGroupRedactionsListIsOmitted() { .tokenGroupRedactions(new ArrayList<>()) .build(); - V1FlowDetokenizeRequest body = Utils.getBulkDetokenizeRequestBody(request, VAULT_ID); + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest body = Utils.getBulkDetokenizeRequestBody(request, VAULT_ID); Assert.assertFalse(body.getTokenGroupRedactions().isPresent()); } @@ -640,13 +647,13 @@ public void testBulkDetokenize_tokenOrderPreservedAcrossBatches() { } BulkDetokenizeRequest request = BulkDetokenizeRequest.builder().tokens(tokens).build(); - V1FlowDetokenizeRequest body = Utils.getBulkDetokenizeRequestBody(request, VAULT_ID); - List batches = Utils.createBulkDetokenizeBatches(body, batchSize); + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest body = Utils.getBulkDetokenizeRequestBody(request, VAULT_ID); + List batches = Utils.createBulkDetokenizeBatches(body, batchSize); Assert.assertEquals(3, batches.size()); List flattened = new ArrayList<>(); - for (V1FlowDetokenizeRequest batch : batches) { - flattened.addAll(batch.getTokens().get()); + for (com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest batch : batches) { + flattened.addAll(batch.getTokens()); } Assert.assertEquals(tokens, flattened); } @@ -668,12 +675,12 @@ public void testBulkDetokenize_vaultIdAndRedactionsPresentOnEveryBatch() { .tokenGroupRedactions(Collections.singletonList(group)) .build(); - V1FlowDetokenizeRequest body = Utils.getBulkDetokenizeRequestBody(request, VAULT_ID); - List batches = Utils.createBulkDetokenizeBatches(body, batchSize); + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest body = Utils.getBulkDetokenizeRequestBody(request, VAULT_ID); + List batches = Utils.createBulkDetokenizeBatches(body, batchSize); Assert.assertEquals(3, batches.size()); - for (V1FlowDetokenizeRequest batch : batches) { - Assert.assertEquals(VAULT_ID, batch.getVaultId().get()); + for (com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest batch : batches) { + Assert.assertEquals(VAULT_ID, batch.getVaultId()); Assert.assertTrue(batch.getTokenGroupRedactions().isPresent()); Assert.assertEquals(1, batch.getTokenGroupRedactions().get().size()); Assert.assertEquals("group one", batch.getTokenGroupRedactions().get().get(0).getTokenGroupName().get()); @@ -690,17 +697,17 @@ public void testBulkDetokenize_responseIndexMapsToOriginalInputPosition_acrossBa tokens.add("token-" + i); } BulkDetokenizeRequest request = BulkDetokenizeRequest.builder().tokens(tokens).build(); - V1FlowDetokenizeRequest body = Utils.getBulkDetokenizeRequestBody(request, VAULT_ID); - List batches = Utils.createBulkDetokenizeBatches(body, batchSize); + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest body = Utils.getBulkDetokenizeRequestBody(request, VAULT_ID); + List batches = Utils.createBulkDetokenizeBatches(body, batchSize); List indices = new ArrayList<>(); List echoedTokens = new ArrayList<>(); for (int batchNumber = 0; batchNumber < batches.size(); batchNumber++) { - List responseRecords = new ArrayList<>(); - for (String token : batches.get(batchNumber).getTokens().get()) { - responseRecords.add(V1FlowDetokenizeResponseObject.builder().token(token).build()); + List responseRecords = new ArrayList<>(); + for (String token : batches.get(batchNumber).getTokens()) { + responseRecords.add(DetokenizeResponseObject.builder().token(token).build()); } - V1FlowDetokenizeResponse response = V1FlowDetokenizeResponse.builder().response(responseRecords).build(); + com.skyflow.generated.rest.types.DetokenizeResponse response = com.skyflow.generated.rest.types.DetokenizeResponse.builder().response(responseRecords).build(); BulkDetokenizeResponse formatted = Utils.formatBulkDetokenizeResponse(response, batchNumber, batchSize, new HashMap<>()); formatted.getRecords().forEach(r -> { @@ -729,14 +736,14 @@ public void testBulkTokenize_everyFieldReachesWire() { .build(); List records = Collections.singletonList(record); - V1FlowTokenizeRequest body = Utils.getBulkTokenizeRequestBody(records, VAULT_ID); + com.skyflow.generated.rest.resources.tokens.requests.TokenizeRequest body = Utils.getBulkTokenizeRequestBody(records, VAULT_ID); - Assert.assertEquals(VAULT_ID, body.getVaultId().get()); - Assert.assertEquals(1, body.getData().get().size()); - V1FlowTokenizeRequestObject wire = body.getData().get().get(0); + Assert.assertEquals(VAULT_ID, body.getVaultId()); + Assert.assertEquals(1, body.getData().size()); + TokenizeRequestObject wire = body.getData().get(0); Assert.assertEquals(NON_ASCII_NAME, wire.getValue().get()); - Assert.assertSame(groupNames, wire.getTokenGroupNames().get()); - Assert.assertEquals(Arrays.asList("group one", NON_ASCII_NAME), wire.getTokenGroupNames().get()); + Assert.assertEquals(groupNames, wire.getTokenGroupNames()); + Assert.assertEquals(Arrays.asList("group one", NON_ASCII_NAME), wire.getTokenGroupNames()); } @Test @@ -747,10 +754,10 @@ public void testBulkTokenize_byotTokenReachesWire() { .tokenGroupNames(Collections.singletonList("g1")) .build(); - V1FlowTokenizeRequest body = Utils.getBulkTokenizeRequestBody( + com.skyflow.generated.rest.resources.tokens.requests.TokenizeRequest body = Utils.getBulkTokenizeRequestBody( Collections.singletonList(record), VAULT_ID); - Assert.assertEquals("my-own-token", body.getData().get().get(0).getToken().get()); + Assert.assertEquals("my-own-token", body.getData().get(0).getToken().get().get()); } @Test @@ -760,11 +767,11 @@ public void testBulkTokenize_absentByotTokenIsOmittedFromWire() { .tokenGroupNames(Collections.singletonList("g1")) .build(); - V1FlowTokenizeRequest body = Utils.getBulkTokenizeRequestBody( + com.skyflow.generated.rest.resources.tokens.requests.TokenizeRequest body = Utils.getBulkTokenizeRequestBody( Collections.singletonList(record), VAULT_ID); // omitted rather than sent as null, so a non-BYOT request is byte-identical to before - Assert.assertFalse(body.getData().get().get(0).getToken().isPresent()); + Assert.assertFalse(body.getData().get(0).getToken().isPresent()); } @Test @@ -781,8 +788,8 @@ public void testBulkTokenize_nonStringValues_objectIdentitySurvives() { BulkTokenizeRequestRecord.builder().value(nested).build(), BulkTokenizeRequestRecord.builder().value(listValue).build()); - V1FlowTokenizeRequest body = Utils.getBulkTokenizeRequestBody(records, VAULT_ID); - List wire = body.getData().get(); + com.skyflow.generated.rest.resources.tokens.requests.TokenizeRequest body = Utils.getBulkTokenizeRequestBody(records, VAULT_ID); + List wire = body.getData(); Assert.assertEquals(Integer.valueOf(42), wire.get(0).getValue().get()); Assert.assertEquals(Double.valueOf(3.14d), wire.get(1).getValue().get()); @@ -796,9 +803,9 @@ public void testBulkTokenize_nullTokenGroupNamesIsOmitted() { List records = Collections.singletonList(BulkTokenizeRequestRecord.builder().value("v1").build()); - V1FlowTokenizeRequest body = Utils.getBulkTokenizeRequestBody(records, VAULT_ID); + com.skyflow.generated.rest.resources.tokens.requests.TokenizeRequest body = Utils.getBulkTokenizeRequestBody(records, VAULT_ID); - Assert.assertFalse(body.getData().get().get(0).getTokenGroupNames().isPresent()); + Assert.assertTrue(body.getData().get(0).getTokenGroupNames().isEmpty()); } @Test @@ -818,10 +825,10 @@ public void testBulkTokenize_recordOrderPreservedAcrossBatches() { Assert.assertEquals(3, batches.size()); List flattened = new ArrayList<>(); for (List batch : batches) { - V1FlowTokenizeRequest body = Utils.getBulkTokenizeRequestBody(batch, VAULT_ID); + com.skyflow.generated.rest.resources.tokens.requests.TokenizeRequest body = Utils.getBulkTokenizeRequestBody(batch, VAULT_ID); // vaultId is a non-batched field and must be re-applied on every batch. - Assert.assertEquals(VAULT_ID, body.getVaultId().get()); - for (V1FlowTokenizeRequestObject obj : body.getData().get()) { + Assert.assertEquals(VAULT_ID, body.getVaultId()); + for (TokenizeRequestObject obj : body.getData()) { flattened.add(obj.getValue().get()); } } @@ -840,11 +847,11 @@ public void testBulkDeleteTokens_everyFieldReachesWire() { List tokens = Arrays.asList("token-1", "token 2", "トークン-3"); BulkDeleteTokensRequest request = BulkDeleteTokensRequest.builder().tokens(tokens).build(); - V1FlowDeleteTokenRequest body = Utils.getBulkDeleteTokensRequestBody(request, VAULT_ID); + DeleteTokenRequest body = Utils.getBulkDeleteTokensRequestBody(request, VAULT_ID); - Assert.assertEquals(VAULT_ID, body.getVaultId().get()); - Assert.assertSame(tokens, body.getTokens().get()); - Assert.assertEquals(Arrays.asList("token-1", "token 2", "トークン-3"), body.getTokens().get()); + Assert.assertEquals(VAULT_ID, body.getVaultId()); + Assert.assertEquals(tokens, body.getTokens()); + Assert.assertEquals(Arrays.asList("token-1", "token 2", "トークン-3"), body.getTokens()); } @Test @@ -857,14 +864,14 @@ public void testBulkDeleteTokens_tokenOrderPreservedAndVaultIdOnEveryBatch() { } BulkDeleteTokensRequest request = BulkDeleteTokensRequest.builder().tokens(tokens).build(); - V1FlowDeleteTokenRequest body = Utils.getBulkDeleteTokensRequestBody(request, VAULT_ID); - List batches = Utils.createBulkDeleteTokensBatches(body, batchSize); + DeleteTokenRequest body = Utils.getBulkDeleteTokensRequestBody(request, VAULT_ID); + List batches = Utils.createBulkDeleteTokensBatches(body, batchSize); Assert.assertEquals(3, batches.size()); List flattened = new ArrayList<>(); - for (V1FlowDeleteTokenRequest batch : batches) { - Assert.assertEquals(VAULT_ID, batch.getVaultId().get()); - flattened.addAll(batch.getTokens().get()); + for (DeleteTokenRequest batch : batches) { + Assert.assertEquals(VAULT_ID, batch.getVaultId()); + flattened.addAll(batch.getTokens()); } Assert.assertEquals(tokens, flattened); } @@ -878,18 +885,18 @@ public void testBulkDeleteTokens_responseIndexMapsToOriginalInputPosition_across tokens.add("token-" + i); } BulkDeleteTokensRequest request = BulkDeleteTokensRequest.builder().tokens(tokens).build(); - V1FlowDeleteTokenRequest body = Utils.getBulkDeleteTokensRequestBody(request, VAULT_ID); - List batches = Utils.createBulkDeleteTokensBatches(body, batchSize); + DeleteTokenRequest body = Utils.getBulkDeleteTokensRequestBody(request, VAULT_ID); + List batches = Utils.createBulkDeleteTokensBatches(body, batchSize); List indices = new ArrayList<>(); List echoed = new ArrayList<>(); for (int batchNumber = 0; batchNumber < batches.size(); batchNumber++) { - List responseRecords = new ArrayList<>(); - for (String token : batches.get(batchNumber).getTokens().get()) { - responseRecords.add(V1DeleteTokenResponseObject.builder().value(token).build()); + List responseRecords = new ArrayList<>(); + for (String token : batches.get(batchNumber).getTokens()) { + responseRecords.add(DeleteTokenResponseObject.builder().value(token).build()); } - V1FlowDeleteTokenResponse response = - V1FlowDeleteTokenResponse.builder().tokens(responseRecords).build(); + DeleteTokenResponse response = + DeleteTokenResponse.builder().tokens(responseRecords).build(); // successes and errors now share one records list, keyed by index BulkDeleteTokensResponse formatted = Utils.formatBulkDeleteTokensResponse( response, batches.get(batchNumber), batchNumber, batchSize, new HashMap<>()); @@ -905,4 +912,111 @@ public void testBulkDeleteTokens_responseIndexMapsToOriginalInputPosition_across Assert.assertEquals(tokens.get(i), echoed.get(i)); } } + + // ───────────────────────────────────────────────────────────────────────── + // Query + // ───────────────────────────────────────────────────────────────────────── + + @Test + public void testQuery_queryStringReachesWireUntouched() { + String query = "SELECT name, \"street address\" FROM " + NON_ASCII_TABLE + + " WHERE name = '" + NON_ASCII_NAME + "' LIMIT 25 OFFSET 50"; + QueryRequest request = QueryRequest.builder().query(query).build(); + + ExecuteQueryRequest body = Utils.getQueryRequestBody(request, VAULT_ID); + + Assert.assertEquals(VAULT_ID, body.getVaultId()); + Assert.assertEquals(query, body.getQuery()); + } + + @Test + public void testQuery_serializesToDocumentedWireShape() throws Exception { + QueryRequest request = QueryRequest.builder().query("SELECT * FROM persons").build(); + + String json = ObjectMappers.JSON_MAPPER.writeValueAsString(Utils.getQueryRequestBody(request, VAULT_ID)); + + Assert.assertEquals("{\"vaultID\":\"" + VAULT_ID + "\",\"query\":\"SELECT * FROM persons\"}", json); + } + + @Test + public void testQuery_wireResponseRowsReachCallerInOrder() throws Exception { + ExecuteQueryResponse wire = ObjectMappers.JSON_MAPPER.readValue( + "{\"records\":[" + + "{\"data\":{\"skyflow_id\":\"sky-1\",\"name\":\"" + NON_ASCII_NAME + "\",\"age\":30}}," + + "{\"data\":{\"skyflow_id\":\"sky-2\",\"name\":\"jane\",\"age\":null}}]," + + "\"metadata\":{\"columns\":[\"skyflow_id\",\"name\",\"age\"]}}", + ExecuteQueryResponse.class); + + QueryResponse response = Utils.formatQueryResponse(wire, new HashMap<>()); + + Assert.assertEquals(2, response.getFields().size()); + Assert.assertEquals(Arrays.asList("skyflow_id", "name", "age"), + new ArrayList<>(response.getFields().get(0).keySet())); + Assert.assertEquals(NON_ASCII_NAME, response.getFields().get(0).get("name")); + Assert.assertEquals(30, response.getFields().get(0).get("age")); + Assert.assertEquals("sky-2", response.getFields().get(1).get("skyflow_id")); + Assert.assertTrue(response.getFields().get(1).containsKey("age")); + Assert.assertNull(response.getFields().get(1).get("age")); + Assert.assertEquals(Arrays.asList("skyflow_id", "name", "age"), response.getMetadata().getColumns()); + } + + // ───────────────────────────────────────────────────────────────────────── + // Get tokens + // ───────────────────────────────────────────────────────────────────────── + + @Test + public void testGetTokens_everyRecordReachesWireInOrderWithoutCollapsingDuplicates() { + Map structured = new LinkedHashMap<>(); + structured.put("k", "v"); + List records = Arrays.asList( + GetTokensRequestRecord.builder().value(NON_ASCII_NAME).tokenGroupName("group one").build(), + GetTokensRequestRecord.builder().value(42).tokenGroupName("det_number").build(), + GetTokensRequestRecord.builder().value(structured).tokenGroupName("det_json").build(), + GetTokensRequestRecord.builder().value(NON_ASCII_NAME).tokenGroupName("group one").build()); + GetTokensRequest request = GetTokensRequest.builder().records(records).build(); + + GetTokensFromValuesRequest body = Utils.getGetTokensRequestBody(request, VAULT_ID); + + Assert.assertEquals(VAULT_ID, body.getVaultId()); + Assert.assertEquals(4, body.getRecords().size()); + for (int i = 0; i < records.size(); i++) { + // arbitrary values must be handed to the wire object untouched + Assert.assertSame(records.get(i).getValue(), body.getRecords().get(i).getValue().get()); + Assert.assertEquals(records.get(i).getTokenGroupName(), + body.getRecords().get(i).getTokenGroupName()); + } + } + + @Test + public void testGetTokens_serializesToDocumentedWireShape() throws Exception { + GetTokensRequest request = GetTokensRequest.builder().records(Arrays.asList( + GetTokensRequestRecord.builder().value("john@example.com").tokenGroupName("det_email").build(), + GetTokensRequestRecord.builder().value(42).tokenGroupName("det_number").build())).build(); + + String json = ObjectMappers.JSON_MAPPER.writeValueAsString(Utils.getGetTokensRequestBody(request, VAULT_ID)); + + Assert.assertEquals("{\"vaultID\":\"" + VAULT_ID + "\",\"records\":[" + + "{\"value\":\"john@example.com\",\"tokenGroupName\":\"det_email\"}," + + "{\"value\":42,\"tokenGroupName\":\"det_number\"}]}", json); + } + + @Test + public void testGetTokens_wireResponseRecordsReachCallerInOrder() throws Exception { + GetTokensFromValuesResponse wire = ObjectMappers.JSON_MAPPER.readValue( + "{\"records\":[" + + "{\"token\":\"1R9kNnLOPM\",\"value\":\"john@example.com\",\"tokenGroupName\":\"det_reg_rtf\",\"error\":\"\",\"httpCode\":200}," + + "{\"token\":\"\",\"value\":\"unknown@example.com\",\"tokenGroupName\":\"det_reg_rtf\",\"error\":\"Token not found.\",\"httpCode\":404}]}", + GetTokensFromValuesResponse.class); + + GetTokensResponse response = Utils.formatGetTokensResponse(wire, new HashMap<>()); + + Assert.assertEquals(2, response.getRecords().size()); + Assert.assertEquals("john@example.com", response.getRecords().get(0).get("value")); + Assert.assertEquals("1R9kNnLOPM", response.getRecords().get(0).get("token")); + Assert.assertNull(response.getRecords().get(0).get("error")); + Assert.assertEquals("unknown@example.com", response.getRecords().get(1).get("value")); + Assert.assertEquals("", response.getRecords().get(1).get("token")); + Assert.assertEquals("Token not found.", response.getRecords().get(1).get("error")); + Assert.assertEquals(404, response.getRecords().get(1).get("httpCode")); + } } diff --git a/flowvault/src/test/java/com/skyflow/utils/RequestIdTests.java b/flowvault/src/test/java/com/skyflow/utils/RequestIdTests.java index 8572ba0d..660d19f5 100644 --- a/flowvault/src/test/java/com/skyflow/utils/RequestIdTests.java +++ b/flowvault/src/test/java/com/skyflow/utils/RequestIdTests.java @@ -1,17 +1,20 @@ package com.skyflow.utils; +import com.skyflow.generated.rest.resources.tokens.requests.DeleteTokenRequest; +import com.skyflow.generated.rest.types.DeleteTokenResponse; +import com.skyflow.generated.rest.types.DeleteTokenResponseObject; +import com.skyflow.generated.rest.types.ExecuteQueryResponse; +import com.skyflow.generated.rest.types.GetTokensFromValuesResponse; import com.skyflow.generated.rest.core.ApiClientApiException; import com.skyflow.generated.rest.core.ObjectMappers; -import com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest; -import com.skyflow.generated.rest.types.V1DeleteTokenResponseObject; -import com.skyflow.generated.rest.types.V1FlowDeleteTokenResponse; -import com.skyflow.generated.rest.types.V1FlowTokenizeResponse; import com.skyflow.utils.BaseConstants; import com.skyflow.vault.data.BulkDeleteTokensResponse; import com.skyflow.vault.data.BulkDeleteTokensResponseRecord; import com.skyflow.vault.data.BulkTokenizeRequestRecord; import com.skyflow.vault.data.BulkTokenizeResponse; import com.skyflow.vault.data.BulkTokenizeResponseRecord; +import com.skyflow.vault.data.GetTokensResponse; +import com.skyflow.vault.data.QueryResponse; import okhttp3.Protocol; import okhttp3.Request; import okhttp3.Response; @@ -67,9 +70,9 @@ private static ApiClientApiException apiException(String message, int status, Ob return new ApiClientApiException(message, status, body, raw.build()); } - private static V1FlowTokenizeResponse tokenizeWire(String json) { + private static com.skyflow.generated.rest.types.TokenizeResponse tokenizeWire(String json) { try { - return ObjectMappers.JSON_MAPPER.readValue(json, V1FlowTokenizeResponse.class); + return ObjectMappers.JSON_MAPPER.readValue(json, com.skyflow.generated.rest.types.TokenizeResponse.class); } catch (Exception e) { throw new IllegalStateException(e); } @@ -265,20 +268,20 @@ public void testTokenize_transportFailureHasNoRequestId() { // ── delete: success carries no id, errors carry the batch's ──────────────── - private static V1FlowDeleteTokenResponse deleteWire(V1DeleteTokenResponseObject... rows) { - return V1FlowDeleteTokenResponse.builder().tokens(Arrays.asList(rows)).build(); + private static DeleteTokenResponse deleteWire(DeleteTokenResponseObject... rows) { + return DeleteTokenResponse.builder().tokens(Arrays.asList(rows)).build(); } - private static V1DeleteTokenResponseObject deleted(String token) { - return V1DeleteTokenResponseObject.builder().value(token).httpCode(200).build(); + private static DeleteTokenResponseObject deleted(String token) { + return DeleteTokenResponseObject.builder().value(token).httpCode(200).build(); } - private static V1DeleteTokenResponseObject failed(String token, String error) { - return V1DeleteTokenResponseObject.builder().value(token).error(error).httpCode(404).build(); + private static DeleteTokenResponseObject failed(String token, String error) { + return DeleteTokenResponseObject.builder().value(token).error(error).httpCode(404).build(); } - private static V1FlowDeleteTokenRequest deleteBatch(String... tokens) { - return V1FlowDeleteTokenRequest.builder() + private static DeleteTokenRequest deleteBatch(String... tokens) { + return DeleteTokenRequest.builder() .vaultId("vault123").tokens(Arrays.asList(tokens)).build(); } @@ -407,6 +410,72 @@ public void testDelete_transportFailureHasNoRequestId() { Assert.assertEquals("connection reset", records.get(0).getError()); } + // ── getTokens: success carries no id, errors carry the call's ───────────── + + @Test + public void testGetTokens_onlyErrorRecordsCarryTheCallsRequestId() throws Exception { + GetTokensFromValuesResponse wire = ObjectMappers.JSON_MAPPER.readValue( + "{\"records\":[" + + "{\"token\":\"tok-0\",\"value\":\"v0\",\"tokenGroupName\":\"g\",\"httpCode\":200}," + + "{\"token\":\"\",\"value\":\"v1\",\"tokenGroupName\":\"g\",\"error\":\"Token not found.\",\"httpCode\":404}," + + "{\"token\":\"\",\"value\":\"v2\",\"tokenGroupName\":\"g\",\"error\":\"Token not found.\",\"httpCode\":404}]}", + GetTokensFromValuesResponse.class); + + GetTokensResponse result = Utils.formatGetTokensResponse(wire, headers(REQ_ID_A)); + + Assert.assertNull(result.getRecords().get(0).get("requestId")); + Assert.assertEquals(REQ_ID_A, result.getRecords().get(1).get("requestId")); + Assert.assertEquals(REQ_ID_A, result.getRecords().get(2).get("requestId")); + } + + @Test + public void testGetTokens_errorRecordWithoutHeaderHasNullRequestId() throws Exception { + GetTokensFromValuesResponse wire = ObjectMappers.JSON_MAPPER.readValue( + "{\"records\":[{\"value\":\"v0\",\"error\":\"boom\",\"httpCode\":500}]}", + GetTokensFromValuesResponse.class); + + GetTokensResponse result = Utils.formatGetTokensResponse(wire, headers(null)); + + Assert.assertNull(result.getRecords().get(0).get("requestId")); + } + + @Test + public void testGetTokens_rejectedRequestWithPerRecordBodyStampsEveryRecord() { + Map row0 = new LinkedHashMap<>(); + row0.put("value", "v0"); + row0.put("error", "Token not found."); + row0.put("httpCode", 404); + Map row1 = new LinkedHashMap<>(); + row1.put("value", "v1"); + row1.put("error", "Token not found."); + row1.put("httpCode", 404); + Map body = new LinkedHashMap<>(); + body.put("records", Arrays.asList(row0, row1)); + + GetTokensResponse result = Utils.handleGetTokensRequestException( + apiException("Error with status code 404", 404, body, REQ_ID_B)); + + Assert.assertNotNull(result); + Assert.assertEquals(REQ_ID_B, result.getRecords().get(0).get("requestId")); + Assert.assertEquals(REQ_ID_B, result.getRecords().get(1).get("requestId")); + } + + // ── query: the id is call-level, set on success too ─────────────────────── + + @Test + public void testQuery_successCarriesTheCallsRequestId() { + QueryResponse result = Utils.formatQueryResponse(ExecuteQueryResponse.builder().build(), headers(REQ_ID_A)); + + Assert.assertEquals(REQ_ID_A, result.getRequestId()); + } + + @Test + public void testQuery_missingHeaderLeavesRequestIdNull() { + QueryResponse result = Utils.formatQueryResponse(ExecuteQueryResponse.builder().build(), headers(null)); + + Assert.assertNull(result.getRequestId()); + } + // ── JSON output ─────────────────────────────────────────────────────────── @Test diff --git a/flowvault/src/test/java/com/skyflow/utils/UtilsTests.java b/flowvault/src/test/java/com/skyflow/utils/UtilsTests.java index 1470ee30..bdaa2690 100644 --- a/flowvault/src/test/java/com/skyflow/utils/UtilsTests.java +++ b/flowvault/src/test/java/com/skyflow/utils/UtilsTests.java @@ -1,33 +1,28 @@ package com.skyflow.utils; +import com.skyflow.generated.rest.resources.query.requests.ExecuteQueryRequest; +import com.skyflow.generated.rest.resources.tokens.requests.DeleteTokenRequest; +import com.skyflow.generated.rest.resources.tokens.requests.GetTokensFromValuesRequest; +import com.skyflow.generated.rest.types.DeleteResponseObject; +import com.skyflow.generated.rest.types.DeleteTokenResponse; +import com.skyflow.generated.rest.types.DeleteTokenResponseObject; +import com.skyflow.generated.rest.types.DetokenizeResponseObject; +import com.skyflow.generated.rest.types.ExecuteQueryRecordResponse; +import com.skyflow.generated.rest.types.ExecuteQueryResponse; +import com.skyflow.generated.rest.types.ExecuteQueryResponseMetadata; +import com.skyflow.generated.rest.types.GetTokensFromValuesRequestObject; +import com.skyflow.generated.rest.types.GetTokensFromValuesResponse; +import com.skyflow.generated.rest.types.InsertRecordData; +import com.skyflow.generated.rest.types.RecordResponseObject; +import com.skyflow.generated.rest.types.TokenizeResponseObject; import com.google.gson.JsonObject; import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; import com.skyflow.enums.Env; import com.skyflow.enums.UpdateType; +import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; import com.skyflow.generated.rest.core.ApiClientApiException; -import com.skyflow.generated.rest.resources.flowservice.requests.V1DeleteRequest; -import com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest; -import com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest; -import com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest; -import com.skyflow.generated.rest.resources.flowservice.requests.V1GetRequest; -import com.skyflow.generated.rest.resources.flowservice.requests.V1InsertRequest; -import com.skyflow.generated.rest.resources.flowservice.requests.V1UpdateRequest; -import com.skyflow.generated.rest.types.FlowEnumUpdateType; -import com.skyflow.generated.rest.types.V1DeleteResponse; -import com.skyflow.generated.rest.types.V1DeleteResponseObject; -import com.skyflow.generated.rest.types.V1DeleteTokenResponseObject; -import com.skyflow.generated.rest.types.V1FlowDeleteTokenResponse; -import com.skyflow.generated.rest.types.V1FlowDetokenizeResponse; -import com.skyflow.generated.rest.types.V1FlowDetokenizeResponseObject; -import com.skyflow.generated.rest.types.V1FlowTokenizeResponse; -import com.skyflow.generated.rest.types.V1FlowTokenizeResponseObject; -import com.skyflow.generated.rest.types.V1GetResponse; -import com.skyflow.generated.rest.types.V1InsertRecordData; -import com.skyflow.generated.rest.types.V1InsertResponse; -import com.skyflow.generated.rest.types.V1RecordResponseObject; -import com.skyflow.generated.rest.types.V1UpdateResponse; import com.skyflow.vault.data.BulkDeleteTokensRequest; import com.skyflow.vault.data.BulkDeleteTokensResponse; import com.skyflow.vault.data.BulkDeleteTokensResponseRecord; @@ -53,10 +48,15 @@ import com.skyflow.vault.data.GetRequestRecord; import com.skyflow.vault.data.GetResponse; import com.skyflow.vault.data.GetResponseRecord; +import com.skyflow.vault.data.GetTokensRequest; +import com.skyflow.vault.data.GetTokensRequestRecord; +import com.skyflow.vault.data.GetTokensResponse; import com.skyflow.vault.data.InsertRequestRecord; import com.skyflow.vault.data.InsertRequest; import com.skyflow.vault.data.InsertResponse; import com.skyflow.vault.data.InsertResponseRecord; +import com.skyflow.vault.data.QueryRequest; +import com.skyflow.vault.data.QueryResponse; import com.skyflow.vault.data.TokenGroupRedactions; import com.skyflow.vault.data.BulkTokenizeResponseRecord; import com.skyflow.vault.data.TokenizeRequestRecord; @@ -67,6 +67,7 @@ import com.skyflow.vault.data.UpdateResponse; import com.skyflow.vault.data.UpsertOptions; import org.junit.After; +import com.skyflow.generated.rest.types.UpsertUpdateType; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -80,6 +81,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -254,12 +256,12 @@ public void testGetInsertRequestBody_buildsCorrectRequest() { VaultConfig config = new VaultConfig(); config.setVaultId("vault123"); - V1InsertRequest body = Utils.getInsertRequestBody(request, config); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getInsertRequestBody(request, config); - Assert.assertEquals("vault123", body.getVaultId().get()); - Assert.assertEquals(1, body.getRecords().get().size()); - Assert.assertEquals("table1", body.getRecords().get().get(0).getTableName().get()); - Assert.assertEquals(data, body.getRecords().get().get(0).getData().get()); + Assert.assertEquals("vault123", body.getVaultId()); + Assert.assertEquals(1, body.getRecords().size()); + Assert.assertEquals("table1", body.getRecords().get(0).getTableName().get()); + Assert.assertEquals(data, body.getRecords().get(0).getData()); } @Test @@ -273,10 +275,10 @@ public void testGetInsertRequestBody_keepsRequestLevelTableNameOnEnvelopeOnly() VaultConfig config = new VaultConfig(); config.setVaultId("vault123"); - V1InsertRequest body = Utils.getInsertRequestBody(request, config); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getInsertRequestBody(request, config); - Assert.assertEquals("table1", body.getTableName().get()); - Assert.assertFalse(body.getRecords().get().get(0).getTableName().isPresent()); + Assert.assertEquals("table1", body.getTableName()); + Assert.assertFalse(body.getRecords().get(0).getTableName().isPresent()); } @Test @@ -292,9 +294,9 @@ public void testGetInsertRequestBody_withTokens() { VaultConfig config = new VaultConfig(); config.setVaultId("vault123"); - V1InsertRequest body = Utils.getInsertRequestBody(request, config); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getInsertRequestBody(request, config); - Assert.assertEquals(tokens, body.getRecords().get().get(0).getTokens().get()); + Assert.assertEquals(tokens, body.getRecords().get(0).getAdditionalProperties().get("tokens")); } @Test @@ -315,13 +317,13 @@ public void testGetInsertRequestBody_withUpsertAtRequestLevel() { VaultConfig config = new VaultConfig(); config.setVaultId("vault123"); - V1InsertRequest body = Utils.getInsertRequestBody(request, config); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getInsertRequestBody(request, config); // Request-level upsert stays on the envelope; it is not copied onto the records. - Assert.assertFalse(body.getRecords().get().get(0).getUpsert().isPresent()); + Assert.assertFalse(body.getRecords().get(0).getUpsert().isPresent()); Assert.assertTrue(body.getUpsert().isPresent()); - Assert.assertEquals(Collections.singletonList("email"), body.getUpsert().get().getUniqueColumns().get()); - Assert.assertEquals(FlowEnumUpdateType.UPDATE, body.getUpsert().get().getUpdateType().get()); + Assert.assertEquals(Collections.singletonList("email"), body.getUpsert().get().getUniqueColumns()); + Assert.assertEquals(UpsertUpdateType.UPDATE, body.getUpsert().get().getUpdateType().get()); } @Test @@ -343,11 +345,11 @@ public void testGetInsertRequestBody_withUpsertAtRecordLevel() { VaultConfig config = new VaultConfig(); config.setVaultId("vault123"); - V1InsertRequest body = Utils.getInsertRequestBody(request, config); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getInsertRequestBody(request, config); - Assert.assertEquals("table1", body.getRecords().get().get(0).getTableName().get()); - Assert.assertTrue(body.getRecords().get().get(0).getUpsert().isPresent()); - Assert.assertEquals(FlowEnumUpdateType.REPLACE, body.getRecords().get().get(0).getUpsert().get().getUpdateType().get()); + Assert.assertEquals("table1", body.getRecords().get(0).getTableName().get()); + Assert.assertTrue(body.getRecords().get(0).getUpsert().isPresent()); + Assert.assertEquals(UpsertUpdateType.REPLACE, body.getRecords().get(0).getUpsert().get().getUpdateType().get()); } // ── formatInsertResponse (unary) ────────────────────────────────────────── @@ -356,9 +358,9 @@ public void testGetInsertRequestBody_withUpsertAtRecordLevel() { public void testFormatInsertResponse_successRecord() { Map tokens = new HashMap<>(); tokens.put("name", "tok-abc"); - V1RecordResponseObject record = V1RecordResponseObject.builder() + RecordResponseObject record = RecordResponseObject.builder().httpCode(200) .tableName("table1").skyflowId("sky-id-1").tokens(tokens).build(); - V1InsertResponse response = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); + com.skyflow.generated.rest.types.InsertResponse response = com.skyflow.generated.rest.types.InsertResponse.builder().records(Collections.singletonList(record)).build(); InsertResponse formatted = Utils.formatInsertResponse(response, new HashMap<>()); @@ -371,8 +373,8 @@ public void testFormatInsertResponse_successRecord() { @Test public void testFormatInsertResponse_errorRecordDefaultsHttpCode500() { - V1RecordResponseObject record = V1RecordResponseObject.builder().error("failed").build(); - V1InsertResponse response = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); + RecordResponseObject record = RecordResponseObject.builder().httpCode(500).error("failed").build(); + com.skyflow.generated.rest.types.InsertResponse response = com.skyflow.generated.rest.types.InsertResponse.builder().records(Collections.singletonList(record)).build(); InsertResponse formatted = Utils.formatInsertResponse(response, new HashMap<>()); @@ -390,9 +392,9 @@ public void testFormatInsertResponse_nullResponseReturnsEmptyRecords() { public void testFormatInsertResponse_requestIdOnlyPopulatedOnError() { Map> headers = new HashMap<>(); headers.put(Constants.REQUEST_ID_HEADER_KEY, Collections.singletonList("req-insert-1")); - V1RecordResponseObject success = V1RecordResponseObject.builder().skyflowId("sky-id-1").build(); - V1RecordResponseObject failure = V1RecordResponseObject.builder().error("failed").build(); - V1InsertResponse response = V1InsertResponse.builder().records(Arrays.asList(success, failure)).build(); + RecordResponseObject success = RecordResponseObject.builder().httpCode(200).skyflowId("sky-id-1").build(); + RecordResponseObject failure = RecordResponseObject.builder().httpCode(500).error("failed").build(); + com.skyflow.generated.rest.types.InsertResponse response = com.skyflow.generated.rest.types.InsertResponse.builder().records(Arrays.asList(success, failure)).build(); InsertResponse formatted = Utils.formatInsertResponse(response, headers); @@ -407,10 +409,10 @@ public void testGetDetokenizeRequestBody_buildsCorrectRequest() { List tokens = Collections.singletonList("tok-1"); DetokenizeRequest request = DetokenizeRequest.builder().tokens(tokens).build(); - V1FlowDetokenizeRequest body = Utils.getDetokenizeRequestBody(request, "vault123"); + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest body = Utils.getDetokenizeRequestBody(request, "vault123"); - Assert.assertEquals("vault123", body.getVaultId().get()); - Assert.assertEquals(tokens, body.getTokens().get()); + Assert.assertEquals("vault123", body.getVaultId()); + Assert.assertEquals(tokens, body.getTokens()); Assert.assertFalse(body.getTokenGroupRedactions().isPresent()); } @@ -422,7 +424,7 @@ public void testGetDetokenizeRequestBody_withTokenGroupRedactions() { TokenGroupRedactions.builder().tokenGroupName("group1").redaction("MASKED").build())) .build(); - V1FlowDetokenizeRequest body = Utils.getDetokenizeRequestBody(request, "vault123"); + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest body = Utils.getDetokenizeRequestBody(request, "vault123"); Assert.assertEquals(1, body.getTokenGroupRedactions().get().size()); Assert.assertEquals("group1", body.getTokenGroupRedactions().get().get(0).getTokenGroupName().get()); @@ -434,9 +436,9 @@ public void testFormatDetokenizeResponse_successRecord() { Map metadata = new HashMap<>(); metadata.put("skyflowId", "sky-1"); metadata.put("tableName", "table1"); - V1FlowDetokenizeResponseObject record = V1FlowDetokenizeResponseObject.builder() - .token("tok-1").value("john@example.com").tokenGroupName("group1").metadata(metadata).build(); - V1FlowDetokenizeResponse response = V1FlowDetokenizeResponse.builder() + DetokenizeResponseObject record = DetokenizeResponseObject.builder() + .token("tok-1").value(com.skyflow.generated.rest.types.GoogleProtobufValue.of("john@example.com")).tokenGroupName("group1").metadata(metadata).build(); + com.skyflow.generated.rest.types.DetokenizeResponse response = com.skyflow.generated.rest.types.DetokenizeResponse.builder() .response(Collections.singletonList(record)).build(); DetokenizeResponse formatted = Utils.formatDetokenizeResponse(response, new HashMap<>()); @@ -459,10 +461,10 @@ public void testFormatDetokenizeResponse_nullResponseReturnsEmptyRecords() { public void testFormatDetokenizeResponse_requestIdOnlyPopulatedOnError() { Map> headers = new HashMap<>(); headers.put(Constants.REQUEST_ID_HEADER_KEY, Collections.singletonList("req-detok-1")); - V1FlowDetokenizeResponseObject success = V1FlowDetokenizeResponseObject.builder().token("tok-1").build(); - V1FlowDetokenizeResponseObject failure = V1FlowDetokenizeResponseObject.builder() + DetokenizeResponseObject success = DetokenizeResponseObject.builder().token("tok-1").build(); + DetokenizeResponseObject failure = DetokenizeResponseObject.builder() .token("tok-2").error("failed").build(); - V1FlowDetokenizeResponse response = V1FlowDetokenizeResponse.builder() + com.skyflow.generated.rest.types.DetokenizeResponse response = com.skyflow.generated.rest.types.DetokenizeResponse.builder() .response(Arrays.asList(success, failure)).build(); DetokenizeResponse formatted = Utils.formatDetokenizeResponse(response, headers); @@ -482,12 +484,12 @@ public void testGetUpdateRequestBody_buildsCorrectRequest() { VaultConfig config = new VaultConfig(); config.setVaultId("vault123"); - V1UpdateRequest body = Utils.getUpdateRequestBody(request, config); + com.skyflow.generated.rest.resources.records.requests.UpdateRequest body = Utils.getUpdateRequestBody(request, config); - Assert.assertEquals("vault123", body.getVaultId().get()); - Assert.assertEquals("table1", body.getTableName().get()); - Assert.assertEquals("sky-1", body.getRecords().get().get(0).getSkyflowId().get()); - Assert.assertEquals(data, body.getRecords().get().get(0).getData().get()); + Assert.assertEquals("vault123", body.getVaultId()); + Assert.assertEquals("table1", body.getTableName()); + Assert.assertEquals("sky-1", body.getRecords().get(0).getSkyflowId()); + Assert.assertEquals(data, body.getRecords().get(0).getData()); Assert.assertFalse(body.getUpdateType().isPresent()); } @@ -500,10 +502,10 @@ public void testGetUpdateRequestBody_withRequestLevelUpdateTypeAndRecordTableNam VaultConfig config = new VaultConfig(); config.setVaultId("vault123"); - V1UpdateRequest body = Utils.getUpdateRequestBody(request, config); + com.skyflow.generated.rest.resources.records.requests.UpdateRequest body = Utils.getUpdateRequestBody(request, config); - Assert.assertEquals(FlowEnumUpdateType.REPLACE, body.getUpdateType().get()); - Assert.assertEquals("table2", body.getRecords().get().get(0).getTableName().get()); + Assert.assertEquals(com.skyflow.generated.rest.resources.records.types.UpdateRequestUpdateType.REPLACE, body.getUpdateType().get()); + Assert.assertEquals("table2", body.getRecords().get(0).getTableName().get()); } @Test @@ -516,16 +518,16 @@ public void testGetUpdateRequestBody_withTokens() { VaultConfig config = new VaultConfig(); config.setVaultId("vault123"); - V1UpdateRequest body = Utils.getUpdateRequestBody(request, config); + com.skyflow.generated.rest.resources.records.requests.UpdateRequest body = Utils.getUpdateRequestBody(request, config); - Assert.assertEquals(tokens, body.getRecords().get().get(0).getTokens().get()); + Assert.assertEquals(tokens, body.getRecords().get(0).getAdditionalProperties().get("tokens")); } @Test public void testFormatUpdateResponse_successRecord() { - V1RecordResponseObject record = V1RecordResponseObject.builder() + RecordResponseObject record = RecordResponseObject.builder().httpCode(200) .tableName("table1").skyflowId("sky-1").build(); - V1UpdateResponse response = V1UpdateResponse.builder().records(Collections.singletonList(record)).build(); + com.skyflow.generated.rest.types.UpdateResponse response = com.skyflow.generated.rest.types.UpdateResponse.builder().records(Collections.singletonList(record)).build(); UpdateResponse formatted = Utils.formatUpdateResponse(response, new HashMap<>()); @@ -545,9 +547,9 @@ public void testFormatUpdateResponse_nullResponseReturnsEmptyRecords() { public void testFormatUpdateResponse_requestIdOnlyPopulatedOnError() { Map> headers = new HashMap<>(); headers.put(Constants.REQUEST_ID_HEADER_KEY, Collections.singletonList("req-update-1")); - V1RecordResponseObject success = V1RecordResponseObject.builder().skyflowId("sky-id-1").build(); - V1RecordResponseObject failure = V1RecordResponseObject.builder().error("failed").build(); - V1UpdateResponse response = V1UpdateResponse.builder().records(Arrays.asList(success, failure)).build(); + RecordResponseObject success = RecordResponseObject.builder().httpCode(200).skyflowId("sky-id-1").build(); + RecordResponseObject failure = RecordResponseObject.builder().httpCode(500).error("failed").build(); + com.skyflow.generated.rest.types.UpdateResponse response = com.skyflow.generated.rest.types.UpdateResponse.builder().records(Arrays.asList(success, failure)).build(); UpdateResponse formatted = Utils.formatUpdateResponse(response, headers); @@ -573,13 +575,13 @@ public void testGetGetRequestBody_singleTableMode() { VaultConfig config = new VaultConfig(); config.setVaultId("vault123"); - V1GetRequest body = Utils.getGetRequestBody(request, config); + com.skyflow.generated.rest.resources.records.requests.GetRequest body = Utils.getGetRequestBody(request, config); - Assert.assertEquals("vault123", body.getVaultId().get()); + Assert.assertEquals("vault123", body.getVaultId()); Assert.assertEquals("table1", body.getTableName().get()); Assert.assertEquals(Collections.singletonList("id1"), body.getSkyflowIDs().get()); Assert.assertEquals(Collections.singletonList("name"), body.getColumns().get()); - Assert.assertEquals("email", body.getColumnRedactions().get().get(0).getColumnName().get()); + Assert.assertEquals("email", body.getColumnRedactions().get().get(0).getColumnName()); Assert.assertEquals(Integer.valueOf(10), body.getLimit().get()); Assert.assertEquals(Integer.valueOf(5), body.getOffset().get()); Assert.assertFalse(body.getRecords().isPresent()); @@ -593,20 +595,20 @@ public void testGetGetRequestBody_multiTableModeIgnoresSingleTableFields() { VaultConfig config = new VaultConfig(); config.setVaultId("vault123"); - V1GetRequest body = Utils.getGetRequestBody(request, config); + com.skyflow.generated.rest.resources.records.requests.GetRequest body = Utils.getGetRequestBody(request, config); Assert.assertTrue(body.getRecords().isPresent()); Assert.assertEquals(1, body.getRecords().get().size()); - Assert.assertEquals("table2", body.getRecords().get().get(0).getTableName().get()); - Assert.assertEquals(Collections.singletonList("id2"), body.getRecords().get().get(0).getSkyflowIDs().get()); + Assert.assertEquals("table2", body.getRecords().get().get(0).getTableName()); + Assert.assertEquals(Collections.singletonList("id2"), body.getRecords().get().get(0).getSkyflowIDs()); Assert.assertFalse(body.getTableName().isPresent()); } @Test public void testFormatGetResponse_successRecord() { - V1RecordResponseObject record = V1RecordResponseObject.builder() + RecordResponseObject record = RecordResponseObject.builder().httpCode(200) .tableName("table1").skyflowId("sky-1").build(); - V1GetResponse response = V1GetResponse.builder().records(Collections.singletonList(record)).build(); + com.skyflow.generated.rest.types.GetResponse response = com.skyflow.generated.rest.types.GetResponse.builder().records(Collections.singletonList(record)).build(); GetResponse formatted = Utils.formatGetResponse(response, new HashMap<>()); @@ -625,9 +627,9 @@ public void testFormatGetResponse_nullResponseReturnsEmptyRecords() { public void testFormatGetResponse_requestIdOnlyPopulatedOnError() { Map> headers = new HashMap<>(); headers.put(Constants.REQUEST_ID_HEADER_KEY, Collections.singletonList("req-get-1")); - V1RecordResponseObject success = V1RecordResponseObject.builder().skyflowId("sky-id-1").build(); - V1RecordResponseObject failure = V1RecordResponseObject.builder().error("failed").build(); - V1GetResponse response = V1GetResponse.builder().records(Arrays.asList(success, failure)).build(); + RecordResponseObject success = RecordResponseObject.builder().httpCode(200).skyflowId("sky-id-1").build(); + RecordResponseObject failure = RecordResponseObject.builder().httpCode(500).error("failed").build(); + com.skyflow.generated.rest.types.GetResponse response = com.skyflow.generated.rest.types.GetResponse.builder().records(Arrays.asList(success, failure)).build(); GetResponse formatted = Utils.formatGetResponse(response, headers); @@ -643,9 +645,9 @@ public void testGetDeleteRequestBody_withIds() { VaultConfig config = new VaultConfig(); config.setVaultId("vault123"); - V1DeleteRequest body = Utils.getDeleteRequestBody(request, config); + com.skyflow.generated.rest.resources.records.requests.DeleteRequest body = Utils.getDeleteRequestBody(request, config); - Assert.assertEquals("vault123", body.getVaultId().get()); + Assert.assertEquals("vault123", body.getVaultId()); Assert.assertEquals("table1", body.getTableName().get()); Assert.assertEquals(Collections.singletonList("id1"), body.getSkyflowIDs().get()); Assert.assertFalse(body.getUniqueValues().isPresent()); @@ -660,17 +662,17 @@ public void testGetDeleteRequestBody_withUniqueValues() { VaultConfig config = new VaultConfig(); config.setVaultId("vault123"); - V1DeleteRequest body = Utils.getDeleteRequestBody(request, config); + com.skyflow.generated.rest.resources.records.requests.DeleteRequest body = Utils.getDeleteRequestBody(request, config); - Assert.assertEquals(uniqueValue, body.getUniqueValues().get().get(0).getData().get()); + Assert.assertEquals(uniqueValue, body.getUniqueValues().get().get(0).getData()); Assert.assertFalse(body.getSkyflowIDs().isPresent()); } @Test public void testFormatDeleteResponse_successAndErrorRecords() { - V1DeleteResponseObject success = V1DeleteResponseObject.builder().skyflowId("sky-1").httpCode(200).build(); - V1DeleteResponseObject failure = V1DeleteResponseObject.builder().error("not found").httpCode(404).build(); - V1DeleteResponse response = V1DeleteResponse.builder().records(Arrays.asList(success, failure)).build(); + DeleteResponseObject success = DeleteResponseObject.builder().skyflowId("sky-1").httpCode(200).build(); + DeleteResponseObject failure = DeleteResponseObject.builder().skyflowId("").httpCode(404).error("not found").build(); + com.skyflow.generated.rest.types.DeleteResponse response = com.skyflow.generated.rest.types.DeleteResponse.builder().records(Arrays.asList(success, failure)).build(); DeleteResponse formatted = Utils.formatDeleteResponse(response, new HashMap<>()); @@ -692,9 +694,9 @@ public void testFormatDeleteResponse_nullResponseReturnsEmptyRecords() { public void testFormatDeleteResponse_requestIdOnlyPopulatedOnError() { Map> headers = new HashMap<>(); headers.put(Constants.REQUEST_ID_HEADER_KEY, Collections.singletonList("req-delete-1")); - V1DeleteResponseObject success = V1DeleteResponseObject.builder().skyflowId("sky-1").httpCode(200).build(); - V1DeleteResponseObject failure = V1DeleteResponseObject.builder().error("not found").httpCode(404).build(); - V1DeleteResponse response = V1DeleteResponse.builder().records(Arrays.asList(success, failure)).build(); + DeleteResponseObject success = DeleteResponseObject.builder().skyflowId("sky-1").httpCode(200).build(); + DeleteResponseObject failure = DeleteResponseObject.builder().skyflowId("").httpCode(404).error("not found").build(); + com.skyflow.generated.rest.types.DeleteResponse response = com.skyflow.generated.rest.types.DeleteResponse.builder().records(Arrays.asList(success, failure)).build(); DeleteResponse formatted = Utils.formatDeleteResponse(response, headers); @@ -702,6 +704,214 @@ public void testFormatDeleteResponse_requestIdOnlyPopulatedOnError() { Assert.assertEquals("req-delete-1", formatted.getRecords().get(1).getRequestId()); } + // ── getQueryRequestBody / formatQueryResponse ───────────────────────────── + + @Test + public void testGetQueryRequestBody_mapsVaultIdAndQuery() { + QueryRequest request = QueryRequest.builder().query("SELECT * FROM table1 LIMIT 25 OFFSET 25").build(); + + ExecuteQueryRequest body = Utils.getQueryRequestBody(request, "vault123"); + + Assert.assertEquals("vault123", body.getVaultId()); + Assert.assertEquals("SELECT * FROM table1 LIMIT 25 OFFSET 25", body.getQuery()); + } + + @Test + public void testFormatQueryResponse_rowsMetadataAndRequestId() { + Map> headers = new HashMap<>(); + headers.put(Constants.REQUEST_ID_HEADER_KEY, Collections.singletonList("req-query-1")); + Map row1 = new LinkedHashMap<>(); + row1.put("skyflow_id", "sky-1"); + row1.put("name", "john"); + Map row2 = new LinkedHashMap<>(); + row2.put("skyflow_id", "sky-2"); + row2.put("name", "jane"); + ExecuteQueryResponse response = ExecuteQueryResponse.builder() + .records(Arrays.asList( + ExecuteQueryRecordResponse.builder().data(row1).build(), + ExecuteQueryRecordResponse.builder().data(row2).build())) + .metadata(ExecuteQueryResponseMetadata.builder().columns(Arrays.asList("skyflow_id", "name")).build()) + .build(); + + QueryResponse formatted = Utils.formatQueryResponse(response, headers); + + Assert.assertEquals(2, formatted.getFields().size()); + Assert.assertEquals(row1, formatted.getFields().get(0)); + Assert.assertEquals(row2, formatted.getFields().get(1)); + Assert.assertNull(formatted.getErrors()); + Assert.assertEquals(Arrays.asList("skyflow_id", "name"), formatted.getMetadata().getColumns()); + // call-level: set even though nothing failed + Assert.assertEquals("req-query-1", formatted.getRequestId()); + } + + @Test + public void testFormatQueryResponse_preservesColumnOrderOfEachRow() { + Map row = new LinkedHashMap<>(); + row.put("zeta", 1); + row.put("alpha", 2); + row.put("mid", 3); + ExecuteQueryResponse response = ExecuteQueryResponse.builder() + .records(Collections.singletonList(ExecuteQueryRecordResponse.builder().data(row).build())) + .build(); + + QueryResponse formatted = Utils.formatQueryResponse(response, new HashMap<>()); + + Assert.assertEquals(Arrays.asList("zeta", "alpha", "mid"), + new ArrayList<>(formatted.getFields().get(0).keySet())); + } + + @Test + public void testFormatQueryResponse_recordWithoutDataBecomesEmptyRow() { + ExecuteQueryResponse response = ExecuteQueryResponse.builder() + .records(Collections.singletonList(ExecuteQueryRecordResponse.builder().build())) + .build(); + + QueryResponse formatted = Utils.formatQueryResponse(response, new HashMap<>()); + + Assert.assertEquals(1, formatted.getFields().size()); + Assert.assertTrue(formatted.getFields().get(0).isEmpty()); + } + + @Test + public void testFormatQueryResponse_nullResponseReturnsEmptyFieldsAndNonNullMetadata() { + QueryResponse formatted = Utils.formatQueryResponse(null, null); + + Assert.assertTrue(formatted.getFields().isEmpty()); + Assert.assertNull(formatted.getErrors()); + Assert.assertNotNull(formatted.getMetadata()); + Assert.assertNull(formatted.getMetadata().getColumns()); + Assert.assertNull(formatted.getRequestId()); + } + + @Test + public void testFormatQueryResponse_metadataWithoutColumns() { + ExecuteQueryResponse response = ExecuteQueryResponse.builder() + .metadata(ExecuteQueryResponseMetadata.builder().build()) + .build(); + + QueryResponse formatted = Utils.formatQueryResponse(response, new HashMap<>()); + + Assert.assertTrue(formatted.getFields().isEmpty()); + Assert.assertNull(formatted.getMetadata().getColumns()); + } + + // ── getGetTokensRequestBody / formatGetTokensResponse ───────────────────── + + @Test + public void testGetGetTokensRequestBody_mapsEveryRecordInOrder() { + GetTokensRequest request = GetTokensRequest.builder() + .records(Arrays.asList( + GetTokensRequestRecord.builder().value("john@example.com").tokenGroupName("det_email").build(), + GetTokensRequestRecord.builder().value(42).tokenGroupName("det_number").build())) + .build(); + + GetTokensFromValuesRequest body = Utils.getGetTokensRequestBody(request, "vault123"); + + Assert.assertEquals("vault123", body.getVaultId()); + List records = body.getRecords(); + Assert.assertEquals(2, records.size()); + Assert.assertEquals("john@example.com", records.get(0).getValue().get()); + Assert.assertEquals("det_email", records.get(0).getTokenGroupName()); + Assert.assertEquals(42, records.get(1).getValue().get()); + Assert.assertEquals("det_number", records.get(1).getTokenGroupName()); + } + + @Test + public void testFormatGetTokensResponse_successAndErrorRecords() { + Map> headers = new HashMap<>(); + headers.put(Constants.REQUEST_ID_HEADER_KEY, Collections.singletonList("req-gettokens-1")); + TokenizeResponseObject success = TokenizeResponseObject.builder().token("tok-1") + .value(com.skyflow.generated.rest.types.GoogleProtobufValue.of("john@example.com")).tokenGroupName("det_group").httpCode(200).build(); + TokenizeResponseObject failure = TokenizeResponseObject.builder().token("") + .value(com.skyflow.generated.rest.types.GoogleProtobufValue.of("unknown@example.com")).tokenGroupName("det_group").error("Token not found.").httpCode(404).build(); + GetTokensFromValuesResponse response = GetTokensFromValuesResponse.builder() + .records(Arrays.asList(success, failure)).build(); + + GetTokensResponse formatted = Utils.formatGetTokensResponse(response, headers); + + Assert.assertEquals(2, formatted.getRecords().size()); + Map first = formatted.getRecords().get(0); + Assert.assertEquals("john@example.com", first.get("value")); + Assert.assertEquals("det_group", first.get("tokenGroupName")); + Assert.assertEquals("tok-1", first.get("token")); + Assert.assertEquals(200, first.get("httpCode")); + Assert.assertNull(first.get("error")); + Assert.assertNull(first.get("requestId")); + Map second = formatted.getRecords().get(1); + Assert.assertEquals("unknown@example.com", second.get("value")); + Assert.assertEquals("", second.get("token")); + Assert.assertEquals(404, second.get("httpCode")); + Assert.assertEquals("Token not found.", second.get("error")); + Assert.assertEquals("req-gettokens-1", second.get("requestId")); + } + + @Test + public void testFormatGetTokensResponse_recordMapKeysInDocumentedOrder() { + TokenizeResponseObject record = TokenizeResponseObject.builder().token("t") + .value(com.skyflow.generated.rest.types.GoogleProtobufValue.of("v")).tokenGroupName("g").build(); + GetTokensFromValuesResponse response = GetTokensFromValuesResponse.builder() + .records(Collections.singletonList(record)).build(); + + GetTokensResponse formatted = Utils.formatGetTokensResponse(response, new HashMap<>()); + + Assert.assertEquals(Arrays.asList("value", "tokenGroupName", "token", "httpCode", "error", "requestId"), + new ArrayList<>(formatted.getRecords().get(0).keySet())); + } + + @Test + public void testFormatGetTokensResponse_emptyTokenKeptEmptyErrorNormalisedToNull() { + // the API sends "" for a token or error that does not apply; the token stays "" (matching + // the python SDK) while an empty error still reads as null + TokenizeResponseObject record = TokenizeResponseObject.builder().token("") + .value(com.skyflow.generated.rest.types.GoogleProtobufValue.of("v")).tokenGroupName("g").error("").httpCode(200).build(); + GetTokensFromValuesResponse response = GetTokensFromValuesResponse.builder() + .records(Collections.singletonList(record)).build(); + + GetTokensResponse formatted = Utils.formatGetTokensResponse(response, new HashMap<>()); + + Assert.assertEquals("", formatted.getRecords().get(0).get("token")); + Assert.assertNull(formatted.getRecords().get(0).get("error")); + Assert.assertNull(formatted.getRecords().get(0).get("requestId")); + } + + @Test + public void testFormatGetTokensResponse_missingHttpCodeDefaultsByOutcome() { + TokenizeResponseObject success = TokenizeResponseObject.builder().token("tok-a").value(com.skyflow.generated.rest.types.GoogleProtobufValue.of("a")).tokenGroupName("").build(); + TokenizeResponseObject failure = TokenizeResponseObject.builder().token("").value(com.skyflow.generated.rest.types.GoogleProtobufValue.of("b")).tokenGroupName("").error("boom").build(); + GetTokensFromValuesResponse response = GetTokensFromValuesResponse.builder() + .records(Arrays.asList(success, failure)).build(); + + GetTokensResponse formatted = Utils.formatGetTokensResponse(response, new HashMap<>()); + + Assert.assertEquals(200, formatted.getRecords().get(0).get("httpCode")); + Assert.assertEquals(500, formatted.getRecords().get(1).get("httpCode")); + } + + @Test + public void testFormatGetTokensResponse_nonStringValueEchoedAsIs() { + TokenizeResponseObject record = TokenizeResponseObject.builder().token("tok-42") + .value(com.skyflow.generated.rest.types.GoogleProtobufValue.of(42)).tokenGroupName("det_number").build(); + GetTokensFromValuesResponse response = GetTokensFromValuesResponse.builder() + .records(Collections.singletonList(record)).build(); + + GetTokensResponse formatted = Utils.formatGetTokensResponse(response, new HashMap<>()); + + Assert.assertEquals(42, formatted.getRecords().get(0).get("value")); + } + + @Test + public void testFormatGetTokensResponse_nullResponseReturnsEmptyRecords() { + GetTokensResponse formatted = Utils.formatGetTokensResponse(null, new HashMap<>()); + Assert.assertTrue(formatted.getRecords().isEmpty()); + } + + @Test + public void testFormatGetTokensResponse_absentRecordsReturnsEmptyRecords() { + GetTokensResponse formatted = Utils.formatGetTokensResponse( + GetTokensFromValuesResponse.builder().build(), new HashMap<>()); + Assert.assertTrue(formatted.getRecords().isEmpty()); + } + // ── getBulkInsertRequestBody (bulk overload) ────────────────────────────── @Test @@ -715,13 +925,13 @@ public void testGetBulkInsertRequestBody_bulk_buildsCorrectRequest() { VaultConfig config = new VaultConfig(); config.setVaultId("vault123"); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, config); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, config); - Assert.assertEquals("vault123", body.getVaultId().get()); - Assert.assertEquals("table1", body.getTableName().get()); - Assert.assertEquals(1, body.getRecords().get().size()); - Assert.assertFalse(body.getRecords().get().get(0).getTableName().isPresent()); - Assert.assertEquals(data, body.getRecords().get().get(0).getData().get()); + Assert.assertEquals("vault123", body.getVaultId()); + Assert.assertEquals("table1", body.getTableName()); + Assert.assertEquals(1, body.getRecords().size()); + Assert.assertFalse(body.getRecords().get(0).getTableName().isPresent()); + Assert.assertEquals(data, body.getRecords().get(0).getData()); } @Test @@ -742,13 +952,13 @@ public void testGetBulkInsertRequestBody_bulk_withUpsertAtRequestLevel() { VaultConfig config = new VaultConfig(); config.setVaultId("vault123"); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, config); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, config); // Request-level upsert stays on the envelope; it is not copied onto the records. - Assert.assertFalse(body.getRecords().get().get(0).getUpsert().isPresent()); + Assert.assertFalse(body.getRecords().get(0).getUpsert().isPresent()); Assert.assertTrue(body.getUpsert().isPresent()); - Assert.assertEquals(Collections.singletonList("email"), body.getUpsert().get().getUniqueColumns().get()); - Assert.assertEquals(FlowEnumUpdateType.UPDATE, body.getUpsert().get().getUpdateType().get()); + Assert.assertEquals(Collections.singletonList("email"), body.getUpsert().get().getUniqueColumns()); + Assert.assertEquals(UpsertUpdateType.UPDATE, body.getUpsert().get().getUpdateType().get()); } @Test @@ -769,11 +979,11 @@ public void testGetBulkInsertRequestBody_bulk_withUpsertAtRecordLevel() { VaultConfig config = new VaultConfig(); config.setVaultId("vault123"); - V1InsertRequest body = Utils.getBulkInsertRequestBody(request, config); + com.skyflow.generated.rest.resources.records.requests.InsertRequest body = Utils.getBulkInsertRequestBody(request, config); - Assert.assertEquals("table1", body.getRecords().get().get(0).getTableName().get()); - Assert.assertTrue(body.getRecords().get().get(0).getUpsert().isPresent()); - Assert.assertEquals(FlowEnumUpdateType.REPLACE, body.getRecords().get().get(0).getUpsert().get().getUpdateType().get()); + Assert.assertEquals("table1", body.getRecords().get(0).getTableName().get()); + Assert.assertTrue(body.getRecords().get(0).getUpsert().isPresent()); + Assert.assertEquals(UpsertUpdateType.REPLACE, body.getRecords().get(0).getUpsert().get().getUpdateType().get()); } // ── getBulkDetokenizeRequestBody ────────────────────────────────────────── @@ -784,10 +994,10 @@ public void testGetBulkDetokenizeRequestBody_buildsCorrectRequest() { .tokens(Arrays.asList("token1", "token2")) .build(); - V1FlowDetokenizeRequest body = Utils.getBulkDetokenizeRequestBody(request, "vault123"); + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest body = Utils.getBulkDetokenizeRequestBody(request, "vault123"); - Assert.assertEquals("vault123", body.getVaultId().get()); - Assert.assertEquals(Arrays.asList("token1", "token2"), body.getTokens().get()); + Assert.assertEquals("vault123", body.getVaultId()); + Assert.assertEquals(Arrays.asList("token1", "token2"), body.getTokens()); Assert.assertFalse(body.getTokenGroupRedactions().isPresent()); } @@ -802,7 +1012,7 @@ public void testGetBulkDetokenizeRequestBody_withTokenGroupRedactions() { .tokenGroupRedactions(Collections.singletonList(redaction)) .build(); - V1FlowDetokenizeRequest body = Utils.getBulkDetokenizeRequestBody(request, "vault123"); + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest body = Utils.getBulkDetokenizeRequestBody(request, "vault123"); Assert.assertTrue(body.getTokenGroupRedactions().isPresent()); Assert.assertEquals(1, body.getTokenGroupRedactions().get().size()); @@ -818,10 +1028,10 @@ public void testGetBulkDeleteTokensRequestBody_buildsCorrectRequest() { .tokens(Arrays.asList("token1", "token2")) .build(); - V1FlowDeleteTokenRequest body = Utils.getBulkDeleteTokensRequestBody(request, "vault123"); + DeleteTokenRequest body = Utils.getBulkDeleteTokensRequestBody(request, "vault123"); - Assert.assertEquals("vault123", body.getVaultId().get()); - Assert.assertEquals(Arrays.asList("token1", "token2"), body.getTokens().get()); + Assert.assertEquals("vault123", body.getVaultId()); + Assert.assertEquals(Arrays.asList("token1", "token2"), body.getTokens()); } // ── getBulkTokenizeRequestBody ───────────────────────────────────────────── @@ -834,13 +1044,13 @@ public void testGetBulkTokenizeRequestBody_buildsCorrectRequest() { .tokenGroupNames(Collections.singletonList("group1")) .build()); - V1FlowTokenizeRequest body = Utils.getBulkTokenizeRequestBody(records, "vault123"); + com.skyflow.generated.rest.resources.tokens.requests.TokenizeRequest body = Utils.getBulkTokenizeRequestBody(records, "vault123"); - Assert.assertEquals("vault123", body.getVaultId().get()); - Assert.assertEquals(1, body.getData().get().size()); - Assert.assertEquals("value1", body.getData().get().get(0).getValue().get()); - Assert.assertEquals(Collections.singletonList("group1"), body.getData().get().get(0).getTokenGroupNames().get()); - Assert.assertFalse(body.getData().get().get(0).getToken().isPresent()); + Assert.assertEquals("vault123", body.getVaultId()); + Assert.assertEquals(1, body.getData().size()); + Assert.assertEquals("value1", body.getData().get(0).getValue().get()); + Assert.assertEquals(Collections.singletonList("group1"), body.getData().get(0).getTokenGroupNames()); + Assert.assertFalse(body.getData().get(0).getToken().isPresent()); } @Test @@ -852,21 +1062,21 @@ public void testGetBulkTokenizeRequestBody_carriesByotToken() { .tokenGroupNames(Collections.singletonList("group1")) .build()); - V1FlowTokenizeRequest body = Utils.getBulkTokenizeRequestBody(records, "vault123"); + com.skyflow.generated.rest.resources.tokens.requests.TokenizeRequest body = Utils.getBulkTokenizeRequestBody(records, "vault123"); - Assert.assertEquals("my-own-token", body.getData().get().get(0).getToken().get()); + Assert.assertEquals("my-own-token", body.getData().get(0).getToken().get().get()); } // ── createBulkInsertBatches ──────────────────────────────────────────────── @Test public void testCreateBulkInsertBatches_splitsEvenly() { - List records = new ArrayList<>(); + List records = new ArrayList<>(); for (int i = 0; i < 4; i++) { - records.add(V1InsertRecordData.builder().data(new HashMap<>()).build()); + records.add(InsertRecordData.builder().data(new HashMap<>()).build()); } - List> batches = Utils.createBulkInsertBatches(records, 2); + List> batches = Utils.createBulkInsertBatches(records, 2); Assert.assertEquals(2, batches.size()); Assert.assertEquals(2, batches.get(0).size()); @@ -875,12 +1085,12 @@ public void testCreateBulkInsertBatches_splitsEvenly() { @Test public void testCreateBulkInsertBatches_splitsWithRemainder() { - List records = new ArrayList<>(); + List records = new ArrayList<>(); for (int i = 0; i < 5; i++) { - records.add(V1InsertRecordData.builder().data(new HashMap<>()).build()); + records.add(InsertRecordData.builder().data(new HashMap<>()).build()); } - List> batches = Utils.createBulkInsertBatches(records, 2); + List> batches = Utils.createBulkInsertBatches(records, 2); Assert.assertEquals(3, batches.size()); Assert.assertEquals(1, batches.get(2).size()); @@ -890,33 +1100,33 @@ public void testCreateBulkInsertBatches_splitsWithRemainder() { @Test public void testCreateBulkDetokenizeBatches_splitsTokens() { - V1FlowDetokenizeRequest request = V1FlowDetokenizeRequest.builder() + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest request = com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest.builder() .vaultId("vault123") .tokens(Arrays.asList("t1", "t2", "t3")) .build(); - List batches = Utils.createBulkDetokenizeBatches(request, 2); + List batches = Utils.createBulkDetokenizeBatches(request, 2); Assert.assertEquals(2, batches.size()); - Assert.assertEquals(Arrays.asList("t1", "t2"), batches.get(0).getTokens().get()); - Assert.assertEquals(Collections.singletonList("t3"), batches.get(1).getTokens().get()); - Assert.assertEquals("vault123", batches.get(0).getVaultId().get()); + Assert.assertEquals(Arrays.asList("t1", "t2"), batches.get(0).getTokens()); + Assert.assertEquals(Collections.singletonList("t3"), batches.get(1).getTokens()); + Assert.assertEquals("vault123", batches.get(0).getVaultId()); } @Test public void testCreateBulkDetokenizeBatches_carriesTokenGroupRedactions() { - com.skyflow.generated.rest.types.V1TokenGroupRedactions redaction = - com.skyflow.generated.rest.types.V1TokenGroupRedactions.builder() + com.skyflow.generated.rest.types.TokenGroupRedactions redaction = + com.skyflow.generated.rest.types.TokenGroupRedactions.builder() .tokenGroupName("group1") .redaction("MASKED") .build(); - V1FlowDetokenizeRequest request = V1FlowDetokenizeRequest.builder() + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest request = com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest.builder() .vaultId("vault123") .tokens(Arrays.asList("t1", "t2")) .tokenGroupRedactions(Collections.singletonList(redaction)) .build(); - List batches = Utils.createBulkDetokenizeBatches(request, 5); + List batches = Utils.createBulkDetokenizeBatches(request, 5); Assert.assertEquals(1, batches.size()); Assert.assertTrue(batches.get(0).getTokenGroupRedactions().isPresent()); @@ -927,16 +1137,16 @@ public void testCreateBulkDetokenizeBatches_carriesTokenGroupRedactions() { @Test public void testCreateBulkDeleteTokensBatches_splitsTokens() { - V1FlowDeleteTokenRequest request = V1FlowDeleteTokenRequest.builder() + DeleteTokenRequest request = DeleteTokenRequest.builder() .vaultId("vault123") .tokens(Arrays.asList("t1", "t2", "t3")) .build(); - List batches = Utils.createBulkDeleteTokensBatches(request, 2); + List batches = Utils.createBulkDeleteTokensBatches(request, 2); Assert.assertEquals(2, batches.size()); - Assert.assertEquals(Arrays.asList("t1", "t2"), batches.get(0).getTokens().get()); - Assert.assertEquals(Collections.singletonList("t3"), batches.get(1).getTokens().get()); + Assert.assertEquals(Arrays.asList("t1", "t2"), batches.get(0).getTokens()); + Assert.assertEquals(Collections.singletonList("t3"), batches.get(1).getTokens()); } // ── createBulkTokenizeBatches ────────────────────────────────────────────── @@ -1022,7 +1232,7 @@ public void testHandleBulkInsertBatchException_apiExceptionWithRecordsBody() { ApiClientApiException apiEx = new ApiClientApiException("insert failed", 409, body); RuntimeException wrapper = new RuntimeException(apiEx); - List batch = Collections.singletonList(V1InsertRecordData.builder().data(new HashMap<>()).build()); + List batch = Collections.singletonList(InsertRecordData.builder().data(new HashMap<>()).build()); List errors = Utils.handleBulkInsertBatchException(wrapper, batch, 0, 50); Assert.assertEquals(1, errors.size()); @@ -1035,9 +1245,9 @@ public void testHandleBulkInsertBatchException_apiExceptionWithNoParsableBody() ApiClientApiException apiEx = new ApiClientApiException("insert failed", 401, "unauthorized"); RuntimeException wrapper = new RuntimeException(apiEx); - List batch = Arrays.asList( - V1InsertRecordData.builder().data(new HashMap<>()).build(), - V1InsertRecordData.builder().data(new HashMap<>()).build()); + List batch = Arrays.asList( + InsertRecordData.builder().data(new HashMap<>()).build(), + InsertRecordData.builder().data(new HashMap<>()).build()); List errors = Utils.handleBulkInsertBatchException(wrapper, batch, 0, 50); Assert.assertEquals(2, errors.size()); @@ -1052,7 +1262,7 @@ public void testHandleBulkInsertBatchException_apiExceptionWithErrorKeyBody() { ApiClientApiException apiEx = new ApiClientApiException("insert failed", 401, body); RuntimeException wrapper = new RuntimeException(apiEx); - List batch = Collections.singletonList(V1InsertRecordData.builder().data(new HashMap<>()).build()); + List batch = Collections.singletonList(InsertRecordData.builder().data(new HashMap<>()).build()); List errors = Utils.handleBulkInsertBatchException(wrapper, batch, 0, 50); Assert.assertEquals(1, errors.size()); @@ -1063,7 +1273,7 @@ public void testHandleBulkInsertBatchException_apiExceptionWithErrorKeyBody() { @Test public void testHandleBulkInsertBatchException_genericException() { RuntimeException ex = new RuntimeException("boom"); - List batch = Collections.singletonList(V1InsertRecordData.builder().data(new HashMap<>()).build()); + List batch = Collections.singletonList(InsertRecordData.builder().data(new HashMap<>()).build()); List errors = Utils.handleBulkInsertBatchException(ex, batch, 1, 2); @@ -1091,8 +1301,8 @@ public void testHandleBulkInsertBatchException_recordsBodyCarriesTableAndSkyflow ApiClientApiException apiEx = new ApiClientApiException("insert failed", 409, body); RuntimeException wrapper = new RuntimeException(apiEx); - List batch = Collections.singletonList( - V1InsertRecordData.builder().data(new HashMap<>()).build()); + List batch = Collections.singletonList( + InsertRecordData.builder().data(new HashMap<>()).build()); List records = Utils.handleBulkInsertBatchException(wrapper, batch, 0, 50); Assert.assertEquals(1, records.size()); @@ -1111,8 +1321,8 @@ public void testHandleBulkInsertBatchException_recordsBodyFallsBackToUnknownErro ApiClientApiException apiEx = new ApiClientApiException("insert failed", 500, body); RuntimeException wrapper = new RuntimeException(apiEx); - List batch = Collections.singletonList( - V1InsertRecordData.builder().data(new HashMap<>()).build()); + List batch = Collections.singletonList( + InsertRecordData.builder().data(new HashMap<>()).build()); List records = Utils.handleBulkInsertBatchException(wrapper, batch, 0, 50); Assert.assertEquals(1, records.size()); @@ -1127,9 +1337,9 @@ public void testHandleBulkInsertBatchException_indexOffsetAcrossBatches() { ApiClientApiException apiEx = new ApiClientApiException("insert failed", 401, body); RuntimeException wrapper = new RuntimeException(apiEx); - List batch = Arrays.asList( - V1InsertRecordData.builder().data(new HashMap<>()).build(), - V1InsertRecordData.builder().data(new HashMap<>()).build()); + List batch = Arrays.asList( + InsertRecordData.builder().data(new HashMap<>()).build(), + InsertRecordData.builder().data(new HashMap<>()).build()); List records = Utils.handleBulkInsertBatchException(wrapper, batch, 2, 50); Assert.assertEquals(100, records.get(0).getIndex()); @@ -1140,8 +1350,8 @@ public void testHandleBulkInsertBatchException_indexOffsetAcrossBatches() { public void testHandleBulkInsertBatchException_genericExceptionHasNoRequestId() { // A non-API failure has no response headers to read a request id from. RuntimeException ex = new RuntimeException("boom"); - List batch = Collections.singletonList( - V1InsertRecordData.builder().data(new HashMap<>()).build()); + List batch = Collections.singletonList( + InsertRecordData.builder().data(new HashMap<>()).build()); List records = Utils.handleBulkInsertBatchException(ex, batch, 0, 50); @@ -1155,8 +1365,8 @@ public void testHandleBulkInsertBatchException_nonApiCauseUsesCauseMessage() { // Cause is non-null but not an ApiClientApiException: the message ladder should // pick up the cause's own message rather than the outer wrapper's. RuntimeException ex = new RuntimeException("wrapper", new IllegalStateException("inner boom")); - List batch = Collections.singletonList( - V1InsertRecordData.builder().data(new HashMap<>()).build()); + List batch = Collections.singletonList( + InsertRecordData.builder().data(new HashMap<>()).build()); List records = Utils.handleBulkInsertBatchException(ex, batch, 0, 50); @@ -1171,8 +1381,8 @@ public void testHandleBulkInsertBatchException_nonApiCauseWithNestedCauseUsesNes // down to the nested cause's toString(). RuntimeException ex = new RuntimeException("wrapper", new IllegalStateException("inner boom", new IllegalArgumentException("root cause"))); - List batch = Collections.singletonList( - V1InsertRecordData.builder().data(new HashMap<>()).build()); + List batch = Collections.singletonList( + InsertRecordData.builder().data(new HashMap<>()).build()); List records = Utils.handleBulkInsertBatchException(ex, batch, 0, 50); @@ -1323,7 +1533,7 @@ public void testCreateErrorRecords_messageKeyIsUsedWhenErrorKeyAbsent() { @Test public void testCreateInsertErrorRecord_readsSkyflowIdUsingWireCasing() { // The API returns the id as "skyflowID" — matching @JsonProperty("skyflowID") on the - // generated V1RecordResponseObject — even though the SDK exposes it as getSkyflowId(). + // generated RecordResponseObject — even though the SDK exposes it as getSkyflowId(). Map recordMap = new HashMap<>(); recordMap.put("skyflowID", "id-1"); recordMap.put("tableName", "cards"); @@ -1358,9 +1568,9 @@ public void testHandleBulkInsertBatchException_errorFieldAsObjectUsesHelper() { ApiClientApiException apiEx = new ApiClientApiException("insert failed", 404, body); RuntimeException wrapper = new RuntimeException(apiEx); - List batch = Arrays.asList( - V1InsertRecordData.builder().data(new HashMap<>()).build(), - V1InsertRecordData.builder().data(new HashMap<>()).build()); + List batch = Arrays.asList( + InsertRecordData.builder().data(new HashMap<>()).build(), + InsertRecordData.builder().data(new HashMap<>()).build()); List records = Utils.handleBulkInsertBatchException(wrapper, batch, 0, 50); Assert.assertEquals(2, records.size()); @@ -1377,8 +1587,8 @@ public void testHandleBulkInsertBatchException_errorFieldNeitherMapNorStringUses ApiClientApiException apiEx = new ApiClientApiException("insert failed", 500, body); RuntimeException wrapper = new RuntimeException(apiEx); - List batch = Collections.singletonList( - V1InsertRecordData.builder().data(new HashMap<>()).build()); + List batch = Collections.singletonList( + InsertRecordData.builder().data(new HashMap<>()).build()); List records = Utils.handleBulkInsertBatchException(wrapper, batch, 0, 50); Assert.assertEquals(1, records.size()); @@ -1392,8 +1602,8 @@ public void testHandleBulkInsertBatchException_recordsNotAListFallsBackToBatchWi ApiClientApiException apiEx = new ApiClientApiException("insert failed", 400, body); RuntimeException wrapper = new RuntimeException(apiEx); - List batch = Collections.singletonList( - V1InsertRecordData.builder().data(new HashMap<>()).build()); + List batch = Collections.singletonList( + InsertRecordData.builder().data(new HashMap<>()).build()); List records = Utils.handleBulkInsertBatchException(wrapper, batch, 0, 50); Assert.assertEquals(1, records.size()); @@ -1408,8 +1618,8 @@ public void testHandleBulkInsertBatchException_nonMapEntriesAreSkipped() { ApiClientApiException apiEx = new ApiClientApiException("insert failed", 400, body); RuntimeException wrapper = new RuntimeException(apiEx); - List batch = Collections.singletonList( - V1InsertRecordData.builder().data(new HashMap<>()).build()); + List batch = Collections.singletonList( + InsertRecordData.builder().data(new HashMap<>()).build()); List records = Utils.handleBulkInsertBatchException(wrapper, batch, 0, 50); // No entry parsed, so the batch-wide fallback fires instead. @@ -1425,8 +1635,8 @@ public void testHandleBulkInsertBatchException_bodyWithNeitherRecordsNorErrorKey ApiClientApiException apiEx = new ApiClientApiException("insert failed", 503, body); RuntimeException wrapper = new RuntimeException(apiEx); - List batch = Collections.singletonList( - V1InsertRecordData.builder().data(new HashMap<>()).build()); + List batch = Collections.singletonList( + InsertRecordData.builder().data(new HashMap<>()).build()); List records = Utils.handleBulkInsertBatchException(wrapper, batch, 0, 50); Assert.assertEquals(1, records.size()); @@ -1446,7 +1656,7 @@ public void testHandleBulkDetokenizeBatchException_apiExceptionWithResponseBody( ApiClientApiException apiEx = new ApiClientApiException("detokenize failed", 404, body); RuntimeException wrapper = new RuntimeException(apiEx); - V1FlowDetokenizeRequest batch = V1FlowDetokenizeRequest.builder() + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest batch = com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest.builder() .vaultId("vault123") .tokens(Collections.singletonList("t1")) .build(); @@ -1476,7 +1686,7 @@ public void testHandleBulkDetokenizeBatchException_responseBodyCarriesTokenAndGr ApiClientApiException apiEx = new ApiClientApiException("detokenize failed", 404, body); RuntimeException wrapper = new RuntimeException(apiEx); - V1FlowDetokenizeRequest batch = V1FlowDetokenizeRequest.builder() + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest batch = com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest.builder() .vaultId("vault123") .tokens(Collections.singletonList("tok-bad")) .build(); @@ -1498,7 +1708,7 @@ public void testHandleBulkDetokenizeBatchException_responseBodyFallsBackToUnknow ApiClientApiException apiEx = new ApiClientApiException("detokenize failed", 500, body); RuntimeException wrapper = new RuntimeException(apiEx); - V1FlowDetokenizeRequest batch = V1FlowDetokenizeRequest.builder() + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest batch = com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest.builder() .vaultId("vault123") .tokens(Collections.singletonList("t1")) .build(); @@ -1516,7 +1726,7 @@ public void testHandleBulkDetokenizeBatchException_topLevelErrorAppliesToEveryTo ApiClientApiException apiEx = new ApiClientApiException("detokenize failed", 401, body); RuntimeException wrapper = new RuntimeException(apiEx); - V1FlowDetokenizeRequest batch = V1FlowDetokenizeRequest.builder() + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest batch = com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest.builder() .vaultId("vault123") .tokens(Arrays.asList("t1", "t2")) .build(); @@ -1540,7 +1750,7 @@ public void testHandleBulkDetokenizeBatchException_errorFieldAsObjectUsesHelper( ApiClientApiException apiEx = new ApiClientApiException("detokenize failed", 404, body); RuntimeException wrapper = new RuntimeException(apiEx); - V1FlowDetokenizeRequest batch = V1FlowDetokenizeRequest.builder() + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest batch = com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest.builder() .vaultId("vault123") .tokens(Arrays.asList("t1", "t2")) .build(); @@ -1560,7 +1770,7 @@ public void testHandleBulkDetokenizeBatchException_errorFieldNeitherMapNorString ApiClientApiException apiEx = new ApiClientApiException("detokenize failed", 500, body); RuntimeException wrapper = new RuntimeException(apiEx); - V1FlowDetokenizeRequest batch = V1FlowDetokenizeRequest.builder() + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest batch = com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest.builder() .vaultId("vault123") .tokens(Collections.singletonList("t1")) .build(); @@ -1577,7 +1787,7 @@ public void testHandleBulkDetokenizeBatchException_responseNotAListFallsBackToBa ApiClientApiException apiEx = new ApiClientApiException("detokenize failed", 400, body); RuntimeException wrapper = new RuntimeException(apiEx); - V1FlowDetokenizeRequest batch = V1FlowDetokenizeRequest.builder() + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest batch = com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest.builder() .vaultId("vault123") .tokens(Collections.singletonList("t1")) .build(); @@ -1594,7 +1804,7 @@ public void testHandleBulkDetokenizeBatchException_nonMapEntriesAreSkipped() { ApiClientApiException apiEx = new ApiClientApiException("detokenize failed", 400, body); RuntimeException wrapper = new RuntimeException(apiEx); - V1FlowDetokenizeRequest batch = V1FlowDetokenizeRequest.builder() + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest batch = com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest.builder() .vaultId("vault123") .tokens(Collections.singletonList("t1")) .build(); @@ -1611,7 +1821,7 @@ public void testHandleBulkDetokenizeBatchException_batchWithNoTokensProducesNoRe ApiClientApiException apiEx = new ApiClientApiException("detokenize failed", 401, body); RuntimeException wrapper = new RuntimeException(apiEx); - V1FlowDetokenizeRequest batch = V1FlowDetokenizeRequest.builder().vaultId("vault123").build(); + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest batch = com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest.builder().vaultId("vault123").build(); List records = Utils.handleBulkDetokenizeBatchException(wrapper, batch, 0, 50); Assert.assertTrue(records.isEmpty()); @@ -1624,7 +1834,7 @@ public void testHandleBulkDetokenizeBatchException_bodyWithNeitherResponseNorErr ApiClientApiException apiEx = new ApiClientApiException("detokenize failed", 503, body); RuntimeException wrapper = new RuntimeException(apiEx); - V1FlowDetokenizeRequest batch = V1FlowDetokenizeRequest.builder() + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest batch = com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest.builder() .vaultId("vault123") .tokens(Collections.singletonList("t1")) .build(); @@ -1643,18 +1853,19 @@ public void testFormatBulkResponses_nullResponseReturnsNull() { Assert.assertNull(Utils.formatBulkDetokenizeResponse(null, 0, 50, null)); } + // The wire record lists are required now, so a body without them reads as an empty list. @Test - public void testFormatBulkResponses_absentRecordsReturnsNull() { - Assert.assertNull(Utils.formatBulkInsertResponse( - V1InsertResponse.builder().build(), 0, 50, null)); - Assert.assertNull(Utils.formatBulkDetokenizeResponse( - V1FlowDetokenizeResponse.builder().build(), 0, 50, null)); + public void testFormatBulkResponses_absentRecordsYieldsNoRecords() { + Assert.assertTrue(Utils.formatBulkInsertResponse( + com.skyflow.generated.rest.types.InsertResponse.builder().build(), 0, 50, null).getRecords().isEmpty()); + Assert.assertTrue(Utils.formatBulkDetokenizeResponse( + com.skyflow.generated.rest.types.DetokenizeResponse.builder().build(), 0, 50, null).getRecords().isEmpty()); } @Test public void testHandleBulkDetokenizeBatchException_genericExceptionHasNoRequestId() { RuntimeException ex = new RuntimeException("boom"); - V1FlowDetokenizeRequest batch = V1FlowDetokenizeRequest.builder() + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest batch = com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest.builder() .vaultId("vault123") .tokens(Collections.singletonList("t1")) .build(); @@ -1669,7 +1880,7 @@ public void testHandleBulkDetokenizeBatchException_genericExceptionHasNoRequestI @Test public void testHandleBulkDetokenizeBatchException_genericException() { RuntimeException ex = new RuntimeException("boom"); - V1FlowDetokenizeRequest batch = V1FlowDetokenizeRequest.builder() + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest batch = com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest.builder() .vaultId("vault123") .tokens(Collections.singletonList("t1")) .build(); @@ -1687,7 +1898,7 @@ public void testHandleBulkDetokenizeBatchException_nonApiCauseUsesCauseMessage() // nested cause's toString() rather than the outer wrapper's message. RuntimeException ex = new RuntimeException("wrapper", new IllegalStateException("inner boom", new IllegalArgumentException("root cause"))); - V1FlowDetokenizeRequest batch = V1FlowDetokenizeRequest.builder() + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest batch = com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest.builder() .vaultId("vault123") .tokens(Collections.singletonList("t1")) .build(); @@ -1711,7 +1922,7 @@ public void testHandleBulkDeleteTokensBatchException_apiExceptionWithTokensBody( ApiClientApiException apiEx = new ApiClientApiException("delete failed", 404, body); RuntimeException wrapper = new RuntimeException(apiEx); - V1FlowDeleteTokenRequest batch = V1FlowDeleteTokenRequest.builder() + DeleteTokenRequest batch = DeleteTokenRequest.builder() .vaultId("vault123") .tokens(Collections.singletonList("t1")) .build(); @@ -1732,7 +1943,7 @@ public void testHandleBulkDeleteTokensBatchException_apiExceptionWithErrorKeyBod ApiClientApiException apiEx = new ApiClientApiException("delete failed", 403, body); RuntimeException wrapper = new RuntimeException(apiEx); - V1FlowDeleteTokenRequest batch = V1FlowDeleteTokenRequest.builder() + DeleteTokenRequest batch = DeleteTokenRequest.builder() .vaultId("vault123") .tokens(Collections.singletonList("t1")) .build(); @@ -1747,7 +1958,7 @@ public void testHandleBulkDeleteTokensBatchException_apiExceptionWithErrorKeyBod @Test public void testHandleBulkDeleteTokensBatchException_genericException() { RuntimeException ex = new RuntimeException("boom"); - V1FlowDeleteTokenRequest batch = V1FlowDeleteTokenRequest.builder() + DeleteTokenRequest batch = DeleteTokenRequest.builder() .vaultId("vault123") .tokens(Collections.singletonList("t1")) .build(); @@ -1770,7 +1981,7 @@ public void testHandleBulkDeleteTokensBatchException_errorFieldAsObjectUsesHelpe ApiClientApiException apiEx = new ApiClientApiException("delete failed", 404, body); RuntimeException wrapper = new RuntimeException(apiEx); - V1FlowDeleteTokenRequest batch = V1FlowDeleteTokenRequest.builder() + DeleteTokenRequest batch = DeleteTokenRequest.builder() .vaultId("vault123") .tokens(Collections.singletonList("t1")) .build(); @@ -1789,7 +2000,7 @@ public void testHandleBulkDeleteTokensBatchException_errorFieldNeitherMapNorStri ApiClientApiException apiEx = new ApiClientApiException("delete failed", 500, body); RuntimeException wrapper = new RuntimeException(apiEx); - V1FlowDeleteTokenRequest batch = V1FlowDeleteTokenRequest.builder() + DeleteTokenRequest batch = DeleteTokenRequest.builder() .vaultId("vault123") .tokens(Collections.singletonList("t1")) .build(); @@ -1807,7 +2018,7 @@ public void testHandleBulkDeleteTokensBatchException_bodyWithNeitherTokensNorErr ApiClientApiException apiEx = new ApiClientApiException("delete failed", 503, body); RuntimeException wrapper = new RuntimeException(apiEx); - V1FlowDeleteTokenRequest batch = V1FlowDeleteTokenRequest.builder() + DeleteTokenRequest batch = DeleteTokenRequest.builder() .vaultId("vault123") .tokens(Arrays.asList("t1", "t2")) .build(); @@ -1829,7 +2040,7 @@ public void testHandleBulkDeleteTokensBatchException_tokensNotAListFallsBackToBa ApiClientApiException apiEx = new ApiClientApiException("delete failed", 400, body); RuntimeException wrapper = new RuntimeException(apiEx); - V1FlowDeleteTokenRequest batch = V1FlowDeleteTokenRequest.builder() + DeleteTokenRequest batch = DeleteTokenRequest.builder() .vaultId("vault123") .tokens(Collections.singletonList("t1")) .build(); @@ -1847,7 +2058,7 @@ public void testHandleBulkDeleteTokensBatchException_nonMapEntriesAreSkipped() { ApiClientApiException apiEx = new ApiClientApiException("delete failed", 400, body); RuntimeException wrapper = new RuntimeException(apiEx); - V1FlowDeleteTokenRequest batch = V1FlowDeleteTokenRequest.builder() + DeleteTokenRequest batch = DeleteTokenRequest.builder() .vaultId("vault123") .tokens(Collections.singletonList("t1")) .build(); @@ -1870,7 +2081,7 @@ public void testHandleBulkDeleteTokensBatchException_recordEchoesValueAndReadsHt ApiClientApiException apiEx = new ApiClientApiException("delete failed", 409, body); RuntimeException wrapper = new RuntimeException(apiEx); - V1FlowDeleteTokenRequest batch = V1FlowDeleteTokenRequest.builder() + DeleteTokenRequest batch = DeleteTokenRequest.builder() .vaultId("vault123") .tokens(Collections.singletonList("requested-token")) .build(); @@ -1893,7 +2104,7 @@ public void testHandleBulkDeleteTokensBatchException_recordUsesStatusCodeAndUnkn ApiClientApiException apiEx = new ApiClientApiException("delete failed", 410, body); RuntimeException wrapper = new RuntimeException(apiEx); - V1FlowDeleteTokenRequest batch = V1FlowDeleteTokenRequest.builder() + DeleteTokenRequest batch = DeleteTokenRequest.builder() .vaultId("vault123") .tokens(Collections.singletonList("t1")) .build(); @@ -2099,12 +2310,12 @@ public void testFormatBulkInsertResponse_success() { tokens.put("name", "tok-abc"); Map data = new HashMap<>(); data.put("name", "john"); - V1RecordResponseObject record = V1RecordResponseObject.builder() + RecordResponseObject record = RecordResponseObject.builder().httpCode(200) .skyflowId("sky-id-1") .tokens(tokens) .data(data) .build(); - V1InsertResponse response = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); + com.skyflow.generated.rest.types.InsertResponse response = com.skyflow.generated.rest.types.InsertResponse.builder().records(Collections.singletonList(record)).build(); BulkInsertResponse result = Utils.formatBulkInsertResponse(response, 0, 50, new HashMap<>()); @@ -2130,8 +2341,8 @@ public void testFormatBulkInsertResponse_success() { @Test public void testFormatBulkInsertResponse_indexOffsetByBatchNumber() { - V1RecordResponseObject record = V1RecordResponseObject.builder().skyflowId("sky-id-1").build(); - V1InsertResponse response = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); + RecordResponseObject record = RecordResponseObject.builder().httpCode(200).skyflowId("sky-id-1").build(); + com.skyflow.generated.rest.types.InsertResponse response = com.skyflow.generated.rest.types.InsertResponse.builder().records(Collections.singletonList(record)).build(); BulkInsertResponse result = Utils.formatBulkInsertResponse(response, 2, 50, new HashMap<>()); @@ -2140,10 +2351,10 @@ public void testFormatBulkInsertResponse_indexOffsetByBatchNumber() { @Test public void testFormatBulkInsertResponse_errorWithMissingHttpCodeDefaultsTo500() { - V1RecordResponseObject record = V1RecordResponseObject.builder() + RecordResponseObject record = RecordResponseObject.builder().httpCode(500) .error("insert failed") .build(); - V1InsertResponse response = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); + com.skyflow.generated.rest.types.InsertResponse response = com.skyflow.generated.rest.types.InsertResponse.builder().records(Collections.singletonList(record)).build(); BulkInsertResponse result = Utils.formatBulkInsertResponse(response, 0, 50, new HashMap<>()); @@ -2161,11 +2372,11 @@ public void testFormatBulkInsertResponse_nullResponseReturnsNull() { @Test public void testFormatBulkDetokenizeResponse_success() { - V1FlowDetokenizeResponseObject record = V1FlowDetokenizeResponseObject.builder() + DetokenizeResponseObject record = DetokenizeResponseObject.builder() .token("token1") - .value("secret-value") + .value(com.skyflow.generated.rest.types.GoogleProtobufValue.of("secret-value")) .build(); - V1FlowDetokenizeResponse response = V1FlowDetokenizeResponse.builder() + com.skyflow.generated.rest.types.DetokenizeResponse response = com.skyflow.generated.rest.types.DetokenizeResponse.builder() .response(Collections.singletonList(record)) .build(); @@ -2184,10 +2395,10 @@ public void testFormatBulkDetokenizeResponse_success() { @Test public void testFormatBulkDetokenizeResponse_indexOffsetByBatchNumber() { - V1FlowDetokenizeResponseObject record = V1FlowDetokenizeResponseObject.builder() + DetokenizeResponseObject record = DetokenizeResponseObject.builder() .token("token1") .build(); - V1FlowDetokenizeResponse response = V1FlowDetokenizeResponse.builder() + com.skyflow.generated.rest.types.DetokenizeResponse response = com.skyflow.generated.rest.types.DetokenizeResponse.builder() .response(Collections.singletonList(record)) .build(); @@ -2198,11 +2409,11 @@ public void testFormatBulkDetokenizeResponse_indexOffsetByBatchNumber() { @Test public void testFormatBulkDetokenizeResponse_errorWithMissingHttpCodeDefaultsTo500() { - V1FlowDetokenizeResponseObject record = V1FlowDetokenizeResponseObject.builder() + DetokenizeResponseObject record = DetokenizeResponseObject.builder() .token("token1") .error("token not found") .build(); - V1FlowDetokenizeResponse response = V1FlowDetokenizeResponse.builder() + com.skyflow.generated.rest.types.DetokenizeResponse response = com.skyflow.generated.rest.types.DetokenizeResponse.builder() .response(Collections.singletonList(record)) .build(); @@ -2214,15 +2425,15 @@ public void testFormatBulkDetokenizeResponse_errorWithMissingHttpCodeDefaultsTo5 } @Test - public void testFormatBulkDetokenizeResponse_emptyResponseReturnsNull() { - V1FlowDetokenizeResponse response = V1FlowDetokenizeResponse.builder().build(); - Assert.assertNull(Utils.formatBulkDetokenizeResponse(response, 0, 50, new HashMap<>())); + public void testFormatBulkDetokenizeResponse_emptyResponseYieldsNoRecords() { + com.skyflow.generated.rest.types.DetokenizeResponse response = com.skyflow.generated.rest.types.DetokenizeResponse.builder().build(); + Assert.assertTrue(Utils.formatBulkDetokenizeResponse(response, 0, 50, new HashMap<>()).getRecords().isEmpty()); } // ── formatBulkDeleteTokensResponse ───────────────────────────────────────── - private static V1FlowDeleteTokenRequest deleteBatchOf(String... tokens) { - return V1FlowDeleteTokenRequest.builder() + private static DeleteTokenRequest deleteBatchOf(String... tokens) { + return DeleteTokenRequest.builder() .vaultId("vault123") .tokens(Arrays.asList(tokens)) .build(); @@ -2235,10 +2446,10 @@ public void testFormatBulkDeleteTokensResponse_duplicateTokenRelaysEachRowVerbat // must reach the caller unchanged - no deduplication, no normalising one row against the other. String token = ""; String message = "DeleteToken failed. Token " + token + " is invalid. Specify a valid token."; - V1FlowDeleteTokenResponse response = V1FlowDeleteTokenResponse.builder() + DeleteTokenResponse response = DeleteTokenResponse.builder() .tokens(Arrays.asList( - V1DeleteTokenResponseObject.builder().value(token).httpCode(200).build(), - V1DeleteTokenResponseObject.builder() + DeleteTokenResponseObject.builder().value(token).httpCode(200).build(), + DeleteTokenResponseObject.builder() .value(token).error(message).httpCode(404).build())) .build(); @@ -2264,10 +2475,10 @@ public void testFormatBulkDeleteTokensResponse_duplicateTokenRelaysEachRowVerbat @Test public void testFormatBulkDeleteTokensResponse_success() { - V1DeleteTokenResponseObject record = V1DeleteTokenResponseObject.builder() + DeleteTokenResponseObject record = DeleteTokenResponseObject.builder() .value("token1") .build(); - V1FlowDeleteTokenResponse response = V1FlowDeleteTokenResponse.builder() + DeleteTokenResponse response = DeleteTokenResponse.builder() .tokens(Collections.singletonList(record)) .build(); @@ -2283,11 +2494,11 @@ public void testFormatBulkDeleteTokensResponse_success() { @Test public void testFormatBulkDeleteTokensResponse_error() { - V1DeleteTokenResponseObject record = V1DeleteTokenResponseObject.builder() + DeleteTokenResponseObject record = DeleteTokenResponseObject.builder() .error("token not found") .httpCode(404) .build(); - V1FlowDeleteTokenResponse response = V1FlowDeleteTokenResponse.builder() + DeleteTokenResponse response = DeleteTokenResponse.builder() .tokens(Collections.singletonList(record)) .build(); @@ -2303,11 +2514,11 @@ public void testFormatBulkDeleteTokensResponse_error() { @Test public void testFormatBulkDeleteTokensResponse_errorTextWithoutHttpCodeTreatedAsSuccess() { - V1DeleteTokenResponseObject record = V1DeleteTokenResponseObject.builder() + DeleteTokenResponseObject record = DeleteTokenResponseObject.builder() .value("token1") .error("transient warning") .build(); - V1FlowDeleteTokenResponse response = V1FlowDeleteTokenResponse.builder() + DeleteTokenResponse response = DeleteTokenResponse.builder() .tokens(Collections.singletonList(record)) .build(); @@ -2321,10 +2532,10 @@ public void testFormatBulkDeleteTokensResponse_errorTextWithoutHttpCodeTreatedAs @Test public void testFormatBulkDeleteTokensResponse_indexesOffsetByBatch() { - V1FlowDeleteTokenResponse response = V1FlowDeleteTokenResponse.builder() + DeleteTokenResponse response = DeleteTokenResponse.builder() .tokens(Arrays.asList( - V1DeleteTokenResponseObject.builder().value("token3").build(), - V1DeleteTokenResponseObject.builder().value("token4").build())) + DeleteTokenResponseObject.builder().value("token3").build(), + DeleteTokenResponseObject.builder().value("token4").build())) .build(); // batch 1 with batchSize 2 => indexes continue at 2 @@ -2336,22 +2547,22 @@ public void testFormatBulkDeleteTokensResponse_indexesOffsetByBatch() { } @Test - public void testFormatBulkDeleteTokensResponse_emptyResponseReturnsNull() { - V1FlowDeleteTokenResponse response = V1FlowDeleteTokenResponse.builder().build(); - Assert.assertNull(Utils.formatBulkDeleteTokensResponse( - response, deleteBatchOf("token1"), 0, 50, new HashMap<>())); + public void testFormatBulkDeleteTokensResponse_emptyResponseYieldsNoRecords() { + DeleteTokenResponse response = DeleteTokenResponse.builder().build(); + Assert.assertTrue(Utils.formatBulkDeleteTokensResponse( + response, deleteBatchOf("token1"), 0, 50, new HashMap<>()).getRecords().isEmpty()); } // ── formatBulkTokenizeResponse ───────────────────────────────────────────── - private static V1FlowTokenizeResponse tokenizeWire(V1FlowTokenizeResponseObject... records) { - return V1FlowTokenizeResponse.builder().response(java.util.Arrays.asList(records)).build(); + private static com.skyflow.generated.rest.types.TokenizeResponse tokenizeWire(TokenizeResponseObject... records) { + return com.skyflow.generated.rest.types.TokenizeResponse.builder().response(java.util.Arrays.asList(records)).build(); } @Test public void testFormatBulkTokenizeResponse_success() { - V1FlowTokenizeResponse response = tokenizeWire(V1FlowTokenizeResponseObject.builder() - .value("value1").tokenGroupName("group1").token("tok-abc").build()); + com.skyflow.generated.rest.types.TokenizeResponse response = tokenizeWire(TokenizeResponseObject.builder().token("tok-abc") + .value(com.skyflow.generated.rest.types.GoogleProtobufValue.of("value1")).tokenGroupName("group1").build()); BulkTokenizeResponse result = Utils.formatBulkTokenizeResponse( response, tokenizeBatch("value1", "group1"), 0, new HashMap<>()); @@ -2366,8 +2577,8 @@ public void testFormatBulkTokenizeResponse_success() { @Test public void testFormatBulkTokenizeResponse_tokenError() { - V1FlowTokenizeResponse response = tokenizeWire(V1FlowTokenizeResponseObject.builder() - .value("value1").tokenGroupName("group1").error("invalid value").httpCode(400).build()); + com.skyflow.generated.rest.types.TokenizeResponse response = tokenizeWire(TokenizeResponseObject.builder().token("") + .value(com.skyflow.generated.rest.types.GoogleProtobufValue.of("value1")).tokenGroupName("group1").error("invalid value").httpCode(400).build()); BulkTokenizeResponse result = Utils.formatBulkTokenizeResponse( response, tokenizeBatch("value1", "group1"), 0, new HashMap<>()); @@ -2380,8 +2591,8 @@ public void testFormatBulkTokenizeResponse_tokenError() { @Test public void testFormatBulkTokenizeResponse_derivesIndexFromBatchPosition() { - V1FlowTokenizeResponse response = tokenizeWire(V1FlowTokenizeResponseObject.builder() - .value("value1").tokenGroupName("group1").token("tok-abc").build()); + com.skyflow.generated.rest.types.TokenizeResponse response = tokenizeWire(TokenizeResponseObject.builder().token("tok-abc") + .value(com.skyflow.generated.rest.types.GoogleProtobufValue.of("value1")).tokenGroupName("group1").build()); // this batch starts at index 40 in the caller's list BulkTokenizeResponse result = Utils.formatBulkTokenizeResponse( @@ -2391,10 +2602,10 @@ public void testFormatBulkTokenizeResponse_derivesIndexFromBatchPosition() { } @Test - public void testFormatBulkTokenizeResponse_emptyResponseReturnsNull() { - Assert.assertNull(Utils.formatBulkTokenizeResponse( - V1FlowTokenizeResponse.builder().build(), - tokenizeBatch("value1", "group1"), 0, new HashMap<>())); + public void testFormatBulkTokenizeResponse_emptyResponseYieldsNoRecords() { + Assert.assertTrue(Utils.formatBulkTokenizeResponse( + com.skyflow.generated.rest.types.TokenizeResponse.builder().build(), + tokenizeBatch("value1", "group1"), 0, new HashMap<>()).getRecords().isEmpty()); } @Test @@ -2417,7 +2628,7 @@ private static BulkDeleteTokensResponseRecord deleteError(Object httpCode) { recordMap.put("value", "tok-1"); Map body = new HashMap<>(); body.put("tokens", Collections.singletonList(recordMap)); - V1FlowDeleteTokenRequest batch = V1FlowDeleteTokenRequest.builder() + DeleteTokenRequest batch = DeleteTokenRequest.builder() .vaultId("vault123") .tokens(Collections.singletonList("tok-1")) .build(); @@ -2462,10 +2673,10 @@ public void testDeleteTokensErrorRecord_keepsTheErrorAndEchoedToken() { } // ── handleInsertRequestException / handleUpdateRequestException / handleGetRequestException / - // handleDeleteRequestException / handleDetokenizeRequestException ────────────────────────── + // handleDeleteRequestException / handleDetokenizeRequestException / handleGetTokensRequestException // // These convert a unary call's ApiClientApiException back into a normal response when the - // body still has the familiar per-record shape. extractExceptionRecords is shared by all five, + // body still has the familiar per-record shape. extractExceptionRecords is shared by all six, // so its null/malformed-input robustness is exercised thoroughly once here (via insert) and // the remaining handlers each get a focused shape-guard + happy-path check. @@ -2683,4 +2894,300 @@ public void testHandleDetokenizeRequestException_validResponseShapePopulatesResp Assert.assertEquals("DETOKENIZE failed. Token not found.", result.getError()); Assert.assertEquals(404, result.getHttpCode()); } + + @Test + public void testHandleGetTokensRequestException_nonRecordsShapeReturnsNull() { + Map errorBody = new HashMap<>(); + errorBody.put("message", "Permission denied."); + Map body = new HashMap<>(); + body.put("error", errorBody); + ApiClientApiException ex = new ApiClientApiException("boom", 403, body); + Assert.assertNull(Utils.handleGetTokensRequestException(ex)); + } + + @Test + @SuppressWarnings("unchecked") + public void testUploadFilesErrorBody_recordsShapedBodyLiftsRecordErrorsIntoMessage() { + // uploadFiles can be rejected with {"records":[...]}, which SkyflowException can't read a message from + Map first = new HashMap<>(); + first.put("error", "sky-1 isn't a valid Skyflow ID."); + Map second = new HashMap<>(); + second.put("error", "sky-2 isn't a valid Skyflow ID."); + Map noError = new HashMap<>(); + noError.put("tableName", "table5"); + Map body = new HashMap<>(); + body.put("records", Arrays.asList(first, noError, second, first)); + ApiClientApiException ex = new ApiClientApiException("boom", 404, body); + + Map error = (Map) ((Map) Utils.uploadFilesErrorBody(ex)).get("error"); + Assert.assertEquals(404, error.get("http_code")); + Assert.assertEquals("sky-1 isn't a valid Skyflow ID.; sky-2 isn't a valid Skyflow ID.", error.get("message")); + } + + @Test + public void testUploadFilesErrorBody_errorShapedBodyPassedThrough() { + Map errorBody = new HashMap<>(); + errorBody.put("message", "Permission denied."); + Map body = new HashMap<>(); + body.put("error", errorBody); + ApiClientApiException ex = new ApiClientApiException("boom", 403, body); + Assert.assertEquals(body, Utils.uploadFilesErrorBody(ex)); + } + + @Test + public void testHandleGetTokensRequestException_responseKeyIsWrongShapeReturnsNull() { + // getTokens's wire key is "records"; a detokenize-shaped body must not be mistaken for it + Map record = new HashMap<>(); + record.put("error", "some error"); + Map body = new HashMap<>(); + body.put("response", Collections.singletonList(record)); + ApiClientApiException ex = new ApiClientApiException("boom", 400, body); + Assert.assertNull(Utils.handleGetTokensRequestException(ex)); + } + + @Test + public void testHandleGetTokensRequestException_validRecordsShapePopulatesResponse() { + Map record = new HashMap<>(); + record.put("value", "unknown@example.com"); + record.put("tokenGroupName", "det_group"); + record.put("token", ""); + record.put("error", "Token not found."); + record.put("httpCode", 404); + Map body = new HashMap<>(); + body.put("records", Collections.singletonList(record)); + ApiClientApiException ex = new ApiClientApiException("boom", 404, body); + + GetTokensResponse response = Utils.handleGetTokensRequestException(ex); + Assert.assertNotNull(response); + Map result = response.getRecords().get(0); + Assert.assertEquals("unknown@example.com", result.get("value")); + Assert.assertEquals("det_group", result.get("tokenGroupName")); + Assert.assertEquals("", result.get("token")); + Assert.assertEquals("Token not found.", result.get("error")); + Assert.assertEquals(404, result.get("httpCode")); + } + + @Test + public void testHandleGetTokensRequestException_missingHttpCodeAndErrorFallBack() { + Map record = new HashMap<>(); + record.put("value", "v"); + Map body = new HashMap<>(); + body.put("records", Collections.singletonList(record)); + ApiClientApiException ex = new ApiClientApiException("boom", 422, body); + + GetTokensResponse response = Utils.handleGetTokensRequestException(ex); + Assert.assertNotNull(response); + Assert.assertEquals(422, response.getRecords().get(0).get("httpCode")); + Assert.assertEquals("Unknown error", response.getRecords().get(0).get("error")); + } + + // ── Upload files ────────────────────────────────────────────────────────── + + @org.junit.Rule + public org.junit.rules.TemporaryFolder filesFolder = new org.junit.rules.TemporaryFolder(); + + private static com.skyflow.vault.data.UploadFilesRequestRecord uploadRecord( + String skyflowId, com.skyflow.vault.data.UploadFilesRequestColumn... columns) { + return com.skyflow.vault.data.UploadFilesRequestRecord.builder() + .tableName("onboarding").skyflowId(skyflowId).columns(Arrays.asList(columns)).build(); + } + + private static com.skyflow.vault.data.UploadFilesRequest uploadRequest( + com.skyflow.vault.data.UploadFilesRequestRecord... records) { + return com.skyflow.vault.data.UploadFilesRequest.builder().records(Arrays.asList(records)).build(); + } + + @Test + public void testGetUploadFilesRequestBody_mapsRecordsAndDerivesFileNames() throws Exception { + File resume = filesFolder.newFile("resume.pdf"); + File photo = filesFolder.newFile("photo.jpg"); + com.skyflow.vault.data.UploadFilesRequest request = uploadRequest( + uploadRecord(null, + com.skyflow.vault.data.UploadFilesRequestColumn.builder().column("resumePDF").filePath(resume.getPath()).build(), + com.skyflow.vault.data.UploadFilesRequestColumn.builder().column("photoID").fileObject(photo).build()), + uploadRecord("sky-1", + com.skyflow.vault.data.UploadFilesRequestColumn.builder().column("kyc").base64("aGVsbG8=").fileName("kyc.txt").build(), + com.skyflow.vault.data.UploadFilesRequestColumn.builder().column("cv").filePath(resume.getPath()).fileName("renamed.pdf").build())); + + com.skyflow.generated.rest.resources.files.requests.FileUploadRequest body = + Utils.getUploadFilesRequestBody(request, "vault123"); + + Assert.assertEquals("vault123", body.getVaultId()); + Assert.assertEquals(2, body.getRecords().size()); + com.skyflow.generated.rest.types.FileUploadRecord created = body.getRecords().get(0); + Assert.assertEquals("onboarding", created.getTableName()); + Assert.assertFalse(created.getSkyflowId().isPresent()); + Assert.assertEquals("resumePDF", created.getColumns().get(0).getColumn()); + Assert.assertEquals("resume.pdf", created.getColumns().get(0).getFileName().get()); + Assert.assertEquals("photo.jpg", created.getColumns().get(1).getFileName().get()); + com.skyflow.generated.rest.types.FileUploadRecord updated = body.getRecords().get(1); + Assert.assertEquals("sky-1", updated.getSkyflowId().get()); + Assert.assertEquals("kyc.txt", updated.getColumns().get(0).getFileName().get()); + Assert.assertEquals("renamed.pdf", updated.getColumns().get(1).getFileName().get()); + } + + @Test + public void testResolveUploadFileName_derivedFromTheSourceOrLeftToTheServer() { + Assert.assertEquals("a.pdf", Utils.resolveUploadFileName(com.skyflow.vault.data.UploadFilesRequestColumn.builder() + .filePath("/tmp/dir/a.pdf").build())); + Assert.assertEquals("b.png", Utils.resolveUploadFileName(com.skyflow.vault.data.UploadFilesRequestColumn.builder() + .fileObject(new File("/tmp/b.png")).build())); + Assert.assertEquals("kyc.txt", Utils.resolveUploadFileName(com.skyflow.vault.data.UploadFilesRequestColumn.builder() + .base64("aGVsbG8=").fileName("kyc.txt").build())); + // with no name to derive, the server generates one + Assert.assertNull(Utils.resolveUploadFileName(com.skyflow.vault.data.UploadFilesRequestColumn.builder() + .base64("aGVsbG8=").build())); + } + + @Test + public void testResolveUploadContentType() { + Assert.assertEquals("image/png", Utils.resolveUploadContentType("photo.png")); + Assert.assertEquals("application/octet-stream", Utils.resolveUploadContentType("data.unknownext")); + Assert.assertEquals("application/octet-stream", Utils.resolveUploadContentType(null)); + } + + @Test + public void testBuildUploadFileBody_sendsTheBytesOfEachSource() throws Exception { + File file = filesFolder.newFile("note.txt"); + try (FileWriter writer = new FileWriter(file)) { + writer.write("from disk"); + } + Assert.assertEquals("from disk", bodyText(Utils.buildUploadFileBody( + com.skyflow.vault.data.UploadFilesRequestColumn.builder().filePath(file.getPath()).build(), + null, "text/plain"))); + // base64 content is sent from the bytes decoded up front, not decoded again here + Assert.assertEquals("hello", bodyText(Utils.buildUploadFileBody( + com.skyflow.vault.data.UploadFilesRequestColumn.builder().base64("aGVsbG8=").fileName("h.txt").build(), + "hello".getBytes(java.nio.charset.StandardCharsets.UTF_8), "text/plain"))); + okhttp3.RequestBody fromObject = Utils.buildUploadFileBody( + com.skyflow.vault.data.UploadFilesRequestColumn.builder().fileObject(file).build(), null, "text/plain"); + Assert.assertEquals("from disk", bodyText(fromObject)); + Assert.assertEquals("text/plain", fromObject.contentType().toString()); + } + + @Test + public void testDecodeBase64Columns_decodesEachBase64ColumnOnce() throws Exception { + com.skyflow.vault.data.UploadFilesRequestColumn first = + com.skyflow.vault.data.UploadFilesRequestColumn.builder().column("a").base64("aGVsbG8=").fileName("a.txt").build(); + com.skyflow.vault.data.UploadFilesRequestColumn second = + com.skyflow.vault.data.UploadFilesRequestColumn.builder().column("b").base64("aGVsbG8=").fileName("b.txt").build(); + com.skyflow.vault.data.UploadFilesRequestColumn fromDisk = + com.skyflow.vault.data.UploadFilesRequestColumn.builder().column("c").filePath("/tmp/c.pdf").build(); + + Map decoded = + Utils.decodeBase64Columns(uploadRequest(uploadRecord(null, first, fromDisk), uploadRecord("sky-1", second))); + + Assert.assertEquals(2, decoded.size()); + Assert.assertArrayEquals("hello".getBytes(java.nio.charset.StandardCharsets.UTF_8), decoded.get(first)); + // keyed by the column itself, so two columns with equal content keep separate entries + Assert.assertNotSame(decoded.get(first), decoded.get(second)); + Assert.assertFalse(decoded.containsKey(fromDisk)); + } + + @Test + public void testDecodeBase64Columns_invalidContentThrows() { + try { + Utils.decodeBase64Columns(uploadRequest(uploadRecord(null, + com.skyflow.vault.data.UploadFilesRequestColumn.builder().column("kyc").base64("not base64!") + .fileName("kyc.txt").build()))); + Assert.fail("Should have thrown an exception"); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorMessage.InvalidBase64InUploadFilesColumn.getMessage(), e.getMessage()); + } + } + + private static String bodyText(okhttp3.RequestBody body) throws IOException { + okio.Buffer buffer = new okio.Buffer(); + body.writeTo(buffer); + return buffer.readUtf8(); + } + + // ── Delete files ────────────────────────────────────────────────────────── + + @Test + public void testGetDeleteFilesRequestBody_sendsTheIdentifierEachRecordSets() { + Map unique = new HashMap<>(); + unique.put("email", "a@b.com"); + com.skyflow.vault.data.DeleteFilesRequest request = com.skyflow.vault.data.DeleteFilesRequest.builder() + .records(Arrays.asList( + com.skyflow.vault.data.DeleteFilesRequestRecord.builder().tableName("onboarding") + .skyflowId("sky-1").columns(Arrays.asList("resumePDF", "photoID")).build(), + com.skyflow.vault.data.DeleteFilesRequestRecord.builder().tableName("employees") + .uniqueValues(Collections.singletonList(unique)).columns(Collections.singletonList("photo")).build())) + .build(); + + com.skyflow.generated.rest.resources.files.requests.FileDeleteRequest body = + Utils.getDeleteFilesRequestBody(request, "vault123"); + + Assert.assertEquals("vault123", body.getVaultId()); + com.skyflow.generated.rest.types.FileDeleteRecord byId = body.getRecords().get(0); + Assert.assertEquals("onboarding", byId.getTableName()); + Assert.assertEquals("sky-1", byId.getSkyflowId().get()); + Assert.assertEquals(Arrays.asList("resumePDF", "photoID"), byId.getColumns()); + Assert.assertFalse(byId.getUniqueValues().isPresent()); + com.skyflow.generated.rest.types.FileDeleteRecord byUnique = body.getRecords().get(1); + Assert.assertFalse(byUnique.getSkyflowId().isPresent()); + Assert.assertEquals(unique, byUnique.getUniqueValues().get().get(0).getData()); + } + + @Test + public void testFormatDeleteFilesResponse_partialSuccess() throws Exception { + com.skyflow.generated.rest.types.FileDeleteResponse response = com.skyflow.generated.rest.core.ObjectMappers.JSON_MAPPER.readValue( + "{\"records\":[" + + "{\"skyflowID\":\"sky-1\",\"tableName\":\"onboarding\",\"httpCode\":200," + + "\"data\":{\"resumePDF\":\"DELETED\",\"photoID\":{\"status\":\"DELETED\"}},\"error\":null}," + + "{\"skyflowID\":\"invalid-id-0000\",\"tableName\":\"employees\",\"httpCode\":404," + + "\"error\":\"Invalid request. skyflowID invalid-id-0000 is invalid.\"}]}", + com.skyflow.generated.rest.types.FileDeleteResponse.class); + Map> headers = new HashMap<>(); + headers.put(Constants.REQUEST_ID_HEADER_KEY, Collections.singletonList("req-del-1")); + + com.skyflow.vault.data.DeleteFilesResponse result = Utils.formatDeleteFilesResponse(response, headers); + + Assert.assertEquals(2, result.getRecords().size()); + HashMap ok = result.getRecords().get(0); + Assert.assertEquals("sky-1", ok.get("skyflowId")); + Assert.assertEquals("onboarding", ok.get("tableName")); + Assert.assertEquals(200, ok.get("httpCode")); + Assert.assertNull(ok.get("error")); + Assert.assertNull(ok.get("requestId")); + @SuppressWarnings("unchecked") + List> columns = (List>) ok.get("columns"); + Assert.assertEquals("resumePDF", columns.get(0).get("column")); + Assert.assertEquals("DELETED", columns.get(0).get("status")); + Assert.assertEquals("photoID", columns.get(1).get("column")); + Assert.assertEquals("DELETED", columns.get(1).get("status")); + HashMap failed = result.getRecords().get(1); + Assert.assertNull(failed.get("columns")); + Assert.assertEquals(404, failed.get("httpCode")); + Assert.assertEquals("Invalid request. skyflowID invalid-id-0000 is invalid.", failed.get("error")); + Assert.assertEquals("req-del-1", failed.get("requestId")); + } + + @Test + public void testFormatDeleteFilesResponse_nullResponseYieldsNoRecords() { + Assert.assertTrue(Utils.formatDeleteFilesResponse(null, new HashMap<>()).getRecords().isEmpty()); + } + + @Test + public void testHandleDeleteFilesRequestException() { + Map failed = new HashMap<>(); + failed.put("skyflowID", "invalid-id-0000"); + failed.put("tableName", "employees"); + failed.put("error", "Invalid request. skyflowID invalid-id-0000 is invalid."); + failed.put("httpCode", 404); + Map body = new HashMap<>(); + body.put("records", Collections.singletonList(failed)); + + com.skyflow.vault.data.DeleteFilesResponse response = Utils.handleDeleteFilesRequestException( + new ApiClientApiException("Error with status code 404", 404, body)); + + HashMap record = response.getRecords().get(0); + Assert.assertEquals("invalid-id-0000", record.get("skyflowId")); + Assert.assertEquals("employees", record.get("tableName")); + Assert.assertNull(record.get("columns")); + Assert.assertEquals(404, record.get("httpCode")); + Assert.assertNull(Utils.handleDeleteFilesRequestException( + new ApiClientApiException("Error with status code 500", 500, "boom"))); + } } diff --git a/flowvault/src/test/java/com/skyflow/utils/validations/ValidationsTests.java b/flowvault/src/test/java/com/skyflow/utils/validations/ValidationsTests.java index f900c03a..5c6acb29 100644 --- a/flowvault/src/test/java/com/skyflow/utils/validations/ValidationsTests.java +++ b/flowvault/src/test/java/com/skyflow/utils/validations/ValidationsTests.java @@ -1,5 +1,6 @@ package com.skyflow.utils.validations; +import java.io.File; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; @@ -9,7 +10,9 @@ import java.util.Map; import org.junit.Assert; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; @@ -25,15 +28,23 @@ import com.skyflow.vault.data.BulkTokenizeRequest; import com.skyflow.vault.data.BulkTokenizeRequestRecord; import com.skyflow.vault.data.ColumnRedactions; +import com.skyflow.vault.data.DeleteFilesRequest; +import com.skyflow.vault.data.DeleteFilesRequestRecord; import com.skyflow.vault.data.DeleteRequest; import com.skyflow.vault.data.DetokenizeRequest; import com.skyflow.vault.data.GetRequest; import com.skyflow.vault.data.GetRequestRecord; +import com.skyflow.vault.data.GetTokensRequest; +import com.skyflow.vault.data.GetTokensRequestRecord; import com.skyflow.vault.data.InsertRequest; import com.skyflow.vault.data.InsertRequestRecord; +import com.skyflow.vault.data.QueryRequest; import com.skyflow.vault.data.TokenGroupRedactions; import com.skyflow.vault.data.UpdateRequest; import com.skyflow.vault.data.UpdateRequestRecord; +import com.skyflow.vault.data.UploadFilesRequest; +import com.skyflow.vault.data.UploadFilesRequestColumn; +import com.skyflow.vault.data.UploadFilesRequestRecord; import com.skyflow.vault.data.UpsertOptions; public class ValidationsTests { @@ -2166,4 +2177,407 @@ public void testValidateGetRequest_multiTableRecordMissingTableThrows() { Assert.assertEquals(ErrorMessage.TableKeyError.getMessage(), e.getMessage()); } } + + // ── validateQueryRequest ────────────────────────────────────────────────── + + @Test + public void testValidateQueryRequest_nullRequestThrows() { + try { + Validations.validateQueryRequest(null); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorMessage.QueryRequestNull.getMessage(), e.getMessage()); + } + } + + @Test + public void testValidateQueryRequest_nullQueryThrows() { + QueryRequest request = QueryRequest.builder().build(); + try { + Validations.validateQueryRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorMessage.QueryKeyError.getMessage(), e.getMessage()); + } + } + + @Test + public void testValidateQueryRequest_emptyQueryThrows() { + QueryRequest request = QueryRequest.builder().query("").build(); + try { + Validations.validateQueryRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorMessage.EmptyQuery.getMessage(), e.getMessage()); + } + } + + @Test + public void testValidateQueryRequest_blankQueryThrows() { + QueryRequest request = QueryRequest.builder().query(" ").build(); + try { + Validations.validateQueryRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorMessage.EmptyQuery.getMessage(), e.getMessage()); + } + } + + @Test + public void testValidateQueryRequest_validQueryDoesNotThrow() { + QueryRequest request = QueryRequest.builder().query("SELECT * FROM table1").build(); + try { + Validations.validateQueryRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + // ── validateGetTokensRequest ────────────────────────────────────────────── + + private static GetTokensRequestRecord getTokensRecord(Object value, String tokenGroupName) { + return GetTokensRequestRecord.builder().value(value).tokenGroupName(tokenGroupName).build(); + } + + @Test + public void testValidateGetTokensRequest_nullRequestThrows() { + try { + Validations.validateGetTokensRequest(null); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorMessage.GetTokensRequestNull.getMessage(), e.getMessage()); + } + } + + @Test + public void testValidateGetTokensRequest_nullRecordsThrows() { + GetTokensRequest request = GetTokensRequest.builder().build(); + try { + Validations.validateGetTokensRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorMessage.EmptyGetTokensRecords.getMessage(), e.getMessage()); + } + } + + @Test + public void testValidateGetTokensRequest_emptyRecordsThrows() { + GetTokensRequest request = GetTokensRequest.builder().records(new ArrayList<>()).build(); + try { + Validations.validateGetTokensRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorMessage.EmptyGetTokensRecords.getMessage(), e.getMessage()); + } + } + + @Test + public void testValidateGetTokensRequest_nullRecordThrows() { + List records = new ArrayList<>(); + records.add(getTokensRecord("john@example.com", "det_group")); + records.add(null); + GetTokensRequest request = GetTokensRequest.builder().records(records).build(); + try { + Validations.validateGetTokensRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorMessage.GetTokensRecordNull.getMessage(), e.getMessage()); + } + } + + @Test + public void testValidateGetTokensRequest_nullValueThrows() { + GetTokensRequest request = GetTokensRequest.builder() + .records(Collections.singletonList(getTokensRecord(null, "det_group"))).build(); + try { + Validations.validateGetTokensRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorMessage.EmptyValueInGetTokensRecord.getMessage(), e.getMessage()); + } + } + + @Test + public void testValidateGetTokensRequest_blankStringValueThrows() { + GetTokensRequest request = GetTokensRequest.builder() + .records(Collections.singletonList(getTokensRecord(" ", "det_group"))).build(); + try { + Validations.validateGetTokensRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorMessage.EmptyValueInGetTokensRecord.getMessage(), e.getMessage()); + } + } + + @Test + public void testValidateGetTokensRequest_nullTokenGroupNameThrows() { + GetTokensRequest request = GetTokensRequest.builder() + .records(Collections.singletonList(getTokensRecord("john@example.com", null))).build(); + try { + Validations.validateGetTokensRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorMessage.EmptyTokenGroupNameInGetTokensRecord.getMessage(), e.getMessage()); + } + } + + @Test + public void testValidateGetTokensRequest_blankTokenGroupNameThrows() { + GetTokensRequest request = GetTokensRequest.builder() + .records(Collections.singletonList(getTokensRecord("john@example.com", " "))).build(); + try { + Validations.validateGetTokensRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorMessage.EmptyTokenGroupNameInGetTokensRecord.getMessage(), e.getMessage()); + } + } + + @Test + public void testValidateGetTokensRequest_invalidLaterRecordIsCaught() { + GetTokensRequest request = GetTokensRequest.builder() + .records(Arrays.asList( + getTokensRecord("john@example.com", "det_group"), + getTokensRecord("jane@example.com", ""))) + .build(); + try { + Validations.validateGetTokensRequest(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorMessage.EmptyTokenGroupNameInGetTokensRecord.getMessage(), e.getMessage()); + } + } + + @Test + public void testValidateGetTokensRequest_nonStringValuesDoNotThrow() { + // value is an arbitrary JSON value; only null and blank strings are rejected + GetTokensRequest request = GetTokensRequest.builder() + .records(Arrays.asList( + getTokensRecord(42, "det_number"), + getTokensRecord(true, "det_flag"), + getTokensRecord("john@example.com", "det_group"))) + .build(); + try { + Validations.validateGetTokensRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + // ── validateUploadFilesRequest ──────────────────────────────────────────── + + @Rule + public TemporaryFolder tempFolder = new TemporaryFolder(); + + private interface Validation { + void run() throws SkyflowException; + } + + private static void assertRejected(Validation validation, ErrorMessage expected) { + try { + validation.run(); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(expected.getMessage(), e.getMessage()); + } + } + + private static UploadFilesRequest uploadRequest(UploadFilesRequestRecord... records) { + return UploadFilesRequest.builder().records(Arrays.asList(records)).build(); + } + + private static UploadFilesRequestRecord uploadRecord(UploadFilesRequestColumn... columns) { + return UploadFilesRequestRecord.builder().tableName("onboarding").columns(Arrays.asList(columns)).build(); + } + + private UploadFilesRequestColumn pathColumn() throws Exception { + File file = tempFolder.newFile("resume.pdf"); + return UploadFilesRequestColumn.builder().column("resumePDF").filePath(file.getPath()).build(); + } + + @Test + public void testValidateUploadFilesRequest_validSourcesPass() throws Exception { + File file = tempFolder.newFile("photo.jpg"); + UploadFilesRequest request = uploadRequest( + uploadRecord(pathColumn()), + UploadFilesRequestRecord.builder().tableName("onboarding").skyflowId("sky-1").columns(Arrays.asList( + UploadFilesRequestColumn.builder().column("kyc").base64("aGVsbG8=").fileName("kyc.txt").build(), + UploadFilesRequestColumn.builder().column("photoID").fileObject(file).build())).build()); + try { + Validations.validateUploadFilesRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testValidateUploadFilesRequest_requestAndRecordShape() throws Exception { + assertRejected(() -> Validations.validateUploadFilesRequest(null), ErrorMessage.UploadFilesRequestNull); + assertRejected(() -> Validations.validateUploadFilesRequest(UploadFilesRequest.builder().build()), + ErrorMessage.EmptyUploadFilesRecords); + assertRejected(() -> Validations.validateUploadFilesRequest( + UploadFilesRequest.builder().records(new ArrayList<>()).build()), ErrorMessage.EmptyUploadFilesRecords); + List withNull = new ArrayList<>(); + withNull.add(null); + assertRejected(() -> Validations.validateUploadFilesRequest( + UploadFilesRequest.builder().records(withNull).build()), ErrorMessage.UploadFilesRecordNull); + UploadFilesRequestColumn column = pathColumn(); + assertRejected(() -> Validations.validateUploadFilesRequest(uploadRequest(UploadFilesRequestRecord.builder() + .tableName(" ").columns(Collections.singletonList(column)).build())), + ErrorMessage.EmptyTableNameInUploadFilesRecord); + assertRejected(() -> Validations.validateUploadFilesRequest(uploadRequest(UploadFilesRequestRecord.builder() + .tableName("onboarding").skyflowId(" ").columns(Collections.singletonList(column)).build())), + ErrorMessage.EmptySkyflowIdInUploadFilesRecord); + assertRejected(() -> Validations.validateUploadFilesRequest(uploadRequest(UploadFilesRequestRecord.builder() + .tableName("onboarding").build())), ErrorMessage.EmptyUploadFilesColumns); + assertRejected(() -> Validations.validateUploadFilesRequest(uploadRequest(UploadFilesRequestRecord.builder() + .tableName("onboarding").columns(new ArrayList<>()).build())), ErrorMessage.EmptyUploadFilesColumns); + List nullColumn = new ArrayList<>(); + nullColumn.add(null); + assertRejected(() -> Validations.validateUploadFilesRequest(uploadRequest(UploadFilesRequestRecord.builder() + .tableName("onboarding").columns(nullColumn).build())), ErrorMessage.UploadFilesColumnNull); + } + + @Test + public void testValidateUploadFilesRequest_columnRules() throws Exception { + String path = pathColumn().getFilePath(); + assertRejected(() -> Validations.validateUploadFilesRequest(uploadRequest(uploadRecord( + UploadFilesRequestColumn.builder().filePath(path).build()))), ErrorMessage.EmptyColumnInUploadFilesColumn); + assertRejected(() -> Validations.validateUploadFilesRequest(uploadRequest(uploadRecord( + UploadFilesRequestColumn.builder().column("resumePDF").fileName("a.pdf").build()))), + ErrorMessage.MissingFileSourceInUploadFilesColumn); + assertRejected(() -> Validations.validateUploadFilesRequest(uploadRequest(uploadRecord( + UploadFilesRequestColumn.builder().column("resumePDF").filePath(path + ".missing").build()))), + ErrorMessage.InvalidFilePathInUploadFilesColumn); + assertRejected(() -> Validations.validateUploadFilesRequest(uploadRequest(uploadRecord( + UploadFilesRequestColumn.builder().column("resumePDF").filePath(tempFolder.getRoot().getPath()).build()))), + ErrorMessage.InvalidFilePathInUploadFilesColumn); + assertRejected(() -> Validations.validateUploadFilesRequest(uploadRequest(uploadRecord( + UploadFilesRequestColumn.builder().column("kyc").base64("aGVsbG8=").build()))), + ErrorMessage.FileNameRequiredWithBase64InUploadFilesColumn); + assertRejected(() -> Validations.validateUploadFilesRequest(uploadRequest(uploadRecord( + UploadFilesRequestColumn.builder().column("photoID").fileObject(new File(path + ".missing")).build()))), + ErrorMessage.InvalidFileObjectInUploadFilesColumn); + } + + @Test + public void testValidateUploadFilesRequest_moreThanOneFileSourceRejected() throws Exception { + String path = pathColumn().getFilePath(); + File file = new File(path); + assertRejected(() -> Validations.validateUploadFilesRequest(uploadRequest(uploadRecord( + UploadFilesRequestColumn.builder().column("resumePDF").filePath(path).base64("aGVsbG8=") + .fileName("a.pdf").build()))), ErrorMessage.MultipleFileSourcesInUploadFilesColumn); + assertRejected(() -> Validations.validateUploadFilesRequest(uploadRequest(uploadRecord( + UploadFilesRequestColumn.builder().column("resumePDF").filePath(path).fileObject(file).build()))), + ErrorMessage.MultipleFileSourcesInUploadFilesColumn); + assertRejected(() -> Validations.validateUploadFilesRequest(uploadRequest(uploadRecord( + UploadFilesRequestColumn.builder().column("resumePDF").base64("aGVsbG8=").fileName("a.pdf") + .fileObject(file).build()))), ErrorMessage.MultipleFileSourcesInUploadFilesColumn); + } + + @Test + public void testValidateUploadFilesRequest_duplicateColumnRejected() throws Exception { + UploadFilesRequestColumn first = pathColumn(); + UploadFilesRequestColumn second = UploadFilesRequestColumn.builder().column(first.getColumn()) + .base64("aGVsbG8=").fileName("other.pdf").build(); + assertRejected(() -> Validations.validateUploadFilesRequest(uploadRequest(uploadRecord(first, second))), + ErrorMessage.DuplicateColumnInUploadFilesRecord); + // the same column on different records is fine + try { + Validations.validateUploadFilesRequest(uploadRequest(uploadRecord(first), uploadRecord(second))); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testValidateUploadFilesRequest_leavesBase64DecodingToTheUploadStep() { + // the content is decoded once, by Utils.decodeBase64Columns, rather than here and again on upload + try { + Validations.validateUploadFilesRequest(uploadRequest(uploadRecord( + UploadFilesRequestColumn.builder().column("kyc").base64("not base64!").fileName("kyc.txt").build()))); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + // ── validateDeleteFilesRequest ──────────────────────────────────────────── + + private static DeleteFilesRequest deleteFilesRequest(DeleteFilesRequestRecord... records) { + return DeleteFilesRequest.builder().records(Arrays.asList(records)).build(); + } + + @Test + public void testValidateDeleteFilesRequest_validRecordsPass() { + Map unique = new HashMap<>(); + unique.put("email", "a@b.com"); + DeleteFilesRequest request = deleteFilesRequest( + DeleteFilesRequestRecord.builder().tableName("onboarding").skyflowId("sky-1") + .columns(Arrays.asList("resumePDF", "photoID")).build(), + DeleteFilesRequestRecord.builder().tableName("employees") + .uniqueValues(Collections.singletonList(unique)).columns(Collections.singletonList("photo")).build()); + try { + Validations.validateDeleteFilesRequest(request); + } catch (SkyflowException e) { + Assert.fail(INVALID_EXCEPTION_THROWN); + } + } + + @Test + public void testValidateDeleteFilesRequest_rejectsMalformedRequests() { + assertRejected(() -> Validations.validateDeleteFilesRequest(null), ErrorMessage.DeleteFilesRequestNull); + assertRejected(() -> Validations.validateDeleteFilesRequest(DeleteFilesRequest.builder().build()), + ErrorMessage.EmptyDeleteFilesRecords); + List withNull = new ArrayList<>(); + withNull.add(null); + assertRejected(() -> Validations.validateDeleteFilesRequest( + DeleteFilesRequest.builder().records(withNull).build()), ErrorMessage.DeleteFilesRecordNull); + assertRejected(() -> Validations.validateDeleteFilesRequest(deleteFilesRequest(DeleteFilesRequestRecord.builder() + .skyflowId("sky-1").columns(Collections.singletonList("photo")).build())), + ErrorMessage.EmptyTableNameInDeleteFilesRecord); + assertRejected(() -> Validations.validateDeleteFilesRequest(deleteFilesRequest(DeleteFilesRequestRecord.builder() + .tableName("onboarding").skyflowId("sky-1").build())), ErrorMessage.EmptyDeleteFilesColumns); + assertRejected(() -> Validations.validateDeleteFilesRequest(deleteFilesRequest(DeleteFilesRequestRecord.builder() + .tableName("onboarding").skyflowId("sky-1").columns(Arrays.asList("photo", " ")).build())), + ErrorMessage.EmptyColumnInDeleteFilesColumns); + assertRejected(() -> Validations.validateDeleteFilesRequest(deleteFilesRequest(DeleteFilesRequestRecord.builder() + .tableName("onboarding").skyflowId("sky-1").columns(Arrays.asList("photo", "resume", "photo")).build())), + ErrorMessage.DuplicateColumnInDeleteFilesColumns); + } + + @Test + public void testValidateDeleteFilesRequest_rejectsNullOrEmptyUniqueValue() { + Map unique = new HashMap<>(); + unique.put("email", "a@b.com"); + List> withNull = new ArrayList<>(); + withNull.add(unique); + withNull.add(null); + assertRejected(() -> Validations.validateDeleteFilesRequest(deleteFilesRequest(DeleteFilesRequestRecord.builder() + .tableName("onboarding").uniqueValues(withNull).columns(Collections.singletonList("photo")).build())), + ErrorMessage.EmptyUniqueValueInUniqueValues); + assertRejected(() -> Validations.validateDeleteFilesRequest(deleteFilesRequest(DeleteFilesRequestRecord.builder() + .tableName("onboarding").uniqueValues(Arrays.asList(unique, new HashMap<>())) + .columns(Collections.singletonList("photo")).build())), + ErrorMessage.EmptyUniqueValueInUniqueValues); + } + + @Test + public void testValidateDeleteFilesRequest_requiresExactlyOneOfSkyflowIdAndUniqueValues() { + Map unique = new HashMap<>(); + unique.put("email", "a@b.com"); + // neither + assertRejected(() -> Validations.validateDeleteFilesRequest(deleteFilesRequest(DeleteFilesRequestRecord.builder() + .tableName("onboarding").columns(Collections.singletonList("photo")).build())), + ErrorMessage.InvalidIdOrUniqueValuesInDeleteFilesRecord); + // a blank skyflowId and an empty uniqueValues list both count as absent + assertRejected(() -> Validations.validateDeleteFilesRequest(deleteFilesRequest(DeleteFilesRequestRecord.builder() + .tableName("onboarding").skyflowId(" ").uniqueValues(new ArrayList<>()) + .columns(Collections.singletonList("photo")).build())), + ErrorMessage.InvalidIdOrUniqueValuesInDeleteFilesRecord); + // both + assertRejected(() -> Validations.validateDeleteFilesRequest(deleteFilesRequest(DeleteFilesRequestRecord.builder() + .tableName("onboarding").skyflowId("sky-1").uniqueValues(Collections.singletonList(unique)) + .columns(Collections.singletonList("photo")).build())), + ErrorMessage.InvalidIdOrUniqueValuesInDeleteFilesRecord); + } } diff --git a/flowvault/src/test/java/com/skyflow/vault/controller/BulkDeleteTokensBatchingTests.java b/flowvault/src/test/java/com/skyflow/vault/controller/BulkDeleteTokensBatchingTests.java index 66bb20a0..1927069d 100644 --- a/flowvault/src/test/java/com/skyflow/vault/controller/BulkDeleteTokensBatchingTests.java +++ b/flowvault/src/test/java/com/skyflow/vault/controller/BulkDeleteTokensBatchingTests.java @@ -1,17 +1,21 @@ package com.skyflow.vault.controller; +import com.skyflow.generated.rest.resources.tokens.requests.DeleteTokenRequest; +import com.skyflow.generated.rest.types.DeleteTokenResponse; +import com.skyflow.generated.rest.types.DeleteTokenResponseObject; import com.skyflow.VaultClient; import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; import com.skyflow.enums.Env; import com.skyflow.generated.rest.ApiClient; +import com.skyflow.generated.rest.resources.query.QueryClient; +import com.skyflow.generated.rest.resources.query.RawQueryClient; +import com.skyflow.generated.rest.resources.records.RawRecordsClient; +import com.skyflow.generated.rest.resources.records.RecordsClient; +import com.skyflow.generated.rest.resources.tokens.RawTokensClient; +import com.skyflow.generated.rest.resources.tokens.TokensClient; import com.skyflow.generated.rest.core.ApiClientApiException; import com.skyflow.generated.rest.core.ApiClientHttpResponse; -import com.skyflow.generated.rest.resources.flowservice.FlowserviceClient; -import com.skyflow.generated.rest.resources.flowservice.RawFlowserviceClient; -import com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest; -import com.skyflow.generated.rest.types.V1DeleteTokenResponseObject; -import com.skyflow.generated.rest.types.V1FlowDeleteTokenResponse; import com.skyflow.utils.Constants; import com.skyflow.vault.data.BulkDeleteTokensRequest; import com.skyflow.vault.data.BulkDeleteTokensResponse; @@ -97,34 +101,47 @@ private static VaultController controllerWith(ApiClient mockApi) throws Exceptio return controller; } - private static RawFlowserviceClient mockRawFlowservice(ApiClient mockApi) { - FlowserviceClient mockFlow = Mockito.mock(FlowserviceClient.class); - RawFlowserviceClient mockRaw = Mockito.mock(RawFlowserviceClient.class); - when(mockApi.flowservice()).thenReturn(mockFlow); - when(mockFlow.withRawResponse()).thenReturn(mockRaw); + /** Raw-response mocks for each generated resource client the controller calls. */ + private static final class MockRaw { + final RawRecordsClient records = Mockito.mock(RawRecordsClient.class); + final RawTokensClient tokens = Mockito.mock(RawTokensClient.class); + final RawQueryClient query = Mockito.mock(RawQueryClient.class); + } + + private static MockRaw mockRawFlowservice(ApiClient mockApi) { + MockRaw mockRaw = new MockRaw(); + RecordsClient records = Mockito.mock(RecordsClient.class); + TokensClient tokens = Mockito.mock(TokensClient.class); + QueryClient query = Mockito.mock(QueryClient.class); + when(mockApi.records()).thenReturn(records); + when(mockApi.tokens()).thenReturn(tokens); + when(mockApi.query()).thenReturn(query); + when(records.withRawResponse()).thenReturn(mockRaw.records); + when(tokens.withRawResponse()).thenReturn(mockRaw.tokens); + when(query.withRawResponse()).thenReturn(mockRaw.query); return mockRaw; } /** Echoes each batch back; any token whose number ends in 7 fails with 404. */ private static ApiClient mockApiEchoingBatches() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); - when(mockRaw.deletetoken(any(), any())).thenAnswer(invocation -> { - V1FlowDeleteTokenRequest request = invocation.getArgument(0); - List batchTokens = request.getTokens().get(); + MockRaw mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.tokens.deleteToken(any(), any())).thenAnswer(invocation -> { + DeleteTokenRequest request = invocation.getArgument(0); + List batchTokens = request.getTokens(); scrambleCompletion(batchTokens); - List records = new ArrayList<>(); + List records = new ArrayList<>(); for (String token : batchTokens) { if (token.endsWith("7")) { - records.add(V1DeleteTokenResponseObject.builder() + records.add(DeleteTokenResponseObject.builder() .value(token).error("Token not found").httpCode(404).build()); } else { - records.add(V1DeleteTokenResponseObject.builder() + records.add(DeleteTokenResponseObject.builder() .value(token).httpCode(200).build()); } } return new ApiClientHttpResponse<>( - V1FlowDeleteTokenResponse.builder().tokens(records).build(), okHttp()); + DeleteTokenResponse.builder().tokens(records).build(), okHttp()); }); return mockApi; } @@ -187,21 +204,21 @@ public void testBulkDeleteTokens_maxConcurrencyStillPreservesIndexOrder() throws public void testBulkDeleteTokens_failedBatchKeepsItsOwnIndexSlice() throws Exception { useBatching(10, 5); ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); // the batch starting at tok-20 fails wholesale; the rest succeed - when(mockRaw.deletetoken(any(), any())).thenAnswer(invocation -> { - V1FlowDeleteTokenRequest request = invocation.getArgument(0); - List batchTokens = request.getTokens().get(); + when(mockRaw.tokens.deleteToken(any(), any())).thenAnswer(invocation -> { + DeleteTokenRequest request = invocation.getArgument(0); + List batchTokens = request.getTokens(); scrambleCompletion(batchTokens); if ("tok-20".equals(batchTokens.get(0))) { throw new ApiClientApiException("delete failed", 503, "service unavailable"); } - List records = new ArrayList<>(); + List records = new ArrayList<>(); for (String token : batchTokens) { - records.add(V1DeleteTokenResponseObject.builder().value(token).httpCode(200).build()); + records.add(DeleteTokenResponseObject.builder().value(token).httpCode(200).build()); } return new ApiClientHttpResponse<>( - V1FlowDeleteTokenResponse.builder().tokens(records).build(), okHttp()); + DeleteTokenResponse.builder().tokens(records).build(), okHttp()); }); VaultController controller = controllerWith(mockApi); diff --git a/flowvault/src/test/java/com/skyflow/vault/controller/UploadFilesFormatsTests.java b/flowvault/src/test/java/com/skyflow/vault/controller/UploadFilesFormatsTests.java new file mode 100644 index 00000000..9955b79a --- /dev/null +++ b/flowvault/src/test/java/com/skyflow/vault/controller/UploadFilesFormatsTests.java @@ -0,0 +1,464 @@ +package com.skyflow.vault.controller; + +import com.skyflow.VaultClient; +import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; +import com.skyflow.enums.Env; +import com.skyflow.generated.rest.ApiClient; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; +import com.skyflow.generated.rest.resources.files.FilesClient; +import com.skyflow.generated.rest.resources.files.RawFilesClient; +import com.skyflow.generated.rest.resources.files.requests.FileUploadRequest; +import com.skyflow.generated.rest.types.FileUploadColumn; +import com.skyflow.generated.rest.types.FileUploadRecord; +import com.skyflow.generated.rest.types.FileUploadResponse; +import com.skyflow.generated.rest.types.FileUploadResponseObject; +import com.skyflow.utils.Constants; +import com.skyflow.vault.data.UploadFilesRequest; +import com.skyflow.vault.data.UploadFilesRequestColumn; +import com.skyflow.vault.data.UploadFilesRequestRecord; +import com.skyflow.vault.data.UploadFilesResponse; +import com.sun.net.httpserver.HttpServer; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Response; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Base64; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.ConcurrentHashMap; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +/** + * uploadFiles across file formats, end to end over real HTTP: Phase A is mocked to hand out signed + * URLs that point at a local server, and the SDK's own uploader PUTs each file there. For every + * format and every source (filePath, base64, fileObject) this checks the bytes that arrive, the + * Content-Type sent, the file name announced to the vault, and that no Authorization header leaks. + */ +public class UploadFilesFormatsTests { + + /** One format under test: the file name to upload and the Content-Type it must be sent with. */ + private static final class Format { + final String fileName; + final String contentType; + final byte[] magic; + + Format(String fileName, String contentType, int... magic) { + this.fileName = fileName; + this.contentType = contentType; + this.magic = new byte[magic.length]; + for (int i = 0; i < magic.length; i++) { + this.magic[i] = (byte) magic[i]; + } + } + + String column() { + return "col_" + fileName.replaceAll("[^A-Za-z0-9]", "_"); + } + } + + // Each file starts with its format's real signature, so the content is representative of the + // format and not just its extension. + private static final List FORMATS = Arrays.asList( + new Format("document.pdf", "application/pdf", 0x25, 0x50, 0x44, 0x46, 0x2D, 0x31, 0x2E, 0x37), + new Format("photo.jpg", "image/jpeg", 0xFF, 0xD8, 0xFF, 0xE0), + new Format("photo.jpeg", "image/jpeg", 0xFF, 0xD8, 0xFF, 0xE1), + new Format("image.png", "image/png", 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A), + new Format("anim.gif", "image/gif", 0x47, 0x49, 0x46, 0x38, 0x39, 0x61), + new Format("bitmap.bmp", "image/bmp", 0x42, 0x4D), + new Format("scan.tiff", "image/tiff", 0x49, 0x49, 0x2A, 0x00), + new Format("picture.webp", "image/webp", 0x52, 0x49, 0x46, 0x46, 0, 0, 0, 0, 0x57, 0x45, 0x42, 0x50), + new Format("iphone.heic", "image/heic", 0, 0, 0, 0x18, 0x66, 0x74, 0x79, 0x70, 0x68, 0x65, 0x69, 0x63), + new Format("logo.svg", "image/svg+xml", '<', 's', 'v', 'g'), + new Format("notes.txt", "text/plain", 'h', 'e', 'l', 'l', 'o'), + new Format("report.csv", "text/csv", 'a', ',', 'b', '\n'), + new Format("payload.json", "application/json", '{', '"', 'k', '"', ':', '1', '}'), + new Format("config.xml", "application/xml", '<', '?', 'x', 'm', 'l'), + new Format("page.html", "text/html", '<', 'h', 't', 'm', 'l', '>'), + new Format("letter.doc", "application/msword", 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1), + new Format("letter.docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + 0x50, 0x4B, 0x03, 0x04), + new Format("sheet.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + 0x50, 0x4B, 0x03, 0x04), + new Format("deck.pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation", + 0x50, 0x4B, 0x03, 0x04), + new Format("archive.zip", "application/zip", 0x50, 0x4B, 0x03, 0x04), + new Format("backup.tar.gz", "application/gzip", 0x1F, 0x8B, 0x08), + new Format("voice.mp3", "audio/mpeg", 0x49, 0x44, 0x33, 0x03), + new Format("call.wav", "audio/wav", 0x52, 0x49, 0x46, 0x46, 0, 0, 0, 0, 0x57, 0x41, 0x56, 0x45), + new Format("clip.mp4", "video/mp4", 0, 0, 0, 0x20, 0x66, 0x74, 0x79, 0x70, 0x69, 0x73, 0x6F, 0x6D), + new Format("movie.mov", "video/quicktime", 0, 0, 0, 0x14, 0x66, 0x74, 0x79, 0x70, 0x71, 0x74), + // extension case, no extension, an unknown extension, and a name with spaces and accents + new Format("PHOTO.JPG", "image/jpeg", 0xFF, 0xD8, 0xFF), + new Format("Report.PDF", "application/pdf", 0x25, 0x50, 0x44, 0x46), + new Format("README", "application/octet-stream", 'r', 'e', 'a', 'd'), + new Format("blob.unknownext", "application/octet-stream", 0x00, 0x01, 0x02), + new Format("résumé final 2026.pdf", "application/pdf", 0x25, 0x50, 0x44, 0x46)); + + private enum Source { FILE_PATH, BASE64, FILE_OBJECT } + + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + private HttpServer server; + private final Map receivedBodies = new ConcurrentHashMap<>(); + private final Map receivedContentTypes = new ConcurrentHashMap<>(); + private final Map receivedAuthorization = new ConcurrentHashMap<>(); + private final Map receivedMethods = new ConcurrentHashMap<>(); + + @Before + public void startStorageServer() throws Exception { + server = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0); + server.createContext("/", exchange -> { + String path = exchange.getRequestURI().getPath(); + receivedMethods.put(path, exchange.getRequestMethod()); + receivedBodies.put(path, readAll(exchange.getRequestBody())); + receivedContentTypes.put(path, String.valueOf(exchange.getRequestHeaders().getFirst("Content-Type"))); + receivedAuthorization.put(path, String.valueOf(exchange.getRequestHeaders().getFirst("Authorization"))); + exchange.sendResponseHeaders(201, -1); + exchange.close(); + }); + server.start(); + } + + @After + public void stopStorageServer() { + server.stop(0); + } + + // ── fixtures ────────────────────────────────────────────────────────────── + + private static byte[] readAll(InputStream in) throws java.io.IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] chunk = new byte[8192]; + int n; + while ((n = in.read(chunk)) > 0) { + out.write(chunk, 0, n); + } + return out.toByteArray(); + } + + /** The format's signature, then every byte value 0-255, then seeded random bytes. */ + private static byte[] content(Format format, int randomBytes) { + Random random = new Random(format.fileName.hashCode()); + byte[] tail = new byte[randomBytes]; + random.nextBytes(tail); + byte[] all = new byte[format.magic.length + 256 + randomBytes]; + System.arraycopy(format.magic, 0, all, 0, format.magic.length); + for (int i = 0; i < 256; i++) { + all[format.magic.length + i] = (byte) i; + } + System.arraycopy(tail, 0, all, format.magic.length + 256, randomBytes); + return all; + } + + private File write(String subdirectory, String name, byte[] bytes) throws Exception { + File dir = new File(folder.getRoot(), subdirectory); + if (!dir.isDirectory() && !dir.mkdirs()) { + throw new IllegalStateException("could not create " + dir); + } + File file = new File(dir, name); + Files.write(file.toPath(), bytes); + return file; + } + + private UploadFilesRequestColumn column(Format format, Source source, byte[] bytes) throws Exception { + UploadFilesRequestColumn.UploadFilesRequestColumnBuilder builder = + UploadFilesRequestColumn.builder().column(format.column()); + switch (source) { + case FILE_PATH: + return builder.filePath(write("path", format.fileName, bytes).getPath()).build(); + case BASE64: + return builder.base64(Base64.getEncoder().encodeToString(bytes)).fileName(format.fileName).build(); + default: + return builder.fileObject(write("object", format.fileName, bytes)).build(); + } + } + + // ── controller wiring ───────────────────────────────────────────────────── + + private static VaultController controller(ApiClient apiClient) throws Exception { + return controller(apiClient, null); + } + + private static VaultController controller(ApiClient apiClient, Integer vaultCallTimeoutSeconds) throws Exception { + Credentials credentials = new Credentials(); + credentials.setApiKey("sky-ab123-abcd1234cdef1234abcd4321cdef4321"); + VaultConfig config = new VaultConfig(); + config.setVaultId("vault123"); + config.setClusterId("cluster123"); + config.setEnv(Env.DEV); + config.setTimeout(vaultCallTimeoutSeconds); + VaultController controller = new VaultController(config, credentials); + Field field = VaultClient.class.getDeclaredField("apiClient"); + field.setAccessible(true); + field.set(controller, apiClient); + // Build the vault's real HTTP client, which stamps a bearer token on every request, so the + // test proves the signed-URL upload does not inherit it. + Method buildHttpClient = VaultClient.class.getDeclaredMethod("updateExecutorInHTTP"); + buildHttpClient.setAccessible(true); + buildHttpClient.invoke(controller); + return controller; + } + + private static Response okResponse() { + return new Response.Builder() + .request(new Request.Builder().url("https://dummy.example.com").build()) + .protocol(Protocol.HTTP_1_1) + .code(200) + .message("OK") + .header(Constants.REQUEST_ID_HEADER_KEY, "req-files-1") + .build(); + } + + private String signedUrl(int record, String column) { + return "http://127.0.0.1:" + server.getAddress().getPort() + "/upload/" + record + "/" + column + + "?X-Goog-Signature=abc123"; + } + + /** + * Mocks Phase A: answers every requested column of every record with a signed URL on the local + * server, the way the vault does. Returns the raw files client so the request can be captured. + */ + private RawFilesClient mockPhaseA(ApiClient apiClient) { + FilesClient files = Mockito.mock(FilesClient.class); + RawFilesClient raw = Mockito.mock(RawFilesClient.class); + when(apiClient.files()).thenReturn(files); + when(files.withRawResponse()).thenReturn(raw); + when(raw.uploadFiles(any(), any())).thenAnswer(invocation -> { + FileUploadRequest request = invocation.getArgument(0); + List records = new ArrayList<>(); + for (int i = 0; i < request.getRecords().size(); i++) { + FileUploadRecord record = request.getRecords().get(i); + Map urls = new LinkedHashMap<>(); + for (FileUploadColumn column : record.getColumns()) { + urls.put(column.getColumn(), signedUrl(i, column.getColumn())); + } + records.add(FileUploadResponseObject.builder() + .skyflowId(record.getSkyflowId().orElse("sky-new-" + i)) + .tableName(record.getTableName()) + .httpCode(200) + .data(urls) + .build()); + } + return new ApiClientHttpResponse<>(FileUploadResponse.builder().records(records).build(), okResponse()); + }); + return raw; + } + + @SuppressWarnings("unchecked") + private static List> columnsOf(Map record) { + return (List>) record.get("columns"); + } + + // ── tests ───────────────────────────────────────────────────────────────── + + @Test + public void testEveryFormatFromEverySourceArrivesByteForByteWithItsContentType() throws Exception { + ApiClient apiClient = Mockito.mock(ApiClient.class); + RawFilesClient raw = mockPhaseA(apiClient); + VaultController controller = controller(apiClient); + + // one record per source, each carrying every format + List sources = Arrays.asList(Source.values()); + Map expected = new HashMap<>(); + List records = new ArrayList<>(); + for (int r = 0; r < sources.size(); r++) { + List columns = new ArrayList<>(); + for (Format format : FORMATS) { + byte[] bytes = content(format, 4096); + expected.put("/upload/" + r + "/" + format.column(), bytes); + columns.add(column(format, sources.get(r), bytes)); + } + records.add(UploadFilesRequestRecord.builder().tableName("documents").columns(columns).build()); + } + + UploadFilesResponse response = controller.uploadFiles(UploadFilesRequest.builder().records(records).build()); + + // Phase A announced each file under the name it will be stored as + ArgumentCaptor captor = ArgumentCaptor.forClass(FileUploadRequest.class); + Mockito.verify(raw).uploadFiles(captor.capture(), any()); + for (int r = 0; r < sources.size(); r++) { + List announced = captor.getValue().getRecords().get(r).getColumns(); + for (int c = 0; c < FORMATS.size(); c++) { + Assert.assertEquals(sources.get(r) + " " + FORMATS.get(c).fileName, + FORMATS.get(c).fileName, announced.get(c).getFileName().orElse(null)); + } + } + + Assert.assertEquals(sources.size(), response.getRecords().size()); + for (int r = 0; r < sources.size(); r++) { + Map record = response.getRecords().get(r); + Assert.assertNull(record.get("error")); + List> columns = columnsOf(record); + Assert.assertEquals(FORMATS.size(), columns.size()); + for (int c = 0; c < FORMATS.size(); c++) { + Format format = FORMATS.get(c); + String label = sources.get(r) + " " + format.fileName; + String path = "/upload/" + r + "/" + format.column(); + Map column = columns.get(c); + + Assert.assertEquals(label, "UPLOADED", column.get("uploadStatus")); + Assert.assertNull(label, column.get("error")); + Assert.assertEquals(label, format.fileName, column.get("fileName")); + Assert.assertEquals(label, "PUT", receivedMethods.get(path)); + Assert.assertArrayEquals(label, expected.get(path), receivedBodies.get(path)); + Assert.assertEquals(label, format.contentType, receivedContentTypes.get(path)); + Assert.assertEquals(label, "null", receivedAuthorization.get(path)); + } + } + Assert.assertEquals(sources.size() * FORMATS.size(), receivedBodies.size()); + // the signed URLs are credentials and must not reach the caller + Assert.assertFalse(response.toString().contains("X-Goog-Signature")); + } + + @Test + public void testLargeBinaryFileIsStreamedIntact() throws Exception { + ApiClient apiClient = Mockito.mock(ApiClient.class); + mockPhaseA(apiClient); + VaultController controller = controller(apiClient); + Format video = new Format("recording.mp4", "video/mp4", 0, 0, 0, 0x20, 0x66, 0x74, 0x79, 0x70); + byte[] bytes = content(video, 12 * 1024 * 1024); + + UploadFilesResponse response = controller.uploadFiles(UploadFilesRequest.builder().records( + Collections.singletonList(UploadFilesRequestRecord.builder().tableName("documents").columns( + Collections.singletonList(column(video, Source.FILE_PATH, bytes))).build())).build()); + + Assert.assertEquals("UPLOADED", columnsOf(response.getRecords().get(0)).get(0).get("uploadStatus")); + byte[] received = receivedBodies.get("/upload/0/" + video.column()); + Assert.assertEquals(bytes.length, received.length); + Assert.assertArrayEquals(bytes, received); + } + + @Test + public void testEmptyFileIsSentAsAZeroLengthBody() throws Exception { + ApiClient apiClient = Mockito.mock(ApiClient.class); + mockPhaseA(apiClient); + VaultController controller = controller(apiClient); + File empty = write("path", "empty.txt", new byte[0]); + + UploadFilesResponse response = controller.uploadFiles(UploadFilesRequest.builder().records( + Collections.singletonList(UploadFilesRequestRecord.builder().tableName("documents").columns( + Collections.singletonList(UploadFilesRequestColumn.builder().column("notes") + .filePath(empty.getPath()).build())).build())).build()); + + Assert.assertEquals("UPLOADED", columnsOf(response.getRecords().get(0)).get(0).get("uploadStatus")); + Assert.assertEquals(0, receivedBodies.get("/upload/0/notes").length); + Assert.assertEquals("text/plain", receivedContentTypes.get("/upload/0/notes")); + } + + @Test + public void testExplicitFileNameDecidesStoredNameAndContentType() throws Exception { + ApiClient apiClient = Mockito.mock(ApiClient.class); + RawFilesClient raw = mockPhaseA(apiClient); + VaultController controller = controller(apiClient); + byte[] pdf = "%PDF-1.7 scanned".getBytes(StandardCharsets.UTF_8); + File scan = write("path", "scan.bin", pdf); + + UploadFilesResponse response = controller.uploadFiles(UploadFilesRequest.builder().records( + Collections.singletonList(UploadFilesRequestRecord.builder().tableName("documents").columns(Arrays.asList( + // no fileName: typed by the file's own extension + UploadFilesRequestColumn.builder().column("scan").filePath(scan.getPath()).build(), + // stored under a different name, still typed by that name + UploadFilesRequestColumn.builder().column("renamed").fileObject(scan) + .fileName("statement.pdf").build())).build())).build()); + + List> columns = columnsOf(response.getRecords().get(0)); + Assert.assertEquals("scan.bin", columns.get(0).get("fileName")); + Assert.assertEquals("application/octet-stream", receivedContentTypes.get("/upload/0/scan")); + Assert.assertEquals("statement.pdf", columns.get(1).get("fileName")); + Assert.assertEquals("application/pdf", receivedContentTypes.get("/upload/0/renamed")); + Assert.assertArrayEquals(pdf, receivedBodies.get("/upload/0/renamed")); + + ArgumentCaptor captor = ArgumentCaptor.forClass(FileUploadRequest.class); + Mockito.verify(raw).uploadFiles(captor.capture(), any()); + Assert.assertEquals("statement.pdf", + captor.getValue().getRecords().get(0).getColumns().get(1).getFileName().orElse(null)); + } + + @Test + public void testStorageRejectingOneFormatFailsOnlyThatColumn() throws Exception { + server.removeContext("/"); + server.createContext("/", exchange -> { + String path = exchange.getRequestURI().getPath(); + receivedBodies.put(path, readAll(exchange.getRequestBody())); + String type = String.valueOf(exchange.getRequestHeaders().getFirst("Content-Type")); + exchange.sendResponseHeaders(type.startsWith("video/") ? 415 : 200, -1); + exchange.close(); + }); + ApiClient apiClient = Mockito.mock(ApiClient.class); + mockPhaseA(apiClient); + VaultController controller = controller(apiClient); + Format pdf = FORMATS.get(0); + Format mp4 = new Format("clip.mp4", "video/mp4", 0, 0, 0, 0x20); + Format png = new Format("image.png", "image/png", 0x89, 0x50, 0x4E, 0x47); + + UploadFilesResponse response = controller.uploadFiles(UploadFilesRequest.builder().records( + Collections.singletonList(UploadFilesRequestRecord.builder().tableName("documents").columns(Arrays.asList( + column(pdf, Source.BASE64, content(pdf, 64)), + column(mp4, Source.BASE64, content(mp4, 64)), + column(png, Source.BASE64, content(png, 64)))).build())).build()); + + List> columns = columnsOf(response.getRecords().get(0)); + Assert.assertEquals("UPLOADED", columns.get(0).get("uploadStatus")); + Assert.assertEquals("FAILED", columns.get(1).get("uploadStatus")); + Assert.assertEquals("PUT failed: 415", columns.get(1).get("error")); + Assert.assertEquals("UPLOADED", columns.get(2).get("uploadStatus")); + Assert.assertNull(response.getRecords().get(0).get("error")); + Assert.assertEquals(200, response.getRecords().get(0).get("httpCode")); + } + + @Test + public void testUploadLongerThanTheVaultCallTimeoutStillCompletes() throws Exception { + // storage takes ~2s to accept the file, twice the 1s ceiling configured for vault calls + server.removeContext("/"); + server.createContext("/", exchange -> { + String path = exchange.getRequestURI().getPath(); + receivedBodies.put(path, readAll(exchange.getRequestBody())); + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + exchange.sendResponseHeaders(200, -1); + exchange.close(); + }); + ApiClient apiClient = Mockito.mock(ApiClient.class); + mockPhaseA(apiClient); + VaultController controller = controller(apiClient, 1); + Format pdf = FORMATS.get(0); + byte[] bytes = content(pdf, 1024); + + UploadFilesResponse response = controller.uploadFiles(UploadFilesRequest.builder().records( + Collections.singletonList(UploadFilesRequestRecord.builder().tableName("documents").columns( + Collections.singletonList(column(pdf, Source.FILE_PATH, bytes))).build())).build()); + + Map column = columnsOf(response.getRecords().get(0)).get(0); + Assert.assertEquals(String.valueOf(column.get("error")), "UPLOADED", column.get("uploadStatus")); + Assert.assertArrayEquals(bytes, receivedBodies.get("/upload/0/" + pdf.column())); + } +} diff --git a/flowvault/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java b/flowvault/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java index 5d711ff1..7ea85ca5 100644 --- a/flowvault/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java +++ b/flowvault/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java @@ -1,5 +1,15 @@ package com.skyflow.vault.controller; +import com.skyflow.generated.rest.types.DeleteResponseObject; +import com.skyflow.generated.rest.types.DeleteTokenResponse; +import com.skyflow.generated.rest.types.DeleteTokenResponseObject; +import com.skyflow.generated.rest.types.DetokenizeResponseObject; +import com.skyflow.generated.rest.types.ExecuteQueryRecordResponse; +import com.skyflow.generated.rest.types.ExecuteQueryResponse; +import com.skyflow.generated.rest.types.ExecuteQueryResponseMetadata; +import com.skyflow.generated.rest.types.GetTokensFromValuesResponse; +import com.skyflow.generated.rest.types.RecordResponseObject; +import com.skyflow.generated.rest.types.TokenizeResponseObject; import com.skyflow.VaultClient; import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; @@ -7,23 +17,34 @@ import com.skyflow.enums.Env; import com.skyflow.errors.SkyflowException; import com.skyflow.generated.rest.ApiClient; +import com.skyflow.generated.rest.errors.NotFoundError; +import com.skyflow.generated.rest.errors.UnauthorizedError; +import com.skyflow.vault.data.DeleteFilesOptions; +import com.skyflow.vault.data.DeleteFilesRequest; +import com.skyflow.vault.data.DeleteFilesRequestRecord; +import com.skyflow.vault.data.DeleteFilesResponse; +import com.skyflow.vault.data.UploadFilesOptions; +import com.skyflow.vault.data.UploadFilesRequest; +import com.skyflow.vault.data.UploadFilesRequestColumn; +import com.skyflow.vault.data.UploadFilesRequestRecord; +import com.skyflow.vault.data.UploadFilesResponse; +import com.skyflow.errors.ErrorMessage; +import java.io.File; +import com.skyflow.generated.rest.core.ObjectMappers; +import com.skyflow.generated.rest.errors.BadRequestError; +import com.skyflow.generated.rest.errors.ForbiddenError; +import com.skyflow.generated.rest.types.ErrorResponse; +import com.skyflow.generated.rest.resources.files.FilesClient; +import com.skyflow.generated.rest.resources.files.RawFilesClient; +import com.skyflow.generated.rest.resources.query.QueryClient; +import com.skyflow.generated.rest.resources.query.RawQueryClient; +import com.skyflow.generated.rest.resources.records.RawRecordsClient; +import com.skyflow.generated.rest.resources.records.RecordsClient; +import com.skyflow.generated.rest.resources.tokens.RawTokensClient; +import com.skyflow.generated.rest.resources.tokens.TokensClient; import com.skyflow.generated.rest.core.ApiClientApiException; import com.skyflow.generated.rest.core.ApiClientHttpResponse; import com.skyflow.generated.rest.core.RequestOptions; -import com.skyflow.generated.rest.resources.flowservice.FlowserviceClient; -import com.skyflow.generated.rest.resources.flowservice.RawFlowserviceClient; -import com.skyflow.generated.rest.types.V1DeleteResponse; -import com.skyflow.generated.rest.types.V1DeleteResponseObject; -import com.skyflow.generated.rest.types.V1DeleteTokenResponseObject; -import com.skyflow.generated.rest.types.V1FlowDeleteTokenResponse; -import com.skyflow.generated.rest.types.V1FlowDetokenizeResponse; -import com.skyflow.generated.rest.types.V1FlowDetokenizeResponseObject; -import com.skyflow.generated.rest.types.V1FlowTokenizeResponse; -import com.skyflow.generated.rest.types.V1FlowTokenizeResponseObject; -import com.skyflow.generated.rest.types.V1GetResponse; -import com.skyflow.generated.rest.types.V1InsertResponse; -import com.skyflow.generated.rest.types.V1RecordResponseObject; -import com.skyflow.generated.rest.types.V1UpdateResponse; import com.skyflow.utils.Constants; import com.skyflow.vault.data.BulkDeleteTokensOptions; import com.skyflow.vault.data.BulkTokenizeOptions; @@ -52,10 +73,17 @@ import com.skyflow.vault.data.GetOptions; import com.skyflow.vault.data.GetRequest; import com.skyflow.vault.data.GetResponse; +import com.skyflow.vault.data.GetTokensOptions; +import com.skyflow.vault.data.GetTokensRequest; +import com.skyflow.vault.data.GetTokensRequestRecord; +import com.skyflow.vault.data.GetTokensResponse; import com.skyflow.vault.data.InsertOptions; import com.skyflow.vault.data.InsertRequest; import com.skyflow.vault.data.InsertRequestRecord; import com.skyflow.vault.data.InsertResponse; +import com.skyflow.vault.data.QueryOptions; +import com.skyflow.vault.data.QueryRequest; +import com.skyflow.vault.data.QueryResponse; import com.skyflow.vault.data.RequestInterceptor; import com.skyflow.vault.data.Token; import com.skyflow.vault.data.TokenGroupRedactions; @@ -117,11 +145,28 @@ private static Response buildOkHttpResponse() { .build(); } - private static RawFlowserviceClient mockRawFlowservice(ApiClient mockApi) { - FlowserviceClient mockFlowservice = Mockito.mock(FlowserviceClient.class); - RawFlowserviceClient mockRaw = Mockito.mock(RawFlowserviceClient.class); - when(mockApi.flowservice()).thenReturn(mockFlowservice); - when(mockFlowservice.withRawResponse()).thenReturn(mockRaw); + /** Raw-response mocks for each generated resource client the controller calls. */ + private static final class MockRaw { + final RawRecordsClient records = Mockito.mock(RawRecordsClient.class); + final RawTokensClient tokens = Mockito.mock(RawTokensClient.class); + final RawQueryClient query = Mockito.mock(RawQueryClient.class); + final RawFilesClient files = Mockito.mock(RawFilesClient.class); + } + + private static MockRaw mockRawFlowservice(ApiClient mockApi) { + MockRaw mockRaw = new MockRaw(); + RecordsClient records = Mockito.mock(RecordsClient.class); + TokensClient tokens = Mockito.mock(TokensClient.class); + QueryClient query = Mockito.mock(QueryClient.class); + FilesClient files = Mockito.mock(FilesClient.class); + when(mockApi.records()).thenReturn(records); + when(mockApi.files()).thenReturn(files); + when(files.withRawResponse()).thenReturn(mockRaw.files); + when(mockApi.tokens()).thenReturn(tokens); + when(mockApi.query()).thenReturn(query); + when(records.withRawResponse()).thenReturn(mockRaw.records); + when(tokens.withRawResponse()).thenReturn(mockRaw.tokens); + when(query.withRawResponse()).thenReturn(mockRaw.query); return mockRaw; } @@ -130,15 +175,15 @@ private static RawFlowserviceClient mockRawFlowservice(ApiClient mockApi) { @Test public void testInsert_success() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); Map tokens = new HashMap<>(); tokens.put("name", "tok-abc"); - V1RecordResponseObject record = V1RecordResponseObject.builder() + RecordResponseObject record = RecordResponseObject.builder().httpCode(200) .tableName("table1").skyflowId("sky-id-1").tokens(tokens).build(); - V1InsertResponse body = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); - ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); - when(mockRaw.insert(any(), any())).thenReturn(httpResp); + com.skyflow.generated.rest.types.InsertResponse body = com.skyflow.generated.rest.types.InsertResponse.builder().records(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.records.insertRecords(any(), any())).thenReturn(httpResp); VaultController controller = createControllerWithMock(mockApi); @@ -173,12 +218,12 @@ public void testInsert_invalidRequestThrowsSkyflowException() throws Exception { @Test public void testInsert_interceptorAddsCustomHeader() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); - V1RecordResponseObject record = V1RecordResponseObject.builder().skyflowId("sky-id-1").build(); - V1InsertResponse body = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); - ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); - when(mockRaw.insert(any(), any())).thenReturn(httpResp); + RecordResponseObject record = RecordResponseObject.builder().httpCode(200).skyflowId("sky-id-1").build(); + com.skyflow.generated.rest.types.InsertResponse body = com.skyflow.generated.rest.types.InsertResponse.builder().records(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.records.insertRecords(any(), any())).thenReturn(httpResp); VaultController controller = createControllerWithMock(mockApi); @@ -196,7 +241,7 @@ public void testInsert_interceptorAddsCustomHeader() throws Exception { controller.insert(request, options); ArgumentCaptor captor = ArgumentCaptor.forClass(RequestOptions.class); - Mockito.verify(mockRaw).insert(any(), captor.capture()); + Mockito.verify(mockRaw.records).insertRecords(any(), captor.capture()); Assert.assertEquals("acct-123", captor.getValue().getHeaders().get(CustomHeaderKey.SKYFLOW_ACCOUNT_ID.toString())); } @@ -205,14 +250,14 @@ public void testInsert_interceptorAddsCustomHeader() throws Exception { @Test public void testDetokenize_success() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); - V1FlowDetokenizeResponseObject record = V1FlowDetokenizeResponseObject.builder() - .token("tok-1").value("john@example.com").build(); - V1FlowDetokenizeResponse body = V1FlowDetokenizeResponse.builder() + DetokenizeResponseObject record = DetokenizeResponseObject.builder() + .token("tok-1").value(com.skyflow.generated.rest.types.GoogleProtobufValue.of("john@example.com")).build(); + com.skyflow.generated.rest.types.DetokenizeResponse body = com.skyflow.generated.rest.types.DetokenizeResponse.builder() .response(Collections.singletonList(record)).build(); - ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); - when(mockRaw.detokenize(any(), any())).thenReturn(httpResp); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.tokens.detokenize(any(), any())).thenReturn(httpResp); VaultController controller = createControllerWithMock(mockApi); DetokenizeRequest request = DetokenizeRequest.builder().tokens(Collections.singletonList("tok-1")).build(); @@ -240,12 +285,12 @@ public void testDetokenize_invalidRequestThrowsSkyflowException() throws Excepti @Test public void testDelete_success() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); - V1DeleteResponseObject record = V1DeleteResponseObject.builder().skyflowId("sky-1").httpCode(200).build(); - V1DeleteResponse body = V1DeleteResponse.builder().records(Collections.singletonList(record)).build(); - ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); - when(mockRaw.delete(any(), any())).thenReturn(httpResp); + DeleteResponseObject record = DeleteResponseObject.builder().skyflowId("sky-1").httpCode(200).build(); + com.skyflow.generated.rest.types.DeleteResponse body = com.skyflow.generated.rest.types.DeleteResponse.builder().records(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.records.deleteRecords(any(), any())).thenReturn(httpResp); VaultController controller = createControllerWithMock(mockApi); DeleteRequest request = DeleteRequest.builder().tableName("table1").skyflowIds(Collections.singletonList("sky-1")).build(); @@ -274,13 +319,13 @@ public void testDelete_invalidRequestThrowsSkyflowException() throws Exception { @Test public void testUpdate_success() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); - V1RecordResponseObject record = V1RecordResponseObject.builder() + RecordResponseObject record = RecordResponseObject.builder().httpCode(200) .tableName("table1").skyflowId("sky-1").build(); - V1UpdateResponse body = V1UpdateResponse.builder().records(Collections.singletonList(record)).build(); - ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); - when(mockRaw.update(any(), any())).thenReturn(httpResp); + com.skyflow.generated.rest.types.UpdateResponse body = com.skyflow.generated.rest.types.UpdateResponse.builder().records(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.records.updateRecords(any(), any())).thenReturn(httpResp); VaultController controller = createControllerWithMock(mockApi); @@ -305,7 +350,7 @@ public void testUpdate_success() throws Exception { @Test public void testUpdate_recordLevelFailureReflectedAsHttpErrorStillReturnsResponse() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); Map failedRecord = new HashMap<>(); failedRecord.put("skyflowID", null); @@ -318,7 +363,7 @@ public void testUpdate_recordLevelFailureReflectedAsHttpErrorStillReturnsRespons Map responseBody = new HashMap<>(); responseBody.put("records", Collections.singletonList(failedRecord)); - when(mockRaw.update(any(), any())) + when(mockRaw.records.updateRecords(any(), any())) .thenThrow(new ApiClientApiException("Error with status code 400", 400, responseBody)); VaultController controller = createControllerWithMock(mockApi); @@ -342,7 +387,7 @@ public void testUpdate_recordLevelFailureReflectedAsHttpErrorStillReturnsRespons @Test public void testUpdate_wholeRequestApiErrorStillThrows() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); Map errorBody = new HashMap<>(); errorBody.put("grpc_code", 5); @@ -353,7 +398,7 @@ public void testUpdate_wholeRequestApiErrorStillThrows() throws Exception { Map responseBody = new HashMap<>(); responseBody.put("error", errorBody); - when(mockRaw.update(any(), any())) + when(mockRaw.records.updateRecords(any(), any())) .thenThrow(new ApiClientApiException("Error with status code 404", 404, responseBody)); VaultController controller = createControllerWithMock(mockApi); @@ -393,13 +438,13 @@ public void testUpdate_invalidRequestThrowsSkyflowException() throws Exception { @Test public void testGet_success() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); - V1RecordResponseObject record = V1RecordResponseObject.builder() + RecordResponseObject record = RecordResponseObject.builder().httpCode(200) .tableName("table1").skyflowId("sky-1").build(); - V1GetResponse body = V1GetResponse.builder().records(Collections.singletonList(record)).build(); - ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); - when(mockRaw.get(any(), any())).thenReturn(httpResp); + com.skyflow.generated.rest.types.GetResponse body = com.skyflow.generated.rest.types.GetResponse.builder().records(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.records.getRecords(any(), any())).thenReturn(httpResp); VaultController controller = createControllerWithMock(mockApi); GetRequest request = GetRequest.builder() @@ -425,19 +470,761 @@ public void testGet_invalidRequestThrowsSkyflowException() throws Exception { } } + // ── query (unary) ───────────────────────────────────────────────────────── + + @Test + public void testQuery_success() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + + Map row = new HashMap<>(); + row.put("skyflow_id", "sky-1"); + row.put("name", "john"); + ExecuteQueryResponse body = ExecuteQueryResponse.builder() + .records(Collections.singletonList(ExecuteQueryRecordResponse.builder().data(row).build())) + .metadata(ExecuteQueryResponseMetadata.builder().columns(Arrays.asList("skyflow_id", "name")).build()) + .build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.query.executeQuery(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + QueryRequest request = QueryRequest.builder().query("SELECT * FROM table1").build(); + + QueryResponse response = controller.query(request); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertEquals(1, response.getFields().size()); + Assert.assertEquals("sky-1", response.getFields().get(0).get("skyflow_id")); + Assert.assertNull(response.getErrors()); + Assert.assertEquals(Arrays.asList("skyflow_id", "name"), response.getMetadata().getColumns()); + Assert.assertEquals("req-test-123", response.getRequestId()); + } + + @Test + public void testQuery_invalidRequestThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + VaultController controller = createControllerWithMock(mockApi); + QueryRequest request = QueryRequest.builder().query(" ").build(); + try { + controller.query(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + Mockito.verifyNoInteractions(mockApi); + } + + @Test + public void testQuery_apiErrorThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + Map error = new HashMap<>(); + error.put("http_code", 400); + error.put("message", "Only SELECT queries are supported."); + Map responseBody = new HashMap<>(); + responseBody.put("error", error); + when(mockRaw.query.executeQuery(any(), any())) + .thenThrow(new ApiClientApiException("Error with status code 400", 400, responseBody)); + + VaultController controller = createControllerWithMock(mockApi); + QueryRequest request = QueryRequest.builder().query("DELETE FROM table1").build(); + try { + controller.query(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(400, e.getHttpCode()); + Assert.assertEquals("Only SELECT queries are supported.", e.getMessage()); + } + } + + @Test + public void testQuery_typedErrorThrowsSkyflowExceptionWithApiMessage() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + ErrorResponse body = ObjectMappers.JSON_MAPPER.readValue( + "{\"error\":{\"grpc_code\":3,\"http_code\":400,\"http_status\":\"Bad Request\"," + + "\"message\":\"Only SELECT queries are supported.\"}}", + ErrorResponse.class); + when(mockRaw.query.executeQuery(any(), any())).thenThrow(new BadRequestError(body)); + + VaultController controller = createControllerWithMock(mockApi); + QueryRequest request = QueryRequest.builder().query("DELETE FROM table1").build(); + try { + controller.query(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(400, e.getHttpCode()); + Assert.assertEquals("Only SELECT queries are supported.", e.getMessage()); + } + } + + @Test + public void testQuery_interceptorAddsCustomHeader() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + ApiClientHttpResponse httpResp = + new ApiClientHttpResponse<>(ExecuteQueryResponse.builder().build(), buildOkHttpResponse()); + when(mockRaw.query.executeQuery(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + List operations = new ArrayList<>(); + RequestInterceptor interceptor = ctx -> { + operations.add(ctx.getOperation()); + ctx.addHeader(CustomHeaderKey.SKYFLOW_ACCOUNT_ID, "acct-123"); + }; + QueryOptions options = QueryOptions.builder().interceptor(interceptor).build(); + + controller.query(QueryRequest.builder().query("SELECT * FROM table1").build(), options); + + ArgumentCaptor captor = ArgumentCaptor.forClass(RequestOptions.class); + Mockito.verify(mockRaw.query).executeQuery(any(), captor.capture()); + Assert.assertEquals("acct-123", captor.getValue().getHeaders().get(CustomHeaderKey.SKYFLOW_ACCOUNT_ID.toString())); + Assert.assertEquals(Collections.singletonList("QUERY"), operations); + } + + // ── getTokens (unary) ───────────────────────────────────────────────────── + + @Test + public void testGetTokens_success() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + + TokenizeResponseObject record = TokenizeResponseObject.builder().token("tok-1") + .value(com.skyflow.generated.rest.types.GoogleProtobufValue.of("john@example.com")).tokenGroupName("det_group").httpCode(200).build(); + GetTokensFromValuesResponse body = GetTokensFromValuesResponse.builder().records(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.tokens.getTokens(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + GetTokensRequest request = GetTokensRequest.builder() + .records(Collections.singletonList(GetTokensRequestRecord.builder() + .value("john@example.com").tokenGroupName("det_group").build())) + .build(); + + GetTokensResponse response = controller.getTokens(request); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertEquals(1, response.getRecords().size()); + Assert.assertEquals("tok-1", response.getRecords().get(0).get("token")); + Assert.assertNull(response.getRecords().get(0).get("error")); + } + + @Test + public void testGetTokens_invalidRequestThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + VaultController controller = createControllerWithMock(mockApi); + GetTokensRequest request = GetTokensRequest.builder().records(new ArrayList<>()).build(); + try { + controller.getTokens(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertNotNull(e.getMessage()); + } + Mockito.verifyNoInteractions(mockApi); + } + + @Test + public void testGetTokens_recordsShapedErrorBodyReturnedAsResponse() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + Map failedRecord = new HashMap<>(); + failedRecord.put("value", "unknown@example.com"); + failedRecord.put("tokenGroupName", "det_group"); + failedRecord.put("error", "Token not found."); + failedRecord.put("httpCode", 404); + Map responseBody = new HashMap<>(); + responseBody.put("records", Collections.singletonList(failedRecord)); + when(mockRaw.tokens.getTokens(any(), any())) + .thenThrow(new ApiClientApiException("Error with status code 404", 404, responseBody)); + + VaultController controller = createControllerWithMock(mockApi); + GetTokensRequest request = GetTokensRequest.builder() + .records(Collections.singletonList(GetTokensRequestRecord.builder() + .value("unknown@example.com").tokenGroupName("det_group").build())) + .build(); + + GetTokensResponse response = controller.getTokens(request); + Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); + Assert.assertEquals(1, response.getRecords().size()); + Assert.assertEquals(404, response.getRecords().get(0).get("httpCode")); + Assert.assertEquals("Token not found.", response.getRecords().get(0).get("error")); + Assert.assertEquals("", response.getRecords().get(0).get("token")); + } + + @Test + public void testGetTokens_wholeCallErrorThrowsSkyflowException() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + Map error = new HashMap<>(); + error.put("http_code", 403); + error.put("message", "Permission denied."); + Map responseBody = new HashMap<>(); + responseBody.put("error", error); + when(mockRaw.tokens.getTokens(any(), any())) + .thenThrow(new ApiClientApiException("Error with status code 403", 403, responseBody)); + + VaultController controller = createControllerWithMock(mockApi); + GetTokensRequest request = GetTokensRequest.builder() + .records(Collections.singletonList(GetTokensRequestRecord.builder() + .value("john@example.com").tokenGroupName("det_group").build())) + .build(); + try { + controller.getTokens(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(403, e.getHttpCode()); + Assert.assertEquals("Permission denied.", e.getMessage()); + } + } + + // The documented statuses arrive as typed errors whose body is an ErrorResponse, not a map; + // the fields ErrorResponse does not model (here "records") must still be read. + @Test + public void testGetTokens_typedErrorWithRecordsBodyReturnedAsResponse() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + ErrorResponse body = ObjectMappers.JSON_MAPPER.readValue( + "{\"records\":[{\"value\":\"unknown@example.com\",\"tokenGroupName\":\"det_group\"," + + "\"token\":\"\",\"error\":\"Token not found.\",\"httpCode\":400}]}", + ErrorResponse.class); + when(mockRaw.tokens.getTokens(any(), any())).thenThrow(new BadRequestError(body)); + + VaultController controller = createControllerWithMock(mockApi); + GetTokensRequest request = GetTokensRequest.builder() + .records(Collections.singletonList(GetTokensRequestRecord.builder() + .value("unknown@example.com").tokenGroupName("det_group").build())) + .build(); + + GetTokensResponse response = controller.getTokens(request); + Assert.assertEquals(1, response.getRecords().size()); + Assert.assertEquals("unknown@example.com", response.getRecords().get(0).get("value")); + Assert.assertEquals(400, response.getRecords().get(0).get("httpCode")); + Assert.assertEquals("Token not found.", response.getRecords().get(0).get("error")); + Assert.assertEquals("", response.getRecords().get(0).get("token")); + } + + @Test + public void testGetTokens_typedErrorThrowsSkyflowExceptionWithApiMessage() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + ErrorResponse body = ObjectMappers.JSON_MAPPER.readValue( + "{\"error\":{\"grpc_code\":7,\"http_code\":403,\"http_status\":\"Forbidden\"," + + "\"message\":\"Permission denied.\"}}", + ErrorResponse.class); + when(mockRaw.tokens.getTokens(any(), any())).thenThrow(new ForbiddenError(body)); + + VaultController controller = createControllerWithMock(mockApi); + GetTokensRequest request = GetTokensRequest.builder() + .records(Collections.singletonList(GetTokensRequestRecord.builder() + .value("john@example.com").tokenGroupName("det_group").build())) + .build(); + try { + controller.getTokens(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(403, e.getHttpCode()); + Assert.assertEquals("Permission denied.", e.getMessage()); + } + } + + @Test + public void testGetTokens_interceptorAddsCustomHeader() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + ApiClientHttpResponse httpResp = + new ApiClientHttpResponse<>(GetTokensFromValuesResponse.builder().build(), buildOkHttpResponse()); + when(mockRaw.tokens.getTokens(any(), any())).thenReturn(httpResp); + + VaultController controller = createControllerWithMock(mockApi); + List operations = new ArrayList<>(); + RequestInterceptor interceptor = ctx -> { + operations.add(ctx.getOperation()); + ctx.addHeader(CustomHeaderKey.SKYFLOW_ACCOUNT_ID, "acct-123"); + }; + GetTokensOptions options = GetTokensOptions.builder().interceptor(interceptor).build(); + GetTokensRequest request = GetTokensRequest.builder() + .records(Collections.singletonList(GetTokensRequestRecord.builder() + .value("john@example.com").tokenGroupName("det_group").build())) + .build(); + + controller.getTokens(request, options); + + ArgumentCaptor captor = ArgumentCaptor.forClass(RequestOptions.class); + Mockito.verify(mockRaw.tokens).getTokens(any(), captor.capture()); + Assert.assertEquals("acct-123", captor.getValue().getHeaders().get(CustomHeaderKey.SKYFLOW_ACCOUNT_ID.toString())); + Assert.assertEquals(Collections.singletonList("GET_TOKENS"), operations); + } + + // ── uploadFiles (unary, two-phase) ──────────────────────────────────────── + + @org.junit.Rule + public org.junit.rules.TemporaryFolder filesFolder = new org.junit.rules.TemporaryFolder(); + + /** Records each Phase B call and answers with the status mapped to a URL fragment (default 200). */ + // PUTs run concurrently, so uploads are recorded per URL rather than in call order. + private static final class RecordingUploader implements VaultController.SignedUrlUploader { + final Map bodyByUrl = new java.util.concurrent.ConcurrentHashMap<>(); + final Map contentTypeByUrl = new java.util.concurrent.ConcurrentHashMap<>(); + final Map statusByUrlFragment = new HashMap<>(); + + @Override + public int upload(String signedUrl, okhttp3.RequestBody fileBody) throws java.io.IOException { + okio.Buffer buffer = new okio.Buffer(); + fileBody.writeTo(buffer); + bodyByUrl.put(signedUrl, buffer.readUtf8()); + contentTypeByUrl.put(signedUrl, String.valueOf(fileBody.contentType())); + for (Map.Entry entry : statusByUrlFragment.entrySet()) { + if (signedUrl.contains(entry.getKey())) return entry.getValue(); + } + return 200; + } + } + + private static com.skyflow.generated.rest.types.FileUploadResponse uploadWire(String json) throws Exception { + return ObjectMappers.JSON_MAPPER.readValue(json, com.skyflow.generated.rest.types.FileUploadResponse.class); + } + + private File textFile(String name, String content) throws Exception { + File file = filesFolder.newFile(name); + try (java.io.FileWriter writer = new java.io.FileWriter(file)) { + writer.write(content); + } + return file; + } + + @SuppressWarnings("unchecked") + private static List> columnsOf(HashMap record) { + return (List>) record.get("columns"); + } + + @Test + public void testUploadFiles_partialSuccessAcrossColumnsAndRecords() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + File resume = textFile("resume.pdf", "resume bytes"); + when(mockRaw.files.uploadFiles(any(), any())).thenReturn(new ApiClientHttpResponse<>(uploadWire( + "{\"records\":[" + + "{\"skyflowID\":\"sky-new\",\"tableName\":\"onboarding\",\"httpCode\":200," + + "\"data\":{\"resumePDF\":\"https://upload.example.com/resumePDF?signed=t1\"," + + "\"photoID\":\"https://upload.example.com/photoID?signed=t2\"}}," + + "{\"skyflowID\":\"sky-bad\",\"tableName\":\"onboarding\",\"httpCode\":400," + + "\"error\":\"Invalid request. skyflowID sky-bad is invalid.\"}]}"), + buildOkHttpResponse())); + + VaultController controller = createControllerWithMock(mockApi); + RecordingUploader uploader = new RecordingUploader(); + uploader.statusByUrlFragment.put("photoID", 403); + controller.signedUrlUploader = uploader; + + UploadFilesRequest request = UploadFilesRequest.builder().records(Arrays.asList( + UploadFilesRequestRecord.builder().tableName("onboarding").columns(Arrays.asList( + UploadFilesRequestColumn.builder().column("resumePDF").filePath(resume.getPath()).build(), + UploadFilesRequestColumn.builder().column("photoID").base64("cGhvdG8=").fileName("photo.jpg").build())) + .build(), + UploadFilesRequestRecord.builder().tableName("onboarding").skyflowId("sky-bad").columns( + Collections.singletonList(UploadFilesRequestColumn.builder().column("kyc") + .base64("a3lj").fileName("kyc.txt").build())).build())) + .build(); + + UploadFilesResponse response = controller.uploadFiles(request); + + Assert.assertEquals(2, response.getRecords().size()); + HashMap created = response.getRecords().get(0); + Assert.assertEquals("sky-new", created.get("skyflowId")); + Assert.assertEquals("onboarding", created.get("tableName")); + Assert.assertEquals(200, created.get("httpCode")); + Assert.assertNull(created.get("error")); + Assert.assertNull(created.get("requestId")); + List> columns = columnsOf(created); + Assert.assertEquals("resumePDF", columns.get(0).get("column")); + Assert.assertEquals("resume.pdf", columns.get(0).get("fileName")); + Assert.assertEquals("UPLOADED", columns.get(0).get("uploadStatus")); + Assert.assertNull(columns.get(0).get("error")); + Assert.assertEquals("photo.jpg", columns.get(1).get("fileName")); + Assert.assertEquals("FAILED", columns.get(1).get("uploadStatus")); + Assert.assertEquals("PUT failed: 403", columns.get(1).get("error")); + + HashMap rejected = response.getRecords().get(1); + Assert.assertEquals(400, rejected.get("httpCode")); + Assert.assertEquals("Invalid request. skyflowID sky-bad is invalid.", rejected.get("error")); + Assert.assertEquals("req-test-123", rejected.get("requestId")); + Assert.assertEquals("SKIPPED", columnsOf(rejected).get(0).get("uploadStatus")); + Assert.assertEquals("kyc.txt", columnsOf(rejected).get(0).get("fileName")); + + // Phase B: one PUT per signed URL with that column's bytes; the rejected record sends nothing + Assert.assertEquals(2, uploader.bodyByUrl.size()); + Assert.assertEquals("resume bytes", uploader.bodyByUrl.get("https://upload.example.com/resumePDF?signed=t1")); + Assert.assertEquals("photo", uploader.bodyByUrl.get("https://upload.example.com/photoID?signed=t2")); + Assert.assertEquals("application/pdf", + uploader.contentTypeByUrl.get("https://upload.example.com/resumePDF?signed=t1")); + Assert.assertEquals("image/jpeg", + uploader.contentTypeByUrl.get("https://upload.example.com/photoID?signed=t2")); + // the signed URLs are internal credentials and must not reach the caller + Assert.assertFalse(response.toString().contains("signed=")); + } + + @Test + public void testUploadFiles_phaseARequestCarriesRecordsAndFileNames() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.files.uploadFiles(any(), any())).thenReturn(new ApiClientHttpResponse<>( + uploadWire("{\"records\":[]}"), buildOkHttpResponse())); + VaultController controller = createControllerWithMock(mockApi); + controller.signedUrlUploader = new RecordingUploader(); + + controller.uploadFiles(UploadFilesRequest.builder().records(Collections.singletonList( + UploadFilesRequestRecord.builder().tableName("identityDocs").skyflowId("sky-1").columns( + Collections.singletonList(UploadFilesRequestColumn.builder().column("passport") + .base64("cA==").fileName("passport.png").build())).build())).build()); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(com.skyflow.generated.rest.resources.files.requests.FileUploadRequest.class); + Mockito.verify(mockRaw.files).uploadFiles(captor.capture(), any()); + com.skyflow.generated.rest.resources.files.requests.FileUploadRequest sent = captor.getValue(); + Assert.assertEquals("vault123", sent.getVaultId()); + Assert.assertEquals("identityDocs", sent.getRecords().get(0).getTableName()); + Assert.assertEquals("sky-1", sent.getRecords().get(0).getSkyflowId().get()); + Assert.assertEquals("passport", sent.getRecords().get(0).getColumns().get(0).getColumn()); + Assert.assertEquals("passport.png", sent.getRecords().get(0).getColumns().get(0).getFileName().get()); + } + + @Test + public void testUploadFiles_uploadErrorFailsAndMissingSignedUrlSkipsOnlyThatColumn() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.files.uploadFiles(any(), any())).thenReturn(new ApiClientHttpResponse<>(uploadWire( + "{\"records\":[{\"skyflowID\":\"sky-1\",\"tableName\":\"onboarding\",\"httpCode\":200," + + "\"data\":{\"a\":\"https://upload.example.com/a\",\"b\":\"https://upload.example.com/b\"}}]}"), + buildOkHttpResponse())); + VaultController controller = createControllerWithMock(mockApi); + controller.signedUrlUploader = (url, body) -> { + if (url.endsWith("/b")) throw new java.io.IOException("connection reset"); + return 201; + }; + + UploadFilesResponse response = controller.uploadFiles(UploadFilesRequest.builder().records( + Collections.singletonList(UploadFilesRequestRecord.builder().tableName("onboarding").skyflowId("sky-1") + .columns(Arrays.asList( + UploadFilesRequestColumn.builder().column("a").base64("YQ==").fileName("a.txt").build(), + UploadFilesRequestColumn.builder().column("b").base64("Yg==").fileName("b.txt").build(), + UploadFilesRequestColumn.builder().column("c").base64("Yw==").fileName("c.txt").build())) + .build())).build()); + + List> columns = columnsOf(response.getRecords().get(0)); + Assert.assertEquals("UPLOADED", columns.get(0).get("uploadStatus")); + Assert.assertEquals("FAILED", columns.get(1).get("uploadStatus")); + Assert.assertEquals("PUT failed: connection reset", columns.get(1).get("error")); + Assert.assertEquals("SKIPPED", columns.get(2).get("uploadStatus")); + Assert.assertNull(columns.get(2).get("error")); + Assert.assertNull(response.getRecords().get(0).get("error")); + } + + @Test + public void testUploadFiles_putsRunConcurrentlyCappedAtFiveAndKeepRequestOrder() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + int fileCount = 12; + StringBuilder data = new StringBuilder(); + List requestColumns = new ArrayList<>(); + for (int i = 0; i < fileCount; i++) { + data.append(i == 0 ? "" : ",").append("\"c").append(i).append("\":\"https://upload.example.com/c") + .append(i).append("\""); + requestColumns.add(UploadFilesRequestColumn.builder().column("c" + i).base64("YQ==") + .fileName("f" + i + ".txt").build()); + } + when(mockRaw.files.uploadFiles(any(), any())).thenReturn(new ApiClientHttpResponse<>(uploadWire( + "{\"records\":[{\"skyflowID\":\"sky-1\",\"tableName\":\"onboarding\",\"httpCode\":200," + + "\"data\":{" + data + "}}]}"), buildOkHttpResponse())); + VaultController controller = createControllerWithMock(mockApi); + java.util.concurrent.atomic.AtomicInteger inFlight = new java.util.concurrent.atomic.AtomicInteger(); + java.util.concurrent.atomic.AtomicInteger maxInFlight = new java.util.concurrent.atomic.AtomicInteger(); + controller.signedUrlUploader = (url, body) -> { + maxInFlight.accumulateAndGet(inFlight.incrementAndGet(), Math::max); + try { + Thread.sleep(50); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + inFlight.decrementAndGet(); + return url.endsWith("/c3") ? 500 : 200; + }; + + UploadFilesResponse response = controller.uploadFiles(UploadFilesRequest.builder().records( + Collections.singletonList(UploadFilesRequestRecord.builder().tableName("onboarding").skyflowId("sky-1") + .columns(requestColumns).build())).build()); + + Assert.assertTrue("PUTs should overlap", maxInFlight.get() > 1); + Assert.assertTrue("at most 5 PUTs at once", maxInFlight.get() <= 5); + List> columns = columnsOf(response.getRecords().get(0)); + Assert.assertEquals(fileCount, columns.size()); + for (int i = 0; i < fileCount; i++) { + Assert.assertEquals("c" + i, columns.get(i).get("column")); + Assert.assertEquals(i == 3 ? "FAILED" : "UPLOADED", columns.get(i).get("uploadStatus")); + } + } + + @Test + public void testUploadFiles_wholeCallFailureThrowsAndUploadsNothing() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + ErrorResponse body = ObjectMappers.JSON_MAPPER.readValue( + "{\"error\":{\"grpc_code\":7,\"http_code\":403,\"http_status\":\"Forbidden\"," + + "\"message\":\"Permission denied.\"}}", ErrorResponse.class); + when(mockRaw.files.uploadFiles(any(), any())).thenThrow(new ForbiddenError(body)); + VaultController controller = createControllerWithMock(mockApi); + RecordingUploader uploader = new RecordingUploader(); + controller.signedUrlUploader = uploader; + + try { + controller.uploadFiles(UploadFilesRequest.builder().records(Collections.singletonList( + UploadFilesRequestRecord.builder().tableName("onboarding").columns(Collections.singletonList( + UploadFilesRequestColumn.builder().column("kyc").base64("a3lj").fileName("kyc.txt").build())) + .build())).build()); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(403, e.getHttpCode()); + Assert.assertEquals("Permission denied.", e.getMessage()); + } + Assert.assertTrue(uploader.bodyByUrl.isEmpty()); + } + + @Test + public void testUploadFiles_rejectedCallThrowsEvenWhenTheBodyListsRecords() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + ErrorResponse body = ObjectMappers.JSON_MAPPER.readValue( + "{\"records\":[{\"skyflowID\":null,\"tableName\":\"onboarding\",\"httpCode\":400," + + "\"error\":\"Invalid request. skyflowID sky-x is invalid.\"}]}", ErrorResponse.class); + when(mockRaw.files.uploadFiles(any(), any())).thenThrow(new BadRequestError(body)); + VaultController controller = createControllerWithMock(mockApi); + RecordingUploader uploader = new RecordingUploader(); + controller.signedUrlUploader = uploader; + + try { + controller.uploadFiles(UploadFilesRequest.builder().records( + Collections.singletonList(UploadFilesRequestRecord.builder().tableName("onboarding").skyflowId("sky-x") + .columns(Collections.singletonList(UploadFilesRequestColumn.builder().column("kyc") + .base64("a3lj").fileName("kyc.txt").build())).build())).build()); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(400, e.getHttpCode()); + Assert.assertEquals("Invalid request. skyflowID sky-x is invalid.", e.getMessage()); + } + Assert.assertTrue(uploader.bodyByUrl.isEmpty()); + } + + @Test + public void testUploadFiles_invalidRequestThrowsWithoutCallingTheApi() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + VaultController controller = createControllerWithMock(mockApi); + try { + controller.uploadFiles(UploadFilesRequest.builder().records(new ArrayList<>()).build()); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorMessage.EmptyUploadFilesRecords.getMessage(), e.getMessage()); + } + Mockito.verifyNoInteractions(mockApi); + } + + @Test + public void testUploadFiles_invalidBase64ThrowsBeforeCallingTheApi() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + VaultController controller = createControllerWithMock(mockApi); + try { + controller.uploadFiles(UploadFilesRequest.builder().records(Collections.singletonList( + UploadFilesRequestRecord.builder().tableName("onboarding").columns(Collections.singletonList( + UploadFilesRequestColumn.builder().column("kyc").base64("not base64!").fileName("kyc.txt").build())) + .build())).build()); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorMessage.InvalidBase64InUploadFilesColumn.getMessage(), e.getMessage()); + } + Mockito.verifyNoInteractions(mockApi); + } + + @Test + public void testUploadFiles_interceptorAddsCustomHeaderToPhaseA() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.files.uploadFiles(any(), any())).thenReturn(new ApiClientHttpResponse<>( + uploadWire("{\"records\":[]}"), buildOkHttpResponse())); + VaultController controller = createControllerWithMock(mockApi); + controller.signedUrlUploader = new RecordingUploader(); + List operations = new ArrayList<>(); + RequestInterceptor interceptor = ctx -> { + operations.add(ctx.getOperation()); + ctx.addHeader(CustomHeaderKey.SKYFLOW_ACCOUNT_ID, "acct-123"); + }; + + controller.uploadFiles(UploadFilesRequest.builder().records(Collections.singletonList( + UploadFilesRequestRecord.builder().tableName("onboarding").columns(Collections.singletonList( + UploadFilesRequestColumn.builder().column("kyc").base64("a3lj").fileName("kyc.txt").build())) + .build())).build(), UploadFilesOptions.builder().interceptor(interceptor).build()); + + ArgumentCaptor captor = ArgumentCaptor.forClass(RequestOptions.class); + Mockito.verify(mockRaw.files).uploadFiles(any(), captor.capture()); + Assert.assertEquals("acct-123", captor.getValue().getHeaders().get(CustomHeaderKey.SKYFLOW_ACCOUNT_ID.toString())); + Assert.assertEquals(Collections.singletonList("UPLOAD_FILES"), operations); + } + + @Test + public void testUploadFiles_signedUrlPutSendsBytesWithoutAuthorization() throws Exception { + List seen = Collections.synchronizedList(new ArrayList<>()); + com.sun.net.httpserver.HttpServer server = + com.sun.net.httpserver.HttpServer.create(new java.net.InetSocketAddress("127.0.0.1", 0), 0); + server.createContext("/upload", exchange -> { + java.io.ByteArrayOutputStream received = new java.io.ByteArrayOutputStream(); + byte[] chunk = new byte[1024]; + int n; + while ((n = exchange.getRequestBody().read(chunk)) > 0) received.write(chunk, 0, n); + seen.add(exchange.getRequestMethod()); + seen.add(String.valueOf(exchange.getRequestHeaders().getFirst("Authorization"))); + seen.add(exchange.getRequestHeaders().getFirst("Content-Type")); + seen.add(new String(received.toByteArray(), java.nio.charset.StandardCharsets.UTF_8)); + seen.add(exchange.getRequestURI().getQuery()); + exchange.sendResponseHeaders(201, -1); + exchange.close(); + }); + server.start(); + try { + VaultController controller = createControllerWithMock(Mockito.mock(ApiClient.class)); + // build the vault's own HTTP client, which adds a bearer token to every request + java.lang.reflect.Method build = VaultClient.class.getDeclaredMethod("updateExecutorInHTTP"); + build.setAccessible(true); + build.invoke(controller); + + int status = controller.signedUrlUploader.upload( + "http://127.0.0.1:" + server.getAddress().getPort() + "/upload?signed=token1", + okhttp3.RequestBody.create("file bytes".getBytes(java.nio.charset.StandardCharsets.UTF_8), + okhttp3.MediaType.parse("application/pdf"))); + + Assert.assertEquals(201, status); + Assert.assertEquals(Arrays.asList("PUT", "null", "application/pdf", "file bytes", "signed=token1"), seen); + } finally { + server.stop(0); + } + } + + // ── deleteFiles (unary) ─────────────────────────────────────────────────── + + private static DeleteFilesRequest deleteFilesRequest() { + return DeleteFilesRequest.builder().records(Collections.singletonList( + DeleteFilesRequestRecord.builder().tableName("onboarding").skyflowId("sky-1") + .columns(Arrays.asList("resumePDF", "photoID")).build())).build(); + } + + @Test + public void testDeleteFiles_partialSuccess() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + com.skyflow.generated.rest.types.FileDeleteResponse body = ObjectMappers.JSON_MAPPER.readValue( + "{\"records\":[" + + "{\"skyflowID\":\"sky-1\",\"tableName\":\"onboarding\",\"httpCode\":200," + + "\"data\":{\"resumePDF\":\"DELETED\",\"photoID\":\"DELETED\"}}," + + "{\"skyflowID\":\"invalid-id-0000\",\"tableName\":\"employees\",\"httpCode\":404," + + "\"error\":\"Invalid request. skyflowID invalid-id-0000 is invalid.\"}]}", + com.skyflow.generated.rest.types.FileDeleteResponse.class); + when(mockRaw.files.deleteFiles(any(), any())).thenReturn(new ApiClientHttpResponse<>(body, buildOkHttpResponse())); + VaultController controller = createControllerWithMock(mockApi); + + DeleteFilesResponse response = controller.deleteFiles(deleteFilesRequest()); + + Assert.assertEquals(2, response.getRecords().size()); + HashMap ok = response.getRecords().get(0); + Assert.assertEquals("sky-1", ok.get("skyflowId")); + Assert.assertEquals("DELETED", columnsOf(ok).get(1).get("status")); + Assert.assertNull(ok.get("requestId")); + HashMap failed = response.getRecords().get(1); + Assert.assertNull(failed.get("columns")); + Assert.assertEquals(404, failed.get("httpCode")); + Assert.assertEquals("req-test-123", failed.get("requestId")); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(com.skyflow.generated.rest.resources.files.requests.FileDeleteRequest.class); + Mockito.verify(mockRaw.files).deleteFiles(captor.capture(), any()); + Assert.assertEquals("vault123", captor.getValue().getVaultId()); + Assert.assertEquals(Arrays.asList("resumePDF", "photoID"), captor.getValue().getRecords().get(0).getColumns()); + } + + @Test + public void testDeleteFiles_recordsShapedTypedErrorReturnedAsResponse() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + ErrorResponse body = ObjectMappers.JSON_MAPPER.readValue( + "{\"records\":[{\"skyflowID\":\"sky-1\",\"tableName\":\"onboarding\",\"httpCode\":404," + + "\"error\":\"No file present in column photoID.\"}]}", ErrorResponse.class); + when(mockRaw.files.deleteFiles(any(), any())).thenThrow(new NotFoundError(body)); + VaultController controller = createControllerWithMock(mockApi); + + DeleteFilesResponse response = controller.deleteFiles(deleteFilesRequest()); + + Assert.assertEquals(404, response.getRecords().get(0).get("httpCode")); + Assert.assertEquals("No file present in column photoID.", response.getRecords().get(0).get("error")); + } + + @Test + public void testDeleteFiles_wholeCallFailureThrows() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + ErrorResponse body = ObjectMappers.JSON_MAPPER.readValue( + "{\"error\":{\"grpc_code\":16,\"http_code\":401,\"http_status\":\"Unauthorized\"," + + "\"message\":\"Invalid token.\"}}", ErrorResponse.class); + when(mockRaw.files.deleteFiles(any(), any())).thenThrow(new UnauthorizedError(body)); + VaultController controller = createControllerWithMock(mockApi); + try { + controller.deleteFiles(deleteFilesRequest()); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(401, e.getHttpCode()); + Assert.assertEquals("Invalid token.", e.getMessage()); + } + } + + @Test + public void testDeleteFiles_invalidRequestThrowsWithoutCallingTheApi() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + VaultController controller = createControllerWithMock(mockApi); + try { + controller.deleteFiles(null); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorMessage.DeleteFilesRequestNull.getMessage(), e.getMessage()); + } + Mockito.verifyNoInteractions(mockApi); + } + + @Test + public void testDeleteFiles_interceptorAddsCustomHeader() throws Exception { + ApiClient mockApi = Mockito.mock(ApiClient.class); + MockRaw mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.files.deleteFiles(any(), any())).thenReturn(new ApiClientHttpResponse<>( + com.skyflow.generated.rest.types.FileDeleteResponse.builder().build(), buildOkHttpResponse())); + VaultController controller = createControllerWithMock(mockApi); + List operations = new ArrayList<>(); + RequestInterceptor interceptor = ctx -> { + operations.add(ctx.getOperation()); + ctx.addHeader(CustomHeaderKey.SKYFLOW_ACCOUNT_ID, "acct-123"); + }; + + controller.deleteFiles(deleteFilesRequest(), DeleteFilesOptions.builder().interceptor(interceptor).build()); + + ArgumentCaptor captor = ArgumentCaptor.forClass(RequestOptions.class); + Mockito.verify(mockRaw.files).deleteFiles(any(), captor.capture()); + Assert.assertEquals("acct-123", captor.getValue().getHeaders().get(CustomHeaderKey.SKYFLOW_ACCOUNT_ID.toString())); + Assert.assertEquals(Collections.singletonList("DELETE_FILES"), operations); + } + // ── bulkInsert ──────────────────────────────────────────────────────────── @Test public void testBulkInsert_success() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); Map tokens = new HashMap<>(); tokens.put("name", "tok-abc"); - V1RecordResponseObject record = V1RecordResponseObject.builder().skyflowId("sky-id-1").tokens(tokens).build(); - V1InsertResponse body = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); - ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); - when(mockRaw.insert(any(), any())).thenReturn(httpResp); + RecordResponseObject record = RecordResponseObject.builder().httpCode(200).skyflowId("sky-id-1").tokens(tokens).build(); + com.skyflow.generated.rest.types.InsertResponse body = com.skyflow.generated.rest.types.InsertResponse.builder().records(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.records.insertRecords(any(), any())).thenReturn(httpResp); VaultController controller = createControllerWithMock(mockApi); @@ -473,14 +1260,14 @@ public void testBulkInsert_invalidRequestThrowsSkyflowException() throws Excepti @Test public void testBulkInsertAsync_success() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); Map tokens = new HashMap<>(); tokens.put("name", "tok-abc"); - V1RecordResponseObject record = V1RecordResponseObject.builder().skyflowId("sky-id-1").tokens(tokens).build(); - V1InsertResponse body = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); - ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); - when(mockRaw.insert(any(), any())).thenReturn(httpResp); + RecordResponseObject record = RecordResponseObject.builder().httpCode(200).skyflowId("sky-id-1").tokens(tokens).build(); + com.skyflow.generated.rest.types.InsertResponse body = com.skyflow.generated.rest.types.InsertResponse.builder().records(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.records.insertRecords(any(), any())).thenReturn(httpResp); VaultController controller = createControllerWithMock(mockApi); @@ -530,14 +1317,14 @@ public void testBulkInsertAsync_unexpectedExceptionWrappedAsSkyflowException() t @Test public void testBulkInsert_interceptorAddsCustomHeader() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); Map tokens = new HashMap<>(); tokens.put("name", "tok-abc"); - V1RecordResponseObject record = V1RecordResponseObject.builder().skyflowId("sky-id-1").tokens(tokens).build(); - V1InsertResponse body = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); - ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); - when(mockRaw.insert(any(), any())).thenReturn(httpResp); + RecordResponseObject record = RecordResponseObject.builder().httpCode(200).skyflowId("sky-id-1").tokens(tokens).build(); + com.skyflow.generated.rest.types.InsertResponse body = com.skyflow.generated.rest.types.InsertResponse.builder().records(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.records.insertRecords(any(), any())).thenReturn(httpResp); VaultController controller = createControllerWithMock(mockApi); @@ -553,7 +1340,7 @@ public void testBulkInsert_interceptorAddsCustomHeader() throws Exception { controller.bulkInsert(request, options); ArgumentCaptor captor = ArgumentCaptor.forClass(RequestOptions.class); - Mockito.verify(mockRaw).insert(any(), captor.capture()); + Mockito.verify(mockRaw.records).insertRecords(any(), captor.capture()); Assert.assertEquals("acct-123", captor.getValue().getHeaders().get(CustomHeaderKey.SKYFLOW_ACCOUNT_ID.toString())); } @@ -562,14 +1349,14 @@ public void testBulkInsert_interceptorAddsCustomHeader() throws Exception { @Test public void testBulkDetokenize_success() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); - V1FlowDetokenizeResponseObject record = V1FlowDetokenizeResponseObject.builder() - .token("token1").value("secret-value").build(); - V1FlowDetokenizeResponse body = V1FlowDetokenizeResponse.builder() + DetokenizeResponseObject record = DetokenizeResponseObject.builder() + .token("token1").value(com.skyflow.generated.rest.types.GoogleProtobufValue.of("secret-value")).build(); + com.skyflow.generated.rest.types.DetokenizeResponse body = com.skyflow.generated.rest.types.DetokenizeResponse.builder() .response(Collections.singletonList(record)).build(); - ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); - when(mockRaw.detokenize(any(), any())).thenReturn(httpResp); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.tokens.detokenize(any(), any())).thenReturn(httpResp); VaultController controller = createControllerWithMock(mockApi); @@ -606,14 +1393,14 @@ public void testBulkDetokenize_nullRequestThrowsSkyflowExceptionNotNPE() throws @Test public void testBulkDetokenizeAsync_success() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); - V1FlowDetokenizeResponseObject record = V1FlowDetokenizeResponseObject.builder() - .token("token1").value("secret-value").build(); - V1FlowDetokenizeResponse body = V1FlowDetokenizeResponse.builder() + DetokenizeResponseObject record = DetokenizeResponseObject.builder() + .token("token1").value(com.skyflow.generated.rest.types.GoogleProtobufValue.of("secret-value")).build(); + com.skyflow.generated.rest.types.DetokenizeResponse body = com.skyflow.generated.rest.types.DetokenizeResponse.builder() .response(Collections.singletonList(record)).build(); - ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); - when(mockRaw.detokenize(any(), any())).thenReturn(httpResp); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.tokens.detokenize(any(), any())).thenReturn(httpResp); VaultController controller = createControllerWithMock(mockApi); @@ -646,13 +1433,13 @@ public void testBulkDetokenizeAsync_nullRequestThrowsSkyflowExceptionNotNPE() th @Test public void testBulkDeleteTokens_success() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); - V1DeleteTokenResponseObject record = V1DeleteTokenResponseObject.builder().value("token1").build(); - V1FlowDeleteTokenResponse body = V1FlowDeleteTokenResponse.builder() + DeleteTokenResponseObject record = DeleteTokenResponseObject.builder().value("token1").build(); + DeleteTokenResponse body = DeleteTokenResponse.builder() .tokens(Collections.singletonList(record)).build(); - ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); - when(mockRaw.deletetoken(any(), any())).thenReturn(httpResp); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.tokens.deleteToken(any(), any())).thenReturn(httpResp); VaultController controller = createControllerWithMock(mockApi); @@ -683,13 +1470,13 @@ public void testBulkDeleteTokens_nullRequestThrowsSkyflowException() throws Exce @Test public void testBulkDeleteTokensAsync_success() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); - V1DeleteTokenResponseObject record = V1DeleteTokenResponseObject.builder().value("token1").build(); - V1FlowDeleteTokenResponse body = V1FlowDeleteTokenResponse.builder() + DeleteTokenResponseObject record = DeleteTokenResponseObject.builder().value("token1").build(); + DeleteTokenResponse body = DeleteTokenResponse.builder() .tokens(Collections.singletonList(record)).build(); - ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); - when(mockRaw.deletetoken(any(), any())).thenReturn(httpResp); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.tokens.deleteToken(any(), any())).thenReturn(httpResp); VaultController controller = createControllerWithMock(mockApi); @@ -708,14 +1495,14 @@ public void testBulkDeleteTokensAsync_success() throws Exception { @Test public void testBulkTokenize_success() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); - V1FlowTokenizeResponseObject responseObject = V1FlowTokenizeResponseObject.builder() - .value("value1").tokenGroupName("group1").token("tok-abc").build(); - V1FlowTokenizeResponse body = V1FlowTokenizeResponse.builder() + TokenizeResponseObject responseObject = TokenizeResponseObject.builder().token("tok-abc") + .value(com.skyflow.generated.rest.types.GoogleProtobufValue.of("value1")).tokenGroupName("group1").build(); + com.skyflow.generated.rest.types.TokenizeResponse body = com.skyflow.generated.rest.types.TokenizeResponse.builder() .response(Collections.singletonList(responseObject)).build(); - ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); - when(mockRaw.tokenize(any(), any())).thenReturn(httpResp); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.tokens.tokenize(any(), any())).thenReturn(httpResp); VaultController controller = createControllerWithMock(mockApi); @@ -736,16 +1523,16 @@ public void testBulkTokenize_success() throws Exception { public void testBulkTokenize_partialFailureWithRetryableGroupIsRetriedAsWhole() throws Exception { // one value, two groups: group1 succeeds, group2 fails with a retryable 503 ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); - V1FlowTokenizeResponseObject succeeded = V1FlowTokenizeResponseObject.builder() - .value("value1").tokenGroupName("group1").token("tok-abc").httpCode(200).build(); - V1FlowTokenizeResponseObject failed = V1FlowTokenizeResponseObject.builder() - .value("value1").error("service unavailable").httpCode(503).build(); - V1FlowTokenizeResponse body = V1FlowTokenizeResponse.builder() + TokenizeResponseObject succeeded = TokenizeResponseObject.builder().token("tok-abc") + .value(com.skyflow.generated.rest.types.GoogleProtobufValue.of("value1")).tokenGroupName("group1").httpCode(200).build(); + TokenizeResponseObject failed = TokenizeResponseObject.builder().token("") + .value(com.skyflow.generated.rest.types.GoogleProtobufValue.of("value1")).tokenGroupName("").error("service unavailable").httpCode(503).build(); + com.skyflow.generated.rest.types.TokenizeResponse body = com.skyflow.generated.rest.types.TokenizeResponse.builder() .response(Arrays.asList(succeeded, failed)).build(); - ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); - when(mockRaw.tokenize(any(), any())).thenReturn(httpResp); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.tokens.tokenize(any(), any())).thenReturn(httpResp); VaultController controller = createControllerWithMock(mockApi); @@ -781,14 +1568,14 @@ public void testBulkTokenize_nullRequestThrowsSkyflowException() throws Exceptio @Test public void testBulkTokenizeAsync_success() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); - V1FlowTokenizeResponseObject responseObject = V1FlowTokenizeResponseObject.builder() - .value("value1").tokenGroupName("group1").token("tok-abc").build(); - V1FlowTokenizeResponse body = V1FlowTokenizeResponse.builder() + TokenizeResponseObject responseObject = TokenizeResponseObject.builder().token("tok-abc") + .value(com.skyflow.generated.rest.types.GoogleProtobufValue.of("value1")).tokenGroupName("group1").build(); + com.skyflow.generated.rest.types.TokenizeResponse body = com.skyflow.generated.rest.types.TokenizeResponse.builder() .response(Collections.singletonList(responseObject)).build(); - ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); - when(mockRaw.tokenize(any(), any())).thenReturn(httpResp); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.tokens.tokenize(any(), any())).thenReturn(httpResp); VaultController controller = createControllerWithMock(mockApi); @@ -816,8 +1603,8 @@ public void testBulkTokenizeAsync_success() throws Exception { @Test public void testBulkInsertAsync_apiErrorCapturedInErrors() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); - when(mockRaw.insert(any(), any())) + MockRaw mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.records.insertRecords(any(), any())) .thenThrow(new ApiClientApiException("insert failed", 401, "unauthorized")); VaultController controller = createControllerWithMock(mockApi); @@ -839,8 +1626,8 @@ public void testBulkInsertAsync_apiErrorCapturedInErrors() throws Exception { @Test public void testBulkDeleteTokens_apiErrorCapturedInErrors() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); - when(mockRaw.deletetoken(any(), any())) + MockRaw mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.tokens.deleteToken(any(), any())) .thenThrow(new ApiClientApiException("delete failed", 404, "not found")); VaultController controller = createControllerWithMock(mockApi); @@ -860,8 +1647,8 @@ public void testBulkDeleteTokens_apiErrorCapturedInErrors() throws Exception { @Test public void testBulkDeleteTokensAsync_apiErrorCapturedInErrors() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); - when(mockRaw.deletetoken(any(), any())) + MockRaw mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.tokens.deleteToken(any(), any())) .thenThrow(new ApiClientApiException("delete failed", 404, "not found")); VaultController controller = createControllerWithMock(mockApi); @@ -881,8 +1668,8 @@ public void testBulkDeleteTokensAsync_apiErrorCapturedInErrors() throws Exceptio @Test public void testBulkTokenize_apiErrorCapturedInErrors() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); - when(mockRaw.tokenize(any(), any())) + MockRaw mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.tokens.tokenize(any(), any())) .thenThrow(new ApiClientApiException("tokenize failed", 400, "bad request")); VaultController controller = createControllerWithMock(mockApi); @@ -903,8 +1690,8 @@ public void testBulkTokenize_apiErrorCapturedInErrors() throws Exception { @Test public void testBulkTokenizeAsync_apiErrorCapturedInErrors() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); - when(mockRaw.tokenize(any(), any())) + MockRaw mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.tokens.tokenize(any(), any())) .thenThrow(new ApiClientApiException("tokenize failed", 400, "bad request")); VaultController controller = createControllerWithMock(mockApi); @@ -925,8 +1712,8 @@ public void testBulkTokenizeAsync_apiErrorCapturedInErrors() throws Exception { @Test public void testBulkDetokenizeAsync_apiErrorCapturedInErrors() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); - when(mockRaw.detokenize(any(), any())) + MockRaw mockRaw = mockRawFlowservice(mockApi); + when(mockRaw.tokens.detokenize(any(), any())) .thenThrow(new ApiClientApiException("detokenize failed", 401, "unauthorized")); VaultController controller = createControllerWithMock(mockApi); @@ -949,21 +1736,21 @@ public void testBulkDetokenizeAsync_apiErrorCapturedInErrors() throws Exception @Test public void testBulkInsert_multiBatchAggregatesAcrossBatches() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); Map tokens1 = new HashMap<>(); tokens1.put("name", "tok-batch1"); - V1RecordResponseObject record1 = V1RecordResponseObject.builder().skyflowId("sky-id-batch1").tokens(tokens1).build(); - V1InsertResponse body1 = V1InsertResponse.builder().records(Collections.singletonList(record1)).build(); - ApiClientHttpResponse httpResp1 = new ApiClientHttpResponse<>(body1, buildOkHttpResponse()); + RecordResponseObject record1 = RecordResponseObject.builder().httpCode(200).skyflowId("sky-id-batch1").tokens(tokens1).build(); + com.skyflow.generated.rest.types.InsertResponse body1 = com.skyflow.generated.rest.types.InsertResponse.builder().records(Collections.singletonList(record1)).build(); + ApiClientHttpResponse httpResp1 = new ApiClientHttpResponse<>(body1, buildOkHttpResponse()); Map tokens2 = new HashMap<>(); tokens2.put("name", "tok-batch2"); - V1RecordResponseObject record2 = V1RecordResponseObject.builder().skyflowId("sky-id-batch2").tokens(tokens2).build(); - V1InsertResponse body2 = V1InsertResponse.builder().records(Collections.singletonList(record2)).build(); - ApiClientHttpResponse httpResp2 = new ApiClientHttpResponse<>(body2, buildOkHttpResponse()); + RecordResponseObject record2 = RecordResponseObject.builder().httpCode(200).skyflowId("sky-id-batch2").tokens(tokens2).build(); + com.skyflow.generated.rest.types.InsertResponse body2 = com.skyflow.generated.rest.types.InsertResponse.builder().records(Collections.singletonList(record2)).build(); + ApiClientHttpResponse httpResp2 = new ApiClientHttpResponse<>(body2, buildOkHttpResponse()); - when(mockRaw.insert(any(), any())).thenReturn(httpResp1).thenReturn(httpResp2); + when(mockRaw.records.insertRecords(any(), any())).thenReturn(httpResp1).thenReturn(httpResp2); VaultController controller = createControllerWithMock(mockApi); @@ -980,7 +1767,7 @@ public void testBulkInsert_multiBatchAggregatesAcrossBatches() throws Exception BulkInsertResponse response = controller.bulkInsert(request); Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); - Mockito.verify(mockRaw, Mockito.times(2)).insert(any(), any()); + Mockito.verify(mockRaw.records, Mockito.times(2)).insertRecords(any(), any()); Assert.assertEquals(2, response.getRecords().size()); Assert.assertTrue(response.getRecords().stream().allMatch(r -> r.getError() == null)); Assert.assertEquals(75, response.getSummary().getTotalRecords()); @@ -1002,15 +1789,15 @@ public void testBulkInsert_multiBatchAggregatesAcrossBatches() throws Exception @Test public void testBulkInsert_partialBatchFailureKeepsBatch1SuccessAndBatch2Error() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); Map tokens1 = new HashMap<>(); tokens1.put("name", "tok-batch1"); - V1RecordResponseObject record1 = V1RecordResponseObject.builder().skyflowId("sky-id-batch1").tokens(tokens1).build(); - V1InsertResponse body1 = V1InsertResponse.builder().records(Collections.singletonList(record1)).build(); - ApiClientHttpResponse httpResp1 = new ApiClientHttpResponse<>(body1, buildOkHttpResponse()); + RecordResponseObject record1 = RecordResponseObject.builder().httpCode(200).skyflowId("sky-id-batch1").tokens(tokens1).build(); + com.skyflow.generated.rest.types.InsertResponse body1 = com.skyflow.generated.rest.types.InsertResponse.builder().records(Collections.singletonList(record1)).build(); + ApiClientHttpResponse httpResp1 = new ApiClientHttpResponse<>(body1, buildOkHttpResponse()); - when(mockRaw.insert(any(), any())) + when(mockRaw.records.insertRecords(any(), any())) .thenReturn(httpResp1) .thenThrow(new ApiClientApiException("insert failed", 500, "server error")); @@ -1027,7 +1814,7 @@ public void testBulkInsert_partialBatchFailureKeepsBatch1SuccessAndBatch2Error() BulkInsertResponse response = controller.bulkInsert(request); Assert.assertNotNull(INVALID_EXCEPTION_THROWN, response); - Mockito.verify(mockRaw, Mockito.times(2)).insert(any(), any()); + Mockito.verify(mockRaw.records, Mockito.times(2)).insertRecords(any(), any()); Assert.assertEquals(2, response.getRecords().size()); @@ -1053,7 +1840,7 @@ public void testBulkInsert_partialBatchFailureKeepsBatch1SuccessAndBatch2Error() @Test public void testBulkInsert_successWithListOfMapsTokenShape() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); Map tokenEntry = new HashMap<>(); tokenEntry.put("token", "tok-xyz"); @@ -1064,10 +1851,10 @@ public void testBulkInsert_successWithListOfMapsTokenShape() throws Exception { Map tokens = new HashMap<>(); tokens.put("field1", tokenList); - V1RecordResponseObject record = V1RecordResponseObject.builder().skyflowId("sky-id-1").tokens(tokens).build(); - V1InsertResponse body = V1InsertResponse.builder().records(Collections.singletonList(record)).build(); - ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); - when(mockRaw.insert(any(), any())).thenReturn(httpResp); + RecordResponseObject record = RecordResponseObject.builder().httpCode(200).skyflowId("sky-id-1").tokens(tokens).build(); + com.skyflow.generated.rest.types.InsertResponse body = com.skyflow.generated.rest.types.InsertResponse.builder().records(Collections.singletonList(record)).build(); + ApiClientHttpResponse httpResp = new ApiClientHttpResponse<>(body, buildOkHttpResponse()); + when(mockRaw.records.insertRecords(any(), any())).thenReturn(httpResp); VaultController controller = createControllerWithMock(mockApi); @@ -1187,66 +1974,66 @@ private static List multiBatchTokens() { } /** Echoes each request record back as a response record whose skyflowId encodes its "pos". */ - private static void stubInsertEcho(RawFlowserviceClient mockRaw) { - when(mockRaw.insert(any(), any())).thenAnswer(invocation -> { - com.skyflow.generated.rest.resources.flowservice.requests.V1InsertRequest req = + private static void stubInsertEcho(MockRaw mockRaw) { + when(mockRaw.records.insertRecords(any(), any())).thenAnswer(invocation -> { + com.skyflow.generated.rest.resources.records.requests.InsertRequest req = invocation.getArgument(0); - List responseRecords = new ArrayList<>(); - for (com.skyflow.generated.rest.types.V1InsertRecordData record : req.getRecords().get()) { - responseRecords.add(V1RecordResponseObject.builder() - .skyflowId("sky-" + record.getData().get().get("pos")) + List responseRecords = new ArrayList<>(); + for (com.skyflow.generated.rest.types.InsertRecordData record : req.getRecords()) { + responseRecords.add(RecordResponseObject.builder().httpCode(200) + .skyflowId("sky-" + record.getData().get("pos")) .tableName(record.getTableName().orElse(null)) .build()); } - V1InsertResponse body = V1InsertResponse.builder().records(responseRecords).build(); + com.skyflow.generated.rest.types.InsertResponse body = com.skyflow.generated.rest.types.InsertResponse.builder().records(responseRecords).build(); return new ApiClientHttpResponse<>(body, buildOkHttpResponse()); }); } /** Echoes each requested token back as a detokenize response record. */ - private static void stubDetokenizeEcho(RawFlowserviceClient mockRaw) { - when(mockRaw.detokenize(any(), any())).thenAnswer(invocation -> { - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest req = + private static void stubDetokenizeEcho(MockRaw mockRaw) { + when(mockRaw.tokens.detokenize(any(), any())).thenAnswer(invocation -> { + com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest req = invocation.getArgument(0); - List responseRecords = new ArrayList<>(); - for (String token : req.getTokens().get()) { - responseRecords.add(V1FlowDetokenizeResponseObject.builder().token(token).build()); + List responseRecords = new ArrayList<>(); + for (String token : req.getTokens()) { + responseRecords.add(DetokenizeResponseObject.builder().token(token).build()); } - V1FlowDetokenizeResponse body = V1FlowDetokenizeResponse.builder() + com.skyflow.generated.rest.types.DetokenizeResponse body = com.skyflow.generated.rest.types.DetokenizeResponse.builder() .response(responseRecords).build(); return new ApiClientHttpResponse<>(body, buildOkHttpResponse()); }); } /** Echoes each requested token back as a delete-token response record. */ - private static void stubDeleteTokensEcho(RawFlowserviceClient mockRaw) { - when(mockRaw.deletetoken(any(), any())).thenAnswer(invocation -> { - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest req = + private static void stubDeleteTokensEcho(MockRaw mockRaw) { + when(mockRaw.tokens.deleteToken(any(), any())).thenAnswer(invocation -> { + com.skyflow.generated.rest.resources.tokens.requests.DeleteTokenRequest req = invocation.getArgument(0); - List responseRecords = new ArrayList<>(); - for (String token : req.getTokens().get()) { - responseRecords.add(V1DeleteTokenResponseObject.builder().value(token).build()); + List responseRecords = new ArrayList<>(); + for (String token : req.getTokens()) { + responseRecords.add(DeleteTokenResponseObject.builder().value(token).build()); } - V1FlowDeleteTokenResponse body = V1FlowDeleteTokenResponse.builder() + DeleteTokenResponse body = DeleteTokenResponse.builder() .tokens(responseRecords).build(); return new ApiClientHttpResponse<>(body, buildOkHttpResponse()); }); } /** Echoes each requested tokenize value back with one token per requested group name. */ - private static void stubTokenizeEcho(RawFlowserviceClient mockRaw) { - when(mockRaw.tokenize(any(), any())).thenAnswer(invocation -> { - com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest req = + private static void stubTokenizeEcho(MockRaw mockRaw) { + when(mockRaw.tokens.tokenize(any(), any())).thenAnswer(invocation -> { + com.skyflow.generated.rest.resources.tokens.requests.TokenizeRequest req = invocation.getArgument(0); - List responseRecords = new ArrayList<>(); - for (com.skyflow.generated.rest.types.V1FlowTokenizeRequestObject obj : req.getData().get()) { - responseRecords.add(V1FlowTokenizeResponseObject.builder() - .value(obj.getValue().get()) - .tokenGroupName("group1") + List responseRecords = new ArrayList<>(); + for (com.skyflow.generated.rest.types.TokenizeRequestObject obj : req.getData()) { + responseRecords.add(TokenizeResponseObject.builder() .token("tok-" + obj.getValue().get()) + .value(com.skyflow.generated.rest.types.GoogleProtobufValue.of(obj.getValue().get())) + .tokenGroupName("group1") .build()); } - V1FlowTokenizeResponse body = V1FlowTokenizeResponse.builder().response(responseRecords).build(); + com.skyflow.generated.rest.types.TokenizeResponse body = com.skyflow.generated.rest.types.TokenizeResponse.builder().response(responseRecords).build(); return new ApiClientHttpResponse<>(body, buildOkHttpResponse()); }); } @@ -1256,7 +2043,7 @@ private static void stubTokenizeEcho(RawFlowserviceClient mockRaw) { @Test public void testBulkInsert_tableNameAndVaultIdReAppliedOnEveryBatch() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); stubInsertEcho(mockRaw); VaultController controller = createControllerWithMock(mockApi); @@ -1267,19 +2054,19 @@ public void testBulkInsert_tableNameAndVaultIdReAppliedOnEveryBatch() throws Exc controller.bulkInsert(request); - ArgumentCaptor captor = - ArgumentCaptor.forClass(com.skyflow.generated.rest.resources.flowservice.requests.V1InsertRequest.class); - Mockito.verify(mockRaw, Mockito.times(EXPECTED_BATCH_COUNT)).insert(captor.capture(), any()); + ArgumentCaptor captor = + ArgumentCaptor.forClass(com.skyflow.generated.rest.resources.records.requests.InsertRequest.class); + Mockito.verify(mockRaw.records, Mockito.times(EXPECTED_BATCH_COUNT)).insertRecords(captor.capture(), any()); int expectedPos = 0; - for (com.skyflow.generated.rest.resources.flowservice.requests.V1InsertRequest sent : captor.getAllValues()) { + for (com.skyflow.generated.rest.resources.records.requests.InsertRequest sent : captor.getAllValues()) { // insertBatch rebuilds the request per batch, so tableName/vaultId must be re-applied. - Assert.assertEquals("cards", sent.getTableName().get()); - Assert.assertEquals("vault123", sent.getVaultId().get()); - for (com.skyflow.generated.rest.types.V1InsertRecordData record : sent.getRecords().get()) { + Assert.assertEquals("cards", sent.getTableName()); + Assert.assertEquals("vault123", sent.getVaultId()); + for (com.skyflow.generated.rest.types.InsertRecordData record : sent.getRecords()) { // The name rides the envelope only — duplicating it per record is rejected by the vault. Assert.assertFalse(record.getTableName().isPresent()); - Assert.assertEquals(String.valueOf(expectedPos), record.getData().get().get("pos")); + Assert.assertEquals(String.valueOf(expectedPos), record.getData().get("pos")); expectedPos++; } } @@ -1289,7 +2076,7 @@ public void testBulkInsert_tableNameAndVaultIdReAppliedOnEveryBatch() throws Exc @Test public void testBulkInsert_responseIndexMapsToOriginalInputPosition_acrossBatches() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); stubInsertEcho(mockRaw); VaultController controller = createControllerWithMock(mockApi); @@ -1312,7 +2099,7 @@ public void testBulkInsert_responseIndexMapsToOriginalInputPosition_acrossBatche @Test public void testBulkInsert_interceptorInvokedOncePerBatchWithDistinctContext() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); stubInsertEcho(mockRaw); VaultController controller = createControllerWithMock(mockApi); @@ -1325,7 +2112,7 @@ public void testBulkInsert_interceptorInvokedOncePerBatchWithDistinctContext() t controller.bulkInsert(request, BulkInsertOptions.builder().interceptor(interceptor).build()); ArgumentCaptor captor = ArgumentCaptor.forClass(RequestOptions.class); - Mockito.verify(mockRaw, Mockito.times(EXPECTED_BATCH_COUNT)).insert(any(), captor.capture()); + Mockito.verify(mockRaw.records, Mockito.times(EXPECTED_BATCH_COUNT)).insertRecords(any(), captor.capture()); assertInterceptorRanOncePerBatch(interceptor, captor.getAllValues()); } @@ -1334,7 +2121,7 @@ public void testBulkInsert_interceptorInvokedOncePerBatchWithDistinctContext() t @Test public void testBulkDetokenize_vaultIdAndRedactionsReachEveryBatchAndTokenOrderPreserved() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); stubDetokenizeEcho(mockRaw); VaultController controller = createControllerWithMock(mockApi); @@ -1347,17 +2134,17 @@ public void testBulkDetokenize_vaultIdAndRedactionsReachEveryBatchAndTokenOrderP controller.bulkDetokenize(request); - ArgumentCaptor captor = - ArgumentCaptor.forClass(com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest.class); - Mockito.verify(mockRaw, Mockito.times(EXPECTED_BATCH_COUNT)).detokenize(captor.capture(), any()); + ArgumentCaptor captor = + ArgumentCaptor.forClass(com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest.class); + Mockito.verify(mockRaw.tokens, Mockito.times(EXPECTED_BATCH_COUNT)).detokenize(captor.capture(), any()); List flattened = new ArrayList<>(); - for (com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDetokenizeRequest sent : captor.getAllValues()) { - Assert.assertEquals("vault123", sent.getVaultId().get()); + for (com.skyflow.generated.rest.resources.tokens.requests.DetokenizeRequest sent : captor.getAllValues()) { + Assert.assertEquals("vault123", sent.getVaultId()); Assert.assertTrue(sent.getTokenGroupRedactions().isPresent()); Assert.assertEquals("group one", sent.getTokenGroupRedactions().get().get(0).getTokenGroupName().get()); Assert.assertEquals("MASKED", sent.getTokenGroupRedactions().get().get(0).getRedaction().get()); - flattened.addAll(sent.getTokens().get()); + flattened.addAll(sent.getTokens()); } Assert.assertEquals(tokens, flattened); } @@ -1365,7 +2152,7 @@ public void testBulkDetokenize_vaultIdAndRedactionsReachEveryBatchAndTokenOrderP @Test public void testBulkDetokenize_responseIndexMapsToOriginalInputPosition_acrossBatches() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); stubDetokenizeEcho(mockRaw); VaultController controller = createControllerWithMock(mockApi); @@ -1384,7 +2171,7 @@ public void testBulkDetokenize_responseIndexMapsToOriginalInputPosition_acrossBa @Test public void testBulkDetokenize_interceptorInvokedOncePerBatchWithDistinctContext() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); stubDetokenizeEcho(mockRaw); VaultController controller = createControllerWithMock(mockApi); @@ -1394,7 +2181,7 @@ public void testBulkDetokenize_interceptorInvokedOncePerBatchWithDistinctContext controller.bulkDetokenize(request, BulkDetokenizeOptions.builder().interceptor(interceptor).build()); ArgumentCaptor captor = ArgumentCaptor.forClass(RequestOptions.class); - Mockito.verify(mockRaw, Mockito.times(EXPECTED_BATCH_COUNT)).detokenize(any(), captor.capture()); + Mockito.verify(mockRaw.tokens, Mockito.times(EXPECTED_BATCH_COUNT)).detokenize(any(), captor.capture()); assertInterceptorRanOncePerBatch(interceptor, captor.getAllValues()); } @@ -1403,7 +2190,7 @@ public void testBulkDetokenize_interceptorInvokedOncePerBatchWithDistinctContext @Test public void testBulkDeleteTokens_vaultIdOnEveryBatchAndTokenOrderPreserved() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); stubDeleteTokensEcho(mockRaw); VaultController controller = createControllerWithMock(mockApi); @@ -1412,14 +2199,14 @@ public void testBulkDeleteTokens_vaultIdOnEveryBatchAndTokenOrderPreserved() thr BulkDeleteTokensResponse response = controller.bulkDeleteTokens(request); - ArgumentCaptor captor = - ArgumentCaptor.forClass(com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest.class); - Mockito.verify(mockRaw, Mockito.times(EXPECTED_BATCH_COUNT)).deletetoken(captor.capture(), any()); + ArgumentCaptor captor = + ArgumentCaptor.forClass(com.skyflow.generated.rest.resources.tokens.requests.DeleteTokenRequest.class); + Mockito.verify(mockRaw.tokens, Mockito.times(EXPECTED_BATCH_COUNT)).deleteToken(captor.capture(), any()); List flattened = new ArrayList<>(); - for (com.skyflow.generated.rest.resources.flowservice.requests.V1FlowDeleteTokenRequest sent : captor.getAllValues()) { - Assert.assertEquals("vault123", sent.getVaultId().get()); - flattened.addAll(sent.getTokens().get()); + for (com.skyflow.generated.rest.resources.tokens.requests.DeleteTokenRequest sent : captor.getAllValues()) { + Assert.assertEquals("vault123", sent.getVaultId()); + flattened.addAll(sent.getTokens()); } Assert.assertEquals(tokens, flattened); @@ -1433,7 +2220,7 @@ public void testBulkDeleteTokens_vaultIdOnEveryBatchAndTokenOrderPreserved() thr @Test public void testBulkDeleteTokens_interceptorInvokedOncePerBatchWithDistinctContext() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); stubDeleteTokensEcho(mockRaw); VaultController controller = createControllerWithMock(mockApi); @@ -1443,7 +2230,7 @@ public void testBulkDeleteTokens_interceptorInvokedOncePerBatchWithDistinctConte controller.bulkDeleteTokens(request, BulkDeleteTokensOptions.builder().interceptor(interceptor).build()); ArgumentCaptor captor = ArgumentCaptor.forClass(RequestOptions.class); - Mockito.verify(mockRaw, Mockito.times(EXPECTED_BATCH_COUNT)).deletetoken(any(), captor.capture()); + Mockito.verify(mockRaw.tokens, Mockito.times(EXPECTED_BATCH_COUNT)).deleteToken(any(), captor.capture()); assertInterceptorRanOncePerBatch(interceptor, captor.getAllValues()); } @@ -1452,7 +2239,7 @@ public void testBulkDeleteTokens_interceptorInvokedOncePerBatchWithDistinctConte @Test public void testBulkTokenize_vaultIdOnEveryBatchAndValueOrderPreserved() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); stubTokenizeEcho(mockRaw); VaultController controller = createControllerWithMock(mockApi); @@ -1467,15 +2254,15 @@ public void testBulkTokenize_vaultIdOnEveryBatchAndValueOrderPreserved() throws controller.bulkTokenize(request); - ArgumentCaptor captor = - ArgumentCaptor.forClass(com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest.class); - Mockito.verify(mockRaw, Mockito.times(EXPECTED_BATCH_COUNT)).tokenize(captor.capture(), any()); + ArgumentCaptor captor = + ArgumentCaptor.forClass(com.skyflow.generated.rest.resources.tokens.requests.TokenizeRequest.class); + Mockito.verify(mockRaw.tokens, Mockito.times(EXPECTED_BATCH_COUNT)).tokenize(captor.capture(), any()); List flattened = new ArrayList<>(); - for (com.skyflow.generated.rest.resources.flowservice.requests.V1FlowTokenizeRequest sent : captor.getAllValues()) { - Assert.assertEquals("vault123", sent.getVaultId().get()); - for (com.skyflow.generated.rest.types.V1FlowTokenizeRequestObject obj : sent.getData().get()) { - Assert.assertEquals(Collections.singletonList("group1"), obj.getTokenGroupNames().get()); + for (com.skyflow.generated.rest.resources.tokens.requests.TokenizeRequest sent : captor.getAllValues()) { + Assert.assertEquals("vault123", sent.getVaultId()); + for (com.skyflow.generated.rest.types.TokenizeRequestObject obj : sent.getData()) { + Assert.assertEquals(Collections.singletonList("group1"), obj.getTokenGroupNames()); flattened.add(obj.getValue().get()); } } @@ -1488,7 +2275,7 @@ public void testBulkTokenize_vaultIdOnEveryBatchAndValueOrderPreserved() throws @Test public void testBulkTokenize_interceptorInvokedOncePerBatchWithDistinctContext() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); stubTokenizeEcho(mockRaw); VaultController controller = createControllerWithMock(mockApi); @@ -1502,14 +2289,14 @@ public void testBulkTokenize_interceptorInvokedOncePerBatchWithDistinctContext() controller.bulkTokenize(request, BulkTokenizeOptions.builder().interceptor(interceptor).build()); ArgumentCaptor captor = ArgumentCaptor.forClass(RequestOptions.class); - Mockito.verify(mockRaw, Mockito.times(EXPECTED_BATCH_COUNT)).tokenize(any(), captor.capture()); + Mockito.verify(mockRaw.tokens, Mockito.times(EXPECTED_BATCH_COUNT)).tokenize(any(), captor.capture()); assertInterceptorRanOncePerBatch(interceptor, captor.getAllValues()); } @Test public void testBulkInsert_throwingInterceptorWrappedAsSkyflowException() throws Exception { ApiClient mockApi = Mockito.mock(ApiClient.class); - RawFlowserviceClient mockRaw = mockRawFlowservice(mockApi); + MockRaw mockRaw = mockRawFlowservice(mockApi); stubInsertEcho(mockRaw); VaultController controller = createControllerWithMock(mockApi); diff --git a/flowvault/src/test/java/com/skyflow/vault/data/OptionsTests.java b/flowvault/src/test/java/com/skyflow/vault/data/OptionsTests.java index 83b54775..8632230d 100644 --- a/flowvault/src/test/java/com/skyflow/vault/data/OptionsTests.java +++ b/flowvault/src/test/java/com/skyflow/vault/data/OptionsTests.java @@ -156,4 +156,32 @@ public void testBulkDeleteTokensOptions_builderStaysBulkTypedWhileChaining() { BulkDeleteTokensOptions options = builder.build(); Assert.assertSame(INTERCEPTOR, options.getInterceptor()); } + + // ── QueryOptions ───────────────────────────────────────────────────────── + + @Test + public void testQueryOptions_withInterceptor() { + QueryOptions options = QueryOptions.builder().interceptor(INTERCEPTOR).build(); + Assert.assertSame(INTERCEPTOR, options.getInterceptor()); + } + + @Test + public void testQueryOptions_withoutInterceptor() { + QueryOptions options = QueryOptions.builder().build(); + Assert.assertNull(options.getInterceptor()); + } + + // ── GetTokensOptions ───────────────────────────────────────────────────── + + @Test + public void testGetTokensOptions_withInterceptor() { + GetTokensOptions options = GetTokensOptions.builder().interceptor(INTERCEPTOR).build(); + Assert.assertSame(INTERCEPTOR, options.getInterceptor()); + } + + @Test + public void testGetTokensOptions_withoutInterceptor() { + GetTokensOptions options = GetTokensOptions.builder().build(); + Assert.assertNull(options.getInterceptor()); + } } diff --git a/flowvault/src/test/java/com/skyflow/vault/data/RecordAndRedactionTests.java b/flowvault/src/test/java/com/skyflow/vault/data/RecordAndRedactionTests.java index 52cbf10c..61c56f4d 100644 --- a/flowvault/src/test/java/com/skyflow/vault/data/RecordAndRedactionTests.java +++ b/flowvault/src/test/java/com/skyflow/vault/data/RecordAndRedactionTests.java @@ -10,8 +10,8 @@ /** * Tests for the plain record/redaction data holders: {@link TokenGroupRedactions}, - * {@link InsertRequestRecord}, {@link BulkInsertRequestRecord} - * and {@link BulkTokenizeRequestRecord}. None of these classes perform + * {@link InsertRequestRecord}, {@link BulkInsertRequestRecord}, + * {@link BulkTokenizeRequestRecord} and {@link GetTokensRequestRecord}. None of these classes perform * validation in their builders, so coverage here is builder-construction plus getters. */ public class RecordAndRedactionTests { @@ -162,4 +162,30 @@ public void testBulkTokenizeRequestRecord_isATokenizeRequestRecord() { BulkTokenizeRequestRecord record = BulkTokenizeRequestRecord.builder().value("v1").build(); Assert.assertTrue(record instanceof TokenizeRequestRecord); } + + // ── GetTokensRequestRecord ────────────────────────────────────────────────────── + + @Test + public void testGetTokensRequestRecord_gettersReturnBuilderValues() { + GetTokensRequestRecord record = GetTokensRequestRecord.builder() + .value("john@example.com") + .tokenGroupName("det_group") + .build(); + + Assert.assertEquals("john@example.com", record.getValue()); + Assert.assertEquals("det_group", record.getTokenGroupName()); + } + + @Test + public void testGetTokensRequestRecord_nonStringValueKeptAsIs() { + GetTokensRequestRecord record = GetTokensRequestRecord.builder().value(12345).build(); + Assert.assertEquals(12345, record.getValue()); + } + + @Test + public void testGetTokensRequestRecord_defaultsAreNull() { + GetTokensRequestRecord record = GetTokensRequestRecord.builder().build(); + Assert.assertNull(record.getValue()); + Assert.assertNull(record.getTokenGroupName()); + } } diff --git a/flowvault/src/test/java/com/skyflow/vault/data/RequestResponseWrapperTests.java b/flowvault/src/test/java/com/skyflow/vault/data/RequestResponseWrapperTests.java index 47d6df37..a7b64bf3 100644 --- a/flowvault/src/test/java/com/skyflow/vault/data/RequestResponseWrapperTests.java +++ b/flowvault/src/test/java/com/skyflow/vault/data/RequestResponseWrapperTests.java @@ -17,8 +17,9 @@ /** * Tests for the simple request/response wrapper classes: {@link InsertRequest}, * {@link InsertResponseRecord}, {@link DetokenizeRequest}, {@link DetokenizeResponseRecord}, - * {@link BulkDeleteTokensRequest}, {@link BulkDetokenizeRequest}, {@link BulkTokenizeRequest} - * and {@link BulkInsertRequest}. + * {@link BulkDeleteTokensRequest}, {@link BulkDetokenizeRequest}, {@link BulkTokenizeRequest}, + * {@link BulkInsertRequest}, {@link QueryRequest}, {@link QueryResponse}, {@link GetTokensRequest} + * and {@link GetTokensResponse}. */ public class RequestResponseWrapperTests { @@ -326,4 +327,104 @@ public void testDeleteTokensResponse_gettersReturnConstructorValues() { // Tests for DeleteTokensResponse were removed: the class no longer exists (bulk-only module). + // ── QueryRequest ───────────────────────────────────────────────────────── + + @Test + public void testQueryRequest_getterReturnsBuilderValue() { + QueryRequest request = QueryRequest.builder().query("SELECT * FROM persons").build(); + Assert.assertEquals("SELECT * FROM persons", request.getQuery()); + } + + @Test + public void testQueryRequest_defaultsAreNull() { + QueryRequest request = QueryRequest.builder().build(); + Assert.assertNull(request.getQuery()); + } + + @Test + public void testQueryRequest_isABaseQueryRequest() { + QueryRequest request = QueryRequest.builder().query("SELECT 1").build(); + Assert.assertTrue(request instanceof BaseQueryRequest); + } + + // ── QueryResponse ──────────────────────────────────────────────────────── + + @Test + public void testQueryResponse_gettersReturnConstructorValues() { + HashMap row = new HashMap<>(); + row.put("name", "john"); + ArrayList> fields = new ArrayList<>(Collections.singletonList(row)); + QueryResponseMetadata metadata = new QueryResponseMetadata(Collections.singletonList("name")); + + QueryResponse response = new QueryResponse(fields, metadata, "req-1"); + + Assert.assertEquals(fields, response.getFields()); + Assert.assertNull(response.getErrors()); + Assert.assertSame(metadata, response.getMetadata()); + Assert.assertEquals("req-1", response.getRequestId()); + Assert.assertTrue(response instanceof BaseQueryResponse); + } + + @Test + public void testQueryResponse_toStringSerializesAllFieldsIncludingNulls() { + HashMap row = new HashMap<>(); + row.put("name", "john"); + QueryResponse response = new QueryResponse(new ArrayList<>(Collections.singletonList(row)), + new QueryResponseMetadata(Collections.singletonList("name")), "req-1"); + + String json = response.toString(); + + Assert.assertTrue(json, json.contains("\"fields\":[{\"name\":\"john\"}]")); + Assert.assertTrue(json, json.contains("\"errors\":null")); + Assert.assertTrue(json, json.contains("\"metadata\":{\"columns\":[\"name\"]}")); + Assert.assertTrue(json, json.contains("\"requestId\":\"req-1\"")); + } + + // ── GetTokensRequest ───────────────────────────────────────────────────── + + @Test + public void testGetTokensRequest_getterReturnsBuilderValue() { + List records = Collections.singletonList( + GetTokensRequestRecord.builder().value("john@example.com").tokenGroupName("det_group").build()); + + GetTokensRequest request = GetTokensRequest.builder().records(records).build(); + + Assert.assertEquals(records, request.getRecords()); + Assert.assertTrue(request instanceof BaseGetTokensRequest); + } + + @Test + public void testGetTokensRequest_defaultsAreNull() { + GetTokensRequest request = GetTokensRequest.builder().build(); + Assert.assertNull(request.getRecords()); + } + + // ── GetTokensResponse ──────────────────────────────────────────────────── + + @Test + public void testGetTokensResponse_getterReturnsConstructorValue() { + HashMap record = new HashMap<>(); + record.put("token", "tok-1"); + ArrayList> records = new ArrayList<>(Collections.singletonList(record)); + + GetTokensResponse response = new GetTokensResponse(records); + + Assert.assertEquals(records, response.getRecords()); + Assert.assertTrue(response instanceof BaseGetTokensResponse); + } + + @Test + public void testGetTokensResponse_toStringSerializesNulls() { + HashMap record = new HashMap<>(); + record.put("token", "tok-1"); + record.put("error", null); + record.put("requestId", null); + GetTokensResponse response = new GetTokensResponse(new ArrayList<>(Collections.singletonList(record))); + + String json = response.toString(); + + Assert.assertTrue(json, json.contains("\"token\":\"tok-1\"")); + Assert.assertTrue(json, json.contains("\"error\":null")); + Assert.assertTrue(json, json.contains("\"requestId\":null")); + } } diff --git a/flowvault/src/test/java/com/skyflow/vault/data/ResponseComponentTests.java b/flowvault/src/test/java/com/skyflow/vault/data/ResponseComponentTests.java index 3993c8f6..2b540874 100644 --- a/flowvault/src/test/java/com/skyflow/vault/data/ResponseComponentTests.java +++ b/flowvault/src/test/java/com/skyflow/vault/data/ResponseComponentTests.java @@ -15,7 +15,7 @@ * {@link TokenizeResponseRecord}, {@link BulkTokenizeResponseRecord}, {@link TokenizeSummary}, * {@link DeleteTokensRecord}, {@link BulkDeleteTokensResponseRecord}, * {@link DeleteTokensSummary}, {@link DetokenizeSummary}, {@link DetokenizeResponseRecordMetadata}, - * {@link ErrorRecord} and {@link DetokenizeResponseObject}. + * {@link ErrorRecord}, {@link DetokenizeResponseObject} and {@link QueryResponseMetadata}. */ public class ResponseComponentTests { @@ -687,4 +687,19 @@ public void testParseMetadata_missingKeysParseAsNull() { Assert.assertNull(metadata.getSkyflowId()); Assert.assertNull(metadata.getTableName()); } + + // ── QueryResponseMetadata ──────────────────────────────────────────────── + + @Test + public void testQueryResponseMetadata_getterReturnsConstructorValue() { + List columns = Arrays.asList("skyflow_id", "name", "email"); + QueryResponseMetadata metadata = new QueryResponseMetadata(columns); + Assert.assertEquals(columns, metadata.getColumns()); + } + + @Test + public void testQueryResponseMetadata_nullColumns() { + QueryResponseMetadata metadata = new QueryResponseMetadata(null); + Assert.assertNull(metadata.getColumns()); + } } diff --git a/skyvault/pom.xml b/skyvault/pom.xml index ce14cc82..0a43b671 100644 --- a/skyvault/pom.xml +++ b/skyvault/pom.xml @@ -57,25 +57,18 @@ - - - - - org.apache.maven.plugins - maven-shade-plugin - 3.6.0 - + shade-for-japicmp package diff --git a/skyvault/src/test/java/com/skyflow/utils/logger/LogUtilTests.java b/skyvault/src/test/java/com/skyflow/utils/logger/LogUtilTests.java new file mode 100644 index 00000000..56bba165 --- /dev/null +++ b/skyvault/src/test/java/com/skyflow/utils/logger/LogUtilTests.java @@ -0,0 +1,100 @@ +package com.skyflow.utils.logger; + +import com.skyflow.enums.LogLevel; +import com.skyflow.utils.Constants; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +public class LogUtilTests { + + private static final Logger LOGGER = Logger.getLogger(LogUtil.class.getName()); + + private boolean originalSetupDone; + private Level originalLevel; + + private static class CapturingHandler extends Handler { + final List records = new ArrayList<>(); + + @Override + public void publish(LogRecord record) { + records.add(record); + } + + @Override public void flush() {} + @Override public void close() {} + } + + private static Field setupDoneField() throws NoSuchFieldException { + Field field = LogUtil.class.getDeclaredField("isLoggerSetupDone"); + field.setAccessible(true); + return field; + } + + @Before + public void saveLoggerState() throws Exception { + originalSetupDone = setupDoneField().getBoolean(null); + originalLevel = LOGGER.getLevel(); + } + + @After + public void restoreLoggerState() throws Exception { + setupDoneField().setBoolean(null, originalSetupDone); + LOGGER.setLevel(originalLevel); + } + + // setupLogger calls LogManager.reset() which clears all handlers, + // so the capturing handler must be attached after setupLogger runs. + private CapturingHandler attachCapture() { + CapturingHandler handler = new CapturingHandler(); + handler.setLevel(Level.ALL); + LOGGER.addHandler(handler); + return handler; + } + + @Test + public void testErrorLogBeforeSetupSetsUpLoggerAtErrorLevel() throws Exception { + setupDoneField().setBoolean(null, false); + + LogUtil.printErrorLog("first error before any setup"); + + Assert.assertTrue("the first error log should set the logger up", setupDoneField().getBoolean(null)); + Assert.assertEquals(Level.SEVERE, LOGGER.getLevel()); + } + + @Test + public void testErrorLogAfterSetupIsLoggedWithSdkPrefix() { + LogUtil.setupLogger(LogLevel.ERROR); + CapturingHandler handler = attachCapture(); + + LogUtil.printErrorLog("error after setup"); + + Assert.assertEquals(1, handler.records.size()); + LogRecord record = handler.records.get(0); + Assert.assertEquals(Level.SEVERE, record.getLevel()); + Assert.assertEquals("[" + Constants.SDK_PREFIX + "] error after setup", record.getMessage()); + } + + @Test + public void testInfoWarningAndDebugLogsAreSkippedBeforeSetup() throws Exception { + LogUtil.setupLogger(LogLevel.DEBUG); + CapturingHandler handler = attachCapture(); + setupDoneField().setBoolean(null, false); + + LogUtil.printInfoLog("info before setup"); + LogUtil.printWarningLog("warning before setup"); + LogUtil.printDebugLog("debug before setup"); + + Assert.assertTrue(handler.records.isEmpty()); + Assert.assertFalse("only an error log sets the logger up", setupDoneField().getBoolean(null)); + } +}