public void AddPaths(DcColumn sd, DcColumn td, Mapping gMapping) // Add this pair by expanding it using the mapping { Debug.Assert(sd != null && sd.Input == SourceTab, "Wrong use: source path must start from the source table."); Debug.Assert(td != null && td.Input == TargetTab, "Wrong use: target path must start from the target table."); Debug.Assert(sd != null && sd.Output == gMapping.SourceTab, "Wrong use: source path must end where the mapping starts."); Debug.Assert(td != null && td.Output == gMapping.TargetTab, "Wrong use: target path must end where the mapping starts."); if (gMapping.Matches.Count == 0) // If there are no continuations then add only the starting segments (for example, for mappings between primitive tables) { ColumnPath sp = new ColumnPath(); // A path consists of one segment sp.InsertLast(sd); ColumnPath tp = new ColumnPath(); // A path consists of one segment tp.InsertLast(td); PathMatch match = new PathMatch(sp, tp); Matches.Add(match); } foreach (PathMatch gMatch in gMapping.Matches) { ColumnPath sp = new ColumnPath(); // Create source path by concatenating one segment and continuation path from the mapping sp.InsertLast(sd); sp.InsertLast(gMatch.SourcePath); ColumnPath tp = new ColumnPath(); // Create target path by concatenating one segment and continuation path from the mapping tp.InsertLast(td); tp.InsertLast(gMatch.TargetPath); PathMatch match = new PathMatch(sp, tp); Matches.Add(match); } }
public bool Compatible(PathMatch match) // The specified match is compatible with (does not contradicts to) this match { // Main rule: if a coverage condition holds for one path (in one or another direction) then it must hold for the other path (in the same direction) // SourcePath -> TargetPath if (match.SourcePath.StartsWith(SourcePath)) // The specified match continues this path { return(match.TargetPath.StartsWith(TargetPath)); // The same must be true for the other paths } else if (SourcePath.StartsWith(match.SourcePath)) // Opposite { return(TargetPath.StartsWith(match.TargetPath)); // The same must be true for the other paths } // TargetPath -> SourcePath if (match.TargetPath.StartsWith(TargetPath)) { return(match.SourcePath.StartsWith(SourcePath)); } else if (TargetPath.StartsWith(match.TargetPath)) { return(SourcePath.StartsWith(match.SourcePath)); } // Neither source path nor target paths cover. // This means they have some intersection (meet table they both continue). // This meet point defines an implicit match which we do not check but it might contradict to other matches. return(true); }
public void AddMatches(List <PathMatch> matches) // Import all path matches (as new objects) that fit into this mapping { foreach (PathMatch m in matches) { PathMatch match = new PathMatch(m); AddMatch(match); } }
public bool AreMatched(PathMatch match) // Determine if both paths are matched (true if there exist the same or more specific match) { foreach (PathMatch m in Matches) { if (m.Matches(match)) { return(true); } } return(false); // Not found }
public bool Compatible(PathMatch match) // Determine if the specified match does not contradict to this mapping and can be added to it without removing existing matches { foreach (PathMatch m in Matches) { if (!m.Compatible(match)) { return(false); } } return(true); // Compatible and can be added }
public void AddTargetToSchema(DcSchema schema = null) // Ensure that all target elements exist in the specified schema { // The mapping can reference new elements which are not in the schema yet so we try to find them and add if necessary if (schema == null) // Find the schema from the mapping elements { PathMatch match = Matches.FirstOrDefault(m => m.TargetPath.Output.IsPrimitive); schema = match != null ? match.TargetPath.Output.Schema : null; // We assume that primitive tables always have root defined (other tables might not have been added yet). } ColumnTree tree = GetTargetTree(); tree.AddToSchema(schema); }
public virtual void FromJson(JObject json, DcSpace ws) { // No super-object Similarity = (double)json["similarity"]; _sourceTab = (DcTable)Com.Schema.Utils.ResolveJsonRef((JObject)json["source_table"], ws); _targetTab = (DcTable)Com.Schema.Utils.ResolveJsonRef((JObject)json["target_table"], ws); // List of matches foreach (JObject match in json["matches"]) { PathMatch comMatch = (PathMatch)Com.Schema.Utils.CreateObjectFromJson(match); if (comMatch != null) { comMatch.FromJson(match, ws); this.Matches.Add(comMatch); } } }
public void AddMatch(PathMatch match) { Debug.Assert(match != null && match.SourceTab == SourceTab, "Wrong use: source path must start from the source table."); Debug.Assert(match != null && match.TargetTab == TargetTab, "Wrong use: target path must start from the target table."); // In the case of coverage we do nothing. We want to keep more general matches (between tables) while more specific can be added/removed independently (if they satisfy them). // ??? in the case of no coverage, they have a point of intersection. Then - ? Should this point of intersection be within the seconad path or otherwise constrained? // Problem: two tables can be matched explcitly or implicitly, that is, their match logically follows from other path matches. // Implicit match: intersections of two paths produce a more general match // Alternative approach: Incrementally add path segments and checking consistency conditions List <PathMatch> toRemove = new List <PathMatch>(); foreach (PathMatch m in Matches) { if (!m.Compatible(match)) { toRemove.Add(m); } } Matches.Add(match); // Now it is guaranteed to be compatible with all existing matches }
/// <summary> /// Create and initialize a new mapping which produces a flat target set with all primitive columns for copying primitive data from the source set. /// Only identity (PK) source columns are expanded recursively. /// For relational source, this means that all primitive columns of the source table will be mapped with their relational names, no FK-referenced tables will be joined and no artifical column names will be used. /// If it is necessary to expand entity columns (non-PK columns of joined tables) then a different implementation is needed (which will require joins, artifical column/path names etc.) /// </summary> public Mapping CreatePrimitive(DcTable sourceSet, DcTable targetSet, DcSchema targetSchema) { Debug.Assert(!sourceSet.IsPrimitive && !targetSet.IsPrimitive, "Wrong use: copy mapping can be created for only non-primitive tables."); Debug.Assert(targetSchema != null || targetSet.Schema != null, "Wrong use: target schema must be specified."); Mapping map = new Mapping(sourceSet, targetSet); DcSchema sourceSchema = map.SourceTab.Schema; if (targetSchema == null) { targetSchema = targetSet.Schema; } ColumnPath sp; ColumnPath tp; DcColumn td; PathMatch match; if (sourceSchema is SchemaOledb) { TableRel set = (TableRel)map.SourceTab; foreach (ColumnAtt att in set.GreaterPaths) { sp = new ColumnAtt(att); // Recommend matching target type (mapping primitive types) this.MapPrimitiveSet(att.Output, targetSchema); DcTable targetType = this.GetBestTargetSet(att.Output, targetSchema); td = new Schema.Column(att.RelationalColumnName, map.TargetTab, targetType, att.IsKey, false); tp = new ColumnPath(td); tp.Name = sp.Name; match = new PathMatch(sp, tp, 1.0); map.Matches.Add(match); } } else if (sourceSchema is SchemaCsv) { DcTable set = (DcTable)map.SourceTab; foreach (DcColumn sd in set.Columns) { if (sd.IsSuper) { continue; } // Recommend matching target type (mapping primitive types) //this.MapPrimitiveSet(sd, targetSchema); //ComTable targetType = this.GetBestTargetSet(sd.Output, targetSchema); // // Analyze sample values of sd and choose the most specific target type // List <string> values = ((ColumnCsv)sd).SampleValues; string targetTypeName; if (Com.Schema.Utils.isInt32(values.ToArray())) { targetTypeName = "Integer"; } else if (Com.Schema.Utils.isDouble(values.ToArray())) { targetTypeName = "Double"; } else { targetTypeName = "String"; } DcTable targetType = targetSchema.GetPrimitiveType(targetTypeName); td = targetSchema.Space.CreateColumn(sd.Name, map.TargetTab, targetType, sd.IsKey); sp = new ColumnPath(sd); tp = new ColumnPath(td); match = new PathMatch(sp, tp, 1.0); map.Matches.Add(match); } } return(map); }
public PathMatch(PathMatch m) { SourcePath = new ColumnPath(m.SourcePath); TargetPath = new ColumnPath(m.TargetPath); Similarity = m.Similarity; }
public bool Matches(PathMatch match) // This is more specific (longer) than argument { return(MatchesSource(match.SourcePath) && MatchesTarget(match.TargetPath)); }