omf_oml 0.9.5 → 0.9.6

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 CHANGED
@@ -1,2 +1,3 @@
1
1
  .project
2
2
  pkg
3
+ lib/omf_oml/BACKUP
@@ -34,11 +34,20 @@ module OMF::OML
34
34
  'double precision' => :float,
35
35
  'text' => :string,
36
36
  'string' => :string,
37
+ 'varargs' => :string,
37
38
  'date' => :date,
38
39
  'dateTime'.downcase => :dateTime, # should be 'datetime' but we downcase the string for comparison
39
40
  'timestamp' => :dateTime, # Postgreql specific, not sure if this works as it.
40
41
  'key' => :key,
41
42
  }
43
+
44
+ OML_INTERNALS = [
45
+ :oml_sender,
46
+ :oml_sender_id,
47
+ :oml_seq,
48
+ :oml_ts_client,
49
+ :oml_ts_server
50
+ ]
42
51
 
43
52
  def self.create(schema_description)
44
53
  if schema_description.kind_of? self
@@ -83,62 +92,13 @@ module OMF::OML
83
92
  end
84
93
 
85
94
  def insert_column_at(index, col)
86
- if col.kind_of?(Symbol) || col.kind_of?(String)
87
- col = [col]
88
- end
89
- if col.kind_of? Array
90
- # should be [name, type]
91
- if col.length == 1
92
- col = {:name => col[0].to_sym,
93
- :type => :string,
94
- :title => col[0].to_s.split('_').collect {|s| s.capitalize}.join(' ')}
95
- elsif col.length == 2
96
- col = {:name => col[0].to_sym,
97
- :type => col[1].to_sym,
98
- :title => col[0].to_s.split('_').collect {|s| s.capitalize}.join(' ')}
99
- elsif col.length == 3
100
- col = {:name => col[0].to_sym, :type => col[1].to_sym, :title => col[2]}
101
- else
102
- throw "Simple column schema should consist of [name, type, title] array, but found '#{col.inspect}'"
103
- end
104
- elsif col.kind_of? Hash
105
- # ensure there is a :title property
106
- unless col[:title]
107
- col[:title] = col[:name].to_s.split('_').collect {|s| s.capitalize}.join(' ')
108
- end
109
- end
110
-
111
- # should normalize type
112
- if type = col[:type]
113
- unless type = ANY2TYPE[type.to_s.downcase]
114
- warn "Unknown type definition '#{col[:type]}', default to 'string'"
115
- type = :string
116
- end
117
- else
118
- warn "Missing type definition in '#{col[:name]}', default to 'string' (#{col.inspect})"
119
- type = :string
120
- end
121
- col[:type] = type
122
-
123
- col[:type_conversion] = case type
124
- when :string
125
- lambda do |r| r end
126
- when :key
127
- lambda do |r| r end
128
- when :integer
129
- lambda do |r| r.to_i end
130
- when :float
131
- lambda do |r| r.to_f end
132
- when :date
133
- lambda do |r| Date.parse(r) end
134
- when :dateTime
135
- lambda do |r| Time.parse(r) end
136
- else raise "Unrecognized Schema type '#{type}'"
137
- end
138
-
139
- @schema.insert(index, col)
95
+ @schema.insert(index, _create_col_descr(col))
140
96
  end
141
97
 
98
+ def replace_column_at(index, col)
99
+ @schema[index] = _create_col_descr(col)
100
+ end
101
+
142
102
  def each_column(&block)
143
103
  @schema.each do |c|
144
104
  block.call(c)
@@ -151,7 +111,7 @@ module OMF::OML
151
111
  # hrow - Hash describing a row
152
112
  # set_nil_when_missing - If true, set any columns not described in hrow to nil
153
113
  #
154
- def hash_to_row(hrow, set_nil_when_missing = false, call_type_conversion = true)
114
+ def hash_to_row(hrow, set_nil_when_missing = false, call_type_conversion = false)
155
115
  #puts "HASH2A => #{hrow.inspect}"
156
116
  remove_first_col = false
157
117
  r = @schema.collect do |cdescr|
@@ -194,12 +154,22 @@ module OMF::OML
194
154
  describe.to_json(*opt)
195
155
  end
