1 | ;
|
2 | var __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 | };
|
10 | Object.defineProperty(exports, "__esModule", { value: true });
|
11 | const RelationalDBSchemaTransformer_1 = require("./RelationalDBSchemaTransformer");
|
12 | const RelationalDBSchemaTransformerUtils_1 = require("./RelationalDBSchemaTransformerUtils");
|
13 | const 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 | */
|
18 | class 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 | }
|
144 | exports.AuroraServerlessMySQLDatabaseReader = AuroraServerlessMySQLDatabaseReader;
|
145 | //# sourceMappingURL=AuroraServerlessMySQLDatabaseReader.js.map |
\ | No newline at end of file |