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]);
                }
            }
        }
示例#4
0
        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);
        }
示例#6
0
        /// <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", ""));
                }
        }
示例#9
0
        /// <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));
        }
示例#10
0
        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);
        }
示例#11
0
        /// <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));
        }
示例#12
0
        /// <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));
        }
示例#13
0
        /// <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));
        }
示例#14
0
        /// <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));
        }
示例#15
0
        /// <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));
        }
示例#16
0
        /// <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);
        }
示例#17
0
        /// <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}");
        }
示例#18
0
        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"));
        }
示例#19
0
        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());
        }
示例#21
0
        /// <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));
        }
示例#22
0
        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", ""));
            }
        }
示例#23
0
        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);
        }
示例#24
0
        /// <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");
        }
示例#28
0
        /// <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);
        }
示例#29
0
        /// <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);
        }
示例#30
0
        /// <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));
        }