Skip to content

Commit

Permalink
feat(query_result): implement untyped parser
Browse files Browse the repository at this point in the history
  • Loading branch information
kimburgess committed Feb 13, 2020
1 parent c9273f0 commit ee0f429
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 0 deletions.
20 changes: 20 additions & 0 deletions spec/flux/query_result_spec.cr
@@ -0,0 +1,20 @@
require "../spec_helper"

describe Flux::QueryResult do
describe ".from" do
io = IO::Memory.new <<-CSV
#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,string,string,double
#group,false,false,false,false,false,false,false,false
#default,,,,,,,,
,result,table,_start,_stop,_time,region,host,_value
,my-result,0,2018-05-08T20:50:00Z,2018-05-08T20:51:00Z,2018-05-08T20:50:00Z,east,A,15.43
,my-result,0,2018-05-08T20:50:00Z,2018-05-08T20:51:00Z,2018-05-08T20:50:20Z,east,B,59.25
,my-result,0,2018-05-08T20:50:00Z,2018-05-08T20:51:00Z,2018-05-08T20:50:40Z,east,C,52.62
,my-result,1,2018-05-08T20:50:00Z,2018-05-08T20:51:00Z,2018-05-08T20:50:00Z,west,A,62.73
,my-result,1,2018-05-08T20:50:00Z,2018-05-08T20:51:00Z,2018-05-08T20:50:20Z,west,B,12.83
,my-result,1,2018-05-08T20:50:00Z,2018-05-08T20:51:00Z,2018-05-08T20:50:40Z,west,C,51.62
CSV

Flux::QueryResult.parse io
end
end
1 change: 1 addition & 0 deletions src/flux/client.cr
Expand Up @@ -2,6 +2,7 @@ require "http/client"
require "logger"
require "uri"
require "./point"
require "./query_result"

# FIXME: underclared namespaces are infered to by modules by default. Drop this
# when https://github.com/crystal-lang/crystal/issues/8685 is resolved.
Expand Down
35 changes: 35 additions & 0 deletions src/flux/query_result.cr
@@ -0,0 +1,35 @@
require "./annotated_csv"
require "./query_result/*"

# Parsers and data structures for working with returned query results.
module Flux::QueryResult
extend self

# FIXME: support query results containing mutliple schemas
def parse(io : IO) : Enumerable(Table(Array(String)))
tables = [] of Table(Array(String))

AnnotatedCSV.new(io, headers: true).each do |csv|
idx = csv["table"].to_i
table = tables[idx]?

unless table
columns = csv.headers.map do |name|
meta = csv.annotations name
Column.new(
name: name,
type: DataType.parse(meta["datatype"]),
group: meta["group"] == "true",
default: meta["default"]
)
end
table = Table(Array(String)).new columns
tables << table
end

table << csv.row.to_a
end

tables
end
end
14 changes: 14 additions & 0 deletions src/flux/query_result/column.cr
@@ -0,0 +1,14 @@
require "./data_type"

struct Flux::QueryResult::Column
getter name : String

getter type : DataType

getter group : Bool

getter default : String

def initialize(@name, @type, @group, @default)
end
end
21 changes: 21 additions & 0 deletions src/flux/query_result/data_type.cr
@@ -0,0 +1,21 @@
enum Flux::QueryResult::DataType
Annotation
Boolean
UnsignedLong
Long
Double
String
Base64Binary
DateTime
Duration

def self.parse(string : ::String) : self
if string.starts_with? '#'
Annotation
else
# Types can have an optional encodeding appended. This appears to be
# static though? e.g `dateTime:RFC3339`.
super string.split(':')[0]
end
end
end
18 changes: 18 additions & 0 deletions src/flux/query_result/table.cr
@@ -0,0 +1,18 @@
require "./column"

struct Flux::QueryResult::Table(T)
include Indexable(T)

getter columns : Array(Column)

private getter records = [] of T

def initialize(@columns)
end

delegate each, :<<, unsafe_fetch, to: records

def group_key
columns.select(&.group).map(&.name)
end
end

0 comments on commit ee0f429

Please sign in to comment.