Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 23 additions & 29 deletions src/utils/validations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,49 +413,43 @@ export const validateUpdateConnectionConfig = (connectionConfig: ConnectionConfi
};

function validateInsertInput(input: unknown, index: number): void {
try {
const inputObject = input as { [key: string]: unknown };

// Check if the object is empty
const entries = Object.entries(inputObject);

if (entries.length === 0) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_RECORD_IN_INSERT, [index]);
}
if (typeof input !== 'object' || input === null || Array.isArray(input)) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_RECORD_IN_INSERT, [index]);
}

for (const [key] of entries) {
if (key && typeof key !== 'string') {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_RECORD_IN_INSERT, [index]);
}
}
const inputObject = input as { [key: string]: unknown };
const entries = Object.entries(inputObject);

} catch (error) {
if (entries.length === 0) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_RECORD_IN_INSERT, [index]);
}

for (const [key] of entries) {
if (!key || typeof key !== 'string') {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_RECORD_IN_INSERT, [index]);
}
}
}

function validateUpdateInput(input: unknown): void {
try {
const inputObject = input as { [key: string]: unknown };
if (typeof input !== 'object' || input === null || Array.isArray(input)) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_RECORD_IN_UPDATE);
}

// Check if the object is empty
const entries = Object.entries(inputObject);
const inputObject = input as { [key: string]: unknown };

if (entries.length === 0) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_RECORD_IN_UPDATE);
}
// Exclude skyflow_id — it is the record identifier, not a data field to update
const entries = Object.entries(inputObject).filter(([key]) => key !== SKYFLOW.ID);

for (const [key] of entries) {
if (key && typeof key !== 'string') {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_RECORD_IN_UPDATE);
}
}

} catch (error) {
if (entries.length === 0) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_RECORD_IN_UPDATE);
}

for (const [key] of entries) {
if (!key || typeof key !== 'string') {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_RECORD_IN_UPDATE);
}
}
}

