relationizer 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: ac854434e4951f07131e424948782d7121b286c1
4
- data.tar.gz: c1b758d8b06cd83331769f95deaf9862fec7ea0f
2
+ SHA256:
3
+ metadata.gz: c55b691cb2f721fd3fd39909e1745a72cb9743211587c6fdf477ba5e04fd209b
4
+ data.tar.gz: 7233397ac4d8ab8c4f29c2b1de073fa01634593884b53501f6bdfc1957e25f82
5
5
  SHA512:
6
- metadata.gz: 8cb01ce847a6662c03e85eabc5bf092e233b919641b284f1a93c1414004c6f7d56949ca8d3777c64395a398c4718ac9ff4debe4cd072d6d3470665a4566761df
7
- data.tar.gz: 808b44e83b0ed0cebc147763ce528322977f73fbd6826bc2163661e4e915346bcd82979e4c93579cf39ccf024bbe37d5f057d47da16d96d52436eda2a90d067b
6
+ metadata.gz: '093102036edcd8201974a31edb553e35c0cb2e5895ec134e091c50d9bdfdf7377fdaedc6e934d08575eeecafd81602c0d976f7d1716b9a3ad35ac5f9984b11ee'
7
+ data.tar.gz: bdb16173d5c526e7fd86ae4129522479e9913cc0a33d63d3aa7fec753d09f604681767f08ee3cfe26594046225693ee00c3ff557d5f60ce9c102997807a5a13d
@@ -0,0 +1,20 @@
1
+ name: Ruby
2
+
3
+ on: [push]
4
+
5
+ jobs:
6
+ build:
7
+
8
+ runs-on: ubuntu-latest
9
+
10
+ steps:
11
+ - uses: actions/checkout@v1
12
+ - name: Set up Ruby 2.6
13
+ uses: actions/setup-ruby@v1
14
+ with:
15
+ ruby-version: 2.6.x
16
+ - name: Build and test with Rake
17
+ run: |
18
+ gem install bundler
19
+ bundle install --jobs 4 --retry 3
20
+ bundle exec rake
data/lib/relationizer.rb CHANGED
@@ -1,7 +1,6 @@
1
- require "relationizer/version"
1
+ require_relative "relationizer/version"
2
2
  require_relative "relationizer/postgresql"
3
- require_relative "relationizer/big_query/standard"
3
+ require_relative "relationizer/big_query"
4
4
 
5
5
  module Relationizer
