284 lines
9.1 KiB
C#
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
|
|
}
|
|
}
|