function validateUpdateToken(input: unknown): void {
Expand Down
10 changes: 5 additions & 5 deletions src/vault/controller/vault/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ class VaultController {
if (body && Array.isArray(body.records)) {
body.records.forEach((field: StringKeyValueMapType) => {
response.success.push({
skyflowId: String(field?.skyflow_id),
requestIndex: index,
skyflow_id: String(field?.skyflow_id),
request_index: index,
...(typeof field?.tokens === 'object' && field?.tokens !== null ? field.tokens : {})
});
});
Expand Down Expand Up @@ -213,7 +213,7 @@ class VaultController {

private parseBulkInsertResponse(records: Record<string, unknown>[]): InsertResponse {
const insertedFields: InsertResponseType[] = records.map(record => ({
skyflowId: String(record.skyflow_id),
skyflow_id: String(record.skyflow_id),
...(typeof record.tokens === 'object' && record.tokens !== null ? record.tokens : {})
}));
return new InsertResponse({ insertedFields, errors: null });
Expand Down Expand Up @@ -290,7 +290,7 @@ class VaultController {
).then(data => {
printLog(logs.infoLogs.UPDATE_SUCCESS, MessageType.LOG, this.client.getLogLevel());
const updatedRecord = {
skyflowId: data.skyflow_id,
skyflow_id: data.skyflow_id,
...data?.tokens
};
resolve(new UpdateResponse({ updatedField: updatedRecord, errors: null }));
Expand Down Expand Up @@ -490,7 +490,7 @@ class VaultController {
printLog(logs.infoLogs.QUERY_SUCCESS, MessageType.LOG, this.client.getLogLevel());
const processedRecords = response.records.map(record => ({
...(typeof record.fields === 'object' && record.fields !== null ? record.fields : {}),
tokenizedData: {
tokenized_data: {
...(typeof record.tokens === 'object' && record.tokens !== null ? record.tokens : {}),
},
}));
Expand Down
1 change: 0 additions & 1 deletion src/vault/model/response/invoke/invoke.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//imports

import { SkyflowRecordError } from "../../../../utils";
import { QueryResponseType } from "../../../types";

class InvokeConnectionResponse {
//fields
Expand Down
9 changes: 9 additions & 0 deletions src/vault/skyflow/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,15 @@ class Skyflow {
this.updateClients(CONFIG.LOGLEVEL);
}

updateLogLevel(logLevel: LogLevel): Skyflow {
if (logLevel && !isLogLevel(logLevel)) {
throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_LOG_LEVEL);
}
this.logLevel = logLevel;
this.updateClients(CONFIG.LOGLEVEL);
return this;
}

getLogLevel() {
return this.logLevel;
}
Expand Down
2 changes: 1 addition & 1 deletion src/vault/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export interface ClientObj {
}

export interface InsertResponseType {
skyflowId: string;
skyflow_id: string;
[key: string]: unknown;
}

Expand Down
96 changes: 90 additions & 6 deletions test/utils/validations.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1164,7 +1164,6 @@ describe('validateInsertRequest', () => {
});

// Test valid cases
// Test valid cases
test('should accept valid insert request', () => {
const request = {
_table: 'users', // Changed from table to _table
Expand All @@ -1177,6 +1176,52 @@ test('should accept valid insert request', () => {
expect(() => validateInsertRequest(request)).not.toThrow();
});

test('should accept insert request with null field values', () => {
const request = {
_table: 'sensitive_data_table',
table: 'sensitive_data_table',
data: [
{ card_number: null }
]
};
expect(() => validateInsertRequest(request)).not.toThrow();
});

test('should accept insert request with empty string field values', () => {
const request = {
_table: 'sensitive_data_table',
table: 'sensitive_data_table',
data: [
{ card_number: '' }
]
};
expect(() => validateInsertRequest(request)).not.toThrow();
});

test('should accept insert request with mixed null, empty string and valid field values', () => {
const request = {
_table: 'sensitive_data_table',
table: 'sensitive_data_table',
data: [
{ card_number: '4111111111111112', cvv: null, expiry: '' }
]
};
expect(() => validateInsertRequest(request)).not.toThrow();
});

test('should accept insert request with multiple records containing null and empty values', () => {
const request = {
_table: 'sensitive_data_table',
table: 'sensitive_data_table',
data: [
{ card_number: '4111111111111112' },
{ card_number: null },
{ card_number: '' }
]
};
expect(() => validateInsertRequest(request)).not.toThrow();
});

// Also update other test cases that check table property
test('should throw error when table is missing', () => {
const request = {
Expand Down Expand Up @@ -1421,17 +1466,56 @@ describe('validateUpdateRequest - validateUpdateInput', () => {
.toThrow(SKYFLOW_ERROR_CODE.INVALID_TYPE_OF_UPDATE_DATA);
});

// Test validateUpdateInput with null values
test('should throw error when data contains null values', () => {
// Test validateUpdateInput with null values — should be accepted
test('should accept update data with null field values', () => {
const request = {
...validTable,
data: {
skyflow_id: 'valid-id',
skyflowId: 'valid-id',
field: null
}
};
expect(() => validateUpdateRequest(request))
.toThrow(SKYFLOW_ERROR_CODE.INVALID_RECORD_IN_UPDATE);
expect(() => validateUpdateRequest(request)).not.toThrow();
});

// Test validateUpdateInput with empty string field values — should be accepted
test('should accept update data with empty string field values', () => {
const request = {
...validTable,
data: {
skyflowId: 'valid-id',
field: ''
}
};
expect(() => validateUpdateRequest(request)).not.toThrow();
});

// Test validateUpdateInput with mixed null, empty string and valid values
test('should accept update data with mixed null, empty string and valid field values', () => {
const request = {
...validTable,
data: {
skyflowId: 'valid-id',
card_number: null,
name: '',
ssn: '123-45-6789'
}
};
expect(() => validateUpdateRequest(request)).not.toThrow();
});

// Test validateUpdateInput with numeric and boolean field values
test('should accept update data with numeric and boolean field values', () => {
const request = {
...validTable,
data: {
skyflowId: 'valid-id',
age: 0,
active: false,
score: 99.5
}
};
expect(() => validateUpdateRequest(request)).not.toThrow();
});

// Test valid update data with multiple fields
Expand Down
8 changes: 4 additions & 4 deletions test/vault/controller/vault.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1007,7 +1007,7 @@ describe('VaultController query method', () => {
expect(response).toBeInstanceOf(QueryResponse);
expect(response.fields).toHaveLength(1);
expect(response.fields[0].id).toBe('1');
expect(response.fields[0].tokenizedData.id).toBe('token123');
expect(response.fields[0].tokenized_data.id).toBe('token123');
expect(response.errors).toBe(null);
});

Expand Down Expand Up @@ -1154,7 +1154,7 @@ describe('VaultController update method', () => {
expect.any(Object) // Headers
);
expect(response).toBeInstanceOf(UpdateResponse);
expect(response.updatedField.skyflowId).toBe('id123');
expect(response.updatedField.skyflow_id).toBe('id123');
expect(response.updatedField.field1).toBe('token123');
expect(response.errors).toBeNull();
});
Expand Down Expand Up @@ -1185,7 +1185,7 @@ describe('VaultController update method', () => {
expect.any(Object) // Headers
);
expect(response).toBeInstanceOf(UpdateResponse);
expect(response.updatedField.skyflowId).toBe('id123');
expect(response.updatedField.skyflow_id).toBe('id123');
expect(response.updatedField.field1).toBe('token123');
expect(response.errors).toBeNull();
});
Expand Down Expand Up @@ -1219,7 +1219,7 @@ describe('VaultController update method', () => {
expect.any(Object) // Headers
);
expect(response).toBeInstanceOf(UpdateResponse);
expect(response.updatedField.skyflowId).toBe('id123');
expect(response.updatedField.skyflow_id).toBe('id123');
expect(response.updatedField.field1).toBe('token123');
expect(response.errors).toBeNull();
});
Expand Down
62 changes: 62 additions & 0 deletions test/vault/skyflow/skyflow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,68 @@ describe('Skyflow initialization', () => {
expect(() => skyflow.setLogLevel("DUMMY"))
.toThrowError(invalidLogLevelError);
});

test('should update log level using updateLogLevel and return Skyflow instance', () => {
const skyflow = new Skyflow({
vaultConfigs: validVaultConfig,
logLevel: LogLevel.ERROR
});
const result = skyflow.updateLogLevel(LogLevel.DEBUG);
expect(skyflow.getLogLevel()).toBe(LogLevel.DEBUG);
expect(result).toBeInstanceOf(Skyflow);
});

test('should support method chaining with updateLogLevel', () => {
const skyflow = new Skyflow({
vaultConfigs: validVaultConfig,
logLevel: LogLevel.ERROR
});
const result = skyflow.updateLogLevel(LogLevel.INFO);
expect(result).toBe(skyflow);
});

test('should throw error when updateLogLevel is called with invalid logLevel', () => {
const skyflow = new Skyflow({
vaultConfigs: validVaultConfig,
logLevel: LogLevel.ERROR
});
expect(() => skyflow.updateLogLevel("INVALID"))
.toThrowError(invalidLogLevelError);
});

test('should propagate updated log level to all vault clients via updateLogLevel', () => {
const skyflow = new Skyflow({
vaultConfigs: [
{ vaultId: "VAULT_ID_1", clusterId: "CLUSTER_ID" },
{ vaultId: "VAULT_ID_2", clusterId: "CLUSTER_ID" }
],
logLevel: LogLevel.ERROR
});
skyflow.updateLogLevel(LogLevel.WARN);
expect(skyflow.getLogLevel()).toBe(LogLevel.WARN);
});

test('should propagate updated log level to vault and connection clients via updateLogLevel', () => {
const skyflow = new Skyflow({
vaultConfigs: [{ vaultId: "VAULT_ID", clusterId: "CLUSTER_ID" }],
connectionConfigs: [{ connectionId: "CONN_ID", connectionUrl: "https://conn.com" }],
logLevel: LogLevel.ERROR
});
skyflow.updateLogLevel(LogLevel.OFF);
expect(skyflow.getLogLevel()).toBe(LogLevel.OFF);
});

test('should update log level to all valid LogLevel values via updateLogLevel', () => {
const skyflow = new Skyflow({
vaultConfigs: validVaultConfig,
logLevel: LogLevel.ERROR
});
const levels = [LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR, LogLevel.OFF];
levels.forEach(level => {
skyflow.updateLogLevel(level);
expect(skyflow.getLogLevel()).toBe(level);
});
});
});

describe('Skyflow Credentials Tests', () => {
Expand Down
Loading