6
- # Your code goes here...
7
- end
6
+ end
@@ -0,0 +1,138 @@
1
+ require 'bigdecimal'
2
+ require 'date'
3
+
4
+ module Relationizer
5
+ module BigQuery
6
+ class ReasonlessTypeError < StandardError; end
7
+
8
+ KNOWN_TYPES = [:INT64, :FLOAT64, :STRING, :BOOL, :TIMESTAMP, :DATE]
9
+
10
+ DEFAULT_TYPES = -> (obj) {
11
+ case obj
12
+ when Integer then :INT64
13
+ when BigDecimal then :FLOAT64
14
+ when Float then :FLOAT64
15
+ when String then :STRING
16
+ when TrueClass then :BOOL
17
+ when FalseClass then :BOOL
18
+ when Time then :TIMESTAMP
19
+ when DateTime then :TIMESTAMP
20
+ when Date then :DATE
21
+ when Array then :ARRAY
22
+ else
23
+ nil
24
+ end
25
+ }
26
+
27
+ def create_relation_literal(schema, tuples)
28
+ types = fixed_types(schema.values, tuples)
29
+
30
+ _types_exp = types_exp(schema.keys, types)
31
+
32
+ tuples_exp = tuples.map { |tuple|
33
+ tuple.zip(types).
34
+ map { |(col, type)| to_literal(col, type) }.
35
+ join(", ").
36
+ tap { |t| break "(#{t}#{', NULL' if tuple.length == 1})" }
37
+ }.join(", ").tap { |t| break "[#{t}]"}
38
+
39
+ select_exp = if schema.one?
40
+ "#{schema.keys.first}"
41
+ else
42
+ '*'
43
+ end
44
+
45
+ "SELECT #{select_exp} FROM UNNEST(#{_types_exp}#{tuples_exp})"
46
+ end
47
+
48
+ private
49
+
50
+ def array_type(array)
51
+ classes = array.compact.map(&:class).uniq
52
+
53
+ unless classes.length == 1
54
+ raise ReasonlessTypeError.new("Ambiguous type of element in array: #{classes}")
55
+ end
56
+
57
+ DEFAULT_TYPES[array.first] || :STRING
58
+ end
59
+
60
+ def types_exp(names, types)
61
+ case names.length
62
+ when 1
63
+ %Q{ARRAY<STRUCT<`#{names.first}` #{types.first}, `___dummy` STRING>>}
64
+ else
65
+ %Q{ARRAY<STRUCT<#{names.zip(types).map { |(name, type)| "`#{name}` #{type}" }.join(", ")}>>}
66
+ end
67
+ end
68
+
69
+ def many_candidate_check(types)
70
+ raise ReasonlessTypeError.new("Many candidate: #{types.join(', ')}") unless types.one?
71
+ end
72
+
73
+ def empty_candidate_check(types)
74
+ raise ReasonlessTypeError.new("Candidate nothing") if types.empty?
75
+ end
76
+
77
+ def fixed_types(schema, tuples)
78
+ tuples.transpose.zip(schema.to_a).map { |values, type|
79
+ next type if type
80
+
81
+ if values.map { |o| o.is_a?(Array) }.all?
82
+ types = values.
83
+ map(&method(:array_type)).uniq.
84
+ tap(&method(:empty_candidate_check)).
85
+ tap(&method(:many_candidate_check))
86
+
87
+ next "ARRAY<#{types.first}>".to_sym
88
+ end
89
+
90
+ values.
91
+ map(&DEFAULT_TYPES).compact.uniq.
92
+ tap(&method(:empty_candidate_check)).
93
+ tap(&method(:many_candidate_check)).
94
+ first || :STRING
95
+ }
96
+ end
97
+
98
+ def to_literal(obj, type)
99
+ return "NULL" if obj.nil?
100
+
101
+ case type
102
+ when :ARRAY
103
+ t = array_type(obj)
104
+ obj.map { |e| to_literal(e, t) }.join(', ').tap { |s| break "[#{s}]"}
105
+ when /^ARRAY\<.+\>$/
106
+ t = /^ARRAY\<(.+)\>$/.match(type).to_a&.dig(1).to_sym
107
+ raise "Unknown type: #{t}" unless KNOWN_TYPES.include?(t)
108
+ obj.map { |e| to_literal(e, t) }.join(', ').tap { |s| break "[#{s}]"}
109
+ when :TIMESTAMP
110
+ %Q{'#{obj.strftime('%Y-%m-%d %H:%M:%S')}'}
111
+ when :STRING, :DATE
112
+ obj.to_s.gsub(/'/, "\'").tap do |s|
113
+ break "'#{s}'"
114
+ end
115
+ when :BOOL
116
+ case obj
117
+ when TrueClass, FalseClass
118
+ obj
119
+ else
120
+ !!obj
121
+ end
122
+ when :FLOAT64
123
+ case obj
124
+ when Float::INFINITY
125
+ "CAST('inf' AS FLOAT64)"
126
+ when -Float::INFINITY
127
+ "CAST('-inf' AS FLOAT64)"
128
+ else
129
+ obj
130
+ end
131
+ when :INT64
132
+ obj.to_s
133
+ else
134
+ raise "Unknown type: #{type}"
135
+ end
136
+ end
137
+ end
138
+ end
@@ -49,7 +49,7 @@ module Relationizer
49
49
 
50
50
  def select_exp(schema, tuples)
51
51
  tuples.transpose.zip(schema.to_a).map { |(values, (name, type))|
52
- next "#{name}::#{type.to_s.upcase}" if type
52
+ next %Q{"#{name}"::#{type.to_s.upcase}} if type
53
53
 
54
54
  values.
55
55
  map(&DEFAULT_TYPES).compact.uniq.
@@ -57,7 +57,7 @@ module Relationizer
57
57
  tap(&method(:many_candidate_check)).
58
58
  first.
59
59
  to_s.upcase.
60
- tap { |fixed_type| break "#{name}::#{fixed_type}" }
60
+ tap { |fixed_type| break %Q{"#{name}"::#{fixed_type}} }
61
61
  }.join(", ")
62
62
  end
63
63
 
@@ -1,3 +1,3 @@
1
1
  module Relationizer
2
- VERSION = "0.2.3"
2
+ VERSION = "0.3.0"
3
3
  end
data/relationizer.gemspec CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_development_dependency "bundler", "~> 1.12"
21
+ spec.add_development_dependency "bundler"
22
22
  spec.add_development_dependency "rake", "~> 10.0"
23
23
  spec.add_development_dependency "test-unit", "~> 3.0.0"
24
24
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: relationizer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - yancya
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-11-17 00:00:00.000000000 Z
11
+ date: 2019-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.12'
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.12'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -59,6 +59,7 @@ executables: []
59
59
  extensions: []
60
60
  extra_rdoc_files: []
61
61
  files:
62
+ - ".github/workflows/ruby.yml"
62
63
  - ".gitignore"
63
64
  - Gemfile
64
65
  - LICENSE.txt
@@ -66,11 +67,8 @@ files:
66
67
  - Rakefile
67
68
  - bin/console
68
69
  - bin/setup
69
- - lib/rel_lib/relationizer.rb
70
- - lib/rel_lib/relationizer/version.rb
71
70
  - lib/relationizer.rb
72
- - lib/relationizer/big_query/legacy.rb
73
- - lib/relationizer/big_query/standard.rb
71
+ - lib/relationizer/big_query.rb
74
72
  - lib/relationizer/postgresql.rb
75
73
  - lib/relationizer/version.rb
76
74
  - relationizer.gemspec
@@ -93,8 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
93
91
  - !ruby/object:Gem::Version
94
92
  version: '0'
95
93
  requirements: []
96
- rubyforge_project:
97
- rubygems_version: 2.6.13
94
+ rubygems_version: 3.0.3
98
95
  signing_key:
99
96
  specification_version: 4
100
97
  summary: Array<Array> to Relation ppoi String
@@ -1,8 +0,0 @@
1
- require "relationizer/version"
2
- require_relative "./relationizer/postgresql.rb"
3
- require_relative "./relationizer/big_query/Legacy.rb"
4
- require_relative "./relationizer/big_query/Standard.rb"
5
-
6
- module Relationizer
7
- # Your code goes here...
8
- end
@@ -1,3 +0,0 @@
1
- module Relationizer
2
- VERSION = "0.1.0"
3
- end
@@ -1,8 +0,0 @@
1
- module Relationizer
2
- module BigQuery
3
- module Legacy
4
- def create_relation_literal(rows, schema)
5
- end
6
- end
7
- end
8
- end
@@ -1,140 +0,0 @@
1
- require 'bigdecimal'
2
- require 'date'
3
-
4
- module Relationizer
5
- module BigQuery
6
- module Standard
7
- class ReasonlessTypeError < StandardError; end
8
-
9
- KNOWN_TYPES = [:INT64, :FLOAT64, :STRING, :BOOL, :TIMESTAMP, :DATE]
10
-
11
- DEFAULT_TYPES = -> (obj) {
12
- case obj
13
- when Integer then :INT64
14
- when BigDecimal then :FLOAT64
15
- when Float then :FLOAT64
16
- when String then :STRING
17
- when TrueClass then :BOOL
18
- when FalseClass then :BOOL
19
- when Time then :TIMESTAMP
20
- when DateTime then :TIMESTAMP
21
- when Date then :DATE
22
- when Array then :ARRAY
23
- else
24
- nil
25
- end
26
- }
27
-
28
- def create_relation_literal(schema, tuples)
29
- types = fixed_types(schema.values, tuples)
30
-
31
- _types_exp = types_exp(schema.keys, types)
32
-
33
- tuples_exp = tuples.map { |tuple|
34
- tuple.zip(types).
35
- map { |(col, type)| to_literal(col, type) }.
36
- join(", ").
37
- tap { |t| break "(#{t}#{', NULL' if tuple.length == 1})" }
38
- }.join(", ").tap { |t| break "[#{t}]"}
39
-
40
- select_exp = if schema.one?
41
- "#{schema.keys.first}"
42
- else
43
- '*'
44
- end
45
-
46
- "SELECT #{select_exp} FROM UNNEST(#{_types_exp}#{tuples_exp})"
47
- end
48
-
49
- private
50
-
51
- def array_type(array)
52
- classes = array.compact.map(&:class).uniq
53
-
54
- unless classes.length == 1
55
- raise ReasonlessTypeError.new("Ambiguous type of element in array: #{classes}")
56
- end
57
-
58
- DEFAULT_TYPES[array.first] || :STRING
59
- end
60
-
61
- def types_exp(names, types)
62
- case names.length
63
- when 1
64
- %Q{ARRAY<STRUCT<#{names.first} #{types.first}, ___dummy STRING>>}
65
- else
66
- %Q{ARRAY<STRUCT<#{names.zip(types).map { |(name, type)| "#{name} #{type}" }.join(", ")}>>}
67
- end
68
- end
69
-
70
- def many_candidate_check(types)
71
- raise ReasonlessTypeError.new("Many candidate: #{types.join(', ')}") unless types.one?
72
- end
73
-
74
- def empty_candidate_check(types)
75
- raise ReasonlessTypeError.new("Candidate nothing") if types.empty?
76
- end
77
-
78
- def fixed_types(schema, tuples)
79
- tuples.transpose.zip(schema.to_a).map { |values, type|
80
- next type if type
81
-
82
- if values.map { |o| o.is_a?(Array) }.all?
83
- types = values.
84
- map(&method(:array_type)).uniq.
85
- tap(&method(:empty_candidate_check)).
86
- tap(&method(:many_candidate_check))
87
-
88
- next "ARRAY<#{types.first}>".to_sym
89
- end
90
-
91
- values.
92
- map(&DEFAULT_TYPES).compact.uniq.
93
- tap(&method(:empty_candidate_check)).
94
- tap(&method(:many_candidate_check)).
95
- first || :STRING
96
- }
97
- end
98
-
99
- def to_literal(obj, type)
100
- return "NULL" if obj.nil?
101
-
102
- case type
103
- when :ARRAY
104
- t = array_type(obj)
105
- obj.map { |e| to_literal(e, t) }.join(', ').tap { |s| break "[#{s}]"}
106
- when /^ARRAY\<.+\>$/
107
- t = /^ARRAY\<(.+)\>$/.match(type).to_a&.dig(1).to_sym
108
- raise "Unknown type: #{t}" unless KNOWN_TYPES.include?(t)
109
- obj.map { |e| to_literal(e, t) }.join(', ').tap { |s| break "[#{s}]"}
110
- when :TIMESTAMP
111
- %Q{'#{obj.strftime('%Y-%m-%d %H:%M:%S')}'}
112
- when :STRING, :DATE
113
- obj.to_s.gsub(/'/, "\'").tap do |s|
114
- break "'#{s}'"
115
- end
116
- when :BOOL
117
- case obj
118
- when TrueClass, FalseClass
119
- obj
120
- else
121
- !!obj
122
- end
123
- when :FLOAT64
124
- case obj
125
- when Float::INFINITY
126
- "CAST('inf' AS FLOAT64)"
127
- when -Float::INFINITY
128
- "CAST('-inf' AS FLOAT64)"
129
- else
130
- obj
131
- end
132
- when :INT64
133
- obj.to_s
134
- else
135
- raise "Unknown type: #{type}"
136
- end
137
- end
138
- end
139
- end
140
- end