Skip to content

Commit f6eb83a

Browse files
committed
de-duplicate code in mutaiton CRUD functions, and refactor tests
1 parent 863e3b2 commit f6eb83a

2 files changed

Lines changed: 96 additions & 316 deletions

File tree

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

Lines changed: 29 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -520,43 +520,7 @@ export class DataConnectApiClient {
520520
tableName: string,
521521
data: Variables,
522522
): Promise<ExecuteGraphqlResponse<GraphQlResponse>> {
523-
if (!validator.isNonEmptyString(tableName)) {
524-
throw new FirebaseDataConnectError({
525-
code: DATA_CONNECT_ERROR_CODE_MAPPING.INVALID_ARGUMENT,
526-
message: '`tableName` must be a non-empty string.'
527-
});
528-
}
529-
if (validator.isArray(data)) {
530-
throw new FirebaseDataConnectError({
531-
code: DATA_CONNECT_ERROR_CODE_MAPPING.INVALID_ARGUMENT,
532-
message: '`data` must be an object, not an array, for single insert. For arrays, please use '
533-
+ '`insertMany` function.'
534-
});
535-
}
536-
if (!validator.isNonNullObject(data)) {
537-
throw new FirebaseDataConnectError({
538-
code: DATA_CONNECT_ERROR_CODE_MAPPING.INVALID_ARGUMENT,
539-
message: '`data` must be a non-null object.'
540-
});
541-
}
542-
543-
try {
544-
const { capitalized, camelCase } = this.getTableNames(tableName);
545-
const keys = this.getFieldsString(data);
546-
const mutation =
547-
`mutation($data: ${capitalized}_Data! @allow(fields: "${keys}")) {
548-
${camelCase}_insert(data: $data)
549-
}`;
550-
551-
return this.executeGraphql<GraphQlResponse, { data: Variables }>(mutation, { variables: { data } })
552-
.catch(this.handleBulkImportErrors);
553-
} catch (e: any) {
554-
throw new FirebaseDataConnectError({
555-
code: DATA_CONNECT_ERROR_CODE_MAPPING.INTERNAL,
556-
message: `Failed to construct insert mutation: ${e.message}`,
557-
cause: e,
558-
});
559-
}
523+
return this.executeSingleMutation<GraphQlResponse, Variables>(tableName, data, 'insert');
560524
}
561525