196
156
 
197
- def clone()
157
+ def clone(exclude_oml_internals = false)
198
158
  c = self.dup
199
- c.instance_variable_set('@schema', @schema.clone)
159
+ schema = @schema.clone
160
+ if exclude_oml_internals
161
+ schema = schema.select do |cd|
162
+ not OML_INTERNALS.include?(cd[:name])
163
+ end
164
+ end
165
+ c.instance_variable_set('@schema', schema)
200
166
  c
201
167
  end
202
168
 
169
+ def to_s
170
+ "OmlSchema: #{@schema.map {|c| "#{c[:name]}:#{c[:type]}"}.join(', ')}"
171
+ end
172
+
203
173
  protected
204
174
 
205
175
  # schema_description - Array containing [name, type*] for every column in table
@@ -214,6 +184,65 @@ module OMF::OML
214
184
  debug "schema: '#{describe.inspect}'"
215
185
 
216
186
  end
187
+
188
+ # Create a column descriptor from whatever is given by user
189
+ #
190
+ def _create_col_descr(col)
191
+ if col.kind_of?(Symbol) || col.kind_of?(String)
192
+ col = [col]
193
+ end
194
+ if col.kind_of? Array
195
+ # should be [name, type]
196
+ if col.length == 1
197
+ col = {:name => col[0].to_sym,
198
+ :type => :string,
199
+ :title => col[0].to_s.split('_').collect {|s| s.capitalize}.join(' ')}
200
+ elsif col.length == 2
201
+ col = {:name => col[0].to_sym,
202
+ :type => col[1].to_sym,
203
+ :title => col[0].to_s.split('_').collect {|s| s.capitalize}.join(' ')}
204
+ elsif col.length == 3
205
+ col = {:name => col[0].to_sym, :type => col[1].to_sym, :title => col[2]}
206
+ else
207
+ throw "Simple column schema should consist of [name, type, title] array, but found '#{col.inspect}'"
208
+ end
209
+ elsif col.kind_of? Hash
210
+ # ensure there is a :title property
211
+ unless col[:title]
212
+ col[:title] = col[:name].to_s.split('_').collect {|s| s.capitalize}.join(' ')
213
+ end
214
+ end
215
+
216
+ # should normalize type
217
+ if type = col[:type]
218
+ tn = type.to_s.split('(')[0] # take care of types like varargs(..)
219
+ unless type = ANY2TYPE[type.to_s.downcase]
220
+ warn "Unknown type definition '#{tn}', default to 'string'"
221
+ type = :string
222
+ end
223
+ else
224
+ warn "Missing type definition in '#{col[:name]}', default to 'string' (#{col.inspect})"
225
+ type = :string
226
+ end
227
+ col[:type] = type
228
+
229
+ col[:type_conversion] = case type
230
+ when :string
231
+ lambda do |r| r end
232
+ when :key
233
+ lambda do |r| r end
234
+ when :integer
235
+ lambda do |r| r.to_i end
236
+ when :float
237
+ lambda do |r| r.to_f end
238
+ when :date
239
+ lambda do |r| Date.parse(r) end
240
+ when :dateTime
241
+ lambda do |r| Time.parse(r) end
242
+ else raise "Unrecognized Schema type '#{type}'"
243
+ end
244
+ col
245
+ end
217
246
  end # OmlSchema
218
247
 
219
248
  end
@@ -1,5 +1,6 @@
1
1
 
2
2
  require 'omf_oml/tuple'
3
+ require 'omf_oml/table'
3
4
 
4
5
  module OMF::OML
5
6
 
@@ -15,19 +16,20 @@ module OMF::OML
15
16
  #
16
17
  # Create a representation of a row in a database. Can be used to fill a table.
17
18
  #
18
- # table_name - name table in respective SQL database
19
- # schema_raw - a hash returned by the sequel library's #schema method
20
- # db_opts - Enough information to open a Sequel database adapter
21
- # source - Reference to the SqlSource which created this instance
22
- # opts:
19
+ # @param [String] sql_table_name - name of SQL table in respective SQL database
20
+ # @param [OmlSchema] schema - the schema describing the tuple
21
+ # @param [Sequel] db - Database
22
+ # @param [Hash] opts:
23
23
  # - offset: Ignore first +offset+ rows. If negative or zero serve +offset+ rows initially
