Skip to content

Commit 3cac102

Browse files
committed
fix lint issues and function signatures
1 parent 37d7d85 commit 3cac102

4 files changed

Lines changed: 77 additions & 58 deletions

File tree

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

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ function objectToString(data: any): string {
3434
if (typeof data !== 'object' || data === null) {
3535
if (typeof data === 'string') {
3636
// Properly escape double quotes and backslashes within strings
37-
const escapedString = data.replace(/\/g, '\\').replace(/"/g, '\"');
37+
const escapedString = data.replace(/\//g, '\\').replace(/,"/g, '"');
3838
return `"${escapedString}"`;
3939
}
4040
// Handle numbers, booleans, null directly
@@ -233,25 +233,26 @@ export class DataConnectApiClient {
233233
* Insert a single row into the specified table.
234234
* (Implementation moved from DataConnect class)
235235
*/
236-
public insert(
236+
public async insert<GraphQlResponse, Variables extends object>(
237237
tableName: string,
238-
data: object,
239-
): Promise<ExecuteGraphqlResponse<unknown>> {
238+
data: Variables,
239+
): Promise<ExecuteGraphqlResponse<GraphQlResponse>> {
240240
if (!validator.isNonEmptyString(tableName)) {
241241
throw new FirebaseDataConnectError('invalid-argument', '`tableName` must be a non-empty string.');
242242
}
243243
if (!validator.isNonNullObject(data)) {
244244
throw new FirebaseDataConnectError('invalid-argument', '`data` must be a non-null object.');
245245
}
246246
if (Array.isArray(data)) {
247-
throw new FirebaseDataConnectError('invalid-argument', '`data` must be an object, not an array, for single insert.');
247+
throw new FirebaseDataConnectError(
248+
'invalid-argument', '`data` must be an object, not an array, for single insert.');
248249
}
249250

250251
try {
251252
const gqlDataString = objectToString(data);
252253
const mutation = `mutation { ${tableName}_insert(data: ${gqlDataString}) }`;
253254
// Use internal executeGraphql
254-
return this.executeGraphql<unknown, never>(mutation);
255+
return this.executeGraphql<GraphQlResponse, Variables>(mutation);
255256
} catch (e: any) {
256257
throw new FirebaseDataConnectError('internal-error', `Failed to construct insert mutation: ${e.message}`);
257258
}
@@ -261,10 +262,10 @@ export class DataConnectApiClient {
261262
* Insert multiple rows into the specified table.
262263
* (Implementation moved from DataConnect class)
263264
*/
264-
public insertMany(
265+
public async insertMany<GraphQlResponse, Variables extends Array<unknown>>(
265266
tableName: string,
266-
data: object[],
267-
): Promise<ExecuteGraphqlResponse<unknown>> {
267+
data: Variables,
268+
): Promise<ExecuteGraphqlResponse<GraphQlResponse>> {
268269
if (!validator.isNonEmptyString(tableName)) {
269270
throw new FirebaseDataConnectError('invalid-argument', '`tableName` must be a non-empty string.');
270271
}
@@ -276,7 +277,7 @@ export class DataConnectApiClient {
276277
const gqlDataString = objectToString(data);
277278
const mutation = `mutation { ${tableName}_insertMany(data: ${gqlDataString}) }`;
278279
// Use internal executeGraphql
279-
return this.executeGraphql<unknown, never>(mutation);
280+
return this.executeGraphql<GraphQlResponse, Variables>(mutation);
280281
} catch (e: any) {
281282
throw new FirebaseDataConnectError('internal-error', `Failed to construct insertMany mutation: ${e.message}`);
282283
}
@@ -286,25 +287,26 @@ export class DataConnectApiClient {
286287
* Insert a single row into the specified table, or update it if it already exists.
287288
* (Implementation moved from DataConnect class)
288289
*/
289-
public upsert(
290+
public async upsert<GraphQlResponse, Variables extends object>(
290291
tableName: string,
291-
data: object,
292-
): Promise<ExecuteGraphqlResponse<unknown>> {
292+
data: Variables,
293+
): Promise<ExecuteGraphqlResponse<GraphQlResponse>> {
293294
if (!validator.isNonEmptyString(tableName)) {
294295
throw new FirebaseDataConnectError('invalid-argument', '`tableName` must be a non-empty string.');
295296
}
296297
if (!validator.isNonNullObject(data)) {
297298
throw new FirebaseDataConnectError('invalid-argument', '`data` must be a non-null object.');
298299
}
299300
if (Array.isArray(data)) {
300-
throw new FirebaseDataConnectError('invalid-argument', '`data` must be an object, not an array, for single upsert.');
301+
throw new FirebaseDataConnectError(
302+
'invalid-argument', '`data` must be an object, not an array, for single upsert.');
301303
}
302304

303305
try {
304306
const gqlDataString = objectToString(data);
305307
const mutation = `mutation { ${tableName}_upsert(data: ${gqlDataString}) }`;
306308
// Use internal executeGraphql
307-
return this.executeGraphql<unknown, never>(mutation);
309+
return this.executeGraphql<GraphQlResponse, Variables>(mutation);
308310
} catch (e: any) {
309311
throw new FirebaseDataConnectError('internal-error', `Failed to construct upsert mutation: ${e.message}`);
310312
}
@@ -314,10 +316,10 @@ export class DataConnectApiClient {
314316
* Insert multiple rows into the specified table, or update them if they already exist.
315317
* (Implementation moved from DataConnect class)
316318
*/
317-
public upsertMany(
319+
public async upsertMany<GraphQlResponse, Variables extends Array<unknown>>(
318320
tableName: string,
319-
data: object[],
320-
): Promise<ExecuteGraphqlResponse<unknown>> {
321+
data: Variables,
322+
): Promise<ExecuteGraphqlResponse<GraphQlResponse>> {
321323
if (!validator.isNonEmptyString(tableName)) {
322324
throw new FirebaseDataConnectError('invalid-argument', '`tableName` must be a non-empty string.');
323325
}
@@ -329,7 +331,7 @@ export class DataConnectApiClient {
329331
const gqlDataString = objectToString(data);
330332
const mutation = `mutation { ${tableName}_upsertMany(data: ${gqlDataString}) }`;
331333
// Use internal executeGraphql
332-
return this.executeGraphql<unknown, never>(mutation);
334+
return this.executeGraphql<GraphQlResponse, Variables>(mutation);
333335
} catch (e: any) {
334336
throw new FirebaseDataConnectError('internal-error', `Failed to construct upsertMany mutation: ${e.message}`);
335337
}

src/data-connect/data-connect.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -109,61 +109,61 @@ export class DataConnect {
109109
* Insert a single row into the specified table.
110110
*
111111
* @param tableName - The name of the table to insert data into.
112-
* @param data - The data object to insert. The keys should correspond to the column names.
112+
* @param variables - The data object to insert. The keys should correspond to the column names.
113113
* @returns A promise that fulfills with a `ExecuteGraphqlResponse`.
114114
* @beta
115115
*/
116-
public insert(
116+
public insert<GraphQlResponse, Variables extends object>(
117117
tableName: string,
118-
data: object,
119-
): Promise<ExecuteGraphqlResponse<unknown>> {
120-
return this.client.insert(tableName, data);
118+
variables: Variables,
119+
): Promise<ExecuteGraphqlResponse<GraphQlResponse>> {
120+
return this.client.insert(tableName, variables);
121121
}
122122

123123
/**
124124
* Insert multiple rows into the specified table.
125125
*
126126
* @param tableName - The name of the table to insert data into.
127-
* @param data - An array of data objects to insert. Each object's keys should correspond to the column names.
127+
* @param variables - An array of data objects to insert. Each object's keys should correspond to the column names.
128128
* @returns A promise that fulfills with a `ExecuteGraphqlResponse`.
129129
* @beta
130130
*/
131-
public insertMany(
131+
public insertMany<GraphQlResponse, Variables extends Array<unknown>>(
132132
tableName: string,
133-
data: object[],
134-
): Promise<ExecuteGraphqlResponse<unknown>> {
135-
return this.client.insertMany(tableName, data);
133+
variables: Variables,
134+
): Promise<ExecuteGraphqlResponse<GraphQlResponse>> {
135+
return this.client.insertMany(tableName, variables);
136136
}
137137

138138
/**
139139
* Insert a single row into the specified table, or update it if it already exists.
140140
* The specific behavior (insert or update) depends on the underlying database and schema configuration.
141141
*
142142
* @param tableName - The name of the table to upsert data into.
143-
* @param data - The data object to upsert. The keys should correspond to the column names.
143+
* @param variables - The data object to upsert. The keys should correspond to the column names.
144144
* @returns A promise that fulfills with a `ExecuteGraphqlResponse`.
145145
* @beta
146146
*/
147-
public upsert(
147+
public upsert<GraphQlResponse, Variables extends object>(
148148
tableName: string,
149-
data: object,
150-
): Promise<ExecuteGraphqlResponse<unknown>> {
151-
return this.client.upsert(tableName, data);
149+
variables: Variables,
150+
): Promise<ExecuteGraphqlResponse<GraphQlResponse>> {
151+
return this.client.upsert(tableName, variables);
152152
}
153153

154154
/**
155155
* Insert multiple rows into the specified table, or update them if they already exist.
156156
* The specific behavior (insert or update) depends on the underlying database and schema configuration.
157157
*
158158
* @param tableName - The name of the table to upsert data into.
159-
* @param data - An array of data objects to upsert. Each object's keys should correspond to the column names.
159+
* @param variables - An array of data objects to upsert. Each object's keys should correspond to the column names.
160160
* @returns A promise that fulfills with a `ExecuteGraphqlResponse`.
161161
* @beta
162162
*/
163-
public upsertMany(
163+
public upsertMany<GraphQlResponse, Variables extends Array<unknown>>(
164164
tableName: string,
165-
data: object[],
166-
): Promise<ExecuteGraphqlResponse<unknown>> {
167-
return this.client.upsertMany(tableName, data);
165+
variables: Variables,
166+
): Promise<ExecuteGraphqlResponse<GraphQlResponse>> {
167+
return this.client.upsertMany(tableName, variables);
168168
}
169169
}

test/unit/data-connect/data-connect-api-client-internal.spec.ts

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
* @license
33
* Copyright 2024 Google Inc.
44
*
5-
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* Licensed under the Apache License, Version 2.0 (the 'License');
66
* you may not use this file except in compliance with the License.
77
* You may obtain a copy of the License at
88
*
99
* http://www.apache.org/licenses/LICENSE-2.0
1010
*
1111
* Unless required by applicable law or agreed to in writing, software
12-
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* distributed under the License is distributed on an 'AS IS' BASIS,
1313
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1414
* See the License for the specific language governing permissions and
1515
* limitations under the License.
@@ -260,15 +260,21 @@ describe('DataConnectApiClient CRUD helpers', () => {
260260
describe('insert()', () => {
261261
it('should call executeGraphql with the correct mutation for simple data', async () => {
262262
const simpleData = { name: 'test', value: 123 };
263-
const expectedMutation = `mutation { ${testTableName}_insert(data: { name: "test", value: 123 }) }`;
263+
const expectedMutation = `mutation { ${testTableName}_insert(data: { name: 'test', value: 123 }) }`;
264264
await apiClient.insert(testTableName, simpleData);
265265
expect(executeGraphqlStub).to.have.been.calledOnceWithExactly(expectedMutation);
266266
});
267267

268268
it('should call executeGraphql with the correct mutation for complex data', async () => {
269-
const complexData = { id: 'abc', active: true, scores: [10, 20], info: { nested: "yes/no \"quote\" \\slash\\" } };
270-
// Note: Need to match the specific escaping from objectToString: / -> \\, " -> \"
271-
const expectedMutation = `mutation { ${testTableName}_insert(data: { id: "abc", active: true, scores: [10, 20], info: { nested: "yes/no \\"quote\\" \\\\slash\\\\" } }) }`;
269+
const complexData = { id: 'abc', active: true, scores: [10, 20], info: { nested: 'yes/no "quote" \\slash\\' } };
270+
// Note: Need to match the specific escaping from objectToString: / -> \\, ' -> \'
271+
const expectedMutation = `
272+
mutation {
273+
${testTableName}_insert(data: {
274+
id: 'abc', active: true, scores: [10, 20],
275+
info: { nested: 'yes/no \\'quote\\' \\\\slash\\\\' }
276+
})
277+
}`;
272278
await apiClient.insert(testTableName, complexData);
273279
expect(executeGraphqlStub).to.have.been.calledOnceWithExactly(expectedMutation);
274280
});
@@ -296,18 +302,24 @@ describe('DataConnectApiClient CRUD helpers', () => {
296302
describe('insertMany()', () => {
297303
it('should call executeGraphql with the correct mutation for simple data array', async () => {
298304
const simpleDataArray = [{ name: 'test1' }, { name: 'test2', value: 456 }];
299-
const expectedMutation = `mutation { ${testTableName}_insertMany(data: [{ name: "test1" }, { name: "test2", value: 456 }]) }`;
305+
const expectedMutation = `
306+
mutation {
307+
${testTableName}_insertMany(data: [{ name: 'test1' }, { name: 'test2', value: 456 }]) }`;
300308
await apiClient.insertMany(testTableName, simpleDataArray);
301309
expect(executeGraphqlStub).to.have.been.calledOnceWithExactly(expectedMutation);
302310
});
303311

304312
it('should call executeGraphql with the correct mutation for complex data array', async () => {
305313
const complexDataArray = [
306314
{ id: 'a', active: true, info: { nested: 'n1' } },
307-
{ id: 'b', scores: [1, 2], info: { nested: "n2/\\" } }
315+
{ id: 'b', scores: [1, 2], info: { nested: 'n2/\\' } }
308316
];
309-
// Note: Matching specific escaping: / -> \\, " -> \"
310-
const expectedMutation = `mutation { ${testTableName}_insertMany(data: [{ id: "a", active: true, info: { nested: "n1" } }, { id: "b", scores: [1, 2], info: { nested: "n2/\\\\" } }]) }`;
317+
// Note: Matching specific escaping: / -> \\, ' -> \'
318+
const expectedMutation = `
319+
mutation {
320+
${testTableName}_insertMany(data:
321+
[{ id: 'a', active: true, info: { nested: 'n1' } }, { id: 'b', scores: [1, 2],
322+
info: { nested: 'n2/\\\\' } }]) }`;
311323
await apiClient.insertMany(testTableName, complexDataArray);
312324
expect(executeGraphqlStub).to.have.been.calledOnceWithExactly(expectedMutation);
313325
});
@@ -330,7 +342,7 @@ describe('DataConnectApiClient CRUD helpers', () => {
330342
.with.property('code', 'data-connect/invalid-argument');
331343
});
332344

333-
it('should throw FirebaseDataConnectError for non-array data', () => {
345+
it('should throw FirebaseDataConnectError for non-array data', () => {
334346
expect(() => apiClient.insertMany(testTableName, { data: 1 } as any))
335347
.to.throw(FirebaseDataConnectError, /`data` must be a non-empty array for insertMany./)
336348
.with.property('code', 'data-connect/invalid-argument');
@@ -341,15 +353,17 @@ describe('DataConnectApiClient CRUD helpers', () => {
341353
describe('upsert()', () => {
342354
it('should call executeGraphql with the correct mutation for simple data', async () => {
343355
const simpleData = { id: 'key1', value: 'updated' };
344-
const expectedMutation = `mutation { ${testTableName}_upsert(data: { id: "key1", value: "updated" }) }`;
356+
const expectedMutation = `mutation { ${testTableName}_upsert(data: { id: 'key1', value: 'updated' }) }`;
345357
await apiClient.upsert(testTableName, simpleData);
346358
expect(executeGraphqlStub).to.have.been.calledOnceWithExactly(expectedMutation);
347359
});
348360

349361
it('should call executeGraphql with the correct mutation for complex data', async () => {
350-
const complexData = { id: 'key2', active: false, items: [1, null], detail: { status: "done/\\" } };
351-
// Note: Matching specific escaping: / -> \\, " -> \"
352-
const expectedMutation = `mutation { ${testTableName}_upsert(data: { id: "key2", active: false, items: [1, null], detail: { status: "done/\\\\" } }) }`;
362+
const complexData = { id: 'key2', active: false, items: [1, null], detail: { status: 'done/\\' } };
363+
// Note: Matching specific escaping: / -> \\, ' -> \'
364+
const expectedMutation = `
365+
mutation { ${testTableName}_upsert(data:
366+
{ id: 'key2', active: false, items: [1, null], detail: { status: 'done/\\\\' } }) }`;
353367
await apiClient.upsert(testTableName, complexData);
354368
expect(executeGraphqlStub).to.have.been.calledOnceWithExactly(expectedMutation);
355369
});
@@ -377,7 +391,8 @@ describe('DataConnectApiClient CRUD helpers', () => {
377391
describe('upsertMany()', () => {
378392
it('should call executeGraphql with the correct mutation for simple data array', async () => {
379393
const simpleDataArray = [{ id: 'k1' }, { id: 'k2', value: 99 }];
380-
const expectedMutation = `mutation { ${testTableName}_upsertMany(data: [{ id: "k1" }, { id: "k2", value: 99 }]) }`;
394+
const expectedMutation = `
395+
mutation { ${testTableName}_upsertMany(data: [{ id: 'k1' }, { id: 'k2', value: 99 }]) }`;
381396
await apiClient.upsertMany(testTableName, simpleDataArray);
382397
expect(executeGraphqlStub).to.have.been.calledOnceWithExactly(expectedMutation);
383398
});
@@ -387,8 +402,10 @@ describe('DataConnectApiClient CRUD helpers', () => {
387402
{ id: 'x', active: true, info: { nested: 'n1/\\"x' } },
388403
{ id: 'y', scores: [null, 2] }
389404
];
390-
// Note: Matching specific escaping: / -> \\, " -> \"
391-
const expectedMutation = `mutation { ${testTableName}_upsertMany(data: [{ id: "x", active: true, info: { nested: "n1/\\\\\\"x" } }, { id: "y", scores: [null, 2] }]) }`;
405+
// Note: Matching specific escaping: / -> \\, ' -> \'
406+
const expectedMutation = `
407+
mutation { ${testTableName}_upsertMany(data:
408+
[{ id: 'x', active: true, info: { nested: 'n1/\\\\\\'x' } }, { id: 'y', scores: [null, 2] }]) }`;
392409
await apiClient.upsertMany(testTableName, complexDataArray);
393410
expect(executeGraphqlStub).to.have.been.calledOnceWithExactly(expectedMutation);
394411
});

test/unit/data-connect/index.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import * as chaiAsPromised from 'chai-as-promised';
2525
import * as mocks from '../../resources/mocks';
2626
import { App } from '../../../src/app/index';
2727
import { getDataConnect, DataConnect } from '../../../src/data-connect/index';
28-
import { DataConnectApiClient, FirebaseDataConnectError } from '../../../src/data-connect/data-connect-api-client-internal';
28+
import { DataConnectApiClient } from '../../../src/data-connect/data-connect-api-client-internal';
2929

3030
chai.should();
3131
chai.use(sinonChai);

0 commit comments

Comments
 (0)