using System; using System.Collections.Generic; using System.Linq; using Microsoft.AnalysisServices.Tabular; using Tom=Microsoft.AnalysisServices.Tabular; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; namespace BismNormalizer.TabularCompare.TabularMetadata { /// /// Represents a tabular object for comparison. This class handles JSON serialization. /// public class TabularObject { private string _objectDefinition; private string _name; private TabularModel _parentTabularModel; /// /// Initializes a new instance of the TabularObject class. /// /// The Tabular Object Model supertype of the class being abstracted. public TabularObject(NamedMetadataObject namedMetaDataObject, TabularModel parentTabularModel) { _name = namedMetaDataObject.Name; if (namedMetaDataObject is Tom.Model) return; //Model has custom JSON string _parentTabularModel = parentTabularModel; //Serialize json SerializeOptions options = new SerializeOptions(); options.IgnoreInferredProperties = true; options.IgnoreInferredObjects = true; options.IgnoreTimestamps = true; options.SplitMultilineStrings = true; _objectDefinition = Tom.JsonSerializer.SerializeObject(namedMetaDataObject, options, parentTabularModel.ConnectionInfo.CompatibilityLevel, parentTabularModel.ConnectionInfo.CompatibilityMode); //Remove annotations { JToken token = JToken.Parse(_objectDefinition); RemovePropertyFromObjectDefinition(token, "annotations"); _objectDefinition = token.ToString(Formatting.Indented); } //Remove lineageTag if required if (_parentTabularModel != null && _parentTabularModel.ComparisonInfo != null && !_parentTabularModel.ComparisonInfo.OptionsInfo.OptionLineageTag) { JToken token = JToken.Parse(_objectDefinition); RemovePropertyFromObjectDefinition(token, "lineageTag"); _objectDefinition = token.ToString(Formatting.Indented); } ////todo: remove with Giri's fix ////Remove return characters //if (namedMetaDataObject is Tom.NamedExpression || namedMetaDataObject is Tom.Table) //{ // _objectDefinition = _objectDefinition.Replace("\\r", ""); //} //Order table columns if (namedMetaDataObject is Tom.Table) { if (((Tom.Table)namedMetaDataObject).CalculationGroup != null) { JToken token = JToken.Parse(_objectDefinition); RemovePropertyFromObjectDefinition(token, "calculationItems"); _objectDefinition = token.ToString(Formatting.Indented); } _objectDefinition = SortArray(_objectDefinition, "columns"); _objectDefinition = SortArray(_objectDefinition, "partitions"); } //Order role members if (namedMetaDataObject is Tom.ModelRole) { _objectDefinition = SortArray(_objectDefinition, "members"); } //Hide privacy setting on structured data sources if (namedMetaDataObject is Tom.StructuredDataSource) { JToken token = JToken.Parse(_objectDefinition); RemovePropertyFromObjectDefinition(token, "PrivacySetting"); _objectDefinition = token.ToString(Formatting.Indented); } } private string SortArray(string json, string arrayName) { JObject jObj = (JObject)JsonConvert.DeserializeObject(json); foreach (var prop in jObj.Properties()) { if (prop.Value.Type == JTokenType.Array && prop.Name == arrayName) { var vals = prop.Values() .OfType() .OrderBy(x => x.Property((arrayName == "members" ? "memberName" : "name")).Value.ToString()) .ToList(); prop.Value = JContainer.FromObject(vals); } } return jObj.ToString(Formatting.Indented); } private void RemovePropertyFromObjectDefinition(JToken token, string propertyName) { //child object annotations List removeList = new List(); foreach (JToken childToken in token.Children()) { JProperty property = childToken as JProperty; if (property != null && property.Name == propertyName) { removeList.Add(childToken); } RemovePropertyFromObjectDefinition(childToken, propertyName); } foreach (JToken tokenToRemove in removeList) { tokenToRemove.Remove(); } } /// /// Explicitly remove a JSON property from definition. An example of this is removing parititions from table definitions. /// /// The property to remove public void RemovePropertyFromObjectDefinition(string propertyName) { JObject jObj = JObject.Parse(_objectDefinition); jObj.Remove(propertyName); _objectDefinition = jObj.ToString(Formatting.Indented); } /// /// Set a custom JSON string. An example is for the model class which contains properties that cannot be set. /// public void SetCustomObjectDefinition(string customObjectDefinition) { _objectDefinition = JToken.Parse(customObjectDefinition).ToString(); } /// /// Retrieve a JSON property definition from the full object definition. An example is partitions. /// /// /// Property definition retrieved. public string RetrievePropertyFromObjectDefinition(string propertyToRetrieve) { JObject jObj = JObject.Parse(_objectDefinition); JProperty property = jObj.Property(propertyToRetrieve); return property.ToString(); } /// /// The serialized JSON definition of the tabular object. /// public string ObjectDefinition => _objectDefinition; /// /// The name of the tabular object. Gets overriden by Relationship to show friendly name. /// public virtual string Name => _name; /// /// The internal name of the tabular object. Gets overriden by Relationship to store the true name from TOM (GUID form). /// public virtual string InternalName => _name; } }