24
24
  # - limit: Number of rows to fetch each time [1000]
25
25
  # - check_interval: Interval in seconds when to check for new data. If 0, only run once.
26
+ # - query_interval: Interval between consecutive queries when processing large result set.
26
27
  #
27
- def initialize(table_name, schema_raw, db_opts, source, opts = {})
28
- @sname = table_name
29
- @db_opts = db_opts
30
- @source = source
28
+ def initialize(sql_table_name, schema, db, opts = {})
29
+ @sname = sql_table_name
30
+ @schema = schema
31
+ raise "Expected OmlSchema but got '#{schema.class}" unless schema.is_a? OmlSchema
32
+ @db = db
31
33
 
32
34
  unless @offset = opts[:offset]
33
35
  @offset = 0
@@ -37,12 +39,11 @@ module OMF::OML
37
39
 
38
40
  @check_interval = opts[:check_interval]
39
41
  @check_interval = 0 unless @check_interval
42
+ @query_interval = opts[:query_interval]
40
43
 
41
-
42
44
  @on_new_vector_proc = {}
43
45
 
44
- schema = parse_schema(schema_raw)
45
- super table_name, schema
46
+ super opts[:name] || sql_table_name, schema
46
47
  end
47
48
 
48
49
 
@@ -60,10 +61,11 @@ module OMF::OML
60
61
  end
61
62
  end
62
63
 
63
- # Return the elements of the vector as an array
64
- def to_a(include_oml_internals = false)
65
- a = @schema.hash_to_row(@row, false, false) # don't need type conversion as sequel is doing this for us
66
- include_oml_internals ? a : a[4 .. -1]
64
+ # Return the elements of the row as an array using the
65
+ # associated schema or 'schema' if non-nil.
66
+ #
67
+ def to_a(schema = nil)
68
+ a = (schema || @schema).hash_to_row(@row) # don't need type conversion as sequel is doing this for us
67
69
  end
68
70
 
69
71
  # Return an array including the values for the names elements
@@ -72,9 +74,10 @@ module OMF::OML
72
74
  def select(*col_names)
73
75
  r = @row
74
76
  col_names.collect do |n|
75
- p = @vprocs[n]
76
- #puts "#{n}::#{p}"
77
- p ? p.call(r) : nil
77
+ unless @row.key? n
78
+ raise "Unknown column name '#{n}'"
79
+ end
80
+ @row[n]
78
81
  end
79
82
  end
80
83
 
@@ -98,79 +101,54 @@ module OMF::OML
98
101
  run() unless @on_new_vector_proc.empty?
99
102
  end
100
103
 
101
- # Create and return an +OmlTable+ which captures this tuple stream
102
- #
103
- # The argument to this method are either a list of columns to
104
- # to capture in the table, or an array of column names and
105
- # an option hash or just
106
- # the option hash to be provided to the +OmlTable+ constructor.
104
+ # Return a table which will capture the content of this tuple stream.
107
105
  #
108
- # If a block is provided, any arriving tuple is executed by the block
109
- # which is expected to return an array which is added to the table
110
- # or nil in which case nothing is added. If a selector array is given the
111
- # block is called with an array of values in the order of the columns
112
- # listed in the selector. Otherwise, the block is called directly
113
- # with the tuple.
106
+ # @param [string] name - Name to use for returned table
107
+ # @param [Hash] opts Options to be passed on to Table constructor
108
+ # @opts [boolean] opts :include_oml_internals If true will also include OML header columns
109
+ # @opts [OmlSchema] opts :schema use specific schema for table (Needs to be a subset of the tuples schema)
114
110
  #
115
- # opts:
116
- # :schema - use this schema instead for the table
117
- # :name - name to use for table
118
- # .... - remaining options to be passed to table constructur
119
- #
120
- def capture_in_table(*args, &block)
121
- if args.length == 1
122
- if args[0].kind_of?(Array)
123
- select = args[0]
124
- elsif args[0].kind_of?(Hash)
125
- opts = args[0]
111
+ def to_stream(opts = {}, &block)
112
+ unless schema = opts.delete(:schema)
113
+ include_oml_internals = (opts[:include_oml_internals] != false)
114
+ schema = self.schema.clone(!include_oml_internals)
115
+ if include_oml_internals
116
+ # replace sender_id by sender ... see _run_once
117
+ schema.replace_column_at 0, :oml_sender
126
118
  end
