// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Data.WindowsInstaller
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml;
///
/// Object that represents a table in a database.
///
[DebuggerDisplay("{Name}")]
public class Table
{
///
/// Creates a table.
///
/// Definition of the table.
public Table(TableDefinition tableDefinition)
{
this.Definition = tableDefinition;
this.Rows = new List();
}
///
/// Gets the table definition.
///
/// Definition of the table.
public TableDefinition Definition { get; }
///
/// Gets the name of the table.
///
/// Name of the table.
public string Name => this.Definition.Name;
///
/// Gets or sets the table transform operation.
///
/// The table transform operation.
public TableOperation Operation { get; set; }
///
/// Gets the rows contained in the table.
///
/// Rows contained in the table.
public IList Rows { get; }
///
/// Creates a new row and adds it to the table.
///
/// Original source lines for this row.
/// Row created in table.
public Row CreateRow(SourceLineNumber sourceLineNumbers)
{
var row = this.Definition.CreateRow(sourceLineNumbers, this);
this.Rows.Add(row);
return row;
}
///
/// Validates the rows of this OutputTable and throws if it collides on
/// primary keys.
///
public void ValidateRows()
{
var primaryKeys = new Dictionary();
foreach (var row in this.Rows)
{
var primaryKey = row.GetPrimaryKey();
if (primaryKeys.TryGetValue(primaryKey, out var collisionSourceLineNumber))
{
throw new WixException(ErrorMessages.DuplicatePrimaryKey(collisionSourceLineNumber, primaryKey, this.Definition.Name));
}
primaryKeys.Add(primaryKey, row.SourceLineNumbers);
}
}
///
/// Parse a table from the xml.
///
/// XmlReader where the intermediate is persisted.
/// TableDefinitions to use in the intermediate.
/// The parsed table.
internal static Table Read(XmlReader reader, TableDefinitionCollection tableDefinitions)
{
Debug.Assert("table" == reader.LocalName);
bool empty = reader.IsEmptyElement;
TableOperation operation = TableOperation.None;
string name = null;
while (reader.MoveToNextAttribute())
{
switch (reader.LocalName)
{
case "name":
name = reader.Value;
break;
case "op":
switch (reader.Value)
{
case "add":
operation = TableOperation.Add;
break;
case "drop":
operation = TableOperation.Drop;
break;
default:
throw new XmlException();
}
break;
}
}
if (null == name)
{
throw new XmlException();
}
TableDefinition tableDefinition = tableDefinitions[name];
Table table = new Table(tableDefinition);
table.Operation = operation;
if (!empty)
{
bool done = false;
// loop through all the rows in a table
while (!done && reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
switch (reader.LocalName)
{
case "row":
Row.Read(reader, table);
break;
default:
throw new XmlException();
}
break;
case XmlNodeType.EndElement:
done = true;
break;
}
}
if (!done)
{
throw new XmlException();
}
}
return table;
}
///
/// Persists a row in an XML format.
///
/// XmlWriter where the Row should persist itself as XML.
internal void Write(XmlWriter writer)
{
if (null == writer)
{
throw new ArgumentNullException("writer");
}
writer.WriteStartElement("table", WindowsInstallerData.XmlNamespaceUri);
writer.WriteAttributeString("name", this.Name);
if (TableOperation.None != this.Operation)
{
writer.WriteAttributeString("op", this.Operation.ToString().ToLowerInvariant());
}
foreach (var row in this.Rows)
{
row.Write(writer);
}
writer.WriteEndElement();
}
}
}