relation_to_struct 0.0.5 → 1.0.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
2
  SHA1:
3
- metadata.gz: f14569badb2ed3049d91f233ebc208c09bef0251
4
- data.tar.gz: 3513ef3efd8d057645db818927a1939338e75f17
3
+ metadata.gz: 38b9e2235461124930a00545c8f280a149e720e2
4
+ data.tar.gz: e554b29f4b015da645780962aa44985d751ec177
5
5
  SHA512:
6
- metadata.gz: 87b088344c4b07d36ef607bd145a6a4480b6397e07c47b3495e40462d7bf9a4ac564e4590d4addd01deae8353c7abd757ac60fbdd5ded1b2a22e3e71355fa37e
7
- data.tar.gz: 70b3761d903aee08b8a36a3fd16dc53b8bfb416b23dc8445e26421d38ec289d9e6cc548f1dcda139fba0be407f12a4d90aaccb1632d142394a83954d3815818b
6
+ metadata.gz: 60d4d55c08833a5c9f875d06df49c307d192f5ea11985201222ecc42a8fdc5b638ca750dfd89767c8add0f5a5b33e4af47e3d4b1b80b032cf75983ffef1448de
7
+ data.tar.gz: acb30ead089b288b26f417cd985f2da323e95fd996da0a0c3ceca85d83ff123836a6d4480cd6e406dead496e13e1d9992d2797d996a3099c78b8d7d43d13f9d0
data/README.md CHANGED
@@ -20,13 +20,36 @@ Or install it yourself as:
20
20
 
21
21
  $ gem install relation_to_struct
22
22
 
23
- ## Usage
23
+ ## Examples
24
24
 
25
- TODO: Write usage instructions here
25
+ You can query either via direct SQL or from an ActiveRecord relation.
26
+
27
+ ### From an existing relation
28
+
29
+ ```
30
+ UserPostsSummary = Struct.new(:user_name, :post_count)
31
+ relation = User.joins(:blog_posts).where(name: 'Hayek').group('users.id').select('users.name, COUNT(blog_posts.id)')
32
+ relation.to_structs(UserPostsSummary) # => array of structs
33
+ ```
34
+
35
+ ### From raw SQL
36
+
37
+ ```
38
+ UserPostsSummary = Struct.new(:user_name, :post_count)
39
+ sql = <<-eos
40
+ SELECT users.name, COUNT(blog_posts.id)
41
+ FROM users
42
+ LEFT OUTER JOIN blog_posts ON blog_posts.user_id = users.id
43
+ GROUP BY users.id
44
+ eos
45
+
46
+ ActiveRecord::Base.structs_from_sql(UserPostsSummary, sql) # => array of structs
47
+ ActiveRecord::Base.pluck_from_sql(sql) # => array of tuples
48
+ ```
26
49
 
27
50
  ## Contributing
28
51
 
