Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
5 changes: 1 addition & 4 deletions src/data-connect/data-connect-api-client-internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,10 +413,7 @@ export class DataConnectApiClient {
*/
private objectToString(data: unknown): string {
if (typeof data === 'string') {
const escapedString = data
.replace(/\\/g, '\\\\') // Replace \ with \\
.replace(/"/g, '\\"'); // Replace " with \"
return `"${escapedString}"`;
return JSON.stringify(data);
}
if (typeof data === 'number' || typeof data === 'boolean' || data === null) {
return String(data);
Expand Down
66 changes: 66 additions & 0 deletions test/unit/data-connect/data-connect-api-client-internal.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -928,4 +928,70 @@ describe('DataConnectApiClient CRUD helpers', () => {
.to.be.rejectedWith(FirebaseDataConnectError, `${serverErrorString}. ${additionalErrorMessageForBulkImport}`);
});
});

describe('Issue #3043: String serialization', () => {
it('should correctly escape special characters in strings during insert', async () => {
const data = {
content: 'Line 1\nLine 2',
};

await apiClient.insert(tableName, data);
const callArgs = executeGraphqlStub.firstCall.args[0];

// Expected part of the query: content: "Line 1\nLine 2"
// which means the string "Line 1\\nLine 2" should be present in the call args.
expect(callArgs).to.include('content: "Line 1\\nLine 2"');
});

it('should correctly escape backslash', async () => {
const data = {
content: 'Backslash \\',
};

await apiClient.insert(tableName, data);
const callArgs = executeGraphqlStub.firstCall.args[0];

// "Backslash \\"
// Escaped for GraphQL: "Backslash \\\\"
expect(callArgs).to.include('content: "Backslash \\\\"');
});

it('should correctly escape double quotes', async () => {
const data = {
content: 'Quote "test"',
};

await apiClient.insert(tableName, data);
const callArgs = executeGraphqlStub.firstCall.args[0];

// "Quote \"test\""
// Escaped for GraphQL: "Quote \\"test\\""
expect(callArgs).to.include('content: "Quote \\"test\\""');
});

it('should correctly escape tab character', async () => {
const data = {
content: 'Tab\tCharacter',
};

await apiClient.insert(tableName, data);
const callArgs = executeGraphqlStub.firstCall.args[0];

// "Tab\tCharacter"
// Escaped for GraphQL: "Tab\\tCharacter"
expect(callArgs).to.include('content: "Tab\\tCharacter"');
});

it('should correctly handle emojis', async () => {
const data = {
content: 'Emoji 😊',
};

await apiClient.insert(tableName, data);
const callArgs = executeGraphqlStub.firstCall.args[0];

// "Emoji 😊"
expect(callArgs).to.include('content: "Emoji 😊"');
});
});
});
Loading