omf_oml 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -0
- data/Gemfile +4 -0
- data/Rakefile +10 -0
- data/lib/omf_oml/endpoint.rb +170 -0
- data/lib/omf_oml/indexed_table.rb +61 -0
- data/lib/omf_oml/network.rb +467 -0
- data/lib/omf_oml/oml_tuple.rb +64 -0
- data/lib/omf_oml/schema.rb +200 -0
- data/lib/omf_oml/sequel/sequel_server.rb +412 -0
- data/lib/omf_oml/sql_row.rb +302 -0
- data/lib/omf_oml/sql_source.rb +131 -0
- data/lib/omf_oml/table.rb +227 -0
- data/lib/omf_oml/tuple.rb +110 -0
- data/lib/omf_oml/version.rb +6 -0
- data/lib/omf_oml.rb +4 -0
- data/omf_oml.gemspec +26 -0
- metadata +73 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
require 'omf_oml'
|
3
|
+
require 'omf_oml/schema'
|
4
|
+
require 'omf_oml/tuple'
|
5
|
+
|
6
|
+
module OMF::OML
|
7
|
+
|
8
|
+
# This class represents a single vector from an OML measurement stream.
|
9
|
+
# It provides various methods to access the vectors elements.
|
10
|
+
#
|
11
|
+
# NOTE: Do not store the vector itself, but make a copy as the instance may be
|
12
|
+
# reused over various rows by the sender.
|
13
|
+
#
|
14
|
+
class OmlTuple < Tuple
|
15
|
+
|
16
|
+
# Return the elements of the vector as an array
|
17
|
+
# def to_a(include_index_ts = false)
|
18
|
+
# res = []
|
19
|
+
# r = @raw
|
20
|
+
# if include_index_ts
|
21
|
+
# res << @vprocs[:oml_ts].call(r)
|
22
|
+
# res << @vprocs[:oml_seq_no].call(r)
|
23
|
+
# end
|
24
|
+
# @schema.each do |col|
|
25
|
+
# res << @vprocs[col[:name]].call(r)
|
26
|
+
# end
|
27
|
+
# res
|
28
|
+
# end
|
29
|
+
|
30
|
+
def ts
|
31
|
+
@raw[0].to_f
|
32
|
+
end
|
33
|
+
|
34
|
+
def seq_no
|
35
|
+
@raw[1].to_i
|
36
|
+
end
|
37
|
+
|
38
|
+
# Note: This method assumes that the first two elements in each OML tuple,
|
39
|
+
# 'oml_ts' and 'oml_seq_no' are not defined in the associated schema.
|
40
|
+
#
|
41
|
+
def process_schema(schema)
|
42
|
+
i = 0
|
43
|
+
@vprocs = {}
|
44
|
+
schema.each_column do |col| #
|
45
|
+
name = col[:name] || raise("Ill-formed schema '#{schema}'")
|
46
|
+
type = col[:type] || raise("Ill-formed schema '#{schema}'")
|
47
|
+
j = i + 2; # need to create a locally scoped variable for the following lambdas
|
48
|
+
@vprocs[name] = @vprocs[i] = case type
|
49
|
+
when :string
|
50
|
+
lambda do |r| r[j] end
|
51
|
+
when :float
|
52
|
+
lambda do |r| r[j].to_f end
|
53
|
+
when :integer
|
54
|
+
lambda do |r| r[j].to_i end
|
55
|
+
else raise "Unrecognized OML type '#{type}' (#{col.inspect})"
|
56
|
+
end
|
57
|
+
i += 1
|
58
|
+
end
|
59
|
+
@vprocs[:oml_ts] = lambda do |r| r[0].to_f end
|
60
|
+
@vprocs[:oml_seq_no] = lambda do |r| r[1].to_i end
|
61
|
+
end
|
62
|
+
|
63
|
+
end # OmlTuple
|
64
|
+
end # OMF::OML
|
@@ -0,0 +1,200 @@
|
|
1
|
+
|
2
|
+
require 'omf_common/lobject'
|
3
|
+
require 'omf_oml'
|
4
|
+
|
5
|
+
module OMF::OML
|
6
|
+
|
7
|
+
# This class represents the schema of an OML measurement stream.
|
8
|
+
#
|
9
|
+
class OmlSchema < OMF::Common::LObject
|
10
|
+
|
11
|
+
CLASS2TYPE = {
|
12
|
+
TrueClass => 'boolean',
|
13
|
+
FalseClass => 'boolean',
|
14
|
+
String => 'string',
|
15
|
+
Symbol => 'string',
|
16
|
+
Fixnum => 'decimal',
|
17
|
+
Float => 'double',
|
18
|
+
Time => 'dateTime'
|
19
|
+
}
|
20
|
+
|
21
|
+
# Map various type definitions (all lower case) into a single one
|
22
|
+
ANY2TYPE = {
|
23
|
+
'integer' => :integer,
|
24
|
+
'int' => :integer,
|
25
|
+
'int32' => :integer,
|
26
|
+
'int64' => :integer,
|
27
|
+
'bigint' => :integer,
|
28
|
+
'unsigned integer' => :integer,
|
29
|
+
'float' => :float,
|
30
|
+
'real' => :float,
|
31
|
+
'double' => :float,
|
32
|
+
'text' => :string,
|
33
|
+
'string' => :string,
|
34
|
+
'date' => :date,
|
35
|
+
'dateTime'.downcase => :dateTime, # should be 'datetime' but we downcase the string for comparison
|
36
|
+
'key' => :key,
|
37
|
+
}
|
38
|
+
|
39
|
+
def self.create(schema_description)
|
40
|
+
if schema_description.kind_of? self
|
41
|
+
return schema_description
|
42
|
+
end
|
43
|
+
return self.new(schema_description)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Return the col name at a specific index
|
47
|
+
#
|
48
|
+
def name_at(index)
|
49
|
+
@schema[index][:name]
|
50
|
+
end
|
51
|
+
|
52
|
+
# Return the col index for column named +name+
|
53
|
+
#
|
54
|
+
def index_for_col(name)
|
55
|
+
name = name.to_sym
|
56
|
+
@schema.each_with_index do |col, i|
|
57
|
+
return i if col[:name] == name
|
58
|
+
end
|
59
|
+
raise "Unknonw column '#{name}'"
|
60
|
+
end
|
61
|
+
|
62
|
+
# Return the column names as an array
|
63
|
+
#
|
64
|
+
def names
|
65
|
+
@schema.collect do |col| col[:name] end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Return the col type at a specific index
|
69
|
+
#
|
70
|
+
def type_at(index)
|
71
|
+
@schema[index][:type]
|
72
|
+
end
|
73
|
+
|
74
|
+
def columns
|
75
|
+
@schema
|
76
|
+
end
|
77
|
+
|
78
|
+
def insert_column_at(index, col)
|
79
|
+
if col.kind_of?(Symbol) || col.kind_of?(String)
|
80
|
+
col = [col]
|
81
|
+
end
|
82
|
+
if col.kind_of? Array
|
83
|
+
# should be [name, type]
|
84
|
+
if col.length == 1
|
85
|
+
col = {:name => col[0].to_sym,
|
86
|
+
:type => :string,
|
87
|
+
:title => col[0].to_s.split('_').collect {|s| s.capitalize}.join(' ')}
|
88
|
+
elsif col.length == 2
|
89
|
+
col = {:name => col[0].to_sym,
|
90
|
+
:type => col[1].to_sym,
|
91
|
+
:title => col[0].to_s.split('_').collect {|s| s.capitalize}.join(' ')}
|
92
|
+
elsif col.length == 3
|
93
|
+
col = {:name => col[0].to_sym, :type => col[1].to_sym, :title => col[2]}
|
94
|
+
else
|
95
|
+
throw "Simple column schema should consist of [name, type, title] array, but found '#{col.inspect}'"
|
96
|
+
end
|
97
|
+
elsif col.kind_of? Hash
|
98
|
+
# ensure there is a :title property
|
99
|
+
unless col[:title]
|
100
|
+
col[:title] = col[:name].to_s.split('_').collect {|s| s.capitalize}.join(' ')
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# should normalize type
|
105
|
+
if type = col[:type]
|
106
|
+
unless type = ANY2TYPE[type.to_s.downcase]
|
107
|
+
warn "Unknown type definition '#{col[:type]}', default to 'string'"
|
108
|
+
type = :string
|
109
|
+
end
|
110
|
+
else
|
111
|
+
warn "Missing type definition in '#{col[:name]}', default to 'string'"
|
112
|
+
type = :string
|
113
|
+
end
|
114
|
+
col[:type] = type
|
115
|
+
|
116
|
+
col[:type_conversion] = case type
|
117
|
+
when :string
|
118
|
+
lambda do |r| r end
|
119
|
+
when :key
|
120
|
+
lambda do |r| r end
|
121
|
+
when :integer
|
122
|
+
lambda do |r| r.to_i end
|
123
|
+
when :float
|
124
|
+
lambda do |r| r.to_f end
|
125
|
+
when :date
|
126
|
+
lambda do |r| Date.parse(r) end
|
127
|
+
when :dateTime
|
128
|
+
lambda do |r| Time.parse(r) end
|
129
|
+
else raise "Unrecognized Schema type '#{type}'"
|
130
|
+
end
|
131
|
+
|
132
|
+
@schema.insert(index, col)
|
133
|
+
end
|
134
|
+
|
135
|
+
def each_column(&block)
|
136
|
+
@schema.each do |c|
|
137
|
+
block.call(c)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Translate a record described in a hash of 'col_name => value'
|
142
|
+
# to a row array
|
143
|
+
#
|
144
|
+
# hrow - Hash describing a row
|
145
|
+
# set_nil_when_missing - If true, set any columns not described in hrow to nil
|
146
|
+
#
|
147
|
+
def hash_to_row(hrow, set_nil_when_missing = false)
|
148
|
+
r = @schema.collect do |cdescr|
|
149
|
+
cname = cdescr[:name]
|
150
|
+
next nil if cname == :__id__
|
151
|
+
unless hrow.key? cname
|
152
|
+
next nil if set_nil_when_missing
|
153
|
+
raise "Missing record element '#{cname}' in record '#{hrow}'"
|
154
|
+
end
|
155
|
+
cdescr[:type_conversion].call(hrow[cname])
|
156
|
+
end
|
157
|
+
r.shift # remove __id__ columns
|
158
|
+
#puts "#{r.inspect} -- #{@schema.map {|c| c[:name]}.inspect}"
|
159
|
+
r
|
160
|
+
end
|
161
|
+
|
162
|
+
# Cast each element in 'row' into its proper type according to this schema
|
163
|
+
#
|
164
|
+
def cast_row(raw_row)
|
165
|
+
unless raw_row.length == @schema.length
|
166
|
+
raise "Row needs to have same size as schema (#{raw_row.inspect})"
|
167
|
+
end
|
168
|
+
# This can be done more elegantly in 1.9
|
169
|
+
row = []
|
170
|
+
raw_row.each_with_index do |el, i|
|
171
|
+
row << @schema[i][:type_conversion].call(el)
|
172
|
+
end
|
173
|
+
row
|
174
|
+
end
|
175
|
+
|
176
|
+
def describe
|
177
|
+
@schema.map {|c| {:name => c[:name], :type => c[:type], :title => c[:title] }}
|
178
|
+
end
|
179
|
+
|
180
|
+
def to_json(*opt)
|
181
|
+
describe.to_json(*opt)
|
182
|
+
end
|
183
|
+
|
184
|
+
protected
|
185
|
+
|
186
|
+
# schema_description - Array containing [name, type*] for every column in table
|
187
|
+
# TODO: define format of TYPE
|
188
|
+
#
|
189
|
+
def initialize(schema_description)
|
190
|
+
# check if columns are described by hashes or 2-arrays
|
191
|
+
@schema = []
|
192
|
+
schema_description.each_with_index do |cdesc, i|
|
193
|
+
insert_column_at(i, cdesc)
|
194
|
+
end
|
195
|
+
debug "schema: '#{describe.inspect}'"
|
196
|
+
|
197
|
+
end
|
198
|
+
end # OmlSchema
|
199
|
+
|
200
|
+
end
|
@@ -0,0 +1,412 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rexml/document'
|
3
|
+
require 'time'
|
4
|
+
require 'logger'
|
5
|
+
require 'sequel'
|
6
|
+
|
7
|
+
require 'omf_common/lobject'
|
8
|
+
require 'omf_oml'
|
9
|
+
|
10
|
+
# module OMF::OML
|
11
|
+
# module Sequel; end
|
12
|
+
# end
|
13
|
+
|
14
|
+
module OMF::OML::Sequel
|
15
|
+
module Server
|
16
|
+
|
17
|
+
class Query < OMF::Common::LObject
|
18
|
+
|
19
|
+
def self.parse(xmls, repoFactory = RepositoryFactory.new, logger = Logger.new(STDOUT))
|
20
|
+
if xmls.kind_of? String
|
21
|
+
doc = REXML::Document.new(xmls)
|
22
|
+
root = doc.root
|
23
|
+
else
|
24
|
+
root = xmls
|
25
|
+
end
|
26
|
+
unless root.name == 'query'
|
27
|
+
raise "XML fragment needs to start with 'query' but does start with '#{root.name}"
|
28
|
+
end
|
29
|
+
q = self.new(root, repoFactory, logger)
|
30
|
+
q.relation
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(queryEl, repoFactory, logger)
|
34
|
+
@queryEl = queryEl
|
35
|
+
@repoFactory = repoFactory || RepositoryFactory.new
|
36
|
+
@logger = logger || Logger.new(STDOUT)
|
37
|
+
@tables = {}
|
38
|
+
@lastRel = nil
|
39
|
+
@offset = 0
|
40
|
+
@limit = 0
|
41
|
+
queryEl.children.each do |el|
|
42
|
+
@lastRel = parse_el(el, @lastRel)
|
43
|
+
end
|
44
|
+
if @limit > 0
|
45
|
+
@lastRel = @lastRel.limit(@limit, @offset)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def each(&block)
|
50
|
+
# sel_mgr = relation
|
51
|
+
# unless sel_mgr.kind_of? SelectionManager
|
52
|
+
# raise "Can only be called on SELECT statement"
|
53
|
+
# end
|
54
|
+
# puts sel_mgr.engine
|
55
|
+
relation.each(&block)
|
56
|
+
end
|
57
|
+
|
58
|
+
def relation
|
59
|
+
raise "No query defined, yet" unless @lastRel
|
60
|
+
@lastRel
|
61
|
+
end
|
62
|
+
|
63
|
+
# Requested format for result. Default is 'xml'
|
64
|
+
def rformat
|
65
|
+
@queryEl.attributes['rformat'] || 'xml'
|
66
|
+
end
|
67
|
+
|
68
|
+
def parse_el(el, lastRel)
|
69
|
+
if (el.kind_of? REXML::Text)
|
70
|
+
# skip
|
71
|
+
return lastRel
|
72
|
+
end
|
73
|
+
args = parse_args(el)
|
74
|
+
@logger.debug "CHILD #{el.name}"
|
75
|
+
# keep the last table for this level to be used
|
76
|
+
# to create proper columns.
|
77
|
+
# NOTE: This is not fool-proof but we need columns
|
78
|
+
# to later resolve the column type.
|
79
|
+
#
|
80
|
+
name = el.name.downcase
|
81
|
+
if lastRel.nil?
|
82
|
+
case name
|
83
|
+
when /repository/
|
84
|
+
lastRel = repo = parse_repository(el)
|
85
|
+
@tables = repo.tables
|
86
|
+
@logger.debug "Created repository: #{lastRel}"
|
87
|
+
else
|
88
|
+
raise "Need to start with 'table' declaration, but does with '#{name}'"
|
89
|
+
end
|
90
|
+
elsif name == 'table'
|
91
|
+
lastRel = parse_table(el)
|
92
|
+
elsif name == 'project'
|
93
|
+
# turn all arguments into proper columns
|
94
|
+
# cols = convert_to_cols(args)
|
95
|
+
lastRel = lastRel.select(*args)
|
96
|
+
# elsif lastRel.kind_of?(::Arel::Table) && name == 'as'
|
97
|
+
# # keep track of all created tables
|
98
|
+
# lastRel = lastRel.alias(*args)
|
99
|
+
# @repository.add_table(args[0], lastRel)
|
100
|
+
elsif name == 'skip'
|
101
|
+
@offset = args[0].to_i
|
102
|
+
elsif name == 'take'
|
103
|
+
@limit = args[0].to_i
|
104
|
+
else
|
105
|
+
@logger.debug "Sending '#{name}' to #{lastRel.class}"
|
106
|
+
lastRel = lastRel.send(name, *args)
|
107
|
+
end
|
108
|
+
@logger.debug "lastRel for <#{el}> is #{lastRel.class}"
|
109
|
+
lastRel
|
110
|
+
end
|
111
|
+
|
112
|
+
def parse_repository(el)
|
113
|
+
@repository = @repoFactory.create_from_xml(el, @logger)
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
# Return the arguments defined in @parentEl as array
|
118
|
+
def parse_args(parentEl)
|
119
|
+
args = []
|
120
|
+
parentEl.children.each do |el|
|
121
|
+
next if (el.kind_of? REXML::Text)
|
122
|
+
unless el.name == 'arg'
|
123
|
+
raise "Expected argument definition but got element '#{el.name}"
|
124
|
+
end
|
125
|
+
args << parse_arg(el)
|
126
|
+
end
|
127
|
+
args
|
128
|
+
end
|
129
|
+
|
130
|
+
# Return the arguments defined in @parentEl as array
|
131
|
+
def parse_arg(pel)
|
132
|
+
res = nil
|
133
|
+
#col = nil
|
134
|
+
pel.children.each do |el|
|
135
|
+
if (el.kind_of? REXML::Text)
|
136
|
+
val = el.value
|
137
|
+
next if val.strip.empty? # skip text between els
|
138
|
+
return parse_arg_primitive(pel, val)
|
139
|
+
else
|
140
|
+
name = el.name.downcase
|
141
|
+
case name
|
142
|
+
when /col/
|
143
|
+
res = parse_column(el)
|
144
|
+
when /eq/
|
145
|
+
if res.nil?
|
146
|
+
raise "Missing 'col' definiton before 'eq'."
|
147
|
+
end
|
148
|
+
p = parse_args(el)
|
149
|
+
unless p.length == 1
|
150
|
+
raise "'eq' can only hnadle 1 argument, but is '#{p.inspect}'"
|
151
|
+
end
|
152
|
+
res = {res => p[0]}
|
153
|
+
else
|
154
|
+
raise "Need to be 'col' declaration, but is '#{name}'"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
res
|
159
|
+
end
|
160
|
+
|
161
|
+
def parse_arg_primitive(pel, value)
|
162
|
+
type = pel.attributes['type'] || 'string'
|
163
|
+
case type
|
164
|
+
when /string/
|
165
|
+
value
|
166
|
+
when /boolean/
|
167
|
+
value.downcase == 'true' || value == '1'
|
168
|
+
when /decimal/
|
169
|
+
value.to_i
|
170
|
+
when /double/
|
171
|
+
value.to_f
|
172
|
+
when /dateTime/
|
173
|
+
Time.xmlschema
|
174
|
+
else
|
175
|
+
raise "Unknown arg type '#{type}"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def convert_to_cols(args)
|
180
|
+
args.collect do |arg|
|
181
|
+
if arg.kind_of? String
|
182
|
+
table = @repository.get_first_table()
|
183
|
+
raise "Unknown table for column '#{arg}'" unless table
|
184
|
+
table[arg]
|
185
|
+
else
|
186
|
+
arg
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# <col name='oml_sender_id' table='iperf_TCP_Info'/>
|
192
|
+
def parse_column(el)
|
193
|
+
unless colName = el.attributes['name']
|
194
|
+
raise "Missing 'name' attribute for 'col' element"
|
195
|
+
end
|
196
|
+
col = colName
|
197
|
+
unless tblName = el.attributes['table']
|
198
|
+
raise "Missing 'table' attribute for col '#{colName}'"
|
199
|
+
end
|
200
|
+
unless @tables.member?(tblName.to_sym)
|
201
|
+
raise "Unknown table name '#{tblName}' (#{el})"
|
202
|
+
end
|
203
|
+
col = "#{tblName}__#{colName}"
|
204
|
+
|
205
|
+
if colAlias = el.attributes['alias']
|
206
|
+
col = "#{col}___#{colAlias}"
|
207
|
+
end
|
208
|
+
col.to_sym
|
209
|
+
end
|
210
|
+
|
211
|
+
def parse_table(el)
|
212
|
+
unless name = el.attributes['tname']
|
213
|
+
raise "Missing 'tname' attribute for 'table' element"
|
214
|
+
end
|
215
|
+
if talias = el.attributes['talias']
|
216
|
+
name = "#{name}___#{talias}"
|
217
|
+
@tables << talias.to_sym
|
218
|
+
end
|
219
|
+
|
220
|
+
@repository[name.to_sym]
|
221
|
+
end
|
222
|
+
|
223
|
+
end # Query
|
224
|
+
|
225
|
+
class RepositoryFactory < OMF::Common::LObject
|
226
|
+
|
227
|
+
def initialize(opts = {})
|
228
|
+
@opts = opts
|
229
|
+
end
|
230
|
+
|
231
|
+
def create_from_xml(el, logger)
|
232
|
+
name = el ? el.attributes['name'] : nil
|
233
|
+
raise "<repository> is missing attribute 'name'" unless name
|
234
|
+
create(name, logger)
|
235
|
+
end
|
236
|
+
|
237
|
+
def create(database, logger = Logger.new(STDOUT))
|
238
|
+
opts = @opts.dup
|
239
|
+
if pre = opts[:database_prefix]
|
240
|
+
database = pre + database
|
241
|
+
opts.delete(:database_prefix)
|
242
|
+
end
|
243
|
+
if post = opts[:database_postfix]
|
244
|
+
database = database + post
|
245
|
+
opts.delete(:database_postfix)
|
246
|
+
end
|
247
|
+
opts[:database] = database
|
248
|
+
::Sequel.connect(opts)
|
249
|
+
end
|
250
|
+
|
251
|
+
end # RepositoryFactory
|
252
|
+
end # Server
|
253
|
+
end
|
254
|
+
|
255
|
+
module Sequel
|
256
|
+
class Dataset
|
257
|
+
CLASS2TYPE = {
|
258
|
+
TrueClass => 'boolean',
|
259
|
+
FalseClass => 'boolean',
|
260
|
+
String => 'string',
|
261
|
+
Symbol => 'string',
|
262
|
+
Fixnum => 'decimal',
|
263
|
+
Float => 'double',
|
264
|
+
Time => 'dateTime'
|
265
|
+
}
|
266
|
+
|
267
|
+
def row_description(row)
|
268
|
+
n = naked
|
269
|
+
cols = n.columns
|
270
|
+
descr = {}
|
271
|
+
cols.collect do |cn|
|
272
|
+
cv = row[cn]
|
273
|
+
descr[cn] = CLASS2TYPE[cv.class]
|
274
|
+
end
|
275
|
+
descr
|
276
|
+
end
|
277
|
+
|
278
|
+
def schema_for_row(row)
|
279
|
+
n = naked
|
280
|
+
cols = n.columns
|
281
|
+
descr = {}
|
282
|
+
cols.collect do |cn|
|
283
|
+
cv = row[cn]
|
284
|
+
{:name => cn, :type => CLASS2TYPE[cv.class]}
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
|
291
|
+
|
292
|
+
def test_sequel_server()
|
293
|
+
|
294
|
+
tests = []
|
295
|
+
|
296
|
+
tests << %{
|
297
|
+
<query>
|
298
|
+
<repository name='test'/>
|
299
|
+
<table tname='iperf_TCP_Info'/>
|
300
|
+
<project>
|
301
|
+
<arg><col name='Bandwidth_avg' table='iperf_TCP_Info'/></arg>
|
302
|
+
</project>
|
303
|
+
</query>
|
304
|
+
}
|
305
|
+
|
306
|
+
tests << %{
|
307
|
+
<query>
|
308
|
+
<repository name='test'/>
|
309
|
+
<table tname='iperf_TCP_Info' talias='t'/>
|
310
|
+
<project>
|
311
|
+
<arg>
|
312
|
+
<col name='oml_sender_id' alias='foo' table='t'/>
|
313
|
+
</arg>
|
314
|
+
<arg>
|
315
|
+
<col name='oml_ts_server' table='t' alias='goo'/>
|
316
|
+
</arg>
|
317
|
+
<arg><col name='Bandwidth_avg' table='t'/></arg>
|
318
|
+
</project>
|
319
|
+
<where>
|
320
|
+
<arg>
|
321
|
+
<col name='oml_sender_id' table='t'/>
|
322
|
+
<eq>
|
323
|
+
<arg type='decimal'> 2</arg>
|
324
|
+
</eq>
|
325
|
+
</arg>
|
326
|
+
</where>
|
327
|
+
</query>
|
328
|
+
}
|
329
|
+
|
330
|
+
# mc = repo[:mediacontent]
|
331
|
+
# mc2 = mc.alias
|
332
|
+
# accessed = mc2.where(mc2[:status].eq('Accessed')).project(:oml_ts_server, :name)
|
333
|
+
# q = mc.project(:name).join(accessed).on(mc[:name].eq(mc2[:name]))
|
334
|
+
|
335
|
+
# tests << %{
|
336
|
+
# <query>
|
337
|
+
# <repository name='prefetching_4'/>
|
338
|
+
# <table tname='mediacontent'/>
|
339
|
+
# <project>
|
340
|
+
# <arg type='string'>name</arg>
|
341
|
+
# </project>
|
342
|
+
# <join>
|
343
|
+
# <arg>
|
344
|
+
# <table tname='mediacontent' talias='mediacontent1'/>
|
345
|
+
# <where>
|
346
|
+
# <arg>
|
347
|
+
# <col name='status' table='mediacontent' talias='mediacontent1'/>
|
348
|
+
# <eq>
|
349
|
+
# <arg type='string'>Accessed</arg>
|
350
|
+
# </eq>
|
351
|
+
# </arg>
|
352
|
+
# </where>
|
353
|
+
# <project>
|
354
|
+
# <arg type='string'>oml_ts_server</arg>
|
355
|
+
# <arg type='string'>name</arg>
|
356
|
+
# </project>
|
357
|
+
# </arg>
|
358
|
+
# </join>
|
359
|
+
# <on>
|
360
|
+
# <arg>
|
361
|
+
# <col name='name' table='mediacontent'/>
|
362
|
+
# <eq>
|
363
|
+
# <arg>
|
364
|
+
# <col name='name' table='mediacontent' talias='mediacontent1'/>
|
365
|
+
# </arg>
|
366
|
+
# </eq>
|
367
|
+
# </arg>
|
368
|
+
# </on>
|
369
|
+
# </query>
|
370
|
+
# }
|
371
|
+
|
372
|
+
factory = OMF::OML::Sequel::Server::RepositoryFactory.new(
|
373
|
+
:adapter => 'sqlite',
|
374
|
+
:database_prefix => '/Users/max/src/omf_mytestbed_net/omf-common/test/',
|
375
|
+
:database_postfix => '.sq3'
|
376
|
+
)
|
377
|
+
|
378
|
+
repo = factory.create('test')
|
379
|
+
puts repo.tables
|
380
|
+
|
381
|
+
tests.each do |t|
|
382
|
+
ds = OMF::OML::Sequel::Server::Query.parse(t, factory)
|
383
|
+
puts ds.inspect
|
384
|
+
puts ds.columns.inspect
|
385
|
+
puts ds.first.inspect
|
386
|
+
end
|
387
|
+
|
388
|
+
first = true
|
389
|
+
types = []
|
390
|
+
ds = OMF::OML::Sequel::Server::Query.parse(tests[1], factory).limit(10)
|
391
|
+
ds.each do |r|
|
392
|
+
if (first)
|
393
|
+
puts ds.row_description(r).inspect
|
394
|
+
puts ds.schema_for_row(r).inspect
|
395
|
+
#puts (ds.schema_for_row(r).methods - Object.new.methods).sort
|
396
|
+
# cols = ds.columns
|
397
|
+
# #cols.collect do |c|
|
398
|
+
# cols.each do |c|
|
399
|
+
# puts "#{c} : #{OML::Sequel::XML::Server::Query::CLASS2TYPE[r[c].class]}"
|
400
|
+
# end
|
401
|
+
first = false
|
402
|
+
# puts types.inspect
|
403
|
+
end
|
404
|
+
puts r.inspect
|
405
|
+
end
|
406
|
+
puts "QUERY: done"
|
407
|
+
end
|
408
|
+
|
409
|
+
if $0 == __FILE__
|
410
|
+
test_sequel_server
|
411
|
+
end
|
412
|
+
|