traildb 0.1.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: db7de0236d2beb6228f974aaabd1534a1a57949e
4
+ data.tar.gz: 585c4d56fd4fb987e6d1d87f0cd5c0c1b860410d
5
+ SHA512:
6
+ metadata.gz: 5650746b5d2484faf595a5562defb0c675eeb7de6ae41d52230432cf43abd122b2ef02df3ff4df2958b6daea8713e4538e10eb5935649e33ad3e8771566a67f9
7
+ data.tar.gz: 5030283d3ac22d8ffbca26765a344d8f3e8e9f8711cb36f2a6ed856e19012d482af8fed4436be41e2de2fc414e18d40925c47a0bda40b61aeccf92ab8db9bfcb
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /*.tdb
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.2
5
+ before_install: gem install bundler -v 1.15.4
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in traildb.gemspec
6
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Ryosuke IWANAGA
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # Traildb
2
+
3
+ Operate TrailDB from Ruby code using this gem.
4
+
5
+ http://traildb.io/
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'traildb'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install traildb
22
+
23
+ ## Usage
24
+
25
+ ```ruby
26
+ require 'traildb'
27
+
28
+ cookie = '12345678-1234-5678-1234-567812345678'
29
+ cons = Traildb::TrailDBConstructor.new('foo.tdb', ['field1', 'field2'])
30
+ cons.add(cookie, 123, ['a'])
31
+ cons.add(cookie, 124, ['b', 'c'])
32
+ tdb = cons.finalize
33
+
34
+ tdb.trails.each do |cookie, trail|
35
+ trail.each do |event|
36
+ puts "#{cookie} #{event}"
37
+ end
38
+ end
39
+
40
+ #=> 12345678-1234-5678-1234-567812345678 #<struct time=123, field1="a", field2="">
41
+ #=> 12345678-1234-5678-1234-567812345678 #<struct time=124, field1="b", field2="c">
42
+ ```
43
+
44
+ ## Development
45
+
46
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
47
+
48
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
49
+
50
+ ## Contributing
51
+
52
+ Bug reports and pull requests are welcome on GitHub at https://github.com/riywo/traildb.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ t.options = '-v'
9
+ end
10
+
11
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "traildb"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,18 @@
1
+ require 'traildb'
2
+ require 'securerandom'
3
+
4
+ cons = Traildb::TrailDBConstructor.new('tiny', ['username', 'action'])
5
+
6
+ 3.times.each do |i|
7
+ uuid = SecureRandom.uuid
8
+ username = 'user%d' % i
9
+ ['open', 'save', 'close'].each_with_index do |action, day|
10
+ cons.add(uuid, Time.new(2016, i + 1, day + 1), [username, action])
11
+ end
12
+ end
13
+
14
+ cons.finalize
15
+
16
+ Traildb::TrailDB.new('tiny').trails.each do |uuid, trail|
17
+ puts uuid, trail.to_a
18
+ end
@@ -0,0 +1,26 @@
1
+ require 'traildb'
2
+
3
+ SESSION_LIMIT = 30 * 60
4
+
5
+ def sessions(tdb)
6
+ tdb.trails(only_timestamp: true).each_with_index do |(uuid, trail), i|
7
+ trail = trail.to_enum
8
+ prev_time = trail.next
9
+ num_events = 1
10
+ num_sessions = 1
11
+ trail.each do |timestamp|
12
+ if timestamp - prev_time > SESSION_LIMIT
13
+ num_sessions += 1
14
+ end
15
+ prev_time = timestamp
16
+ num_events += 1
17
+ end
18
+ puts 'Trail[%d] Number of Sessions: %d Number of Events: %d' % [i, num_sessions, num_events]
19
+ end
20
+ end
21
+
22
+ if ARGV.size < 1
23
+ puts 'Usage: tutorial_wikipedia_sessions <wikipedia-history.tdb>'
24
+ else
25
+ sessions(Traildb::TrailDB.new(ARGV[0]))
26
+ end
@@ -0,0 +1,3 @@
1
+ module Traildb
2
+ VERSION = "0.1.0"
3
+ end
data/lib/traildb.rb ADDED
@@ -0,0 +1,435 @@
1
+ require "traildb/version"
2
+
3
+ require "ffi"
4
+
5
+ module Traildb
6
+ extend FFI::Library
7
+ ffi_lib "traildb"
8
+
9
+ typedef :pointer, :tdb
10
+ typedef :pointer, :tdb_cons
11
+ typedef :uint32, :tdb_field
12
+ typedef :uint64, :tdb_val
13
+ typedef :uint64, :tdb_item
14
+ typedef :pointer, :tdb_cursor
15
+ typedef :int, :tdb_error
16
+ typedef :pointer, :tdb_event_filter
17
+
18
+ class TdbEvent < FFI::Struct
19
+ layout(
20
+ :timestamp, :uint64,
21
+ :num_items, :uint64,
22
+ :items, [:tdb_item, 0],
23
+ )
24
+
25
+ def tdb_items(valuefun = nil)
26
+ address = pointer + offset_of(:items)
27
+ items = FFI::Pointer.new(:uint64, address).read_array_of_uint64(self[:num_items])
28
+ valuefun.nil? ? items : items.map{|i|valuefun.call(i)}
29
+ end
30
+ end
31
+
32
+ class TdbOptValue < FFI::Union
33
+ layout(
34
+ :ptr, :pointer,
35
+ :value, :uint64,
36
+ )
37
+ end
38
+
39
+ TDB_OPT_EVENT_FILTER = 101
40
+
41
+ attach_function :tdb_cons_init, [], :tdb_cons
42
+ attach_function :tdb_cons_open, [:tdb_cons, :string, :pointer, :uint64], :tdb_error
43
+ attach_function :tdb_cons_close, [:tdb_cons], :void
44
+ attach_function :tdb_cons_add, [:tdb_cons, :pointer, :uint64, :pointer, :pointer], :tdb_error
45
+ attach_function :tdb_cons_append, [:tdb_cons, :tdb], :tdb_error
46
+ attach_function :tdb_cons_finalize, [:tdb_cons], :tdb_error
47
+
48
+ attach_function :tdb_init, [], :tdb
49
+ attach_function :tdb_open, [:tdb, :string], :tdb_error
50
+ attach_function :tdb_close, [:tdb], :void
51
+
52
+ attach_function :tdb_lexicon_size, [:tdb, :tdb_field], :tdb_error
53
+
54
+ attach_function :tdb_get_field, [:tdb, :string], :tdb_error
55
+ attach_function :tdb_get_field_name, [:tdb, :tdb_field], :string
56
+
57
+ attach_function :tdb_get_item, [:tdb, :tdb_field, :pointer, :uint64], :tdb_item
58
+ attach_function :tdb_get_value, [:tdb, :tdb_field, :tdb_val, :pointer], :string
59
+ attach_function :tdb_get_item_value, [:tdb, :tdb_item, :pointer], :string
60
+
61
+ attach_function :tdb_get_uuid, [:tdb, :uint64], :pointer
62
+ attach_function :tdb_get_trail_id, [:tdb, :pointer, :pointer], :tdb_error
63
+
64
+ attach_function :tdb_error_str, [:tdb_error], :string
65
+
66
+ attach_function :tdb_num_trails, [:tdb], :uint64
67
+ attach_function :tdb_num_events, [:tdb], :uint64
68
+ attach_function :tdb_num_fields, [:tdb], :uint64
69
+ attach_function :tdb_min_timestamp, [:tdb], :uint64
70
+ attach_function :tdb_max_timestamp, [:tdb], :uint64
71
+
72
+ attach_function :tdb_version, [:tdb], :uint64
73
+
74
+ attach_function :tdb_cursor_new, [:tdb], :tdb_cursor
75
+ attach_function :tdb_cursor_free, [:tdb_cursor], :void
76
+ attach_function :tdb_cursor_next, [:tdb_cursor], TdbEvent.ptr
77
+ attach_function :tdb_get_trail, [:tdb_cursor, :uint64], :tdb_error
78
+ attach_function :tdb_get_trail_length, [:tdb_cursor], :uint64
79
+ attach_function :tdb_cursor_set_event_filter, [:tdb_cursor, :tdb_event_filter], :tdb_error
80
+
81
+ attach_function :tdb_event_filter_new, [], :tdb_event_filter
82
+ attach_function :tdb_event_filter_add_term, [:tdb_event_filter, :tdb_item, :int], :tdb_error
83
+ attach_function :tdb_event_filter_add_time_range, [:tdb_event_filter, :uint64, :uint64], :tdb_error
84
+ attach_function :tdb_event_filter_new_clause, [:tdb_event_filter], :tdb_error
85
+ attach_function :tdb_event_filter_new_match_none, [], :tdb_event_filter
86
+ attach_function :tdb_event_filter_new_match_all, [], :tdb_event_filter
87
+ attach_function :tdb_event_filter_free, [:tdb_event_filter], :void
88
+
89
+ attach_function :tdb_set_opt, [:tdb, :uint, TdbOptValue.by_value], :tdb_error
90
+ attach_function :tdb_set_trail_opt, [:tdb, :uint64, :uint, TdbOptValue.by_value], :tdb_error
91
+
92
+ def self.uuid_hex(uuid)
93
+ if uuid.is_a? FFI::Pointer
94
+ ary = uuid.read_bytes(16).unpack("NnnnnN")
95
+ uuid = "%08x-%04x-%04x-%04x-%04x%08x" % ary
96
+ end
97
+ uuid
98
+ end
99
+
100
+ def self.uuid_raw(uuid)
101
+ if uuid.is_a? String
102
+ ptr = FFI::MemoryPointer.new(:uint8, 16)
103
+ uuid = ptr.write_bytes(uuid.scan(/[0-9a-f]{2}/).map{|x|x.to_i(16)}.pack('C*'))
104
+ end
105
+ uuid
106
+ end
107
+
108
+ def self.tdb_item_is32(item); (item & 128) == 0 end
109
+ def self.tdb_item_field32(item); item & 127 end
110
+ def self.tdb_item_val32(item); (item >> 8) & 4294967295 end # UINT32_MAX
111
+
112
+ def self.tdb_item_field(item)
113
+ if tdb_item_is32(item)
114
+ tdb_item_field32(item)
115
+ else
116
+ (item & 127) | (((item >> 8) & 127) << 7)
117
+ end
118
+ end
119
+
120
+ def self.tdb_item_val(item)
121
+ if tdb_item_is32(item)
122
+ tdb_item_val32(item)
123
+ else
124
+ item >> 16
125
+ end
126
+ end
127
+
128
+ class TrailDBError < ::StandardError
129
+ def initialize(message, error = 0)
130
+ message += ": " + Traildb.tdb_error_str(error) if error != 0
131
+ super message
132
+ end
133
+ end
134
+
135
+ class TrailDBConstructor < FFI::AutoPointer
136
+ def initialize(path, ofields=[])
137
+ raise TrailDBError.new("Path is required") if path.nil?
138
+ super Traildb.tdb_cons_init()
139
+ n = ofields.size
140
+ ofield_names = FFI::MemoryPointer.new(:string, n)
141
+ ofield_names.write_array_of_pointer(ofields.map{|field|FFI::MemoryPointer.from_string(field)})
142
+ ret = Traildb.tdb_cons_open(self, path, ofield_names, n)
143
+ raise TrailDBError.new("Cannot open constructor", ret) if ret != 0
144
+ @path = path
145
+ @ofields = ofields
146
+ end
147
+
148
+ def add(uuid, tstamp, values)
149
+ tstamp = tstamp.to_i if tstamp.is_a? Time
150
+ uuid = Traildb.uuid_raw(uuid)
151
+ n = @ofields.size
152
+ value_array = FFI::MemoryPointer.new(:string, n)
153
+ value_array.write_array_of_pointer(values.map{|v|FFI::MemoryPointer.from_string(v)})
154
+ value_lengths = FFI::MemoryPointer.new(:uint64, n)
155
+ value_lengths.write_array_of_uint64(values.map{|v|v.size})
156
+ ret = Traildb.tdb_cons_add(self, uuid, tstamp, value_array, value_lengths)
157
+ raise TrailDBError.new("Too many values: %s" % values[ret]) if ret != 0
158
+ end
159
+
160
+ def append(db)
161
+ f = Traildb.tdb_cons_append(self, db)
162
+ if f < 0
163
+ raise TrailDBError.new("Wrong number of fields: %d" % db.num_fields, f)
164
+ elsif f > 0
165
+ raise TrailDBError.new("Too many values", f)
166
+ end
167
+ end
168
+
169
+ def finalize
170
+ ret = Traildb.tdb_cons_finalize(self)
171
+ raise TrailDBError.new("Could not finalize", ret) if ret != 0
172
+ TrailDB.new(@path)
173
+ end
174
+
175
+ def self.release(ptr)
176
+ Traildb.tdb_cons_close(ptr)
177
+ end
178
+ end
179
+
180
+ class TrailDBCursor < FFI::AutoPointer
181
+ include Enumerable
182
+
183
+ def initialize(cursor, cls, valuefun, parsetime, only_timestamp, event_filter_obj)
184
+ super cursor
185
+ @cls = cls
186
+ @valuefun = valuefun
187
+ @parsetime = parsetime
188
+ @only_timestamp = only_timestamp
189
+ if event_filter_obj
190
+ @event_filter_obj = event_filter_obj
191
+ ret = Traildb.tdb_cursor_set_event_filter(self, event_filter_obj)
192
+ raise TrailDBError.new("cursor_set_event_filter failed", ret) if ret != 0
193
+ end
194
+ end
195
+
196
+ def each
197
+ loop do
198
+ event = Traildb.tdb_cursor_next(self)
199
+ break if event.null?
200
+ timestamp = event[:timestamp]
201
+ timestamp = Time.at(timestamp) if @parsetime
202
+ if @only_timestamp
203
+ yield timestamp
204
+ else
205
+ items = event.tdb_items(@valuefun)
206
+ yield @cls.new(timestamp, *items)
207
+ end
208
+ end
209
+ end
210
+
211
+ def self.release(ptr)
212
+ Trailsdb.tdb_cursor_free(ptr)
213
+ end
214
+ end
215
+
216
+ class TrailDB < FFI::AutoPointer
217
+ attr_reader :num_trails, :num_events, :num_fields, :fields
218
+
219
+ def initialize(path)
220
+ super Traildb.tdb_init()
221
+ ret = Traildb.tdb_open(self, path)
222
+ raise TrailDBError.new("Could not open %s" % path, ret) if ret != 0
223
+ @num_trails = Traildb.tdb_num_trails(self)
224
+ @num_events = Traildb.tdb_num_events(self)
225
+ @num_fields = Traildb.tdb_num_fields(self)
226
+ @fields = @num_fields.times.map{|i|Traildb.tdb_get_field_name(self,i)}
227
+ @event_cls = Struct.new(*@fields.map(&:to_sym))
228
+ @uint64_ptr = FFI::MemoryPointer.new(:uint64)
229
+ end
230
+
231
+ def include?(uuidish)
232
+ self[uuidish]
233
+ true
234
+ rescue IndexError
235
+ false
236
+ end
237
+
238
+ def [](uuidish)
239
+ if uuidish.is_a? String
240
+ trail(get_trail_id(uuidish))
241
+ else
242
+ trail(uuidish)
243
+ end
244
+ end
245
+
246
+ def size
247
+ @num_trails
248
+ end
249
+
250
+ def trails(selected_uuids: nil, **kwds)
251
+ if selected_uuids.nil?
252
+ size.times.each.lazy.map do |i|
253
+ [get_uuid(i), trail(i, kwds)]
254
+ end
255
+ else
256
+ selected_uuids.each.lazy.map do |uuid|
257
+ begin
258
+ i = get_trail_id(uuid)
259
+ rescue IndexError
260
+ next
261
+ end
262
+ [uuid, trail(i, kwds)]
263
+ end
264
+ end
265
+ end
266
+
267
+ def trail(trail_id, parsetime: false, rawitems: false, only_timestamp: false, event_filter: nil)
268
+ cursor = Traildb.tdb_cursor_new(self)
269
+ ret = Traildb.tdb_get_trail(cursor, trail_id)
270
+ raise TrailDBError.new("Failed to create cursor", ret) if ret != 0
271
+ valuefun = rawitems ? nil : ->(item){get_item_value(item)}
272
+ event_filter_obj = case event_filter
273
+ when TrailDBEventFilter
274
+ event_filter
275
+ when Array
276
+ create_filter(event_filter)
277
+ else
278
+ nil
279
+ end
280
+ TrailDBCursor.new(cursor, @event_cls, valuefun, parsetime, only_timestamp, event_filter_obj)
281
+ end
282
+
283
+ def field(fieldish)
284
+ if fieldish.is_a? String
285
+ fieldish = @fields.index(fieldish)
286
+ end
287
+ fieldish
288
+ end
289
+
290
+ def lexicon(fieldish)
291
+ field = field(fieldish)
292
+ (1..lexicon_size(field)-1).lazy.map{|i|
293
+ get_value(field, i)
294
+ }
295
+ end
296
+
297
+ def lexicon_size(fieldish)
298
+ field = field(fieldish)
299
+ value = Traildb.tdb_lexicon_size(self, field)
300
+ raise TrailDBError.new("Invalid field index") if value == 0
301
+ value
302
+ end
303
+
304
+ def get_item(fieldish, value)
305
+ field = field(fieldish)
306
+ item = Traildb.tdb_get_item(self, field, value, value.size)
307
+ raise TrailDBError.new("No such value: '%s'" % value) if item.nil?
308
+ item
309
+ end
310
+
311
+ def get_item_value(item)
312
+ value = Traildb.tdb_get_item_value(self, item, @uint64_ptr)
313
+ raise TrailDBError.new("Error reading value") if value.nil?
314
+ value.slice(0, @uint64_ptr.read_uint64)
315
+ end
316
+
317
+ def get_value(fieldish, val)
318
+ field = field(fieldish)
319
+ value = Traildb.tdb_get_value(self, field, val, @uint64_ptr)
320
+ raise TrailDBError.new("Error reading value") if value.nil?
321
+ value.slice(0, @uint64_ptr.read_uint64)
322
+ end
323
+
324
+ def get_uuid(trail_id, raw=false)
325
+ uuid = Traildb.tdb_get_uuid(self, trail_id)
326
+ if uuid.nil?
327
+ raise ::IndexError
328
+ else
329
+ raw ? uuid.read_string : Traildb.uuid_hex(uuid)
330
+ end
331
+ end
332
+
333
+ def get_trail_id(uuid)
334
+ ret = Traildb.tdb_get_trail_id(self, Traildb.uuid_raw(uuid), @uint64_ptr)
335
+ raise ::IndexError if ret != 0
336
+ @uint64_ptr.read_uint64
337
+ end
338
+
339
+ def time_range(parsetime: false)
340
+ tmin = min_timestamp
341
+ tmax = max_timestamp
342
+ parsetime ? [Time.at(tmin), Time.at(tmax)] : [tmin, tmax]
343
+ end
344
+
345
+ def min_timestamp
346
+ Traildb.tdb_min_timestamp(self)
347
+ end
348
+
349
+ def max_timestamp
350
+ Traildb.tdb_max_timestamp(self)
351
+ end
352
+
353
+ def create_filter(event_filter)
354
+ TrailDBEventFilter.new(self, event_filter)
355
+ end
356
+
357
+ def apply_whitelist(uuids)
358
+ empty_filter = Traildb.tdb_event_filter_new_match_none()
359
+ all_filter = Traildb.tdb_event_filter_new_match_all()
360
+ value = TdbOptValue.new
361
+ value[:ptr] = empty_filter
362
+ Traildb.tdb_set_opt(self, TDB_OPT_EVENT_FILTER, value)
363
+ value[:ptr] = all_filter
364
+ uuids.each do |uuid|
365
+ begin
366
+ trail_id = get_trail_id(uuid)
367
+ Traildb.tdb_set_trail_opt(self, trail_id, TDB_OPT_EVENT_FILTER, value)
368
+ rescue IndexError
369
+ next
370
+ end
371
+ end
372
+ end
373
+
374
+ def apply_blacklist(uuids)
375
+ empty_filter = Traildb.tdb_event_filter_new_match_none()
376
+ all_filter = Traildb.tdb_event_filter_new_match_all()
377
+ value = TdbOptValue.new
378
+ value[:ptr] = all_filter
379
+ Traildb.tdb_set_opt(self, TDB_OPT_EVENT_FILTER, value)
380
+ value[:ptr] = empty_filter
381
+ uuids.each do |uuid|
382
+ begin
383
+ trail_id = get_trail_id(uuid)
384
+ Traildb.tdb_set_trail_opt(self, trail_id, TDB_OPT_EVENT_FILTER, value)
385
+ rescue IndexError
386
+ next
387
+ end
388
+ end
389
+ end
390
+
391
+ def self.release(ptr)
392
+ Traildb.tdb_close(ptr)
393
+ end
394
+ end
395
+
396
+ class TrailDBEventFilter < FFI::AutoPointer
397
+ def initialize(db, query)
398
+ super Traildb.tdb_event_filter_new()
399
+ if !query[0][0].is_a? Array
400
+ query = [query]
401
+ end
402
+ query.each_with_index do |clause, i|
403
+ if i > 0
404
+ ret = Traildb.tdb_event_filter_new_clause(self)
405
+ raise TrailDBError.new("Out of memory in create_filter", ret) if ret != 0
406
+ end
407
+ clause.each do |term|
408
+ ret = 0
409
+ if term.size == 2 and term[0].is_a? Integer and term[0].is_a? Integer
410
+ start_time, end_time = term
411
+ ret = Traildb.tdb_event_filter_add_time_range(self, start_time, end_time)
412
+ else
413
+ is_negative = false
414
+ if term.size == 3
415
+ field, value, is_negative = term
416
+ else
417
+ field, value = term
418
+ end
419
+ item = begin
420
+ db.get_item(field, value)
421
+ rescue TrailDBError, ValueError
422
+ 0
423
+ end
424
+ ret = Traildb.tdb_event_filter_add_term(self, item, is_negative ? 1 : 0)
425
+ end
426
+ raise TrailDBError.new("Out of memory in create_filter", ret) if ret != 0
427
+ end
428
+ end
429
+ end
430
+
431
+ def self.release(ptr)
432
+ Traildb.tdb_event_filter_free(ptr)
433
+ end
434
+ end
435
+ end
data/traildb.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "traildb/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "traildb"
8
+ spec.version = Traildb::VERSION
9
+ spec.authors = ["Ryosuke IWANAGA"]
10
+ spec.email = ["riywo.jp@gmail.com"]
11
+
12
+ spec.summary = %q{Ruby bindings for TrailDB}
13
+ spec.description = %q{Operate TrailDB from Ruby code using this gem.}
14
+ spec.homepage = "https://github.com/riywo/traildb-ruby"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_dependency "ffi"
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.15"
27
+ spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "test-unit"
29
+ spec.add_development_dependency "pry"
30
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: traildb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ryosuke IWANAGA
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-11-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ffi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.15'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.15'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: test-unit
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Operate TrailDB from Ruby code using this gem.
84
+ email:
85
+ - riywo.jp@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".travis.yml"
92
+ - Gemfile
93
+ - LICENSE
94
+ - README.md
95
+ - Rakefile
96
+ - bin/console
97
+ - bin/setup
98
+ - examples/tutorial_simple_traildb.rb
99
+ - examples/tutorial_wikipedia_sessions.rb
100
+ - lib/traildb.rb
101
+ - lib/traildb/version.rb
102
+ - traildb.gemspec
103
+ homepage: https://github.com/riywo/traildb-ruby
104
+ licenses:
105
+ - MIT
106
+ metadata: {}
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubyforge_project:
123
+ rubygems_version: 2.6.13
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: Ruby bindings for TrailDB
127
+ test_files: []