mem_db 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.
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MemDB
4
+ module Field
5
+ module Matching
6
+ def match?(_query)
7
+ raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mem_db/field"
4
+ require "mem_db/field/matching"
5
+
6
+ class MemDB
7
+ module Field
8
+ class MayMissing
9
+ include MemDB::Field
10
+
11
+ class Any
12
+ include MemDB::Field::Matching
13
+
14
+ def match?(_query)
15
+ true
16
+ end
17
+ end
18
+
19
+ ANY_MATCHING = Any.new
20
+
21
+ def initialize(original)
22
+ @original = original
23
+ end
24
+
25
+ def field
26
+ @original.field
27
+ end
28
+
29
+ def query_field
30
+ @original.query_field
31
+ end
32
+
33
+ def new_matching(obj)
34
+ v = obj[field]
35
+
36
+ if v.nil?
37
+ ANY_MATCHING
38
+ else
39
+ @original.new_matching(obj)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mem_db/field"
4
+ require "mem_db/field/matching"
5
+
6
+ class MemDB
7
+ module Field
8
+ class Negative
9
+ include MemDB::Field
10
+
11
+ class NegativeMatching
12
+ include MemDB::Field::Matching
13
+
14
+ def initialize(original)
15
+ @original = original
16
+ end
17
+
18
+ def match?(query)
19
+ !@original.match?(query)
20
+ end
21
+ end
22
+
23
+ def initialize(original)
24
+ @original = original
25
+ end
26
+
27
+ def field
28
+ @original.field
29
+ end
30
+
31
+ def query_field
32
+ @original.query_field
33
+ end
34
+
35
+ def new_matching(obj)
36
+ NegativeMatching.new(@original.new_matching(obj))
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mem_db/field"
4
+ require "mem_db/field/matching"
5
+
6
+ class MemDB
7
+ module Field
8
+ class Pattern
9
+ include MemDB::Field
10
+
11
+ class Pattern
12
+ WILDCARD = "*"
13
+
14
+ class Rx
15
+ def initialize(source)
16
+ parts = source.split(WILDCARD, -1).map { |part| ::Regexp.quote(part) }
17
+ parts[0] = "\\A#{parts[0]}"
18
+ parts[-1] = "#{parts[-1]}\\z"
19
+ @rx = ::Regexp.new(parts.join(".*"), ::Regexp::MULTILINE)
20
+ end
21
+
22
+ def match?(str)
23
+ @rx.match?(str)
24
+ end
25
+ end
26
+
27
+ class Exact
28
+ def initialize(source)
29
+ @source = source
30
+ end
31
+
32
+ def match?(str)
33
+ @source == str
34
+ end
35
+ end
36
+
37
+ class Prefix
38
+ def initialize(prefix)
39
+ @prefix = prefix
40
+ end
41
+
42
+ def match?(str)
43
+ str.start_with?(@prefix)
44
+ end
45
+ end
46
+
47
+ class Suffix
48
+ def initialize(suffix)
49
+ @suffix = suffix
50
+ end
51
+
52
+ def match?(str)
53
+ str.end_with?(@suffix)
54
+ end
55
+ end
56
+
57
+ def initialize(source)
58
+ wildcard_count = source.count(WILDCARD)
59
+ @pat =
60
+ if wildcard_count.zero?
61
+ Exact.new(source)
62
+ elsif wildcard_count > 1
63
+ Rx.new(source)
64
+ elsif source.end_with?(WILDCARD)
65
+ Prefix.new(source[0..-2])
66
+ elsif source.start_with?(WILDCARD)
67
+ Suffix.new(source[1..-1])
68
+ else
69
+ Rx.new(source)
70
+ end
71
+ end
72
+
73
+ def match?(str)
74
+ @pat.match?(str)
75
+ end
76
+ end
77
+
78
+ class MultiMatching
79
+ include MemDB::Field::Matching
80
+
81
+ def initialize(f, arr)
82
+ @f = f
83
+ @patterns = arr.map { |source| Pattern.new(source) }
84
+ end
85
+
86
+ def match?(query)
87
+ @f.query_value(query).each do |str|
88
+ return true if @patterns.any? { |pat| pat.match?(str) }
89
+ end
90
+
91
+ false
92
+ end
93
+ end
94
+
95
+ class SingleMatching
96
+ include MemDB::Field::Matching
97
+
98
+ def initialize(f, el)
99
+ @f = f
100
+ @pat = Pattern.new(el)
101
+ end
102
+
103
+ def match?(query)
104
+ @f.query_value(query).any? { |str| @pat.match?(str) }
105
+ end
106
+ end
107
+
108
+ attr_reader :field
109
+
110
+ def initialize(field)
111
+ @field = field
112
+ end
113
+
114
+ def new_matching(obj)
115
+ val = obj[field]
116
+
117
+ if val.is_a?(Array)
118
+ MultiMatching.new(self, val)
119
+ else
120
+ SingleMatching.new(self, val)
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mem_db/field"
4
+ require "mem_db/field/matching"
5
+
6
+ class MemDB
7
+ module Field
8
+ class Regexp
9
+ include MemDB::Field
10
+
11
+ class Rx
12
+ def initialize(source)
13
+ @rx = ::Regexp.new(source, ::Regexp::MULTILINE)
14
+ end
15
+
16
+ def match?(str)
17
+ @rx.match?(str)
18
+ end
19
+ end
20
+
21
+ class MultiMatching
22
+ include MemDB::Field::Matching
23
+
24
+ def initialize(field, arr)
25
+ @field = field
26
+ @patterns = arr.map { |source| Rx.new(source) }
27
+ end
28
+
29
+ def match?(query)
30
+ @field.query_value(query).each do |str|
31
+ return true if @patterns.any? { |pat| pat.match?(str) }
32
+ end
33
+
34
+ false
35
+ end
36
+ end
37
+
38
+ class SingleMatching
39
+ include MemDB::Field::Matching
40
+
41
+ def initialize(field, el)
42
+ @field = field
43
+ @pat = Rx.new(el)
44
+ end
45
+
46
+ def match?(query)
47
+ @field.query_value(query).any? { |str| @pat.match?(str) }
48
+ end
49
+ end
50
+
51
+ attr_reader :field
52
+
53
+ def initialize(field)
54
+ @field = field
55
+ end
56
+
57
+ def new_matching(obj)
58
+ val = obj[field]
59
+
60
+ if val.is_a?(Array)
61
+ MultiMatching.new(self, val)
62
+ else
63
+ SingleMatching.new(self, val)
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MemDB
4
+ class Fields
5
+ class Matching
6
+ def initialize(fields, obj)
7
+ @matchings = fields.map { |field| field.new_matching(obj) }.reject! do |matching|
8
+ matching == MemDB::Field::MayMissing::ANY_MATCHING
9
+ end
10
+ end
11
+
12
+ def match?(query)
13
+ @matchings.all? { |matching| matching.match?(query) }
14
+ end
15
+ end
16
+
17
+ def initialize(fields)
18
+ @fields = fields
19
+ end
20
+
21
+ def new_matching(obj)
22
+ Matching.new(@fields, obj)
23
+ end
24
+ end
25
+ end
data/lib/mem_db/idx.rb ADDED
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MemDB
4
+ module Idx
5
+ ANY = Object.new
6
+
7
+ def default(default)
8
+ MemDB::Idx::Default.new(self, default)
9
+ end
10
+
11
+ def default_any
12
+ default(MemDB::Idx::ANY)
13
+ end
14
+
15
+ def field
16
+ raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
17
+ end
18
+
19
+ def map_value(_obj)
20
+ raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
21
+ end
22
+
23
+ def map_query(_obj)
24
+ raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
25
+ end
26
+
27
+ def value(obj)
28
+ v = obj[field]
29
+
30
+ if v == ANY
31
+ v
32
+ else
33
+ v.map { |e| map_value(e) }
34
+ end
35
+ end
36
+
37
+ def prepare_query(query)
38
+ query[field].map { |v| map_query(v) }
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mem_db/idx"
4
+
5
+ class MemDB
6
+ module Idx
7
+ class Bytes
8
+ include MemDB::Idx
9
+
10
+ attr_reader :field
11
+
12
+ def initialize(field)
13
+ @field = field
14
+ end
15
+
16
+ def map_value(raw)
17
+ raw.bytes
18
+ end
19
+
20
+ def map_query(text)
21
+ text.bytes
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mem_db/idx"
4
+
5
+ class MemDB
6
+ module Idx
7
+ class Chars
8
+ include MemDB::Idx
9
+
10
+ attr_reader :field
11
+
12
+ class Chars
13
+ include Enumerable
14
+
15
+ def initialize(str)
16
+ @str = str
17
+ @length = str.length
18
+ end
19
+
20
+ def [](pos)
21
+ @str[pos]
22
+ end
23
+
24
+ attr_reader :length
25
+
26
+ def reverse
27
+ ReversedChars.new(@str)
28
+ end
29
+
30
+ def each
31
+ return to_enum unless block_given?
32
+
33
+ i = 0
34
+ while i < @length
35
+ yield @str[i]
36
+ i += 1
37
+ end
38
+ end
39
+ end
40
+
41
+ class ReversedChars
42
+ include Enumerable
43
+
44
+ def initialize(str)
45
+ @str = str
46
+ @length = str.length
47
+ end
48
+
49
+ def [](pos)
50
+ @str[@str.length - pos - 1]
51
+ end
52
+
53
+ def length
54
+ @str.length
55
+ end
56
+
57
+ def reverse
58
+ Chars.new(@str)
59
+ end
60
+
61
+ def each
62
+ return to_enum unless block_given?
63
+
64
+ i = @length - 1
65
+ while i >= 0
66
+ yield @str[i]
67
+ i -= 1
68
+ end
69
+ end
70
+ end
71
+
72
+ def initialize(field)
73
+ @field = field
74
+ end
75
+
76
+ def map_value(raw)
77
+ raw.chars
78
+ end
79
+
80
+ def map_query(text)
81
+ Chars.new(text)
82
+ end
83
+ end
84
+ end
85
+ end