private (List <string>, string) BuildResultSetTypescriptDefs(string jsSafeNamespace, string jsSchemaName, string jsFunctionName, ref ConcurrentDictionary <string, string> customTypeLookupWithTypeScriptDef) { var resultTypes = new List <string>(); var typeScriptParameterAndResultTypesSB = new StringBuilder(); int resultIx = 0; foreach (var kv in this.ResultSetMetadata) { var columnCounter = new SortedList <string, int>(); // e.g. Icev0_Accpac_ItemMakeMappingGetListResult0 var tsResultTypeDefName = string.Format("{0}_{1}_{2}Result{3}", jsSafeNamespace, jsSchemaName, jsFunctionName, resultIx++); var tsColumnDefs = new List <string>(); int nonNameColIx = 0; //kv.Value = Table[0...N] foreach (var col in kv.Value) { var colName = col.ColumnName.ToString(); var dbDataType = col.DbDataType.ToString(); if (string.IsNullOrWhiteSpace(colName)) { colName = string.Format("Unknown{0:000}", ++nonNameColIx); } var originalColName = colName; // handle duplicate column names if (columnCounter.ContainsKey(colName)) { //!this.Log.Warning("Duplicate column name encountered for column '{0}' on routine {1}", colName, r.FullName); var n = columnCounter[colName]; colName += ++n; // increase by one to give a new unique name columnCounter[originalColName] = n; } else { columnCounter.Add(colName, 1); } colName = JsFileGenerator.QuoteColumnNameIfNecessary(colName); // a bit backwards but gets the job done var typeScriptDataType = RoutineParameterV2.GetTypescriptTypeFromSql(dbDataType, null, ref customTypeLookupWithTypeScriptDef); // Col: TypeScript DataType var ln = string.Format("{0}: {1}", colName, typeScriptDataType); tsColumnDefs.Add(ln); } // TODO: What to return and what to persist? var typeScriptResultDef = string.Format("class {0} {{ {1} }}", tsResultTypeDefName, string.Join("; ", tsColumnDefs)); resultTypes.Add(tsResultTypeDefName); typeScriptParameterAndResultTypesSB.AppendLine(typeScriptResultDef); } // foreach Result Set return(resultTypes, typeScriptParameterAndResultTypesSB.ToString()); }
// compute & persist some of the TypeScript definitions for reuse during .js generation public void PrecalculateJsGenerationValues(Endpoint endpoint) { try { if (this.IsDeleted) { this.TypescriptOutputParameterTypeDefinition = this.TypescriptParameterTypeDefinition = this.TypescriptMethodStub = this.TypescriptResultSetDefinitions = null; return; } // TODO: Figure out what to do with JsNamespace CASING. Sometimes case changes in connection string and that breaks all existing code string jsNamespace = null;//endpoint.JsNamespace; if (string.IsNullOrWhiteSpace(jsNamespace)) { jsNamespace = endpoint.MetadataConnection.InitialCatalog; } if (string.IsNullOrWhiteSpace(jsNamespace)) { jsNamespace = "NotSet"; } var jsSafeNamespace = JsFileGenerator.MakeNameJsSafe(jsNamespace); var jsSchemaName = JsFileGenerator.MakeNameJsSafe(this.Schema); var jsFunctionName = JsFileGenerator.MakeNameJsSafe(this.Routine); var customTypeLookupWithTypeScriptDef = endpoint.CustomTypeLookupWithTypeScriptDef; var paramTypeScriptDefList = new List <string>(); this.Parameters.Where(p => !string.IsNullOrEmpty(p.Name)).ToList().ForEach(p => { var tsType = RoutineParameterV2.GetTypescriptTypeFromSql(p.SqlDataType, p.CustomType, ref customTypeLookupWithTypeScriptDef); var name = p.Name.TrimStart('@'); if (JsFileGenerator.StartsWithNum(name)) { name = "$" + name; } var tsDefinition = $"{name}{(p.HasDefault ? "?" : "")}: {tsType}"; paramTypeScriptDefList.Add(tsDefinition); }); var tsParameterTypeDefName = $"{ jsSafeNamespace }_{ jsSchemaName }_{ jsFunctionName }Parameters"; // TypeScript input parameter definitions this.TypescriptParameterTypeDefinition = $"type {tsParameterTypeDefName} = {{ { string.Join(", ", paramTypeScriptDefList) } }}"; // TypeScript output parameter definitions var tsOutputParamDefs = (from p in this.Parameters where !string.IsNullOrEmpty(p.Name) && !p.IsResult && p.IsOutput select string.Format("{0}?: {1}", JsFileGenerator.StartsWithNum(p.Name.TrimStart('@')) ? (/*"_" + */ p.Name.TrimStart('@')) : p.Name.TrimStart('@') , RoutineParameterV2.GetTypescriptTypeFromSql(p.SqlDataType, p.CustomType, ref customTypeLookupWithTypeScriptDef))).ToList(); string typeScriptOutputParameterTypeName = null; if (tsOutputParamDefs.Count > 0) { typeScriptOutputParameterTypeName = string.Format("{0}_{1}_{2}OutputParms", jsSafeNamespace, jsSchemaName, jsFunctionName); // TypeScript OUPUT parameter type definition this.TypescriptOutputParameterTypeDefinition = string.Format("type {0} = {{ {1} }}", typeScriptOutputParameterTypeName, string.Join(", ", tsOutputParamDefs)); } var resultTypes = new List <string>(); if (this.ResultSetMetadata != null) { (resultTypes, this.TypescriptResultSetDefinitions) = BuildResultSetTypescriptDefs(jsSafeNamespace, jsSchemaName, jsFunctionName, ref customTypeLookupWithTypeScriptDef); } this.TypescriptMethodStub = BuildMethodTypescriptStub(jsFunctionName, tsParameterTypeDefName, typeScriptOutputParameterTypeName, resultTypes, ref customTypeLookupWithTypeScriptDef); } catch (Exception ex) { ExceptionLogger.LogExceptionThrottled(ex, "PrecalculateJsGenerationValues", 2, $"{endpoint.Pedigree} - {this.Schema}.{this.Routine}"); } }