public static TrackedUseCase UpdateFirms() { var operationIdentity = new StrictOperationIdentity(UpdateIdentity.Instance, new EntitySet(EntityTypeFirm.Instance)); var changes = new[] { ChangeDescriptor.Create(EntityTypeFirm.Instance, 12, ChangeKind.Updated), ChangeDescriptor.Create(EntityTypeFirm.Instance, 13, ChangeKind.Updated) }; var operations = new[] { new OperationDescriptor(Guid.NewGuid(), operationIdentity, new OperationContext(DateTimeOffset.UtcNow, DateTime.UtcNow), new EntityChangesContext(changes)) }; var context = new UseCaseContext(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow, 0); var useCase = new TrackedUseCase(context, operations[0].Id, operations, new Dictionary <Guid, HashSet <Guid> >()); return(useCase); }
public void AddToCache(long maxRowDate, CachedRoutine newCachedRoutine, string lastUpdateByHostName, out ChangeDescriptor changeDescriptor) { changeDescriptor = null; if (this.Id == null) { this.Id = ShortId.Generate(); } if (this.CachedRoutineList == null) { this.CachedRoutineList = new List <CachedRoutine>(); } lock (CachedRoutineList) { // look for an existing item var existing = this.CachedRoutineList.Where(e => newCachedRoutine.Equals(e)).FirstOrDefault(); if (existing != null) { // if existing is not deleted but the update IS if (!existing.IsDeleted && newCachedRoutine.IsDeleted) { changeDescriptor = ChangeDescriptor.Create(lastUpdateByHostName, $"{newCachedRoutine.FullName} DROPPED"); this.CachedRoutineList.Remove(existing); // will be added again below } else if (existing.IsDeleted && newCachedRoutine.IsDeleted) // still deleted then nothing to do { return; } else if (existing.IsDeleted && !newCachedRoutine.IsDeleted) { // "undeleted" changeDescriptor = ChangeDescriptor.Create(lastUpdateByHostName, $"{newCachedRoutine.FullName} (RE)ADDED"); this.CachedRoutineList.Remove(existing); // will be added again below } else if (!newCachedRoutine.IsDeleted) { bool parametersUpdated = newCachedRoutine.ParametersHash != existing.ParametersHash; bool resultSetsUpdated = newCachedRoutine.ResultSetHash != existing.ResultSetHash; bool jsDALMetadataUpdated = false; if (existing.jsDALMetadata == null && newCachedRoutine.jsDALMetadata != null) { jsDALMetadataUpdated = true; } else if (existing.jsDALMetadata != null && newCachedRoutine.jsDALMetadata == null) { jsDALMetadataUpdated = true; } else if (newCachedRoutine.jsDALMetadata != null) { var newMatchesExisting = newCachedRoutine.jsDALMetadata.Equals(existing.jsDALMetadata); jsDALMetadataUpdated = newCachedRoutine.jsDALMetadata != null && !newMatchesExisting; } // no metadata related change if (!parametersUpdated && !resultSetsUpdated && !jsDALMetadataUpdated) { return; } this.CachedRoutineList.Remove(existing); // will be added again below var applicableChanges = new List <string>(); if (parametersUpdated) { applicableChanges.Add("PARAMETERS"); } if (resultSetsUpdated) { applicableChanges.Add("RESULT SETS"); } if (jsDALMetadataUpdated) { applicableChanges.Add("jsDAL metadata"); } changeDescriptor = ChangeDescriptor.Create(lastUpdateByHostName, $"{newCachedRoutine.FullName} UPDATED {string.Join(", ", applicableChanges.ToArray())}"); } } else { changeDescriptor = ChangeDescriptor.Create(lastUpdateByHostName, $"{newCachedRoutine.FullName} ADDED"); } this.CachedRoutineList.Add(newCachedRoutine); } }
public static void GenerateJsFileV2(string source, Endpoint endpoint, JsFile jsFile, Dictionary <string, ChangeDescriptor> fullChangeSet = null, bool rulesChanged = false) { var generateMetric = new Performance.ExecutionBase("GenerateJsFileV2"); var noChanges = false; try { // TODO: Figure out out casing on this property string jsNamespace = null;//endpoint.JsNamespace; if (string.IsNullOrWhiteSpace(jsNamespace)) { jsNamespace = endpoint.MetadataConnection.InitialCatalog; } var jsSafeNamespace = MakeNameJsSafe(jsNamespace); var routineContainerTemplate = WorkSpawner.TEMPLATE_RoutineContainer; var routineTemplate = WorkSpawner.TEMPLATE_Routine; var typescriptDefinitionsContainer = WorkSpawner.TEMPLATE_TypescriptDefinitions; endpoint.ApplyRules(jsFile); var includedRoutines = (from row in endpoint.CachedRoutines where !row.IsDeleted && (row.RuleInstructions[jsFile]?.Included ?? false == true) orderby row.FullName select row).ToList(); List <KeyValuePair <string, ChangeDescriptor> > changesInFile = null; if (fullChangeSet != null) { changesInFile = fullChangeSet.Where(change => includedRoutines.Count(inc => inc.FullName.Equals(change.Key, StringComparison.OrdinalIgnoreCase)) > 0).ToList(); // TODO: Consider if this is a good idea? // If we can reasonably say that there are no changes to routines that this JsFile cares about, why regenerate this file and why give it a new Version if (changesInFile.Count == 0) { noChanges = true; return; } } var jsSchemaLookupForJsFunctions = new Dictionary <string, List <string> /*Routine defs*/>(); var tsSchemaLookup = new Dictionary <string, List <string> /*Routine defs*/>(); var typeScriptParameterAndResultTypesSB = new StringBuilder(); var serverMethodPlugins = PluginLoader.Instance.PluginAssemblies .SelectMany(pa => pa.Plugins) .Where(p => p.Type == PluginType.ServerMethod && endpoint.Application.IsPluginIncluded(p.Guid.ToString())); var uniqueSchemas = new List <string>(); var mainLoopMetric = generateMetric.BeginChildStage("Main loop"); includedRoutines.ForEach(r => { try { if (r.TypescriptMethodStub == null) { r.PrecalculateJsGenerationValues(endpoint); } var jsSchemaName = JsFileGenerator.MakeNameJsSafe(r.Schema); var jsFunctionName = JsFileGenerator.MakeNameJsSafe(r.Routine); if (!jsSchemaLookupForJsFunctions.ContainsKey(jsSchemaName)) { jsSchemaLookupForJsFunctions.Add(jsSchemaName, new List <string>()); } if (!tsSchemaLookup.ContainsKey(jsSchemaName)) { tsSchemaLookup.Add(jsSchemaName, new List <string>()); } if (!uniqueSchemas.Contains(r.Schema)) { uniqueSchemas.Add(r.Schema); } var schemaIx = uniqueSchemas.IndexOf(r.Schema); // .js { var jsFunctionDefLine = routineTemplate.Replace("<<FUNC_NAME>>", jsFunctionName).Replace("<<SCHEMA_IX>>", schemaIx.ToString()).Replace("<<ROUTINE>>", r.Routine); if (r.Type.Equals(string.Intern("PROCEDURE"), StringComparison.OrdinalIgnoreCase)) { jsFunctionDefLine = jsFunctionDefLine.Replace("<<CLASS>>", "S"); } else { jsFunctionDefLine = jsFunctionDefLine.Replace("<<CLASS>>", "U"); } jsSchemaLookupForJsFunctions[jsSchemaName].Add(jsFunctionDefLine); } // .tsd { typeScriptParameterAndResultTypesSB.AppendLine(r.TypescriptParameterTypeDefinition); typeScriptParameterAndResultTypesSB.AppendLine(r.TypescriptOutputParameterTypeDefinition); typeScriptParameterAndResultTypesSB.AppendLine(r.TypescriptResultSetDefinitions); tsSchemaLookup[jsSchemaName].Add(r.TypescriptMethodStub); } } catch (Exception ex) { SessionLog.Exception(ex); // TODO: quit whole process } }); mainLoopMetric.End(); var finalSBMetric = generateMetric.BeginChildStage("Final SB"); var schemaAndRoutineDefs = string.Join("\r\n", jsSchemaLookupForJsFunctions.Select(s => "\tx." + s.Key + " = {\r\n\t\t" + string.Join(",\r\n\t\t", s.Value.ToArray()) + "\r\n\t}\r\n").ToArray()); var tsSchemaAndRoutineDefs = string.Join("\r\n", tsSchemaLookup.Select(s => "\t\tclass " + s.Key + " {\r\n" + string.Join(";\r\n", s.Value.ToArray()) + "\r\n\t\t}\r\n").ToArray()); var finalSB = new StringBuilder(routineContainerTemplate); jsFile.IncrementVersion(); // record changes against new version if (changesInFile != null && changesInFile.Count > 0) { JsFileChangesTracker.Instance.AddUpdate(endpoint, jsFile, changesInFile.Select(kv => kv.Value).ToList()); } if (rulesChanged) { JsFileChangesTracker.Instance.AddUpdate(endpoint, jsFile, new List <ChangeDescriptor> { ChangeDescriptor.Create("System", "One or more rules changed.") }); } finalSB.Replace("<<DATE>>", DateTime.Now.ToString("dd MMM yyyy, HH:mm")) .Replace("<<FILE_VERSION>>", jsFile.Version.ToString()) .Replace("<<SERVER_NAME>>", Environment.MachineName) .Replace("<<ENDPOINT>>", endpoint.Pedigree) .Replace("<<UNIQUE_SCHEMAS>>", string.Join(',', uniqueSchemas.Select(k => $"'{k}'"))) .Replace("<<Catalog>>", jsSafeNamespace) .Replace("<<ROUTINES>>", schemaAndRoutineDefs) ; var finalTypeScriptSB = new StringBuilder(); finalTypeScriptSB = finalTypeScriptSB.Append(typescriptDefinitionsContainer); // Custom/User types if (endpoint.CustomTypeLookupWithTypeScriptDef.Count > 0) { var customTSD = from kv in endpoint.CustomTypeLookupWithTypeScriptDef select $"\t\ttype {kv.Key} = {kv.Value};"; typeScriptParameterAndResultTypesSB.Insert(0, string.Join("\r\n", customTSD)); } var resultAndParameterTypes = typeScriptParameterAndResultTypesSB.ToString(); finalTypeScriptSB.Replace("<<DATE>>", DateTime.Now.ToString("dd MMM yyyy, HH:mm")) .Replace("<<FILE_VERSION>>", jsFile.Version.ToString()) .Replace("<<SERVER_NAME>>", Environment.MachineName) .Replace("<<Catalog>>", jsSafeNamespace) .Replace("<<ResultAndParameterTypes>>", resultAndParameterTypes) .Replace("<<MethodsStubs>>", tsSchemaAndRoutineDefs) ; finalSBMetric.End(); var toStringMetric = generateMetric.BeginChildStage("ToString"); var typescriptDefinitionsOutput = finalTypeScriptSB.ToString(); var finalOutput = finalSB.ToString(); toStringMetric.End(); var filePath = endpoint.OutputFilePath(jsFile); var minfiedFilePath = endpoint.MinifiedOutputFilePath(jsFile); var tsTypingsFilePath = endpoint.OutputTypeScriptTypingsFilePath(jsFile); var minifyMetric = generateMetric.BeginChildStage("Minify"); var minifiedSource = Uglify.Js(finalOutput /*, { }*/).Code; minifyMetric.End(); if (!Directory.Exists(endpoint.OutputDir)) { Directory.CreateDirectory(endpoint.OutputDir); } var fileOutputMetric = generateMetric.BeginChildStage("Write"); var jsFinalBytes = System.Text.Encoding.UTF8.GetBytes(finalOutput); var jsFinalMinifiedBytes = System.Text.Encoding.UTF8.GetBytes(minifiedSource); jsFile.ETag = Controllers.PublicController.ComputeETag(jsFinalBytes); jsFile.ETagMinified = Controllers.PublicController.ComputeETag(jsFinalMinifiedBytes); File.WriteAllText(filePath, finalOutput); File.WriteAllText(minfiedFilePath, minifiedSource); File.WriteAllText(tsTypingsFilePath, typescriptDefinitionsOutput); fileOutputMetric.End(); } finally { generateMetric.End(); SessionLog.InfoToFileOnly($"{endpoint.Pedigree.PadRight(25, ' ')} - {generateMetric.DurationInMS.ToString().PadLeft(4)} ms {jsFile.Filename.PadRight(20)} (source={source};rulesChanged={rulesChanged};changes={!noChanges}); {generateMetric.ChildDurationsSingleLine()}"); } }