Skip to content

Commit 2f62f08

Browse files
committed
clean up unit tests
1 parent 4361fb8 commit 2f62f08

3 files changed

Lines changed: 155 additions & 105 deletions

File tree

src/data-connect/data-connect-api-client-internal.ts

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -199,34 +199,51 @@ export class DataConnectApiClient {
199199
return new FirebaseDataConnectError(code, message);
200200
}
201201

202-
/**
203-
* Converts JSON data into a GraphQL literal string.
204-
* Handles nested objects, arrays, strings, numbers, and booleans.
205-
* Ensures strings are properly escaped.
206-
*/
207-
private objectToString(data: any): string {
208-
if (typeof data !== 'object' || data === null) {
209-
if (typeof data === 'string') {
210-
// Properly escape double quotes and backslashes within strings
211-
const escapedString = data.replace(/\//g, '\\').replace(/,"/g, '"');
212-
return `"${escapedString}"`;
213-
}
214-
// Handle numbers, booleans, null directly
202+
/**
203+
* Converts JSON data into a GraphQL literal string.
204+
* Handles nested objects, arrays, strings, numbers, and booleans.
205+
* Ensures strings are properly escaped.
206+
*/
207+
private objectToString(data: any): string {
208+
if (typeof data === 'string') {
209+
const escapedString = data
210+
.replace(/\\/g, '\\\\') // Replace \ with \\
211+
.replace(/"/g, '\\"'); // Replace " with \"
212+
return `"${escapedString}"`;
213+
}
214+
if (typeof data === 'number' || typeof data === 'boolean' || data === null) {
215215
return String(data);
216216
}
217-
218217
if (validator.isArray(data)) {
219218
const elements = data.map(item => this.objectToString(item)).join(', ');
220219
return `[${elements}]`;
221220
}
221+
if (typeof data === 'object' && data !== null) {
222+
// Filter out properties where the value is undefined BEFORE mapping
223+
const kvPairs = Object.entries(data)
224+
.filter(([, val]) => val !== undefined)
225+
.map(([key, val]) => {
226+
// GraphQL object keys are typically unquoted.
227+
return `${key}: ${this.objectToString(val)}`;
228+
});
229+
230+
if (kvPairs.length === 0) {
231+
return '{}'; // Represent an object with no defined properties as {}
232+
}
233+
return `{ ${kvPairs.join(', ')} }`;
234+
}
235+
236+
// If value is undefined (and not an object property, which is handled above,
237+
// e.g., if objectToString(undefined) is called directly or for an array element)
238+
// it should be represented as 'null'.
239+
if (typeof data === 'undefined') {
240+
return 'null';
241+
}
222242

223-
// Handle plain objects
224-
const entries = Object.entries(data).map(([key, value]) => {
225-
// GraphQL object keys are typically unquoted identifiers
226-
return `${key}: ${this.objectToString(value)}`;
227-
});
228-
229-
return `{ ${entries.join(', ')} }`;
243+
// Fallback for any other types (e.g., Symbol, BigInt - though less common in GQL contexts)
244+
// Consider how these should be handled or if an error should be thrown.
245+
// For now, simple string conversion.
246+
return String(data);
230247
}
231248

232249
/**
@@ -239,13 +256,13 @@ export class DataConnectApiClient {
239256
if (!validator.isNonEmptyString(tableName)) {
240257
throw new FirebaseDataConnectError('invalid-argument', '`tableName` must be a non-empty string.');
241258
}
242-
if (!validator.isNonNullObject(data)) {
243-
throw new FirebaseDataConnectError('invalid-argument', '`data` must be a non-null object.');
244-
}
245259
if (validator.isArray(data)) {
246260
throw new FirebaseDataConnectError(
247261
'invalid-argument', '`data` must be an object, not an array, for single insert.');
248262
}
263+
if (!validator.isNonNullObject(data)) {
264+
throw new FirebaseDataConnectError('invalid-argument', '`data` must be a non-null object.');
265+
}
249266

250267
try {
251268
const gqlDataString = this.objectToString(data);
@@ -291,13 +308,13 @@ export class DataConnectApiClient {
291308
if (!validator.isNonEmptyString(tableName)) {
292309
throw new FirebaseDataConnectError('invalid-argument', '`tableName` must be a non-empty string.');
293310
}
294-
if (!validator.isNonNullObject(data)) {
295-
throw new FirebaseDataConnectError('invalid-argument', '`data` must be a non-null object.');
296-
}
297311
if (validator.isArray(data)) {
298312
throw new FirebaseDataConnectError(
299313
'invalid-argument', '`data` must be an object, not an array, for single upsert.');
300314
}
315+
if (!validator.isNonNullObject(data)) {
316+
throw new FirebaseDataConnectError('invalid-argument', '`data` must be a non-null object.');
317+
}
301318

302319
try {
303320
const gqlDataString = this.objectToString(data);

0 commit comments

Comments
 (0)