mongolitedb 0.0.1 → 0.0.2
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 +4 -4
- data/lib/matcher.rb +87 -0
- data/lib/mongolitedb.rb +77 -145
- data/lib/predicate_matcher.rb +45 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 61d2c498c08966845f3e8d5ac13c8858599f831b
|
4
|
+
data.tar.gz: 514b684b4a2c21f75437f68bdf1b39b7cb8baea0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f89e5e7be09e0992104210f61c7eb3340f23b1628422075f4973a510e29a4c5b5e524eff969363ab50c44c3a5bcf63d71135dd612e4e18c3cd9f4932f82f3b9c
|
7
|
+
data.tar.gz: c5a076ba07eb8f8a2d77da70ef8f7b8f55ae05d898ad89371084981bb90638fdf3d23c437cfb75f416638893703b467bd86715c70b1d68f43047bd9673b7abc0
|
data/lib/matcher.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'predicate_matcher'
|
2
|
+
|
3
|
+
class Matcher
|
4
|
+
def initialize(query)
|
5
|
+
@query = query
|
6
|
+
end
|
7
|
+
|
8
|
+
def match(obj)
|
9
|
+
if @query.length > 1
|
10
|
+
# We always have an implied $and for multiple entries
|
11
|
+
matcher = AndMatcher.new({"$and" => @query.map{|k,v| {k => v}}})
|
12
|
+
elsif @query.length == 0
|
13
|
+
matcher = EmptyMatcher.new(@query)
|
14
|
+
else
|
15
|
+
# we only have one entry
|
16
|
+
case @query.keys.first
|
17
|
+
when "$or"
|
18
|
+
matcher = OrMatcher.new(@query)
|
19
|
+
when "$nor"
|
20
|
+
matcher = NorMatcher.new(@query)
|
21
|
+
when "$and"
|
22
|
+
matcher = AndMatcher.new(@query)
|
23
|
+
else
|
24
|
+
matcher = AttrMatcher.new(@query)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
return matcher.match(obj)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class AttrMatcher < Matcher
|
32
|
+
def match(obj)
|
33
|
+
attribute = @query.keys.first
|
34
|
+
if attribute.include?(".")
|
35
|
+
value = obj
|
36
|
+
attribute.split(".").each do |attr|
|
37
|
+
value = value[attr]
|
38
|
+
if value.nil?
|
39
|
+
return false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
else
|
43
|
+
value = obj[@query.keys.first]
|
44
|
+
end
|
45
|
+
predicate = @query.values.first
|
46
|
+
if predicate.kind_of? Hash
|
47
|
+
matcher = PredicateMatcher.new(predicate)
|
48
|
+
return matcher.match(value)
|
49
|
+
else
|
50
|
+
return value == predicate
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class AndMatcher < Matcher
|
56
|
+
def match(obj)
|
57
|
+
does_it_match = true
|
58
|
+
@query.values.first.each do |subquery|
|
59
|
+
matcher = Matcher.new(subquery)
|
60
|
+
does_it_match &&= matcher.match(obj)
|
61
|
+
end
|
62
|
+
return does_it_match
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class EmptyMatcher < Matcher
|
67
|
+
def match(obj)
|
68
|
+
true
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class OrMatcher < Matcher
|
73
|
+
def match(obj)
|
74
|
+
does_it_match = false
|
75
|
+
@query.values.first.each do |subquery|
|
76
|
+
matcher = Matcher.new(subquery)
|
77
|
+
does_it_match ||= matcher.match(obj)
|
78
|
+
end
|
79
|
+
return does_it_match
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class NorMatcher < Matcher
|
84
|
+
def match(obj)
|
85
|
+
return !OrMatcher.new(@query).match(obj)
|
86
|
+
end
|
87
|
+
end
|
data/lib/mongolitedb.rb
CHANGED
@@ -1,160 +1,92 @@
|
|
1
1
|
require 'json'
|
2
|
+
require 'matcher'
|
2
3
|
|
3
4
|
class MongoLiteDB
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
5
|
+
def initialize(filename="db.nsl")
|
6
|
+
@filename = filename
|
7
|
+
if not File.exists?(@filename)
|
8
|
+
open(@filename, 'w'){|f| f.write(
|
9
|
+
{
|
10
|
+
"max_index" => 0,
|
11
|
+
"objects" => []
|
12
|
+
}.to_json
|
13
|
+
)}
|
14
14
|
end
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
write_to_disk do |db|
|
20
|
-
objects.each do |object|
|
21
|
-
object_copy = object.clone
|
22
|
-
object_copy["id"] = db["max_index"]
|
23
|
-
db["max_index"] += 1
|
24
|
-
db["objects"] << object_copy
|
25
|
-
end
|
26
|
-
end
|
15
|
+
end
|
16
|
+
def insert(objects)
|
17
|
+
if not objects.kind_of?(Array)
|
18
|
+
objects = [objects]
|
27
19
|
end
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
return entries
|
20
|
+
write_to_disk do |db|
|
21
|
+
objects.each do |object|
|
22
|
+
object_copy = object.clone
|
23
|
+
object_copy["id"] = db["max_index"]
|
24
|
+
db["max_index"] += 1
|
25
|
+
db["objects"] << object_copy
|
26
|
+
end
|
36
27
|
end
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
28
|
+
end
|
29
|
+
def find(query)
|
30
|
+
entries = []
|
31
|
+
load_from_disk do |db|
|
32
|
+
each_match(db, query) do |obj|
|
33
|
+
entries << obj
|
34
|
+
end
|
44
35
|
end
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
36
|
+
return entries
|
37
|
+
end
|
38
|
+
def update(query, attr)
|
39
|
+
write_to_disk do |db|
|
40
|
+
each_match(db, query) do |obj|
|
41
|
+
obj.update(attr)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
def delete(query)
|
46
|
+
write_to_disk do |db|
|
47
|
+
each_match(db, query) do |obj|
|
48
|
+
db["objects"].delete(obj)
|
49
|
+
end
|
51
50
|
end
|
51
|
+
end
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
53
|
+
private
|
54
|
+
def write_to_disk
|
55
|
+
f = open(@filename, 'r+')
|
56
|
+
f.flock(File::LOCK_EX)
|
57
|
+
db = JSON.parse f.read
|
58
|
+
yield db
|
59
|
+
ensure
|
60
|
+
if f
|
61
|
+
if db
|
62
|
+
f.rewind
|
63
|
+
f.write db.to_json
|
64
|
+
f.flush
|
65
|
+
f.truncate f.pos
|
66
|
+
end
|
67
|
+
f.close
|
69
68
|
end
|
69
|
+
end
|
70
70
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
71
|
+
def load_from_disk
|
72
|
+
f = open(@filename, 'r+')
|
73
|
+
f.flock(File::LOCK_SH)
|
74
|
+
db = JSON.parse f.read
|
75
|
+
yield db
|
76
|
+
ensure
|
77
|
+
if f
|
78
|
+
f.close
|
79
|
+
end
|
80
|
+
end
|
81
81
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
end
|
82
|
+
def each_match(db, query)
|
83
|
+
db["objects"].clone.each do |obj|
|
84
|
+
yield(obj) unless not match(obj, query)
|
86
85
|
end
|
86
|
+
end
|
87
87
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
# if value is an hash, we should expect it's only key to be a keyword
|
93
|
-
# if value is a string or FixNum , we should check for attribute match
|
94
|
-
# if query is Hash, then we break it into individual queries and recursively call them (as arrays)
|
95
|
-
if query.kind_of? Array
|
96
|
-
if query[1].kind_of? Array
|
97
|
-
case query[0]
|
98
|
-
when "$or"
|
99
|
-
match = false
|
100
|
-
query[1].each do |attr|
|
101
|
-
is_a_match = match(obj, attr)
|
102
|
-
match ||= is_a_match
|
103
|
-
end
|
104
|
-
return match
|
105
|
-
else
|
106
|
-
raise NotImplementedError
|
107
|
-
end
|
108
|
-
elsif query[1].kind_of? Hash
|
109
|
-
match = true
|
110
|
-
query[1].each do |k,v|
|
111
|
-
case k
|
112
|
-
when "$in"
|
113
|
-
local_match = false
|
114
|
-
v.each do |value|
|
115
|
-
is_a_match = match(obj, [query[0], value])
|
116
|
-
local_match ||= is_a_match
|
117
|
-
end
|
118
|
-
match &&= local_match
|
119
|
-
when "$exists"
|
120
|
-
match &&= (not obj[query[0]].nil?) == v
|
121
|
-
when "$nin"
|
122
|
-
local_match = true
|
123
|
-
v.each do |value|
|
124
|
-
is_a_match = match(obj, [query[0], value])
|
125
|
-
local_match &&= (not is_a_match)
|
126
|
-
end
|
127
|
-
match &&= local_match
|
128
|
-
when "$gt"
|
129
|
-
return obj[query[0]] > v
|
130
|
-
when "$gte"
|
131
|
-
return obj[query[0]] >= v
|
132
|
-
when "$lt"
|
133
|
-
return obj[query[0]] < v
|
134
|
-
when "$lte"
|
135
|
-
return obj[query[0]] <= v
|
136
|
-
when "$ne"
|
137
|
-
return obj[query[0]] != v
|
138
|
-
when "$mod"
|
139
|
-
return obj[query[0]] % v[0] == v[1]
|
140
|
-
else
|
141
|
-
raise NotImplementedError
|
142
|
-
end
|
143
|
-
end
|
144
|
-
return match
|
145
|
-
else
|
146
|
-
match = (obj[query[0]] == query[1])
|
147
|
-
return match
|
148
|
-
end
|
149
|
-
elsif query.kind_of? Hash
|
150
|
-
match = true
|
151
|
-
query.to_a.each do |attr|
|
152
|
-
is_a_match = match(obj, attr)
|
153
|
-
match &&= is_a_match
|
154
|
-
end
|
155
|
-
return match
|
156
|
-
else
|
157
|
-
raise NotImplementedError
|
158
|
-
end
|
159
|
-
end
|
88
|
+
def match(obj, query)
|
89
|
+
matcher = Matcher.new(query)
|
90
|
+
return matcher.match(obj)
|
91
|
+
end
|
160
92
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class PredicateMatcher
|
2
|
+
def initialize(predicate)
|
3
|
+
@predicate = predicate
|
4
|
+
end
|
5
|
+
def match(value)
|
6
|
+
if @predicate.length > 1
|
7
|
+
matcher = AndPredicateMatcher.new(@predicate)
|
8
|
+
return matcher.match(value)
|
9
|
+
end
|
10
|
+
case @predicate.keys.first
|
11
|
+
when "$exists"
|
12
|
+
return @predicate.values.first == !value.nil?
|
13
|
+
when "$in"
|
14
|
+
return @predicate.values.first.include?(value)
|
15
|
+
when "$nin"
|
16
|
+
return !@predicate.values.first.include?(value)
|
17
|
+
when "$gt"
|
18
|
+
return value > @predicate.values.first
|
19
|
+
when "$gte"
|
20
|
+
return value >= @predicate.values.first
|
21
|
+
when "$lt"
|
22
|
+
return value < @predicate.values.first
|
23
|
+
when "$lte"
|
24
|
+
return value <= @predicate.values.first
|
25
|
+
when "$ne"
|
26
|
+
return value != @predicate.values.first
|
27
|
+
when "$mod"
|
28
|
+
return value % @predicate.values.first[0] == @predicate.values.first[1]
|
29
|
+
else
|
30
|
+
raise NotImplementedError
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class AndPredicateMatcher < PredicateMatcher
|
36
|
+
def match(value)
|
37
|
+
does_it_match = true
|
38
|
+
@predicate.each do |k,v|
|
39
|
+
matcher = PredicateMatcher.new({k => v})
|
40
|
+
does_it_match &&= matcher.match(value)
|
41
|
+
end
|
42
|
+
return does_it_match
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongolitedb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Hamilton
|
@@ -17,6 +17,8 @@ extensions: []
|
|
17
17
|
extra_rdoc_files: []
|
18
18
|
files:
|
19
19
|
- lib/mongolitedb.rb
|
20
|
+
- lib/matcher.rb
|
21
|
+
- lib/predicate_matcher.rb
|
20
22
|
homepage: https://github.com/hamiltop/MongoLiteDB
|
21
23
|
licenses: []
|
22
24
|
metadata: {}
|
@@ -36,7 +38,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
36
38
|
version: '0'
|
37
39
|
requirements: []
|
38
40
|
rubyforge_project:
|
39
|
-
rubygems_version: 2.0.
|
41
|
+
rubygems_version: 2.0.3
|
40
42
|
signing_key:
|
41
43
|
specification_version: 4
|
42
44
|
summary: MongoLiteDB embedded database
|