127
- elsif args.length == 2 && args[1].kind_of?(Hash)
128
- select = args[0]
129
- opts = args[1]
130
- else
131
- opts = {}
132
- select = args
133
119
  end
134
-
135
- if (tschema = opts.delete(:schema))
136
- # unless tschema[0].kind_of? Hash
137
- # tschema = tschema.collect do |cname| {:name => cname} end
138
- # end
139
- else
140
- tschema = select.collect do |cname| {:name => cname} end
141
- end
142
- tname = opts.delete(:name) || stream_name
143
- t = OMF::OML::OmlTable.new(tname, tschema, opts)
144
- if block
145
- self.on_new_tuple() do |v|
146
- #puts "New vector(#{tname}): #{v.schema.inspect} ---- #{v.select(*select).size} <#{v.select(*select).join('|')}>"
147
- if select
148
- row = block.call(v.select(*select))
149
- else
150
- row = block.call(v)
151
- end
152
- if row
153
- raise "Expected kind of Array, but got '#{row.inspect}'" unless row.kind_of?(Array)
154
- t.add_row(row)
155
- end
156
- end
157
- else
158
- self.on_new_tuple() do |v|
159
- #puts "New vector(#{tname}): #{v.select(*select).join('|')}"
160
- t.add_row(v.select(*select))
161
- end
120
+ self.on_new_tuple(rand()) do |t|
121
+ #v = t.to_a(schema)
122
+ v = t.row
123
+ block.arity == 1 ? block.call(v) : block.call(v, schema)
162
124
  end
163
- t
125
+ schema
164
126
  end
165
-
127
+
128
+ # Return a table which will capture the content of this tuple stream.
129
+ #
130
+ # @param [string] name - Name to use for returned table
131
+ # @param [Hash] opts Options to be passed on to Table constructor
132
+ # @opts [boolean] opts :include_oml_internals If true will also include OML header columns
133
+ # @opts [OmlSchema] opts :schema use specific schema for table (Needs to be a subset of the tuples schema)
134
+ #
166
135
  def to_table(name = nil, opts = {})
167
136
  unless name
168
137
  name = @sname
169
138
  end
170
- t = OMF::OML::OmlTable.new(name, self.schema)
171
- include_oml_internals = opts[:include_oml_internals] || true
172
- self.on_new_tuple() do |v|
173
- r = v.to_a(include_oml_internals)
139
+ unless schema = opts.delete(:schema)
140
+ include_oml_internals = (opts[:include_oml_internals] != false)
141
+ schema = self.schema.clone(!include_oml_internals)
142
+ if include_oml_internals
143
+ # replace sender_id by sender ... see _run_once
144
+ schema.replace_column_at 0, :oml_sender
145
+ end
146
+ end
147
+ t = OMF::OML::OmlTable.new(name, schema, opts)
148
+ #puts ">>>>SCHEMA>>> #{schema.inspect}"
149
+ self.on_new_tuple(t) do |v|
150
+ r = v.to_a(schema)
151
+ #puts r.inspect
174
152
  t.add_row(r)
175
153
  end
176
154
  t
@@ -178,32 +156,6 @@ module OMF::OML
178
156
 
179
157
 
180
158
  protected
181
-
182
- def parse_schema(raw)
183
- #puts ">> PARSE SCHEMA"
184
- sd = raw.collect do |col|
185
- name, opts = col
186
- #puts col.inspect
187
- {:name => name, :type => opts[:db_type]}
188
- end
189
- # Query we are using is adding the 'oml_sender_name' to the front of the table
190
- sd.insert(0, :name => :oml_sender, :type => :string)
191
- OmlSchema.new(sd)
192
- end
193
-
194
- # override
195
- def process_schema(schema)
196
- i = 0
197
- @vprocs = {}
198
- schema.each_column do |col|
199
- name = col[:name]
200
- j = i + 0
201
- puts "SCHEMA: '#{name.inspect}'-#{j}"
202
- l = @vprocs[name] = lambda do |r| r[j] end
203
- @vprocs[i - 4] = l if i > 4
204
- i += 1
205
- end
206
- end
207
159
 