29
- 1. Fork it ( https://github.com/[my-github-username]/relation_to_struct/fork )
52
+ 1. Fork it ( https://github.com/jcoleman/relation_to_struct/fork )
30
53
  2. Create your feature branch (`git checkout -b my-new-feature`)
31
54
  3. Commit your changes (`git commit -am 'Add some feature'`)
32
55
  4. Push to the branch (`git push origin my-new-feature`)
@@ -5,12 +5,12 @@ module RelationToStruct::ActiveRecordBaseExtension
5
5
  def structs_from_sql(struct_class, sql, binds=[])
6
6
  result = connection.select_all(sanitize_sql(sql, nil), "Structs SQL Load", binds)
7
7
 
8
- if result.columns.size != struct_class.members.size
9
- raise ArgumentError, 'Expected struct fields and columns lengths to be equal'
8
+ if result.columns.size != result.columns.uniq.size
9
+ raise ArgumentError, 'Expected column names to be unique'
10
10
  end
11
11
 
12
- if result.columns.size != result.column_types.size
13
- raise ArgumentError, 'Expected unique column names count and column count to be equal'
12
+ if result.columns != struct_class.members.collect(&:to_s)
13
+ raise ArgumentError, 'Expected column names (and their order) to match struct attribute names'
14
14
  end
15
15
 
16
16
  if result.columns.size == 1
@@ -11,8 +11,8 @@ module RelationToStruct::ActiveRecordRelationExtension
11
11
  raise ArgumentError, 'Expected struct fields and columns lengths to be equal'
12
12
  end
13
13
 
14
- if result.columns.size != result.column_types.size
15
- raise ArgumentError, 'Expected unique column names count and column count to be equal'
14
+ if result.columns.size != result.columns.uniq.size
15
+ raise ArgumentError, 'Expected column names to be unique'
16
16
  end
17
17
 
18
18
  result.cast_values(klass.column_types)
@@ -1,3 +1,3 @@
1
1
  module RelationToStruct
2
- VERSION = "0.0.5"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+
3
+ describe RelationToStruct do
4
+ before(:each) do
5
+ Economist.delete_all
6
+ EconomicSchool.delete_all
7
+ end
8
+
9
+ it 'ActiveRecord::Base should respond to :structs_from_sql' do
10
+ expect(ActiveRecord::Base.respond_to?(:structs_from_sql)).to eq(true)
11
+ end
12
+
13
+ it 'should allow querying with SQL directly' do
14
+ test_struct = Struct.new(:number)
15
+ sql = "SELECT 1 * 23 AS number"
16
+ expect(ActiveRecord::Base.structs_from_sql(test_struct, sql)).to eq([test_struct.new(23)])
17
+ end
18
+
19
+ it 'should allow plucking with SQL directly' do
20
+ sql = "SELECT 1 * 23"
21
+ expect(ActiveRecord::Base.pluck_from_sql(sql)).to eq([23])
22
+ end
23
+
24
+ it 'should allow plucking multiple columns with SQL directly' do
25
+ sql = "SELECT 1 * 23, 25"
26
+ expect(ActiveRecord::Base.pluck_from_sql(sql)).to eq([[23, 25]])
27
+ end
28
+
29
+ it 'structs_from_sql should properly cast a single array column' do
30
+ Economist.create!(name: 'F.A. Hayek')
31
+ Economist.create!(name: 'Ludwig von Mises')
32
+
33
+ pluck_results = Economist.select('name').order('id').limit(1).pluck('array[name]') rescue nil
34
+ if pluck_results
35
+ expect(pluck_results).to eq([['F.A. Hayek']]) # Verify ActiveRecord interface.
36
+
37
+ test_struct = Struct.new(:names)
38
+ structs_results = ActiveRecord::Base.structs_from_sql(test_struct, 'SELECT ARRAY_AGG(name ORDER BY id) AS names FROM economists')
39
+ expect(structs_results.first.names).to eq(['F.A. Hayek', 'Ludwig von Mises'])
40
+ else
41
+ skip "DB selection doesn't support ARRAY[]"
42
+ end
43
+ end
44
+
45
+ it 'structs_from_sql should raise an error when column count does not match struct size' do
46
+ expect do
47
+ test_struct = Struct.new(:id, :name, :extra_field)
48
+ ActiveRecord::Base.structs_from_sql(test_struct, 'SELECT id, name FROM economists')
49
+ end.to raise_error(ArgumentError, 'Expected column names (and their order) to match struct attribute names')
50
+ end
51
+
52
+ it 'structs_from_sql should raise an error when column names are not unique' do
53
+ expect do
54
+ test_struct = Struct.new(:id, :id2)
55
+ ActiveRecord::Base.structs_from_sql(test_struct, 'SELECT id, id FROM economists')
56
+ end.to raise_error(ArgumentError, 'Expected column names to be unique')
57
+ end
58
+
59
+ it 'structs_from_sql should raise an error when the column names do not match the struct attribute names' do
60
+ Economist.create!(name: 'F.A. Hayek')
61
+ expect do
62
+ test_struct = Struct.new(:value_a, :value_b)
63
+ ActiveRecord::Base.structs_from_sql(test_struct, 'SELECT 1 AS value_a, 2 AS value_b FROM economists')
64
+ end.not_to raise_error
65
+
66
+ expect do
67
+ test_struct = Struct.new(:value_a, :value_b)
68
+ ActiveRecord::Base.structs_from_sql(test_struct, 'SELECT 1 AS value_b, 2 AS value_a FROM economists')
69
+ end.to raise_error(ArgumentError, 'Expected column names (and their order) to match struct attribute names')
70
+
71
+ expect do
72
+ test_struct = Struct.new(:value_a, :value_b)
73
+ ActiveRecord::Base.structs_from_sql(test_struct, 'SELECT 1 AS value_a, 2 AS value_c FROM economists')
74
+ end.to raise_error(ArgumentError, 'Expected column names (and their order) to match struct attribute names')
75
+ end
76
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe RelationToStruct do
4
+ before(:each) do
5
+ Economist.delete_all
6
+ EconomicSchool.delete_all
7
+ end
8
+
9
+ it 'should respond to :to_structs' do
10
+ expect(Economist.all.respond_to?(:to_structs)).to eq(true)
11
+ end
12
+
13
+ it '#to_structs should raise an error when the relation has no select_values' do
14
+ expect do
15
+ Economist.all.to_structs(Struct.new(:test_struct))
16
+ end.to raise_error
17
+ end
18
+
19
+ it '#to_structs should return an empty array when no results are returned' do
20
+ expect(Economist.where('1 = 0').select(:id).to_structs(Struct.new(:test_struct))).to eq([])
21
+ end
22
+
23
+ it '#to_structs should return an array with struct instances' do
24
+ hayek = Economist.create!(name: 'F.A. Hayek')
25
+ id_struct = Struct.new(:id)
26
+ expect(Economist.all.select(:id).to_structs(id_struct)).to eq([id_struct.new(hayek.id)])
27
+ end
28
+
29
+ it '#to_structs should handle joined elements properly' do
30
+ austrian = EconomicSchool.create!(name: 'Austrian Economics')
31
+ hayek = Economist.create!(name: 'F.A. Hayek', economic_school: austrian)
32
+ test_struct = Struct.new(:name, :school)
33
+ expect(
34
+ Economist
35
+ .joins(:economic_school)
36
+ .select('economists.name', 'economic_schools.name as school_name')
37
+ .to_structs(test_struct)
38
+ ).to eq([test_struct.new(hayek.name, austrian.name)])
39
+ end
40
+
41
+ it '#to_structs should properly cast values from arbitrary calculated columns' do
42
+ hayek = Economist.create!(name: 'F.A. Hayek')
43
+ scope = Economist.all
44
+ pluck_results = scope.pluck("date('now')")
45
+ pluck_column_klass = pluck_results.first.class
46
+
47
+ date_struct = Struct.new(:date)
48
+ struct_scope = scope.select("date('now')")
49
+ structs_results = struct_scope.to_structs(date_struct)
50
+ struct_column_klass = structs_results.first.date.class
51
+ expect(pluck_column_klass).to eq(struct_column_klass)
52
+ end
53
+
54
+ it '#to_structs should properly cast a single array column' do
55
+ Economist.create!(name: 'F.A. Hayek')
56
+
57
+ pluck_results = Economist.select('name').pluck('array[name]') rescue nil
58
+ if pluck_results
59
+ expect(pluck_results).to eq([['F.A. Hayek']]) # Verify ActiveRecord interface.
60
+
61
+ test_struct = Struct.new(:names)
62
+ structs_results = Economist.select('array[name]').to_structs(test_struct)
63
+ expect(structs_results.first.names).to eq(['F.A. Hayek'])
64
+ else
65
+ skip "DB selection doesn't support ARRAY[]"
66
+ end
67
+ end
68
+
69
+ it '#to_structs should raise an error when column count does not match struct size' do
70
+ expect do
71
+ test_struct = Struct.new(:id, :name, :extra_field)
72
+ Economist.select('id, name').to_structs(test_struct)
73
+ end.to raise_error(ArgumentError, 'Expected struct fields and columns lengths to be equal')
74
+ end
75
+
76
+ it '#to_structs should raise an error when column names are not unique' do
77
+ expect do
78
+ test_struct = Struct.new(:id, :id2)
79
+ Economist.select('id, id').to_structs(test_struct)
80
+ end.to raise_error(ArgumentError, 'Expected column names to be unique')
81
+ end
82
+ end
@@ -1,144 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe RelationToStruct do
4
- before(:each) do
5
- Economist.delete_all
6
- EconomicSchool.delete_all
7
- end
8
-
9
4
  it 'has a version number' do
10
5
  expect(RelationToStruct::VERSION).not_to be nil
11
6
  end
12
-
13
- describe 'relation' do
14
- it 'should respond to :to_structs' do
15
- expect(Economist.all.respond_to?(:to_structs)).to eq(true)
16
- end
17
-
18
- it 'should respond to :to_structs' do
19
- pending 'next version'
20
- end
21
-
22
- it '#to_structs should raise an error when the relation has no select_values' do
23
- expect do
24
- Economist.all.to_structs(Struct.new(:test_struct))
25
- end.to raise_error
26
- end
27
-
28
- it '#to_structs should return an empty array when no results are returned' do
29
- expect(Economist.where('1 = 0').select(:id).to_structs(Struct.new(:test_struct))).to eq([])
30
- end
31
-
32
- it '#to_structs should return an array with struct instances' do
33
- hayek = Economist.create!(name: 'F.A. Hayek')
34
- id_struct = Struct.new(:id)
35
- expect(Economist.all.select(:id).to_structs(id_struct)).to eq([id_struct.new(hayek.id)])
36
- end
37
-
38
- it '#to_structs should handle joined elements properly' do
39
- austrian = EconomicSchool.create!(name: 'Austrian Economics')
40
- hayek = Economist.create!(name: 'F.A. Hayek', economic_school: austrian)
41
- test_struct = Struct.new(:name, :school)
42
- expect(
43
- Economist
44
- .joins(:economic_school)
45
- .select('economists.name', 'economic_schools.name as school_name')
46
- .to_structs(test_struct)
47
- ).to eq([test_struct.new(hayek.name, austrian.name)])
48
- end
49
-
50
- it '#to_structs should properly cast values from arbitrary calculated columns' do
51
- hayek = Economist.create!(name: 'F.A. Hayek')
52
- scope = Economist.all
53
- pluck_results = scope.pluck("date('now')")
54
- pluck_column_klass = pluck_results.first.class
55
-
56
- date_struct = Struct.new(:date)
57
- struct_scope = scope.select("date('now')")
58
- structs_results = struct_scope.to_structs(date_struct)
59
- struct_column_klass = structs_results.first.date.class
60
- expect(pluck_column_klass).to eq(struct_column_klass)
61
- end
62
-
63
- it '#to_structs should properly cast a single array column' do
64
- Economist.create!(name: 'F.A. Hayek')
65
-
66
- pluck_results = Economist.select('name').pluck('array[name]') rescue nil
67
- if pluck_results
68
- expect(pluck_results).to eq([['F.A. Hayek']]) # Verify ActiveRecord interface.
69
-
70
- test_struct = Struct.new(:names)
71
- structs_results = Economist.select('array[name]').to_structs(test_struct)
72
- expect(structs_results.first.names).to eq(['F.A. Hayek'])
73
- else
74
- skip "DB selection doesn't support ARRAY[]"
75
- end
76
- end
77
-
78
- it '#to_structs should raise an error when column count does not match struct size' do
79
- expect do
80
- test_struct = Struct.new(:id, :name, :extra_field)
81
- Economist.select('id, name').to_structs(test_struct)
82
- end.to raise_error(ArgumentError, 'Expected struct fields and columns lengths to be equal')
83
- end
84
-
85
- it '#to_structs should raise an error when column_type count does not match the column count' do
86
- expect do
87
- test_struct = Struct.new(:id, :id2)
88
- Economist.select('id, id').to_structs(test_struct)
89
- end.to raise_error(ArgumentError, 'Expected unique column names count and column count to be equal')
90
- end
91
- end
92
-
93
- describe 'non-model specific querying' do
94
- it 'ActiveRecord::Base should respond to :structs_from_sql' do
95
- expect(ActiveRecord::Base.respond_to?(:structs_from_sql)).to eq(true)
96
- end
97
-
98
- it 'should allow querying with SQL directly' do
99
- test_struct = Struct.new(:number)
100
- sql = "SELECT 1 * 23"
101
- expect(ActiveRecord::Base.structs_from_sql(test_struct, sql)).to eq([test_struct.new(23)])
102
- end
103
-
104
- it 'should allow plucking with SQL directly' do
105
- sql = "SELECT 1 * 23"
106
- expect(ActiveRecord::Base.pluck_from_sql(sql)).to eq([23])
107
- end
108
-
109
- it 'should allow plucking multiple columns with SQL directly' do
110
- sql = "SELECT 1 * 23, 25"
111
- expect(ActiveRecord::Base.pluck_from_sql(sql)).to eq([[23, 25]])
112
- end
113
-
114
- it 'structs_from_sql should properly cast a single array column' do
115
- Economist.create!(name: 'F.A. Hayek')
116
- Economist.create!(name: 'Ludwig von Mises')
117
-
118
- pluck_results = Economist.select('name').order('id').limit(1).pluck('array[name]') rescue nil
119
- if pluck_results
120
- expect(pluck_results).to eq([['F.A. Hayek']]) # Verify ActiveRecord interface.
121
-
122
- test_struct = Struct.new(:names)
123
- structs_results = ActiveRecord::Base.structs_from_sql(test_struct, 'SELECT ARRAY_AGG(name ORDER BY id) FROM economists')
124
- expect(structs_results.first.names).to eq(['F.A. Hayek', 'Ludwig von Mises'])
125
- else
126
- skip "DB selection doesn't support ARRAY[]"
127
- end
128
- end
129
-
130
- it 'structs_from_sql should raise an error when column count does not match struct size' do
131
- expect do
132
- test_struct = Struct.new(:id, :name, :extra_field)
133
- ActiveRecord::Base.structs_from_sql(test_struct, 'SELECT id, name FROM economists')
134
- end.to raise_error(ArgumentError, 'Expected struct fields and columns lengths to be equal')
135
- end
136
-
137
- it 'structs_from_sql should raise an error when column_type count does not match the column count' do
138
- expect do
139
- test_struct = Struct.new(:id, :id2)
140
- ActiveRecord::Base.structs_from_sql(test_struct, 'SELECT id, id FROM economists')
141
- end.to raise_error(ArgumentError, 'Expected unique column names count and column count to be equal')
142
- end
143
- end
144
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: relation_to_struct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Coleman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-06 00:00:00.000000000 Z
11
+ date: 2016-04-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -140,10 +140,12 @@ files:
140
140
  - lib/relation_to_struct/active_record_relation_extension.rb
141
141
  - lib/relation_to_struct/version.rb
142
142
  - relation_to_struct.gemspec
143
+ - spec/active_record_base_spec.rb
143
144
  - spec/active_record_helper/economic_school.rb
144
145
  - spec/active_record_helper/economist.rb
145
146
  - spec/active_record_helper/schema.rb
146
147
  - spec/active_record_helper/setup.rb
148
+ - spec/active_record_relation_spec.rb
147
149
  - spec/relation_to_struct_spec.rb
148
150
  - spec/spec_helper.rb
149
151
  homepage: ''
@@ -166,14 +168,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
166
168
  version: '0'
167
169
  requirements: []
168
170
  rubyforge_project:
169
- rubygems_version: 2.4.5
171
+ rubygems_version: 2.5.1
170
172
  signing_key:
171
173
  specification_version: 4
172
174
  summary: Return struct results from ActiveRecord relation queries
173
175
  test_files:
176
+ - spec/active_record_base_spec.rb
174
177
  - spec/active_record_helper/economic_school.rb
175
178
  - spec/active_record_helper/economist.rb
176
179
  - spec/active_record_helper/schema.rb
177
180
  - spec/active_record_helper/setup.rb
181
+ - spec/active_record_relation_spec.rb
178
182
  - spec/relation_to_struct_spec.rb
179
183
  - spec/spec_helper.rb
184
+ has_rdoc: