db-model 0.3.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,221 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
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
13
+ # all 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
21
+ # THE SOFTWARE.
22
+
23
+ require_relative 'literal'
24
+
25
+ module DB
26
+ module Model
27
+ module Statement
28
+ module Predicate
29
+ class Empty
30
+ def append_to(statement)
31
+ statement.literal(true)
32
+ end
33
+
34
+ def + other
35
+ other
36
+ end
37
+
38
+ def eql?(other)
39
+ self.class.eql?(other.class)
40
+ end
41
+
42
+ def hash
43
+ self.class.hash
44
+ end
45
+ end
46
+
47
+ EMPTY = Empty.new
48
+
49
+ class Between
50
+ def initialize(key, minimum, maximum)
51
+ @key = key
52
+ @minimum = minimum
53
+ @maximum = maximum
54
+ end
55
+
56
+ attr :key
57
+ attr :minimum
58
+ attr :maximum
59
+
60
+ def append_to(statement)
61
+ @key.append_to(statement)
62
+ statement.clause("BETWEEN")
63
+ @minimum.append_to(statement)
64
+ statement.clause("AND")
65
+ @maximum.append_to(statement)
66
+ end
67
+
68
+ def eql?(other)
69
+ self.class.eql?(other.class) && self.key.eql?(other.key) && self.minimum.eql?(other.minimum) && self.maximum.eql?(other.maximum)
70
+ end
71
+
72
+ def hash
73
+ [self.class, @key, @minimum, @maximum].hash
74
+ end
75
+ end
76
+
77
+ class Binary
78
+ def initialize(key, operator, value)
79
+ @key = key
80
+ @operator = operator
81
+ @value = value
82
+ end
83
+
84
+ attr :key
85
+ attr :operator
86
+ attr :value
87
+
88
+ def append_to(statement)
89
+ @key.append_to(statement)
90
+ statement.clause(@operator)
91
+ @value.append_to(statement)
92
+ end
93
+
94
+ def eql?(other)
95
+ self.class.eql?(other.class) && self.key.eql?(other.key) && self.operator.eql?(other.operator) && self.value.eql?(other.value)
96
+ end
97
+
98
+ def hash
99
+ [self.class, @key, @operator, @value].hash
100
+ end
101
+ end
102
+
103
+ class Null
104
+ def initialize(key)
105
+ @key = key
106
+ end
107
+
108
+ attr :key
109
+
110
+ def append_to(statement)
111
+ @key.append_to(statement)
112
+ statement.clause("IS NULL")
113
+ end
114
+
115
+ def eql?(other)
116
+ self.class.eql?(other.class) && self.key.eql?(other.key)
117
+ end
118
+
119
+ def hash
120
+ [self.class, @key].hash
121
+ end
122
+ end
123
+
124
+ class Composite
125
+ def self.for(predicates)
126
+ if predicates.size == 0
127
+ return EMPTY
128
+ else
129
+ return self.new(predicates)
130
+ end
131
+ end
132
+
133
+ def initialize(predicates, operator = "AND")
134
+ @predicates = predicates
135
+ @operator = operator
136
+ end
137
+
138
+ attr :predicates
139
+ attr :operator
140
+
141
+ def append_to(statement)
142
+ first = true
143
+
144
+ statement.clause("(")
145
+
146
+ @predicates.each_with_index do |predicate, index|
147
+ statement.clause(@operator) unless first
148
+ first = false
149
+
150
+ predicate.append_to(statement)
151
+ end
152
+
153
+ statement.clause(")")
154
+ end
155
+
156
+ def + other
157
+ Composite.new([self, other])
158
+ end
159
+
160
+ def & other
161
+ Composite.new([self, other], "AND")
162
+ end
163
+
164
+ def | other
165
+ Composite.new([self, other], "OR")
166
+ end
167
+
168
+ def eql?(other)
169
+ self.class.eql?(other.class) && self.predicates.eql?(other.predicates)
170
+ end
171
+
172
+ def hash
173
+ [self.class, @predicates, @operator].hash
174
+ end
175
+ end
176
+
177
+ def self.coerce(key, value)
178
+ case value
179
+ when Array
180
+ Binary.new(key, "IN", Tuple.new(value))
181
+ when Range
182
+ if value.min.nil?
183
+ if value.exclude_end?
184
+ Binary.new(key, "<", Literal.new(value.max))
185
+ else
186
+ Binary.new(key, "<=", Literal.new(value.max))
187
+ end
188
+ elsif value.max.nil?
189
+ if value.exclude_end?
190
+ Binary.new(key, ">", Literal.new(value.max))
191
+ else
192
+ Binary.new(key, ">=", Literal.new(value.max))
193
+ end
194
+ else
195
+ if value.exclude_end?
196
+ Composite.new([
197
+ Binary.new(key, ">", Literal.new(value.min)),
198
+ Binary.new(key, "<", Literal.new(value.max))
199
+ ])
200
+ else
201
+ Between.new(key, Literal.new(value.min), Literal.new(value.max))
202
+ end
203
+ end
204
+ when nil
205
+ Null.new(key)
206
+ else
207
+ Binary.new(key, "=", Literal.new(value))
208
+ end
209
+ end
210
+
211
+ def self.where(*arguments, **options, &block)
212
+ Composite.for(
213
+ options.map do |key, value|
214
+ coerce(Identifier.coerce(key), value)
215
+ end
216
+ )
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
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
13
+ # all 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
21
+ # THE SOFTWARE.
22
+
23
+ module DB
24
+ module Model
25
+ module Statement
26
+ class Replace
27
+ def initialize(source, fields, values)
28
+ @source = source
29
+ @fields = fields
30
+ @values = values
31
+ end
32
+
33
+ def to_sql(context)
34
+ statement = context.query("REPLACE INTO")
35
+
36
+ statement.identifier(@source.type)
37
+
38
+ statement.clause("(")
39
+ @fields.append_to(statement)
40
+ statement.clause(") VALUES")
41
+
42
+ @values.append_to(statement)
43
+
44
+ statement.clause("RETURNING *")
45
+
46
+ return statement
47
+ end
48
+
49
+ def to_a(context, klass)
50
+ to_sql(context).call do |connection|
51
+ result = connection.next_result
52
+ keys = result.field_names.map(&:to_sym)
53
+
54
+ result.map do |row|
55
+ klass.new(context, keys.zip(row).to_h)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
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
13
+ # all 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
21
+ # THE SOFTWARE.
22
+
23
+ module DB
24
+ module Model
25
+ module Statement
26
+ class Select
27
+ def initialize(source, fields: nil, where: nil, limit: nil)
28
+ @source = source
29
+ @fields = fields
30
+ @where = where
31
+ @limit = limit
32
+ end
33
+
34
+ def append_to(statement, limit: @limit)
35
+ statement = statement.clause("SELECT")
36
+
37
+ if @fields
38
+ @fields.append_to(statement)
39
+ else
40
+ statement.clause("*")
41
+ end
42
+
43
+ statement.clause("FROM")
44
+ statement.identifier(@source.type)
45
+
46
+ if @where
47
+ statement.clause "WHERE"
48
+ @where.append_to(statement)
49
+ end
50
+
51
+ limit&.append_to(statement)
52
+
53
+ return statement
54
+ end
55
+
56
+ def to_sql(context)
57
+ self.append_to(context)
58
+ end
59
+
60
+ def to_a(context, cache = nil)
61
+ to_sql(context).call do |connection|
62
+ result = connection.next_result
63
+
64
+ return apply(context, result, cache)
65
+ end
66
+ end
67
+
68
+ def apply(context, result, cache = nil)
69
+ keys = result.field_names.map(&:to_sym)
70
+
71
+ result.map do |row|
72
+ @source.new(context, keys.zip(row).to_h, cache)
73
+ end
74
+ end
75
+
76
+ def each(context, cache = nil)
77
+ to_sql(context).call do |connection|
78
+ result = connection.next_result
79
+ keys = result.field_names.map(&:to_sym)
80
+
81
+ result.each do |row|
82
+ yield @source.new(context, keys.zip(row).to_h, cache)
83
+ end
84
+ end
85
+ end
86
+
87
+ def first(context, count, cache = nil)
88
+ limit = @limit&.first(count) || Limit.new(count)
89
+
90
+ append_to(context, limit: limit).call do |connection|
91
+ result = connection.next_result
92
+
93
+ return apply(context, result, cache)
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
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
13
+ # all 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
21
+ # THE SOFTWARE.
22
+
23
+ module DB
24
+ module Model
25
+ module Statement
26
+ class Truncate
27
+ def initialize(source)
28
+ @source = source
29
+ end
30
+
31
+ def to_sql(context)
32
+ statement = context.clause("TRUNCATE TABLE")
33
+
34
+ statement.identifier(@source.type)
35
+
36
+ return statement
37
+ end
38
+
39
+ def call(context)
40
+ to_sql(context).call
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
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
13
+ # all 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
21
+ # THE SOFTWARE.
22
+
23
+ module DB
24
+ module Model
25
+ module Statement
26
+ class Tuple
27
+ def initialize(values)
28
+ @values = values
29
+ end
30
+
31
+ attr :values
32
+
33
+ def append_to(statement)
34
+ first = true
35
+
36
+ statement.clause("(")
37
+ @values.each do |value|
38
+ statement.clause(",") unless first
39
+ first = false
40
+
41
+ statement.literal(value)
42
+ end
43
+ statement.clause(")")
44
+
45
+ return statement
46
+ end
47
+
48
+ def eql?(other)
49
+ self.class.eql?(other.class) && self.values.eql?(other.values)
50
+ end
51
+
52
+ def hash
53
+ [self.class, @values].hash
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
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
13
+ # all 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
21
+ # THE SOFTWARE.
22
+
23
+ module DB
24
+ module Model
25
+ module Statement
26
+ class Update
27
+ def initialize(source, assignment, where)
28
+ @source = source
29
+ @assignment = assignment
30
+ @where = where
31
+ end
32
+
33
+ def to_sql(context)
34
+ statement = context.query("UPDATE")
35
+
36
+ statement.identifier(@source.type)
37
+
38
+ @assignment.append_to(statement)
39
+
40
+ if @where
41
+ statement.clause "WHERE"
42
+ @where.append_to(statement)
43
+ end
44
+
45
+ return statement
46
+ end
47
+
48
+ def call(context)
49
+ to_sql(context).call
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
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
13
+ # all 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
21
+ # THE SOFTWARE.
22
+
23
+ require_relative 'relation'
24
+ require_relative 'statement/truncate'
25
+
26
+ module DB
27
+ module Model
28
+ class Table < Relation
29
+ def cache_key
30
+ [@model]
31
+ end
32
+
33
+ def truncate
34
+ Statement::Truncate.new(@model).call(@context)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
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
13
+ # all 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
21
+ # THE SOFTWARE.
22
+
23
+ module DB
24
+ module Model
25
+ VERSION = "0.3.0"
26
+ end
27
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
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
13
+ # all 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
21
+ # THE SOFTWARE.
22
+
23
+ require_relative 'statement/select'
24
+ require_relative 'statement/predicate'
25
+
26
+ require_relative 'countable'
27
+
28
+ module DB
29
+ module Model
30
+ class Where
31
+ def initialize(context, model, *arguments, **options, &block)
32
+ @context = context
33
+ @model = model
34
+ @predicate = Statement::Predicate.where(*arguments, **options, &block)
35
+
36
+ @select = nil
37
+ end
38
+
39
+ attr_accessor :predicate
40
+
41
+ include Countable, Deletable
42
+
43
+ def or(*arguments, **options, &block)
44
+ @predicate |= Statement::Predicate.where(*arguments, **options, &block)
45
+
46
+ return self
47
+ end
48
+
49
+ def and(*arguments, **options, &block)
50
+ @predicate &= Statement::Predicate.where(*arguments, **options, &block)
51
+
52
+ return self
53
+ end
54
+
55
+ def find(*key)
56
+ return Statement::Select.new(@model,
57
+ where: @predicate & @model.find_predicate(*key),
58
+ limit: Statement::Limit::ONE
59
+ ).to_a(context)
60
+ end
61
+
62
+ def where(*arguments, **options, &block)
63
+ self.class.new(@context, model,
64
+ @predicate + Statement::Predicate.where(*arguments, **options, &block)
65
+ )
66
+ end
67
+
68
+ def select
69
+ @select ||= Statement::Select.new(@model,
70
+ where: @predicate
71
+ )
72
+ end
73
+
74
+ def each(&block)
75
+ self.select.each(@context, &block)
76
+ end
77
+
78
+ def first(count = nil)
79
+ if count
80
+ self.select.first(@context, count)
81
+ else
82
+ self.select.first(@context, 1).first
83
+ end
84
+ end
85
+
86
+ def to_s
87
+ "\#<#{self.class} #{@model} #{@predicate}>"
88
+ end
89
+
90
+ alias inspect to_s
91
+ end
92
+ end
93
+ end