main
cs 190 lines 6.23 KB
Raw
1 // 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.
2
3 namespace WixToolset.Data.WindowsInstaller
4 {
5 using System;
6 using System.Collections.Generic;
7 using System.Diagnostics;
8 using System.Xml;
9
10 /// <summary>
11 /// Object that represents a table in a database.
12 /// </summary>
13 [DebuggerDisplay("{Name}")]
14 public class Table
15 {
16 /// <summary>
17 /// Creates a table.
18 /// </summary>
19 /// <param name="tableDefinition">Definition of the table.</param>
20 public Table(TableDefinition tableDefinition)
21 {
22 this.Definition = tableDefinition;
23 this.Rows = new List<Row>();
24 }
25
26 /// <summary>
27 /// Gets the table definition.
28 /// </summary>
29 /// <value>Definition of the table.</value>
30 public TableDefinition Definition { get; }
31
32 /// <summary>
33 /// Gets the name of the table.
34 /// </summary>
35 /// <value>Name of the table.</value>
36 public string Name => this.Definition.Name;
37
38 /// <summary>
39 /// Gets or sets the table transform operation.
40 /// </summary>
41 /// <value>The table transform operation.</value>
42 public TableOperation Operation { get; set; }
43
44 /// <summary>
45 /// Gets the rows contained in the table.
46 /// </summary>
47 /// <value>Rows contained in the table.</value>
48 public IList<Row> Rows { get; }
49
50 /// <summary>
51 /// Creates a new row and adds it to the table.
52 /// </summary>
53 /// <param name="sourceLineNumbers">Original source lines for this row.</param>
54 /// <returns>Row created in table.</returns>
55 public Row CreateRow(SourceLineNumber sourceLineNumbers)
56 {
57 var row = this.Definition.CreateRow(sourceLineNumbers, this);
58 this.Rows.Add(row);
59 return row;
60 }
61
62 /// <summary>
63 /// Validates the rows of this OutputTable and throws if it collides on
64 /// primary keys.
65 /// </summary>
66 public void ValidateRows()
67 {
68 var primaryKeys = new Dictionary<string, SourceLineNumber>();
69
70 foreach (var row in this.Rows)
71 {
72 var primaryKey = row.GetPrimaryKey();
73
74 if (primaryKeys.TryGetValue(primaryKey, out var collisionSourceLineNumber))
75 {
76 throw new WixException(ErrorMessages.DuplicatePrimaryKey(collisionSourceLineNumber, primaryKey, this.Definition.Name));
77 }
78
79 primaryKeys.Add(primaryKey, row.SourceLineNumbers);
80 }
81 }
82
83 /// <summary>
84 /// Parse a table from the xml.
85 /// </summary>
86 /// <param name="reader">XmlReader where the intermediate is persisted.</param>
87 /// <param name="tableDefinitions">TableDefinitions to use in the intermediate.</param>
88 /// <returns>The parsed table.</returns>
89 internal static Table Read(XmlReader reader, TableDefinitionCollection tableDefinitions)
90 {
91 Debug.Assert("table" == reader.LocalName);
92
93 bool empty = reader.IsEmptyElement;
94 TableOperation operation = TableOperation.None;
95 string name = null;
96
97 while (reader.MoveToNextAttribute())
98 {
99 switch (reader.LocalName)
100 {
101 case "name":
102 name = reader.Value;
103 break;
104 case "op":
105 switch (reader.Value)
106 {
107 case "add":
108 operation = TableOperation.Add;
109 break;
110 case "drop":
111 operation = TableOperation.Drop;
112 break;
113 default:
114 throw new XmlException();
115 }
116 break;
117 }
118 }
119
120 if (null == name)
121 {
122 throw new XmlException();
123 }
124
125 TableDefinition tableDefinition = tableDefinitions[name];
126 Table table = new Table(tableDefinition);
127 table.Operation = operation;
128
129 if (!empty)
130 {
131 bool done = false;
132
133 // loop through all the rows in a table
134 while (!done && reader.Read())
135 {
136 switch (reader.NodeType)
137 {
138 case XmlNodeType.Element:
139 switch (reader.LocalName)
140 {
141 case "row":
142 Row.Read(reader, table);
143 break;
144 default:
145 throw new XmlException();
146 }
147 break;
148 case XmlNodeType.EndElement:
149 done = true;
150 break;
151 }
152 }
153
154 if (!done)
155 {
156 throw new XmlException();
157 }
158 }
159
160 return table;
161 }
162
163 /// <summary>
164 /// Persists a row in an XML format.
165 /// </summary>
166 /// <param name="writer">XmlWriter where the Row should persist itself as XML.</param>
167 internal void Write(XmlWriter writer)
168 {
169 if (null == writer)
170 {
171 throw new ArgumentNullException("writer");
172 }
173
174 writer.WriteStartElement("table", WindowsInstallerData.XmlNamespaceUri);
175 writer.WriteAttributeString("name", this.Name);
176
177 if (TableOperation.None != this.Operation)
178 {
179 writer.WriteAttributeString("op", this.Operation.ToString().ToLowerInvariant());
180 }
181
182 foreach (var row in this.Rows)
183 {
184 row.Write(writer);
185 }
186
187 writer.WriteEndElement();
188 }
189 }
190 }