private void WriteRow(HaystackGrid grid, HaystackRow row) { var first = true; foreach (var column in grid.Columns) { var value = row.ContainsKey(column.Name) ? row[column.Name] : null; if (first) { first = false; } else { _targetWriter.Write(','); } if (value == null) { _targetWriter.Write('N'); } else { WriteValue(value); } } }
public void WriteGrid(HaystackGrid grid) { // meta WriteValue("ver:\"").WriteValue(_version).WriteValue(".0\"").WriteMeta(grid.Meta).WriteNewline(); // cols if (grid.ColumnCount == 0) { // technically this shoudl be illegal, but // for robustness handle it here throw new ArgumentException("Grid has no cols", "grid"); } else { for (int i = 0; i < grid.ColumnCount; ++i) { if (i > 0) { WriteValue(','); } WriteColumn(grid.Column(i)); } } WriteNewline(); // rows for (int i = 0; i < grid.RowCount; ++i) { WriteRow(grid, grid.Row(i)); WriteNewline(); } }
void VerifyGridEquals(HaystackGrid grid, HaystackDictionary meta, object[] cols, HaystackValue[][] rows) { // meta Assert.IsTrue(grid.Meta.Equals(meta)); // cols Assert.AreEqual(grid.ColumnCount, cols.Length / 2); for (int i = 0; i < grid.ColumnCount; ++i) { Assert.AreEqual(grid.Column(i).Name, cols[i * 2 + 0]); Assert.IsTrue(grid.Column(i).Meta.Equals(cols[i * 2 + 1])); } // rows Assert.AreEqual(grid.RowCount, rows.Length); for (int ri = 0; ri < rows.Length; ++ri) { var expected = rows[ri]; var actual = grid.Row(ri); for (int ci = 0; ci < expected.Length; ++ci) { Assert.AreEqual(expected[ci], actual[grid.Column(ci).Name]); } } }
public void TestNoRows() { var grid = new HaystackGrid(); grid.Meta.Add("dis", new HaystackString("Title")); grid.AddColumn("a", col => col.Meta.Add("dis", new HaystackString("Alpha"))); grid.AddColumn("b"); //.Meta Assert.AreEqual(grid.Meta.Count, 1); Assert.IsTrue(grid.Meta["dis"].Equals(new HaystackString("Title"))); // cols Assert.AreEqual(grid.ColumnCount, 2); var c = VerifyCol(grid, 0, "a"); Assert.AreEqual(c.Display, "Alpha"); Assert.AreEqual(c.Meta.Count, 1); Assert.IsTrue(c.Meta["dis"].Equals(new HaystackString("Alpha"))); // rows Assert.AreEqual(grid.RowCount, 0); Assert.AreEqual(grid.IsEmpty(), true); // iterator VerifyGridIterator(grid); }
public HttpClientMockBuilder WithReadAsync(string expectedFilter, HaystackGrid response) { _requestHandlers.Add(async request => { var relativeUri = _baseUri.MakeRelativeUri(request.RequestUri); if (relativeUri.OriginalString != "read") { return(null); } var reader = new ZincReader(await request.Content.ReadAsStringAsync()); var grid = reader.ReadValue <HaystackGrid>(); var filter = grid.Rows.First().Get <HaystackString>("filter").Value; if (filter != expectedFilter) { return(null); } using (var stream = new MemoryStream()) using (var streamWriter = new StreamWriter(stream)) { var writer = new ZincWriter(streamWriter); writer.WriteValue(response); streamWriter.Flush(); stream.Position = 0; return(new HttpResponseMessage { Content = new StringContent(await new StreamReader(stream).ReadToEndAsync()), }); } }); return(this); }
/// <summary> /// Execute a POST request and parse the raw string result into a grid. /// </summary> /// <param name="op">Operation to execute.</param> /// <param name="req">Properly formatted request string</param> /// <returns>Grid of results.</returns> private async Task <HaystackGrid> PostGridAsync(string op, HaystackGrid req) { string reqStr = ZincWriter.ToZinc(req); string resStr = await PostStringAsync(op, reqStr, "text/zinc"); return(new ZincReader(resStr).ReadValue <HaystackGrid>()); }
public void WriteGrid(HaystackGrid grid) { foreach (var row in grid.Rows) { WriteEntity(row); } }
public void WriteEntity_NestedGrid_IsValid() { using (var writer = new StringWriter()) using (var jsonWriter = new JsonTextWriter(writer) { Formatting = Formatting.Indented }) { // Arrange. var haysonWriter = new HaysonWriter(jsonWriter); var grid = new HaystackGrid() .AddColumn("b", col => col.Meta.AddString("dis", "Column B")) .AddColumn("a") .AddRow(new HaystackNumber(20), new HaystackNumber(10)); var entity = new HaystackDictionary(new Dictionary <string, HaystackValue> { ["type"] = new HaystackString("grid"), ["val"] = grid, }); // Act. haysonWriter.WriteEntity(entity); var hayson = writer.ToString(); // Assert. var target = @"{ ""type"": ""grid"", ""val"": { ""_kind"": ""grid"", ""cols"": [ { ""name"": ""b"", ""meta"": { ""dis"": ""Column B"" } }, { ""name"": ""a"" } ], ""rows"": [ { ""b"": { ""_kind"": ""number"", ""val"": 20.0, ""unit"": null }, ""a"": { ""_kind"": ""number"", ""val"": 10.0, ""unit"": null } } ] } }"; Assert.AreEqual(target.Replace("\r", ""), hayson.Replace("\r", "")); } }
/// <summary> /// Return the current status of a point's priority array. /// The resulting grid has the following columns: /// - level: number [1-17] (17 is default) /// - levelDis: Human description of level /// - val: current value at level or null /// - who: who last controlled the value at this level /// </summary> /// <param name="id">Reference of a writable point.</param> /// <returns>Result grid.</returns> public Task <HaystackGrid> PointWriteArrayAsync(HaystackReference id) { var req = new HaystackGrid() .AddColumn("id") .AddRow(id); return(CallAsync("pointWrite", req)); }
HaystackColumn VerifyCol(HaystackGrid g, int i, string n) { var col = g.Column(i); Assert.IsTrue(g.Column(i).Equals(g.Column(n))); Assert.AreEqual(col.Name, n); return(col); }
/// <summary> /// Use vendor specific logic using the "eval" call. /// </summary> /// <param name="expr">Expression.</param> /// <returns>Grid of results.</returns> public Task <HaystackGrid> EvalAsync(string expr) { var req = new HaystackGrid() .AddColumn("expr") .AddRow(new HaystackString(expr)); return(CallAsync("eval", req)); }
/// <summary> /// Read history time-series data for a given point record and time range. /// The range has an inclusive start and an exclusive end. /// The range must match the timezone configured on the history record. /// The range will use the timezone of the record. /// </summary> /// <param name="id">Record ID.</param> /// <param name="range">Time range.</param> /// <returns>Grid of time-series data.</returns> public Task <HaystackGrid> HisReadAsync(HaystackReference id, string range) { var req = new HaystackGrid() .AddColumn("id") .AddColumn("range") .AddRow(id, new HaystackString(range)); return(CallAsync("hisRead", req)); }
/// <summary> /// Write a set of history time-series data to a given point record. /// The record must already exist and tagged as a historized point. /// The timestamp timezone must exactly match the point's timezone "tz" tag. /// </summary> /// <param name="id">Record ID.</param> /// <param name="items">Time-series data.</param> /// <param name="metaData">Optional metadata to include.</param> public Task <HaystackGrid> HisWriteAsync(HaystackReference id, HaystackHistoryItem[] items, HaystackDictionary metaData = null) { var meta = metaData ?? new HaystackDictionary(); meta.Add("id", id); HaystackGrid req = new HaystackGrid(items, meta); return(CallAsync("hisWrite", req)); }
/// <summary> /// Read history time-series data for a given record and time range. /// The range has an inclusive start and an exclusive end. /// The range must match the timezone configured on the history record. /// </summary> /// <param name="id">Record ID.</param> /// <param name="range">Time range.</param> /// <returns>Grid of time-series data.</returns> public Task <HaystackGrid> HisReadAsync(HaystackReference id, HaystackDateTimeRange range) { var req = new HaystackGrid() .AddColumn("id") .AddColumn("range") .AddRow(id, new HaystackString($"{ZincWriter.ToZinc(range.Start)},{ZincWriter.ToZinc(range.End)}")); return(CallAsync("hisRead", req)); }
/// <summary> /// Invoke an action using the "invokeAction" call. /// </summary> /// <param name="id">Target to invoke the action on.</param> /// <param name="action">Action to invoke.</param> /// <param name="args">Action arguments.</param> /// <returns>Action result grid.</returns> public Task <HaystackGrid> InvokeActionAsync(HaystackReference id, string action, HaystackDictionary args) { var meta = new HaystackDictionary(); meta.Add("id", id); meta.Add("action", new HaystackString(action)); var req = new HaystackGrid(new[] { args }, meta); return(CallAsync("invokeAction", req)); }
/// <summary> /// Call the given operation and throw server-side exceptions. /// </summary> /// <param name="op">Operation to execute.</param> /// <param name="req">Request content.</param> /// <returns>Grid of results.</returns> private async Task <HaystackGrid> CallAsync(string op, HaystackGrid req) { HaystackGrid res = await PostGridAsync(op, req); if (res.IsError()) { throw new HaystackException(res); } return(res); }
/// <summary> /// Read any one record that matches a given filter. /// If no records apply an exception is thrown. /// </summary> /// <param name="filter">Record filter.</param> /// <returns>Matching record.</returns> public async Task <HaystackDictionary> ReadAsync(string filter) { HaystackGrid grid = await ReadAllAsync(filter, 1); if (grid.RowCount > 0) { return(grid.Row(0)); } throw new Exception($"Record not found for: {filter}"); }
public void TestEmpty() { var grid = new HaystackGrid(); Assert.AreEqual(grid.Meta, new HaystackDictionary()); Assert.AreEqual(grid.RowCount, 0); Assert.IsTrue(grid.IsEmpty()); Assert.IsFalse(grid.HasColumn("foo")); Assert.ThrowsException <HaystackUnknownNameException>(() => grid.Column("foo")); }
void VerifyGridIterator(HaystackGrid g) { int c = 0; while (c < g.RowCount) { c++; } Assert.AreEqual(g.RowCount, c); }
public void GridToString_NullColumn() { var grid = new HaystackGrid() .AddColumn("val") .AddColumn("null") .AddRow(new HaystackString("value"), null); var str = ZincWriter.ToZinc(grid); Assert.AreEqual("ver:\"3.0\"\nval,null\n\"value\",N", str.Trim()); }
/// <summary> /// Use vendor specific logic using the "eval" call. /// </summary> /// <param name="exprs">List of expressions.</param> /// <returns>Grid of results per expression.</returns> public Task <HaystackGrid[]> EvalAllAsync(string[] exprs) { var req = new HaystackGrid() .AddColumn("expr"); for (int i = 0; i < exprs.Length; ++i) { req.AddRow(new HaystackString(exprs[i])); } return(EvalAllAsync(req)); }
public void WriteEntities_NestedGrid_IsValid() { using (var writer = new StringWriter()) { // Arrange. var trioWriter = new TrioWriter(writer); var entity1 = new HaystackDictionary(new Dictionary <string, HaystackValue> { ["type"] = new HaystackString("list"), ["val"] = new HaystackList(new HaystackNumber(1), new HaystackNumber(2), new HaystackNumber(3)), }); var entity2 = new HaystackDictionary(new Dictionary <string, HaystackValue> { ["type"] = new HaystackString("dict"), ["val"] = new HaystackDictionary(new Dictionary <string, HaystackValue> { ["dis"] = new HaystackString("Dict!"), ["foo"] = new HaystackMarker(), }), }); var grid = new HaystackGrid() .AddColumn("b") .AddColumn("a") .AddRow(new HaystackNumber(20), new HaystackNumber(10)); var entity3 = new HaystackDictionary(new Dictionary <string, HaystackValue> { ["type"] = new HaystackString("grid"), ["val"] = grid, }); // Act. trioWriter.WriteComment("Trio"); trioWriter.WriteEntity(entity1); trioWriter.WriteEntity(entity2); trioWriter.WriteEntity(entity3); var trio = writer.ToString(); // Assert. var target = @"// Trio type:list val:[1,2,3] --- type:dict val:{dis:""Dict!"" foo} --- type:grid val:Zinc: ver:""3.0"" b,a 20,10 "; Assert.AreEqual(target.Replace("\r", ""), trio.Replace("\r", "")); } }
public void TestSimple() { var grid = new HaystackGrid(); grid.AddColumn("id"); grid.AddColumn("dis"); grid.AddColumn("area"); grid.AddRow(new HaystackReference("a"), new HaystackString("Alpha"), new HaystackNumber(1200)); grid.AddRow(new HaystackReference("b"), null, new HaystackNumber(1400)); //.Meta Assert.AreEqual(grid.Meta.Count, 0); // cols //HCol c; Assert.AreEqual(grid.ColumnCount, 3); VerifyCol(grid, 0, "id"); VerifyCol(grid, 1, "dis"); VerifyCol(grid, 2, "area"); // rows Assert.AreEqual(grid.RowCount, 2); Assert.IsFalse(grid.IsEmpty()); var row = grid.Row(0); Assert.IsTrue(row.Get("id").Equals(new HaystackReference("a"))); Assert.IsTrue(row.Get("dis").Equals(new HaystackString("Alpha"))); Assert.IsTrue(row.Get("area").Equals(new HaystackNumber(1200))); row = grid.Row(1); Assert.IsTrue(row.Get("id").Equals(new HaystackReference("b"))); Assert.IsFalse(row.ContainsKey("dis")); Assert.IsTrue(row.Get("area").Equals(new HaystackNumber(1400))); Assert.ThrowsException <HaystackUnknownNameException>(() => row["dis"]); Assert.IsFalse(row.ContainsKey("fooBar")); Assert.ThrowsException <HaystackUnknownNameException>(() => row["fooBar"]); // HaystackRow no-nulls HaystackRow it = grid.Row(0); Assert.IsFalse(it.Count > 3); VerifyRowIterator(it, 0, "id", new HaystackReference("a")); VerifyRowIterator(it, 1, "dis", new HaystackString("Alpha")); VerifyRowIterator(it, 2, "area", new HaystackNumber(1200)); // HaystackRow with nulls it = grid.Row(1); Assert.IsFalse(it.Count > 3); VerifyRowIterator(it, 0, "id", new HaystackReference("b")); VerifyRowIterator(it, 2, "area", new HaystackNumber(1400)); // iterating VerifyGridIterator(grid); }
/// <summary> /// Write to a given level of a writable point, and return the current status /// of a writable point's priority array <see cref="pointWriteArray"/>. /// </summary> /// <param name="id">Reference of a writable point.</param> /// <param name="level">Number for level to write [1-17].</param> /// <param name="who">Username performing the write, defaults to user dis.</param> /// <param name="val">Value to write or null to auto the level.</param> /// <param name="dur">Number with duration unit if setting level 8.</param> /// <returns>Result grid.</returns> public Task <HaystackGrid> PointWriteAsync(HaystackReference id, int level, string who, HaystackValue val, HaystackNumber dur) { var req = new HaystackGrid() .AddColumn("id") .AddColumn("level") .AddColumn("who") .AddColumn("val") .AddColumn("duration") .AddRow(id, new HaystackNumber(level), new HaystackString(who), val, dur); return(CallAsync("pointWrite", req)); }
public void GridToString_InnerGrid() { var innerGrid = new HaystackGrid() .AddColumn("val") .AddColumn("other") .AddRow(new HaystackString("value"), new HaystackNumber(10)); var grid = new HaystackGrid() .AddColumn("val") .AddColumn("inner") .AddRow(new HaystackString("value"), innerGrid); var str = ZincWriter.ToZinc(grid); Assert.AreEqual("ver:\"3.0\"\nval,inner\n\"value\",<<\nver:\"3.0\"\nval,other\n\"value\",10\n>>", str.Trim()); }
public static IEnumerable <HaystackRow> BuildRows(ICollection <string> cols, params HaystackValue[][] rows) { var grid = new HaystackGrid(); foreach (var col in cols) { grid.AddColumn(col); } foreach (var row in rows) { grid.AddRow(row); } return(grid.Rows); }
public async Task Read() { var grid = new HaystackGrid() .AddColumn("site") .AddRow(new HaystackMarker()); var httpClient = new HttpClientMockBuilder(_uri) .WithBasicAuthentication(_basicAuthHash) .WithReadAsync("site", grid) .Build(); var client = new HaystackClient(httpClient, new BasicAuthenticator(_user, _pass), _uri); await client.OpenAsync(); await client.ReadAsync("site"); }
/// <summary> /// Read a single record by its unique ID. /// Throws an exception if the record was not found. /// </summary> /// <param name="id">Record ID.</param> /// <returns>Matching record.</returns> public async Task <HaystackDictionary> ReadByIdAsync(HaystackReference id) { HaystackGrid res = await ReadByIdsAsync(new HaystackReference[] { id }); if (res.IsEmpty()) { throw new Exception($"Record not found for: {id}"); } HaystackDictionary rec = res.Row(0); if (!rec.ContainsKey("id")) { throw new Exception($"Record not found for: {id}"); } return(rec); }
/// <summary> /// Use vendor specific logic using the "eval" call. /// </summary> /// <param name="req">Grid with expressions in the "expr" field.</param> /// <returns>Grid of results per expression.</returns> public async Task <HaystackGrid[]> EvalAllAsync(HaystackGrid req) { var requestZinc = ZincWriter.ToZinc(req); var resultZinc = await PostStringAsync("evalAll", requestZinc, "text/zinc"); var result = new ZincReader(resultZinc).ReadGrids().ToArray(); for (int i = 0; i < result.Length; ++i) { if (result[i].IsError()) { throw new HaystackException(result[i]); } } return(result); }
/// <summary> /// Read all records with a given filter. /// </summary> /// <param name="filter">Record filter.</param> /// <param name="limit">Maximum number of results to request.</param> /// <returns>Grid with records.</returns> public Task <HaystackGrid> ReadAllAsync(string filter, int limit) { var req = new HaystackGrid() .AddColumn("filter"); if (limit > 0) { req.AddColumn("limit"); req.AddRow(new HaystackString(filter), new HaystackNumber(limit)); } else { req.AddRow(new HaystackString(filter)); } return(CallAsync("read", req)); }