208
160
  def run(in_thread = true)
209
161
  return if @running
@@ -224,10 +176,8 @@ module OMF::OML
224
176
  private
225
177
 
226
178
  def _run
227
- @db = Sequel.connect(@db_opts)
228
-
229
179
  if @check_interval <= 0
230
- _run_once
180
+ while _run_once; end
231
181
  else
232
182
  @running = true
233
183
  while (@running)
@@ -256,8 +206,6 @@ module OMF::OML
256
206
  @offset = 0 if @offset < 0
257
207
  end
258
208
  @db["SELECT _senders.name as oml_sender, #{t}.* FROM #{t} INNER JOIN _senders ON (_senders.id = #{t}.oml_sender_id) LIMIT #{@limit} OFFSET #{@offset};"].each do |r|
259
- #@db["SELECT _senders.name as oml_sender, #{t}.* FROM #{t} JOIN _senders WHERE #{t}.oml_sender_id = _senders.id LIMIT #{@limit} OFFSET #{@offset};"].each do |r|
260
- #puts "ROW>>> #{r.inspect}"
261
209
  @row = r
262
210
  @on_new_vector_proc.each_value do |proc|
263
211
  proc.call(self)
@@ -265,27 +213,13 @@ module OMF::OML
265
213
  row_cnt += 1
266
214
  end
267
215
  @offset += row_cnt
268
- debug "Read #{row_cnt}/#{@offset} rows from '#{@sname}'" if row_cnt > 0
269
- row_cnt >= @limit # there could be more to read
216
+ debug "Read #{row_cnt} (total #{@offset}) rows from '#{@sname}'" if row_cnt > 0
217
+ if more_to_read = row_cnt >= @limit # there could be more to read
218
+ sleep @query_interval if @query_interval # don't hammer database
219
+ end
220
+ more_to_read
270
221
  end
271
222
 
272
- # def _statement
273
- # unless @stmt
274
- # db = @db = SQLite3::Database.new(@db_file)
275
- # @db.type_translation = true
276
- # table_name = t = @sname
277
- # if @offset < 0
278
- # cnt = db.execute("select count(*) from #{table_name};")[0][0].to_i
279
- # #debug "CNT: #{cnt}.#{cnt.class} offset: #{@offset}"
280
- # @offset = cnt + @offset # @offset was negative here
281
- # debug("Initial offset #{@offset} in '#{table_name}' with #{cnt} rows")
282
- # @offset = 0 if @offset < 0
283
- # end
284
- # #@stmt = db.prepare("SELECT * FROM #{table_name} LIMIT ? OFFSET ?;")
285
- # @stmt = db.prepare("SELECT _senders.name, #{t}.* FROM #{t} JOIN _senders WHERE #{t}.oml_sender_id = _senders.id LIMIT ? OFFSET ?;")
286
- # end
287
- # @stmt
288
- # end
289
223
  end # OmlSqlRow
290
224
 
291
225
 
@@ -8,13 +8,21 @@ require 'omf_oml/sql_row'
8
8
 
9
9
  module OMF::OML
10
10
 
11
- # This class fetches the content of an sqlite3 database and serves it as multiple
11
+ # This class fetches the content of an SQL database and serves it as multiple
12
12
  # OML streams.
13
13
  #
14
14
  # After creating the object, the @run@ method needs to be called to
15
15
  # start producing the streams.
16
16
  #
17
17
  class OmlSqlSource < OMF::Common::LObject
18
+
19
+ # Sequel adaptors sometimes don't return a :type identifier,
20
+ # but always return the :db_type. This is a list of maps which may not work
21
+ # for all adaptors
22
+ #
23
+ FALLBACK_MAPPING = {
24
+ 'UNSIGNED INTEGER' => :integer
25
+ }
18
26
 
19
27
  # db_opts - Options used to create a Sequel adapter
20
28
  #
@@ -41,13 +49,58 @@ module OMF::OML
41
49
  @on_new_stream_procs.delete key
42
50
  end
43
51
  end
