mem_db 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mem_db/idx"
4
+
5
+ class MemDB
6
+ module Idx
7
+ class Default
8
+ include MemDB::Idx
9
+
10
+ def initialize(original, default)
11
+ @original = original
12
+ @default = default
13
+ end
14
+
15
+ def field
16
+ @original.field
17
+ end
18
+
19
+ def value(obj)
20
+ v = obj[field]
21
+ if v.nil?
22
+ @default
23
+ else
24
+ @original.value(obj)
25
+ end
26
+ end
27
+
28
+ def prepare_query(query)
29
+ @original.prepare_query(query)
30
+ end
31
+ end
32
+ end
33
+ 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 Itself
8
+ include MemDB::Idx
9
+
10
+ attr_reader :field
11
+
12
+ def initialize(field)
13
+ @field = field
14
+ end
15
+
16
+ def map_value(val)
17
+ val
18
+ end
19
+
20
+ def map_query(val)
21
+ val
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MemDB
4
+ module Idx
5
+ class Pattern
6
+ include MemDB::Idx
7
+
8
+ class Pattern
9
+ def initialize(source, min:)
10
+ @parts = source.split("*", -1)
11
+ @min = min
12
+ end
13
+
14
+ def value # rubocop:disable Metrics/PerceivedComplexity, Metrics/AbcSize, Metrics/CyclomaticComplexity
15
+ if @parts.length == 1
16
+ [:enum, @parts[0]]
17
+ else
18
+ prefix = @parts[0]
19
+ suffix = @parts[-1]
20
+
21
+ if prefix != "" || suffix != ""
22
+ if prefix.length >= @min && prefix.length >= suffix.length
23
+ [:prefix, prefix]
24
+ elsif suffix.length >= @min
25
+ [:suffix, suffix]
26
+ else
27
+ candidates = [
28
+ [:prefix, prefix],
29
+ [:suffix, suffix]
30
+ ]
31
+
32
+ candidates.push([:substring, substring]) if substring # rubocop:disable Metrics/BlockNesting
33
+
34
+ candidates.max_by { |v| v[1].length }
35
+ end
36
+ else
37
+ [:substring, substring]
38
+ end
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def substring
45
+ return @substring if defined?(@substring)
46
+
47
+ @substring =
48
+ if @parts.length > 2
49
+ substrings = @parts[1..-2]
50
+ substrings.find { |p| p.length > @min } || substrings.find { |p| p.length.positive? }
51
+ end
52
+ end
53
+ end
54
+
55
+ attr_reader :field
56
+
57
+ def initialize(field, min: 3)
58
+ @field = field
59
+ @min = min
60
+ end
61
+
62
+ def map_value(pattern)
63
+ Pattern.new(pattern, min: @min).value
64
+ end
65
+
66
+ def map_query(text)
67
+ text
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mem_db/idx"
4
+
5
+ class MemDB
6
+ module Idx
7
+ class Reverse
8
+ include MemDB::Idx
9
+
10
+ def initialize(original)
11
+ @original = original
12
+ end
13
+
14
+ def field
15
+ @original.field
16
+ end
17
+
18
+ def map_value(val)
19
+ @original.map_value(val).reverse
20
+ end
21
+
22
+ def map_query(val)
23
+ @original.map_query(val).reverse
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MemDB
4
+ module Idx
5
+ class Uniq
6
+ include MemDB::Idx
7
+
8
+ def initialize(original)
9
+ @original = original
10
+ end
11
+
12
+ def field
13
+ @original.field
14
+ end
15
+
16
+ def value(obj)
17
+ val = @original.value(obj)
18
+ return val if val == MemDB::Idx::ANY
19
+
20
+ val.uniq
21
+ end
22
+
23
+ def prepare_query(query)
24
+ @original.prepare_query(query).uniq
25
+ end
26
+
27
+ def map_value(raw)
28
+ @original.map_value(raw)
29
+ end
30
+
31
+ def map_query(raw)
32
+ @original.map_query(raw)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mem_db/out"
4
+
5
+ class MemDB
6
+ module Index
7
+ def self.compose(chain)
8
+ (0..chain.length - 2).each do |parent_i|
9
+ chain[parent_i].bucket = chain[parent_i + 1]
10
+ end
11
+ chain[0].new
12
+ end
13
+
14
+ def idx
15
+ raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
16
+ end
17
+
18
+ def bucket
19
+ raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
20
+ end
21
+
22
+ def add(_obj, _value)
23
+ raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
24
+ end
25
+
26
+ # rubocop:disable Lint/UnusedMethodArgument
27
+ def query(_query, out: MemDB::Out.new)
28
+ raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
29
+ end
30
+ # rubocop:enable Lint/UnusedMethodArgument
31
+ end
32
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mem_db/index"
4
+ require "mem_db/index/bucket"
5
+ require "mem_db/out"
6
+ require "mem_db/idx"
7
+
8
+ class MemDB
9
+ module Index
10
+ class Any
11
+ include MemDB::Index
12
+
13
+ class Bucket
14
+ include MemDB::Index::Bucket
15
+
16
+ def initialize(original)
17
+ @original = original
18
+ end
19
+
20
+ def new
21
+ MemDB::Index::Any.new(@original.new)
22
+ end
23
+
24
+ def bucket=(bucket)
25
+ @original.bucket = bucket
26
+ end
27
+ end
28
+
29
+ def initialize(original)
30
+ raise ArgumentError, "original must be MemDB::Index, got: #{original.class}" unless original.is_a?(MemDB::Index)
31
+
32
+ @original = original
33
+ end
34
+
35
+ def idx
36
+ @original.idx
37
+ end
38
+
39
+ def bucket
40
+ @original.bucket
41
+ end
42
+
43
+ def add(obj, value)
44
+ addr = obj.idx_value(idx)
45
+ if addr == MemDB::Idx::ANY
46
+ @any ||= bucket.new
47
+ @any.add(obj, value)
48
+ else
49
+ @original.add(obj, value)
50
+ end
51
+ end
52
+
53
+ def query(query, out: MemDB::Out.new)
54
+ @original.query(query, out: out)
55
+ @any&.query(query, out: out)
56
+ out
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # TODO: move to mem_db/index.rb
4
+ class MemDB
5
+ module Index
6
+ module Bucket
7
+ def new
8
+ raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
9
+ end
10
+
11
+ def bucket=(bucket)
12
+ @bucket = bucket
13
+ end
14
+
15
+ def accept_any
16
+ MemDB::Index::Any::Bucket.new(self)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mem_db/out"
4
+ require "mem_db/index"
5
+ require "mem_db/index/bucket"
6
+ require "mem_db/bucket"
7
+
8
+ class MemDB
9
+ module Index
10
+ class Enum
11
+ include MemDB::Index
12
+
13
+ class Bucket
14
+ include MemDB::Index::Bucket
15
+
16
+ def initialize(idx:, bucket: MemDB::Bucket)
17
+ @idx = idx
18
+ @bucket = bucket
19
+ end
20
+
21
+ def new
22
+ MemDB::Index::Enum.new(idx: @idx, bucket: @bucket)
23
+ end
24
+ end
25
+
26
+ attr_reader :idx, :bucket
27
+
28
+ def initialize(idx:, bucket: MemDB::Bucket)
29
+ @idx = idx
30
+ @bucket = bucket
31
+ @hash = {}
32
+ end
33
+
34
+ def add(obj, value)
35
+ enums = obj.idx_value(@idx)
36
+ enums.each do |enum|
37
+ b = @hash[enum] ||= @bucket.new
38
+ b.add(obj, value)
39
+ end
40
+ end
41
+
42
+ def query(query, out: MemDB::Out.new)
43
+ enums = query.idx_value(@idx)
44
+ enums.each do |enum|
45
+ if (b = @hash[enum])
46
+ b.query(query, out: out)
47
+ end
48
+ end
49
+
50
+ out
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mem_db/index/enum"
4
+ require "mem_db/index/prefix_tree"
5
+ require "mem_db/index/sequence_match"
6
+ require "mem_db/bucket"
7
+ require "mem_db/index/bucket"
8
+ require "mem_db/out"
9
+
10
+ class MemDB
11
+ module Index
12
+ class PatternMatch
13
+ include MemDB::Index
14
+
15
+ class Bucket
16
+ include MemDB::Index::Bucket
17
+
18
+ def initialize(idx:, bucket: MemDB::Bucket)
19
+ @idx = idx
20
+ @bucket = bucket
21
+ end
22
+
23
+ def new
24
+ MemDB::Index::PatternMatch.new(idx: @idx, bucket: @bucket)
25
+ end
26
+ end
27
+
28
+ attr_reader :idx, :bucket
29
+
30
+ def initialize(idx:, bucket: MemDB::Bucket)
31
+ @idx = idx
32
+ @bucket = bucket
33
+ end
34
+
35
+ def add(obj, value)
36
+ obj.idx_value(@idx).each do |pattern|
37
+ type = pattern[0]
38
+ sequence = pattern[1]
39
+ index =
40
+ case type
41
+ when :enum
42
+ enums
43
+ when :prefix
44
+ prefixes
45
+ when :suffix
46
+ suffixes
47
+ when :substring
48
+ substrings
49
+ end
50
+
51
+ obj[self] = sequence
52
+ index.add(obj, value)
53
+ obj.delete(self)
54
+ end
55
+ end
56
+
57
+ def query(query, out: MemDB::Out.new)
58
+ query.idx_value(@idx).each do |q|
59
+ query[self] = q
60
+
61
+ @enums&.query(query, out: out)
62
+ @suffixes&.query(query, out: out)
63
+ @prefixes&.query(query, out: out)
64
+ @substrings&.query(query, out: out)
65
+
66
+ query.delete(self)
67
+ end
68
+
69
+ out
70
+ end
71
+
72
+ private
73
+
74
+ def enums
75
+ @enums ||= MemDB::Index::Enum.new(
76
+ idx: MemDB::Idx::Itself.new(self),
77
+ bucket: @bucket
78
+ )
79
+ end
80
+
81
+ def prefixes
82
+ @prefixes ||= MemDB::Index::PrefixTree.new(
83
+ idx: MemDB::Idx::Bytes.new(self),
84
+ bucket: @bucket
85
+ )
86
+ end
87
+
88
+ def suffixes
89
+ @suffixes ||= MemDB::Index::PrefixTree.new(
90
+ idx: MemDB::Idx::Reverse.new(MemDB::Idx::Bytes.new(self)),
91
+ bucket: @bucket
92
+ )
93
+ end
94
+
95
+ def substrings
96
+ @substrings ||= MemDB::Index::SequenceMatch.new(
97
+ # reverse somehow make it faster
98
+ idx: MemDB::Idx::Reverse.new(MemDB::Idx::Bytes.new(self)),
99
+ bucket: @bucket
100
+ )
101
+ end
102
+ end
103
+ end
104
+ end