562526
/**
@@ -566,42 +530,7 @@ export class DataConnectApiClient {
566530
tableName: string,
567531
data: Variables,
568532
): Promise<ExecuteGraphqlResponse<GraphQlResponse>> {
569-
if (!validator.isNonEmptyString(tableName)) {
570-
throw new FirebaseDataConnectError({
571-
code: DATA_CONNECT_ERROR_CODE_MAPPING.INVALID_ARGUMENT,
572-
message: '`tableName` must be a non-empty string.'
573-
});
574-
}
575-
if (!validator.isNonEmptyArray(data)) {
576-
throw new FirebaseDataConnectError({
577-
code: DATA_CONNECT_ERROR_CODE_MAPPING.INVALID_ARGUMENT,
578-
message: '`data` must be a non-empty array for insertMany.',
579-
});
580-
}
581-
if (data.length > 10000) {
582-
throw new FirebaseDataConnectError({
583-
code: DATA_CONNECT_ERROR_CODE_MAPPING.INVALID_ARGUMENT,
584-
message: '`data` array exceeds the maximum limit of 10,000 items.'
585-
});
586-
}
587-
588-
try {
589-
const { capitalized, camelCase } = this.getTableNames(tableName);
590-
const keys = this.getFieldsString(data);
591-
const mutation =
592-
`mutation($data: [${capitalized}_Data!]! @allow(fields: "${keys}")) {
593-
${camelCase}_insertMany(data: $data)
594-
}`;
595-
596-
return this.executeGraphql<GraphQlResponse, { data: Variables }>(mutation, { variables: { data } })
597-
.catch(this.handleBulkImportErrors);
598-
} catch (e: any) {
599-
throw new FirebaseDataConnectError({
600-
code: DATA_CONNECT_ERROR_CODE_MAPPING.INTERNAL,
601-
message: `Failed to construct insertMany mutation: ${e.message}`,
602-
cause: e,
603-
});
604-
}
533+
return this.executeBulkMutation<GraphQlResponse, Variables>(tableName, data, 'insertMany');
605534
}
606535

607536
/**
@@ -610,6 +539,24 @@ export class DataConnectApiClient {
610539
public async upsert<GraphQlResponse, Variables extends object>(
611540
tableName: string,
612541
data: Variables,
542+
): Promise<ExecuteGraphqlResponse<GraphQlResponse>> {
543+
return this.executeSingleMutation<GraphQlResponse, Variables>(tableName, data, 'upsert');
544+
}
545+
546+
/**
547+
* Insert multiple rows into the specified table, or update them if they already exist.
548+
*/
549+
public async upsertMany<GraphQlResponse, Variables extends Array<unknown>>(
550+
tableName: string,
551+
data: Variables,
552+
): Promise<ExecuteGraphqlResponse<GraphQlResponse>> {
553+
return this.executeBulkMutation<GraphQlResponse, Variables>(tableName, data, 'upsertMany');
554+
}
555+
556+
private async executeSingleMutation<GraphQlResponse, Variables extends object>(
557+
tableName: string,
558+
data: Variables,
559+
operationType: 'insert' | 'upsert'
613560
): Promise<ExecuteGraphqlResponse<GraphQlResponse>> {
614561
if (!validator.isNonEmptyString(tableName)) {
615562
throw new FirebaseDataConnectError({
@@ -620,8 +567,8 @@ export class DataConnectApiClient {
620567
if (validator.isArray(data)) {
621568
throw new FirebaseDataConnectError({
622569
code: DATA_CONNECT_ERROR_CODE_MAPPING.INVALID_ARGUMENT,
623-
message: '`data` must be an object, not an array, for single upsert. For arrays, please use '
624-
+ '`upsertMany` function.'
570+
message: `\`data\` must be an object, not an array, for single ${operationType}.\
571+
For arrays, please use \`${operationType}Many\` function.`
625572
});
626573
}
627574
if (!validator.isNonNullObject(data)) {
@@ -636,26 +583,24 @@ export class DataConnectApiClient {
636583
const keys = this.getFieldsString(data);
637584
const mutation =
638585
`mutation($data: ${capitalized}_Data! @allow(fields: "${keys}")) {
639-
${camelCase}_upsert(data: $data)
586+
${camelCase}_${operationType}(data: $data)
640587
}`;
641588

642589
return this.executeGraphql<GraphQlResponse, { data: Variables }>(mutation, { variables: { data } })
643590
.catch(this.handleBulkImportErrors);
644591
} catch (e: any) {
645592
throw new FirebaseDataConnectError({
646593
code: DATA_CONNECT_ERROR_CODE_MAPPING.INTERNAL,
647-
message: `Failed to construct upsert mutation: ${e.message}`,
594+
message: `Failed to construct ${operationType} mutation: ${e.message}`,
648595
cause: e,
649596
});
650597
}
651598
}
652599

653-
/**
654-
* Insert multiple rows into the specified table, or update them if they already exist.
655-
*/
656-
public async upsertMany<GraphQlResponse, Variables extends Array<unknown>>(
600+
private async executeBulkMutation<GraphQlResponse, Variables extends Array<unknown>>(
657601
tableName: string,
658602
data: Variables,
603+
operationType: 'insertMany' | 'upsertMany'
659604
): Promise<ExecuteGraphqlResponse<GraphQlResponse>> {
660605
if (!validator.isNonEmptyString(tableName)) {
661606
throw new FirebaseDataConnectError({
@@ -666,7 +611,7 @@ export class DataConnectApiClient {
666611
if (!validator.isNonEmptyArray(data)) {
667612
throw new FirebaseDataConnectError({
668613
code: DATA_CONNECT_ERROR_CODE_MAPPING.INVALID_ARGUMENT,
669-
message: '`data` must be a non-empty array for upsertMany.'
614+
message: `\`data\` must be a non-empty array for ${operationType}.`
670615
});
671616
}
672617
if (data.length > 10000) {
@@ -681,15 +626,15 @@ export class DataConnectApiClient {
681626
const keys = this.getFieldsString(data);
682627
const mutation =
683628
`mutation($data: [${capitalized}_Data!]! @allow(fields: "${keys}")) {
684-
${camelCase}_upsertMany(data: $data)
629+
${camelCase}_${operationType}(data: $data)
685630
}`;
686631

687632
return this.executeGraphql<GraphQlResponse, { data: Variables }>(mutation, { variables: { data } })
688633
.catch(this.handleBulkImportErrors);
689634
} catch (e: any) {
690635
throw new FirebaseDataConnectError({
691636
code: DATA_CONNECT_ERROR_CODE_MAPPING.INTERNAL,
692-
message: `Failed to construct upsertMany mutation: ${e.message}`,
637+
message: `Failed to construct ${operationType} mutation: ${e.message}`,
693638
cause: e,
694639
});
695640
}

0 commit comments

Comments
 (0)