52
+
53
+ # Return a table (more precisely an OmlTable instance) fed from
54
+ # the content of a table 'table_name' in this database.
55
+ #
56
+ # table_name - Name of table in the SQL database
57
+ # opts -
58
+ # :include_oml_internals - Include OML 'header' columns [true]
59
+ # :name - name used for returned OML Table [table_name]
60
+ # All other options defined for OmlSqlRow#new
61
+ #
62
+ def create_table(table_name, opts = {})
63
+ tn = opts.delete(:name) || table_name
64
+ schema = _schema_for_table(table_name)
65
+ r = OmlSqlRow.new(table_name, schema, @db, opts)
66
+ r.to_table(tn, opts)
67
+ end
68
+
69
+ # Call 'block' for every row in 'table_name' table.
70
+ #
71
+ # table_name - Name of table in the SQL database
72
+ # opts -
73
+ # :include_oml_internals[boolean] - Include OML 'header' columns [true]
74
+ # :schema[Schema] Schema to use for creating row
75
+ # All other options defined for OmlSqlRow#new
76
+ #
77
+ def create_stream(table_name, opts = {}, &block)
78
+ rschema = opts.delete(:schema)
79
+ schema = _schema_for_table(table_name)
80
+ r = OmlSqlRow.new(table_name, schema, @db, opts)
81
+ ropts = {}
82
+ ropts[:schema] = rschema if rschema
83
+ r.to_stream(ropts, &block)
84
+ end
85
+
86
+ #
87
+ # Run a query on the database and return the result as an OmlTable. The provided schema
88
+ # needs to describe the SQL queries result set. Unfortunately we can only do very little
89
+ # sanity checks here
90
+ #
91
+ def query(sql, table_name, schema)
92
+ tbl = OmlTable.create(table_name, schema)
93
+ @db.fetch(sql).each do |row|
94
+ tbl << schema.hash_to_row(row)
95
+ end
96
+ tbl
97
+ end
44
98
 
45
99
  # Start checking the database for tables and create a new stream
46
100
  # by calling the internal +report_new_table+ method.
47
101
  # If +check_every+ > 0 continue checking every +check_every+ seconds
48
102
  # for new tables in the database, otherwise it's only checked once
49
103
  #
50
- #
51
104
  def run(check_every = -1)
52
105
  if check_every <= 0
53
106
  run_once()
@@ -67,6 +120,8 @@ module OMF::OML
67
120
  end
68
121
  end
69
122
 
123
+ protected
124
+
70
125
  def run_once()
71
126
  debug "Finding tables #{@db.tables}"
72
127
  # first find tables
@@ -83,7 +138,6 @@ module OMF::OML
83
138
  end
84
139
 
85
140
 
86
- protected
87
141
 
88
142
  # THis method is being called for every table detected in the database.
89
143
  # It creates a new +OmlSqlRow+ object with +opts+ as the only argument.
@@ -95,7 +149,9 @@ module OMF::OML
95
149
  def report_new_table(table_name)
96
150
  unless table = @tables[table_name] # check if already reported before
97
151
  debug "Found table: #{table_name}"
98
- table = @tables[table_name] = OmlSqlRow.new(table_name, @db.schema(table_name), @db_opts, self, @row_opts)
152
+ schema = _schema_for_table(table_name)
153
+ table = @tables[table_name] = OmlSqlRow.new(table_name, schema, @db, @row_opts)
154
+ #table = @tables[table_name] = OmlSqlRow.new(table_name, @db.schema(table_name), @db_opts, self, @row_opts)
99
155
  @on_new_stream_procs.each_value do |proc|
100
156
  proc.call(table)
101
157
  end
@@ -103,6 +159,20 @@ module OMF::OML
103
159
  table
104
160
  end
105
161
 
162
+ def _schema_for_table(table_name)
163
+ begin
164
+ schema_descr = @db.schema(table_name).map do |col_name, cd|
165
+ unless type = cd[:type] || FALLBACK_MAPPING[cd[:db_type]]
166
+ warn "Can't find ruby type for database type '#{cd[:db_type]}'"
167
+ end
168
+ {name: col_name, type: type}
169
+ end
170
+ #puts "SCHEMA_DESCR>>>> #{schema_descr}"
171
+ schema = OmlSchema.new(schema_descr)
172
+ rescue Sequel::Error => ex
173
+ raise "Problems reading schema of table '#{table_name}'. Does it exist? (#{@db.tables})"
174
+ end
175
+ end
106
176
  end
