Files
spark/src/DataStreamSuite/DataStreamCore/BlueData/BlueTable.cs
T

284 lines
9.1 KiB
C#

using Bts.DataStreamCore;
using Spark.DataStream;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics.CodeAnalysis;
//using BCG.Utilities;
using System.Linq;
namespace BCG {
/// <summary>
/// Anologue of the dotNet DataTable.
/// </summary>
[Serializable]
public class BlueTable : IBlueRowCollection, IDictionary<int, IBlueRow> {
/// <summary>
/// Hashtable indexed on "id" to speed up removes
/// </summary>
protected Hashtable myIdIndex = new Hashtable();
/// <summary>
/// Schema the table adheres to
/// </summary>
protected IBlueTableSchema mySchema;
#region Constructors
protected BlueTable() { }
/// <summary>
/// The BlueTable constructs the schema from the table being passed and copies
/// all the data over
/// </summary>
/// <param name="table"></param>
public BlueTable(DataTable table) {
ColumnInfo[] cis = new ColumnInfo[table.Columns.Count];
int i = 0;
foreach (DataColumn col in table.Columns)
cis[i] = new ColumnInfo(col.ColumnName, i++, col.DataType);
mySchema = new BlueTableSchema(cis, table.TableName);
foreach (DataRow row in table.Rows) {
IBlueRow newRow = new BlueRow(mySchema, row.ItemArray);
myIdIndex[newRow["id"]] = newRow;
}
}
public BlueTable(IBlueRowCollection table) {
mySchema = table.schema;
foreach (IBlueRow row in table)
addRow(row);
}
public BlueTable(string tableName,
IEnumerable objects,
params CMap[] columnMappers) {
// extract schema from mappers
ColumnInfo[] cols = new ColumnInfo[columnMappers.Length];
for (int i = 0; i < columnMappers.Length; i++) {
cols[i] = new ColumnInfo(
columnMappers[i].getColumnName(), i,
columnMappers[i].getColumnType());
}
mySchema = new BlueTableSchema(cols, tableName);
// load rows
int rowNumber = 0;
foreach (object rowObject in objects) {
object[] values = new object[columnMappers.Length];
for (int cn = 0; cn < columnMappers.Length; cn++)
values[cn] = columnMappers[cn].getColumnValue(rowNumber, rowObject);
addRow(new BlueRow(mySchema, values));
rowNumber++;
}
}
/// <summary>
/// Gets the schema, no data is iniliazed at construction time
/// </summary>
/// <param name="schema"></param>
public BlueTable(IBlueTableSchema schema) { mySchema = schema; }
#endregion
#region IBlueRowCollection members
/// <summary>
/// Returns the row by the index, interface property
/// </summary>
public virtual IBlueRow this[int id] {
get {
object row = myIdIndex[id];
if (row == null)
throw new BlueDataException("ID " + id.ToString() + " does not exist in table " + mySchema.tableName);
return (IBlueRow)row;
}
set {
if ((int)value["id"] != id) {
throw new ArgumentException("id arg not equal to row's actual id", nameof(id));
}
changeRow(value);
}
}
/// <summary>
/// Gets the schema
/// </summary>
public virtual IBlueTableSchema schema { get { return mySchema; } }
public virtual bool containsID(int id) { return myIdIndex[id] != null; }
public virtual bool tryGetValue(int id, out IBlueRow row) {
row = (IBlueRow)myIdIndex[id];
return (row != null);
}
#endregion
#region BlueTable members
public virtual void clear() {
myIdIndex.Clear();
}
/// <summary>
/// If a row with the same id exists, it replaces it
/// </summary>
/// <param name="r"></param>
public virtual void forceAddRow(IBlueRow r) {
myIdIndex[r["id"]] = r;
}
/// <summary>
/// Adds a new row to the table.
/// </summary>
/// <param name="row"></param>
public virtual void addRow(IBlueRow row) {
object id = row["id"];
if (id == null || id == DBNull.Value)
throw new BlueDataException("The ID of the row being added is null/DNBull");
try {
myIdIndex.Add(id, row);
} catch (ArgumentException) {
throw new BlueDataException($"ID: {id} already exists in the table: {mySchema.tableName}");
}
}
public virtual void addRow(DataRow row) {
object val = row["id"];
if (val == null || val == DBNull.Value)
throw new BlueDataException("The ID of the row being added is null/DNBull");
if (myIdIndex[val] != null) {
string err_msg = $"ID: {val} already exists in the table: {mySchema.tableName} duplication of field ID not allowed";
// temp TODOds remove it
bts.Log.assert(false, err_msg);
throw new BlueDataException(err_msg);
}
IBlueRow newRow = new BlueRow(mySchema, row);
myIdIndex[val] = newRow;
}
public virtual void addRows(IBlueRowCollection rows) {
foreach (IBlueRow nr in rows)
addRow(nr);
}
public virtual void addRows(IEnumerable rows) {
foreach (IBlueRow nr in rows)
addRow(nr);
}
/// <summary>
/// Removes a row from the table. Complexity = O(1)
/// </summary>
/// <param name="row"></param>
public virtual bool deleteRow(IBlueRow row) { return deleteRow((int)row["id"]); }
public virtual bool deleteRow(DataRow row) { return deleteRow((int)row["id"]); }
/// <summary>
/// Removes a row specified by the id. The index helps in making this operation O(1)
/// </summary>
/// <param name="id"></param>
public virtual bool deleteRow(int id) {
if (myIdIndex[id] == null)
return false;
myIdIndex.Remove(id);
return true;
}
public virtual bool deleteRows(IBlueRowCollection rows) {
bool retVal = true;
foreach (IBlueRow r in rows)
retVal &= deleteRow(r);
return retVal;
}
public virtual bool deleteRows(IEnumerable rows) {
bool retVal = true;
foreach (IBlueRow r in rows)
retVal &= deleteRow(r);
return retVal;
}
public virtual void changeRow(IBlueRow r) {
myIdIndex[r["id"]] = r;
}
public virtual void changeRows(IBlueRowCollection rows) {
foreach (IBlueRow r in rows)
changeRow(r);
}
#endregion
public IDictionary<int, IBlueRow> AsDictionary() => this;
#region ICollection members
public virtual IEnumerator GetEnumerator() //{return myRows.GetEnumerator ();}
{ return myIdIndex.Values.GetEnumerator(); }
public virtual bool IsSynchronized { get { return false; } }
public virtual object SyncRoot { get { return this; } }
public virtual void CopyTo(Array array, int index) { myIdIndex.Values.CopyTo(array, index); }
public virtual int Count { get { return myIdIndex.Count; } }
#endregion
#region IDictionary<int, IBlueRow> members
public void Add(int key, IBlueRow value) {
throw new NotImplementedException();
}
bool IDictionary<int, IBlueRow>.ContainsKey(int key) =>
containsID(key);
bool IDictionary<int, IBlueRow>.Remove(int key) =>
deleteRow(key);
bool IDictionary<int, IBlueRow>.TryGetValue(
int key, [MaybeNullWhen(false)] out IBlueRow value) =>
tryGetValue(key, out value);
void ICollection<KeyValuePair<int, IBlueRow>>.Add(KeyValuePair<int, IBlueRow> item) =>
addRow(item.Value);
void ICollection<KeyValuePair<int, IBlueRow>>.Clear() =>
clear();
bool ICollection<KeyValuePair<int, IBlueRow>>.Contains(KeyValuePair<int, IBlueRow> item) =>
tryGetValue(item.Key, out var r)
&& BlueRowEqualityComparer.Instance.Equals(r, item.Value);
void ICollection<KeyValuePair<int, IBlueRow>>.CopyTo(
KeyValuePair<int, IBlueRow>[] array, int arrayIndex) {
foreach (DictionaryEntry de in myIdIndex) {
array[arrayIndex++] = new((int)de.Key, (IBlueRow)de.Value);
}
}
bool ICollection<KeyValuePair<int, IBlueRow>>.Remove(KeyValuePair<int, IBlueRow> item) =>
deleteRow(item.Key);
IEnumerator<KeyValuePair<int, IBlueRow>> IEnumerable<KeyValuePair<int, IBlueRow>>.GetEnumerator() {
foreach (DictionaryEntry de in myIdIndex) {
yield return new((int)de.Key, (IBlueRow)de.Value);
}
}
ICollection<int> IDictionary<int, IBlueRow>.Keys =>
GenericCollectionWrapper.Create<int>(myIdIndex.Keys);
ICollection<IBlueRow> IDictionary<int, IBlueRow>.Values =>
GenericCollectionWrapper.Create<IBlueRow>(myIdIndex.Values);
bool ICollection<KeyValuePair<int, IBlueRow>>.IsReadOnly => false;
#endregion
}
}