b_b 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,67 @@
1
+ module BB
2
+ class Factory
3
+ extend Forwardable
4
+
5
+ attr_accessor :filters, :options, :type_of_component
6
+ attr_reader :component
7
+
8
+ def initialize
9
+ @filters = []
10
+ @options = {}
11
+ end
12
+
13
+ def_delegator(:component, :build)
14
+
15
+ def append_formatted_filters(args)
16
+ extract_options!(args)
17
+ format_filters(args).each { |filter| filters << filter }
18
+ end
19
+
20
+ private
21
+
22
+ # Override if you need
23
+ def extract_options!(args)
24
+ return unless args.size > 1 && args.last.is_a?(Hash)
25
+
26
+ options.merge!(args.pop)
27
+ end
28
+
29
+ def format_filters(_expressions)
30
+ raise NotImplementedError, "You must implemented #{self.class}##{__method__}"
31
+ end
32
+
33
+ def component
34
+ @component ||= Component.new.tap do |component|
35
+ component.filters = filters
36
+ component.options = options
37
+ component.type = format_type_of_component
38
+ end
39
+ end
40
+
41
+ # Override if you need
42
+ def format_type_of_component
43
+ type_of_component
44
+ end
45
+
46
+ class << self
47
+ def build(name)
48
+ decorator = FactoryDecorator.const_get(format_decorator_name(name))
49
+
50
+ new.extend(decorator).tap do |factory|
51
+ factory.type_of_component = name
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def format_decorator_name(name)
58
+ case name
59
+ when :group, :group_each, :select then :Selectable
60
+ when :having, :omit_record_if, :where then :Extractable
61
+ when *API[:joins] then :Joinable
62
+ else name.to_s.scan(/[^-_]+/).map(&:capitalize).join.to_sym
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,75 @@
1
+ module BB
2
+ module FactoryDecorator
3
+ module Extractable
4
+ OPERATOR = { and: "AND", or: "OR" }.freeze
5
+
6
+ private
7
+
8
+ def extract_options!(args)
9
+ return unless args.last.is_a?(Hash)
10
+
11
+ if args.size > 2
12
+ super
13
+ else
14
+ extracted_options = {
15
+ negation: args.last.delete(:negation),
16
+ operator: args.last.delete(:operator),
17
+ reduce: args.last.delete(:reduce)
18
+ }.reject { |_k, v| v.nil? }
19
+
20
+ options.merge!(extracted_options)
21
+ end
22
+ end
23
+
24
+ def format_filters(expressions)
25
+ append_operator
26
+
27
+ condition = case type_of_expressions(expressions)
28
+ when :with_args then format_condition_by_args(base_string: expressions.shift, args: expressions)
29
+ when :with_params then format_condition_by_params(base_string: expressions[0], params: expressions[1])
30
+ else expressions.map(&method(:format_condition)).compact.join(concat_operator)
31
+ end
32
+
33
+ [] << format("(%s)", condition)
34
+ end
35
+
36
+ def append_operator
37
+ return if filters.empty?
38
+
39
+ filters << (options.delete(:operator) || OPERATOR[:and])
40
+ end
41
+
42
+ def type_of_expressions(expressions)
43
+ return :with_args if expressions[0].is_a?(String) && expressions[0].include?("?") && !expressions[1].is_a?(Hash)
44
+ return :with_params if expressions[0].is_a?(String) && expressions[0].include?(":") && expressions[1].is_a?(Hash)
45
+ end
46
+
47
+ def format_condition_by_args(base_string: "", args: [])
48
+ formatted_base_string = base_string.gsub(/\?/, "%s")
49
+ formatted_args = args.map { |v| Converter::Value.convert(v) }
50
+ format(formatted_base_string, *formatted_args)
51
+ end
52
+
53
+ def format_condition_by_params(base_string: "", params: {})
54
+ params.each { |k, v| base_string.gsub!(/:#{k}/, Converter::Value.convert(v)) }
55
+ base_string
56
+ end
57
+
58
+ def format_condition(value)
59
+ negation = options.delete(:negation)
60
+
61
+ if value.is_a?(Hash)
62
+ value.map do |col, val|
63
+ Converter::Formula.convert(col, val, negation: negation)
64
+ end
65
+ elsif (value.is_a?(String) && !value.empty?) || value.is_a?(Symbol)
66
+ value.to_s
67
+ end
68
+ end
69
+
70
+ def concat_operator
71
+ format(" %s ", options.delete(:reduce).to_s.upcase == OPERATOR[:or] ? OPERATOR[:or] : OPERATOR[:and])
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,25 @@
1
+ module BB
2
+ module FactoryDecorator
3
+ module From
4
+ private
5
+
6
+ def format_filters(expressions)
7
+ expressions.map(&method(:format_condition)).compact
8
+ end
9
+
10
+ def format_condition(value)
11
+ Converter::Table.convert(value, options.dup)
12
+ end
13
+
14
+ def format_type_of_component
15
+ if options.key?(:as) && filters.size > 1
16
+ :from_union_all_with_alias
17
+ elsif options.key?(:as) && filters.size == 1
18
+ :from_with_alias
19
+ else
20
+ :from
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ module BB
2
+ module FactoryDecorator
3
+ module Joinable
4
+ private
5
+
6
+ def format_filters(expressions)
7
+ expressions.map(&method(:format_condition)).compact
8
+ end
9
+
10
+ def format_condition(value)
11
+ Converter::Table.convert(value, options.dup)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ module BB
2
+ module FactoryDecorator
3
+ module Limit
4
+ private
5
+
6
+ def format_filters(expressions)
7
+ expressions.select(&method(:match?)).map(&:to_i)
8
+ end
9
+
10
+ def match?(value)
11
+ value.respond_to?(:to_i) && !value.to_i.zero?
12
+ end
13
+
14
+ def format_type_of_component
15
+ options.key?(:offset) ? :limit_with_offset : :limit
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ module BB
2
+ module FactoryDecorator
3
+ module Order
4
+ private
5
+
6
+ def format_filters(expressions)
7
+ expressions.map(&method(:format_condition)).compact
8
+ end
9
+
10
+ def format_condition(value)
11
+ if value.is_a?(Hash)
12
+ value.map do |column, sort_key|
13
+ Converter::Order.convert(column, sort_key: sort_key)
14
+ end.join(", ")
15
+ elsif (value.is_a?(String) && !value.empty?) || value.is_a?(Symbol)
16
+ value.to_s
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ module BB
2
+ module FactoryDecorator
3
+ module Selectable
4
+ private
5
+
6
+ def format_filters(expressions)
7
+ expressions.select(&method(:match?)).map(&:to_s)
8
+ end
9
+
10
+ def match?(value)
11
+ (value.is_a?(String) && !value.empty?) || value.is_a?(Symbol)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ module BB
2
+ module FactoryDecorator
3
+ autoload :Extractable, "b_b/factory_decorator/extractable"
4
+ autoload :From, "b_b/factory_decorator/from"
5
+ autoload :Joinable, "b_b/factory_decorator/joinable"
6
+ autoload :Limit, "b_b/factory_decorator/limit"
7
+ autoload :Order, "b_b/factory_decorator/order"
8
+ autoload :Selectable, "b_b/factory_decorator/selectable"
9
+ end
10
+ end
@@ -0,0 +1,49 @@
1
+ module BB
2
+ class Relation
3
+ extend Forwardable
4
+ attr_reader :builder
5
+
6
+ def initialize
7
+ @builder = Builder.new
8
+ end
9
+
10
+ def_delegator(:builder, :build)
11
+ alias_method(:to_sql, :build)
12
+
13
+ API[:basic].each do |name|
14
+ define_method(name) do |*args|
15
+ raise ArgumentError, "wrong number of arguments ##{__method__} (at least 1)" if args.empty?
16
+
17
+ tap { builder.assign(name).append_formatted_filters(args) }
18
+ end
19
+ end
20
+
21
+ API[:joins].each do |name|
22
+ define_method(name) do |*args|
23
+ raise ArgumentError, "wrong number of arguments ##{__method__} (at least 1)" if args.empty?
24
+
25
+ tap { builder.append_joins(name).append_formatted_filters(args) }
26
+ end
27
+ end
28
+
29
+ def and
30
+ tap { builder.options[:operator] = "AND" }
31
+ end
32
+
33
+ def or
34
+ tap { builder.options[:operator] = "OR" }
35
+ end
36
+
37
+ def not
38
+ tap { builder.options[:negation] = true }
39
+ end
40
+
41
+ def on(rel)
42
+ tap { builder.add_option_to_just_before_join(rel) }
43
+ end
44
+
45
+ def offset(offset)
46
+ tap { builder.add_offset_to_limit(offset) }
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,3 @@
1
+ module BB
2
+ VERSION = "0.1.0".freeze
3
+ end
data/lib/b_b.rb ADDED
@@ -0,0 +1,58 @@
1
+ require "date"
2
+ require "forwardable"
3
+
4
+ module BB
5
+ autoload :VERSION, "b_b/version"
6
+ autoload :Builder, "b_b/builder"
7
+ autoload :Component, "b_b/component"
8
+ autoload :Converter, "b_b/converter"
9
+ autoload :Evaluator, "b_b/evaluator"
10
+ autoload :Factory, "b_b/factory"
11
+ autoload :FactoryDecorator, "b_b/factory_decorator"
12
+ autoload :Relation, "b_b/relation"
13
+ autoload :ArgumentError, "b_b/exception"
14
+ autoload :NotImplementedError, "b_b/exception"
15
+ autoload :UnevaluableTypeError, "b_b/exception"
16
+
17
+ API = {
18
+ basic: %i(
19
+ from
20
+ group
21
+ group_each
22
+ having
23
+ limit
24
+ omit_record_if
25
+ order
26
+ select
27
+ where
28
+ ),
29
+ joins: %i(
30
+ cross_join
31
+ full_outer_join_each
32
+ inner_join
33
+ inner_join_each
34
+ join
35
+ join_each
36
+ left_join
37
+ left_join_each
38
+ left_outer_join
39
+ left_outer_join_each
40
+ right_join
41
+ right_join_each
42
+ right_outer_join
43
+ right_outer_join_each
44
+ )
45
+ }.freeze
46
+
47
+ class << self
48
+ def build
49
+ relation = Relation.new
50
+ yield(relation)
51
+ relation.to_sql
52
+ end
53
+
54
+ def method_missing(name, *args)
55
+ Relation.new.public_send(name, *args)
56
+ end
57
+ end
58
+ end
metadata ADDED
@@ -0,0 +1,221 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: b_b
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Yoshiyuki Hirano
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-07-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 4.2.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 4.2.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: factory_girl
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '4.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '4.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: faker
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.6.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 1.6.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.10.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.10.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.40.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.40.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.11.0
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.11.0
139
+ - !ruby/object:Gem::Dependency
140
+ name: coveralls
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 0.8.0
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: 0.8.0
153
+ description: SQL Query Builder in Ruby for Google BigQuery
154
+ email:
155
+ - yhirano@me.com
156
+ executables: []
157
+ extensions: []
158
+ extra_rdoc_files: []
159
+ files:
160
+ - ".coveralls.yml"
161
+ - ".gitignore"
162
+ - ".hound.yml"
163
+ - ".rspec"
164
+ - ".rubocop.yml"
165
+ - ".ruby-style.yml"
166
+ - ".travis.yml"
167
+ - Gemfile
168
+ - LICENSE.txt
169
+ - README.md
170
+ - Rakefile
171
+ - b_b.gemspec
172
+ - bin/console
173
+ - bin/setup
174
+ - lib/b_b.rb
175
+ - lib/b_b/builder.rb
176
+ - lib/b_b/component.rb
177
+ - lib/b_b/converter.rb
178
+ - lib/b_b/converter/formula.rb
179
+ - lib/b_b/converter/order.rb
180
+ - lib/b_b/converter/table.rb
181
+ - lib/b_b/converter/value.rb
182
+ - lib/b_b/evaluator.rb
183
+ - lib/b_b/evaluator/formula.rb
184
+ - lib/b_b/evaluator/table.rb
185
+ - lib/b_b/evaluator/value.rb
186
+ - lib/b_b/exception.rb
187
+ - lib/b_b/factory.rb
188
+ - lib/b_b/factory_decorator.rb
189
+ - lib/b_b/factory_decorator/extractable.rb
190
+ - lib/b_b/factory_decorator/from.rb
191
+ - lib/b_b/factory_decorator/joinable.rb
192
+ - lib/b_b/factory_decorator/limit.rb
193
+ - lib/b_b/factory_decorator/order.rb
194
+ - lib/b_b/factory_decorator/selectable.rb
195
+ - lib/b_b/relation.rb
196
+ - lib/b_b/version.rb
197
+ homepage: https://github.com/yhirano55/BB
198
+ licenses:
199
+ - MIT
200
+ metadata: {}
201
+ post_install_message:
202
+ rdoc_options: []
203
+ require_paths:
204
+ - lib
205
+ required_ruby_version: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - ">="
208
+ - !ruby/object:Gem::Version
209
+ version: 2.0.0
210
+ required_rubygems_version: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - ">="
213
+ - !ruby/object:Gem::Version
214
+ version: '0'
215
+ requirements: []
216
+ rubyforge_project:
217
+ rubygems_version: 2.5.1
218
+ signing_key:
219
+ specification_version: 4
220
+ summary: SQL Query Builder in Ruby for Google BigQuery
221
+ test_files: []