UNPKG

9.39 kBJavaScriptView Raw
1"use strict";
2var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 return new (P || (P = Promise))(function (resolve, reject) {
4 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6 function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
7 step((generator = generator.apply(thisArg, _arguments || [])).next());
8 });
9};
10Object.defineProperty(exports, "__esModule", { value: true });
11const RelationalDBSchemaTransformer_1 = require("./RelationalDBSchemaTransformer");
12const RelationalDBSchemaTransformerUtils_1 = require("./RelationalDBSchemaTransformerUtils");
13const AuroraDataAPIClient_1 = require("./AuroraDataAPIClient");
14/**
15 * A class to manage interactions with a Aurora Serverless MySQL Relational Databse
16 * using the Aurora Data API
17 */
18class AuroraServerlessMySQLDatabaseReader {
19 constructor(dbRegion, awsSecretStoreArn, dbClusterOrInstanceArn, database, aws) {
20 /**
21 * Stores some of the Aurora Serverless MySQL context into the template context,
22 * for later consumption.
23 *
24 * @param contextShell the basic template context, with db source independent fields set.
25 * @returns a fully hydrated template context, complete with Aurora Serverless MySQL context.
26 */
27 this.hydrateTemplateContext = (contextShell) => __awaiter(this, void 0, void 0, function* () {
28 /**
29 * Information needed for creating the AppSync - RDS Data Source
30 * Store as part of the TemplateContext
31 */
32 contextShell.secretStoreArn = this.awsSecretStoreArn;
33 contextShell.rdsClusterIdentifier = this.dbClusterOrInstanceArn;
34 contextShell.databaseSchema = 'mysql';
35 contextShell.databaseName = this.database;
36 contextShell.region = this.dbRegion;
37 return contextShell;
38 });
39 /**
40 * Gets a list of all the table names in the provided database.
41 *
42 * @returns a list of tablenames inside the database.
43 */
44 this.listTables = () => __awaiter(this, void 0, void 0, function* () {
45 const results = yield this.auroraClient.listTables();
46 return results;
47 });
48 /**
49 * Looks up any foreign key constraints that might exist for the provided table.
50 * This is done to ensure our generated schema includes nested types, where possible.
51 *
52 * @param tableName the name of the table to be checked for foreign key constraints.
53 * @returns a list of table names that are applicable as having constraints.
54 */
55 this.getTableForeignKeyReferences = (tableName) => __awaiter(this, void 0, void 0, function* () {
56 const results = yield this.auroraClient.getTableForeignKeyReferences(tableName);
57 return results;
58 });
59 /**
60 * For the provided table, this will create a table context. That context holds definitions for
61 * the base table type, the create input type, and the update input type (e.g. Post, CreatePostInput, and UpdatePostInput, respectively),
62 * as well as the table primary key structure for proper operation definition.
63 *
64 * Create inputs will only differ from the base table type in that any nested types will not be present. Update table
65 * inputs will differ in that the only required field will be the primary key/identifier, as all fields don't have to
66 * be updated. Instead, it assumes the proper ones were provided on create.
67 *
68 * @param tableName the name of the table to be translated into a GraphQL type.
69 * @returns a promise of a table context structure.
70 */
71 this.describeTable = (tableName) => __awaiter(this, void 0, void 0, function* () {
72 const columnDescriptions = yield this.auroraClient.describeTable(tableName);
73 // Fields in the general type (e.g. Post). Both the identifying field and any others the db dictates will be required.
74 const fields = new Array();
75 // Fields in the update input type (e.g. UpdatePostInput). Only the identifying field will be required, any others will be optional.
76 const updateFields = new Array();
77 // Field in the create input type (e.g. CreatePostInput).
78 const createFields = new Array();
79 // The primary key, used to help generate queries and mutations
80 let primaryKey = "";
81 let primaryKeyType = "";
82 // Field Lists needed as context for auto-generating the Query Resolvers
83 const intFieldList = new Array();
84 const stringFieldList = new Array();
85 for (const columnDescription of columnDescriptions) {
86 // If a field is the primary key, save it.
87 if (columnDescription.Key == 'PRI') {
88 primaryKey = columnDescription.Field;
89 primaryKeyType = RelationalDBSchemaTransformerUtils_1.getGraphQLTypeFromMySQLType(columnDescription.Type);
90 }
91 else {
92 /**
93 * If the field is not a key, then store it in the fields list.
94 * As we need this information later to generate query resolvers
95 *
96 * Currently we will only auto-gen query resolvers for the Int and String scalars
97 */
98 const type = RelationalDBSchemaTransformerUtils_1.getGraphQLTypeFromMySQLType(columnDescription.Type);
99 if (type === 'Int') {
100 intFieldList.push(columnDescription.Field);
101 }
102 else if (type === 'String') {
103 stringFieldList.push(columnDescription.Field);
104 }
105 }
106 // Create the basic field type shape, to be consumed by every field definition
107 const baseType = RelationalDBSchemaTransformerUtils_1.getNamedType(RelationalDBSchemaTransformerUtils_1.getGraphQLTypeFromMySQLType(columnDescription.Type));
108 const isPrimaryKey = columnDescription.Key == 'PRI';
109 const isNullable = columnDescription.Null == 'YES';
110 // Generate the field for the general type and the create input type
111 const type = (!isPrimaryKey && isNullable) ? baseType : RelationalDBSchemaTransformerUtils_1.getNonNullType(baseType);
112 fields.push(RelationalDBSchemaTransformerUtils_1.getFieldDefinition(columnDescription.Field, type));
113 createFields.push(RelationalDBSchemaTransformerUtils_1.getInputValueDefinition(type, columnDescription.Field));
114 // Update<type>Input has only the primary key as required, ignoring all other that the database requests as non-nullable
115 const updateType = !isPrimaryKey ? baseType : RelationalDBSchemaTransformerUtils_1.getNonNullType(baseType);
116 updateFields.push(RelationalDBSchemaTransformerUtils_1.getInputValueDefinition(updateType, columnDescription.Field));
117 }
118 // Add foreign key for this table
119 // NOTE from @mikeparisstuff: It would be great to re-enable this such that foreign key relationships are
120 // resolver automatically. This code was breaking compilation because it was not
121 // creating XConnection types correctly. This package also does not yet support
122 // wiring up the resolvers (or ideally selection set introspection & automatic JOINs)
123 // so there is not point in creating these connection fields anyway. Disabling until
124 // supported.
125 // let tablesWithRef = await this.getTableForeignKeyReferences(tableName)
126 // for (const tableWithRef of tablesWithRef) {
127 // if (tableWithRef && tableWithRef.length > 0) {
128 // const baseType = getNamedType(`${tableWithRef}Connection`)
129 // fields.push(getFieldDefinition(`${tableWithRef}`, baseType))
130 // }
131 // }
132 return new RelationalDBSchemaTransformer_1.TableContext(RelationalDBSchemaTransformerUtils_1.getTypeDefinition(fields, tableName), RelationalDBSchemaTransformerUtils_1.getInputTypeDefinition(createFields, `Create${tableName}Input`), RelationalDBSchemaTransformerUtils_1.getInputTypeDefinition(updateFields, `Update${tableName}Input`), primaryKey, primaryKeyType, stringFieldList, intFieldList);
133 });
134 this.auroraClient = new AuroraDataAPIClient_1.AuroraDataAPIClient(dbRegion, awsSecretStoreArn, dbClusterOrInstanceArn, database, aws);
135 this.dbRegion = dbRegion;
136 this.awsSecretStoreArn = awsSecretStoreArn;
137 this.dbClusterOrInstanceArn = dbClusterOrInstanceArn;
138 this.database = database;
139 }
140 setAuroraClient(auroraClient) {
141 this.auroraClient = auroraClient;
142 }
143}
144exports.AuroraServerlessMySQLDatabaseReader = AuroraServerlessMySQLDatabaseReader;
145//# sourceMappingURL=AuroraServerlessMySQLDatabaseReader.js.map
\No newline at end of file