]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - lib/rbot/journal/mongo.rb
journal: add mongodb storage backend
[user/henk/code/ruby/rbot.git] / lib / rbot / journal / mongo.rb
1 # encoding: UTF-8
2 #-- vim:sw=2:et
3 #++
4 #
5 # :title: journal backend for mongoDB
6
7 require 'mongo'
8 require 'json'
9
10 module Irc
11 class Bot
12 module Journal
13
14   module Storage
15
16     class MongoStorage < AbstractStorage
17       attr_reader :client
18
19       def initialize(opts={})
20         Mongo::Logger.logger.level = Logger::WARN
21         @uri = opts[:uri] || 'mongodb://127.0.0.1:27017/rbot'
22         @client = Mongo::Client.new(@uri)
23         @collection = @client['journal']
24         log 'journal storage: mongodb connected to ' + @uri
25         
26         drop if opts[:drop]
27         @collection.indexes.create_one({topic: 1})
28       end
29
30       def ensure_index(key)
31         @collection.indexes.create_one({'payload.'+key => 1})
32       end
33
34       def insert(m)
35         @collection.insert_one({
36           '_id' => m.id,
37           'topic' => m.topic,
38           'timestamp' => m.timestamp,
39           'payload' => m.payload
40         })
41       end
42
43       def find(query=nil, limit=100, offset=0)
44         query_cursor(query).skip(offset).limit(limit).map do |document|
45           JournalMessage.new(id: document['_id'], timestamp: document['timestamp'].localtime,
46             topic: document['topic'], payload: document['payload'].to_h)
47         end
48       end
49
50       # returns the number of messages that match the query
51       def count(query=nil)
52         query_cursor(query).count
53       end
54
55       def remove(query=nil)
56         query_cursor(query).delete_many
57       end
58
59       def drop
60         @collection.drop
61       end
62
63       def query_cursor(query)
64         unless query
65           return @collection.find()
66         end
67
68         query_and = []
69
70         # ID query OR condition
71         unless query.id.empty?
72           query_and << {
73             '$or' => query.id.map { |_id| 
74               {'_id' => _id}
75             }
76           }
77         end
78
79         unless query.topic.empty?
80           query_and << {
81             '$or' => query.topic.map { |topic|
82               if topic.include?('*')
83                 pattern = topic.gsub('.', '\.').gsub('*', '.*')
84                 {'topic' => {'$regex' => pattern}}
85               else
86                 {'topic' => topic}
87               end
88             }
89           }
90         end
91
92         if query.timestamp[:from] or query.timestamp[:to]
93           where = {}
94           if query.timestamp[:from]
95             where['$gte'] = query.timestamp[:from]
96           end
97           if query.timestamp[:to]
98             where['$lte'] = query.timestamp[:to]
99           end
100           query_and << {'timestamp' => where}
101         end
102
103         unless query.payload.empty?
104           query_and << {
105             '$or' => query.payload.map { |key, value|
106               key = 'payload.' + key
107               {key => value}
108             }
109           }
110         end
111
112         @collection.find({
113           '$and' => query_and
114         })
115       end
116     end
117   end
118 end # Journal
119 end # Bot
120 end # Irc