107
177
 
108
178
 
data/lib/omf_oml/table.rb CHANGED
@@ -43,7 +43,9 @@ module OMF::OML
43
43
  #@endpoint = endpoint
44
44
  @name = tname
45
45
  @schema = OmlSchema.create(schema)
46
+ @add_index = false
46
47
  unless @schema.name_at(0) == :__id__
48
+ @add_index = true
47
49
  @schema.insert_column_at(0, [:__id__, 'int'])
48
50
  end
49
51
  @opts = opts
@@ -100,6 +102,14 @@ module OMF::OML
100
102
  end
101
103
  end
102
104
 
105
+ def on_row_added(key, &block)
106
+ on_content_changed(key) do |action, rows|
107
+ if action == :added
108
+ rows.each {|r| block.call(r)}
109
+ end
110
+ end
111
+ end
112
+
103
113
  # NOTE: +on_row_added+ callbacks are done within the monitor.
104
114
  #
105
115
  def add_row(row, needs_casting = false)
@@ -110,6 +120,10 @@ module OMF::OML
110
120
  end
111
121
  end
112
122
 
123
+ def <<(row)
124
+ add_row(row)
125
+ end
126
+
113
127
  # Return a new table which shadows this table but only contains
114
128
  # rows with unique values in the column 'col_name' and of these the
115
129
  # latest added rows to this table.
@@ -164,6 +178,12 @@ module OMF::OML
164
178
  st
165
179
  end
166
180
 
181
+ # Return table as an array of rows
182
+ #
183
+ def to_a
184
+ @rows.dup
185
+ end
186
+
167
187
  def describe()
168
188
  rows
169
189
  end
@@ -177,6 +197,7 @@ module OMF::OML
177
197
  # NOT synchronized
178
198
  #
179
199
  def _add_row(row, needs_casting = false)
200
+ throw "Expected array, but got '#{row}'" unless row.is_a?(Array)
180
201
  if needs_casting
181
202
  row = @schema.cast_row(row, true)
182
203
  end
@@ -186,12 +207,12 @@ module OMF::OML
186
207
  end
187
208
  return nil unless row
188
209
 
189
- row.insert(0, @row_id += 1)
210
+ row.insert(0, @row_id += 1) if @add_index
190
211
  _add_row_finally(row)
191
212
  end
192
213
 
193
- # Finally add 'row' to internal storage. This would be hte method to
194
- # overide in sub classes as this is thread safe and all other pre-storage
214
+ # Finally add 'row' to internal storage. This would be the method to
215
+ # override in sub classes as this is thread safe and all other pre-storage
195
216
  # test have been performed. Should return the row added, or nil if nothing
196
217
  # was ultimately added.
197
218
  #
@@ -1,6 +1,6 @@
1
1
 
2
2
  module OMF
3
3
  module OML
4
- VERSION = '0.9.5'
4
+ VERSION = '0.9.6'
5
5
  end
6
6
  end
data/omf_oml.gemspec CHANGED
@@ -22,5 +22,6 @@ Gem::Specification.new do |s|
22
22
 
23
23
  # specify any dependencies here; for example:
24
24
  # s.add_development_dependency "minitest", "~> 2.11.3"
25
- s.add_runtime_dependency "sqlite3", "~> 1.3.6"
25
+ #s.add_runtime_dependency "sqlite3", "~> 1.3.6"
26
+ s.add_runtime_dependency 'sequel', '~> 3.45'
26
27
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omf_oml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.5
4
+ version: 0.9.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,16 +9,16 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-18 00:00:00.000000000 Z
12
+ date: 2013-03-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: sqlite3
15
+ name: sequel
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: 1.3.6
21
+ version: '3.45'
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
- version: 1.3.6
29
+ version: '3.45'
30
30
  description: ! "Glue functionality between OMF and OMF related libraries, such as
31
31
  OMF Web and Labwiki, and\n OML."
32
32
  email: