pg_funcall 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,147 @@
1
+ require 'spec_helper'
2
+ require 'pg_funcall/type_info'
3
+ require 'pg_funcall/type_map'
4
+
5
+ #
6
+ # Test the utility class for calling database functions
7
+ #
8
+
9
+ describe PgFuncall::TypeInfo do
10
+ let :int4row do
11
+ {
12
+ "oid"=>"23",
13
+ "nspname"=>"pg_catalog",
14
+ "typname"=>"int4",
15
+ "typnamespace"=>"11",
16
+ "typowner"=>"10",
17
+ "typlen"=>"4",
18
+ "typbyval"=>"t",
19
+ "typtype"=>"b",
20
+ "typcategory"=>"N",
21
+ "typispreferred"=>"f",
22
+ "typisdefined"=>"t",
23
+ "typdelim"=>",",
24
+ "typrelid"=>"0",
25
+ "typelem"=>"0",
26
+ "typarray"=>"1007",
27
+ "typinput"=>"int4in",
28
+ "typoutput"=>"int4out",
29
+ "typreceive"=>"int4recv",
30
+ "typsend"=>"int4send",
31
+ "typmodin"=>"-",
32
+ "typmodout"=>"-",
33
+ "typanalyze"=>"-",
34
+ "typalign"=>"i",
35
+ "typstorage"=>"p",
36
+ "typnotnull"=>"f",
37
+ "typbasetype"=>"0",
38
+ "typtypmod"=>"-1",
39
+ "typndims"=>"0",
40
+ "typcollation"=>"0",
41
+ "typdefaultbin"=>nil,
42
+ "typdefault"=>nil,
43
+ "typacl"=>nil,
44
+ "nspowner"=>"10",
45
+ "nspacl"=>"{robertsanders=UC/robertsanders,=U/robertsanders}"
46
+ }
47
+ end
48
+
49
+ let :pg_connection do
50
+ ActiveRecord::Base.connection.raw_connection
51
+ end
52
+
53
+ #
54
+ # Array of string->string hashes representing known Postgres types
55
+ #
56
+ let :all_type_rows do
57
+ pg_connection.query(<<-SQL).to_a
58
+ SELECT pgt.oid, ns.nspname, *
59
+ FROM pg_type as pgt
60
+ JOIN pg_namespace as ns on pgt.typnamespace = ns.oid;
61
+ SQL
62
+ end
63
+
64
+ let :types_by_oid do
65
+ {}.tap do |hash|
66
+ all_type_rows.each do |row|
67
+ hash[row['oid'].to_i] = row
68
+ end
69
+ end
70
+ end
71
+
72
+ let :types_by_name do
73
+ {}.tap do |hash|
74
+ all_type_rows.each do |row|
75
+ raise "Entry for #{row['oid']} - #{row['typname']} already defined!" if hash.has_key?(row['typname'])
76
+ hash[row['typname']] = row
77
+ end
78
+ end
79
+ end
80
+
81
+ let :type_map do
82
+ PgFuncall::TypeMap.fetch(ActiveRecord::Base.connection)
83
+ end
84
+
85
+ let :ar_type do
86
+ type_map.lookup_ar_by_oid(row['oid'].to_i)
87
+ end
88
+
89
+ # currently inspected row; int4 by default
90
+ let :row do
91
+ int4row
92
+ end
93
+
94
+ subject do
95
+ described_class.new(row, ar_type)
96
+ end
97
+
98
+ context 'for int4 hardcoded row' do
99
+ it 'should return the correct OID' do
100
+ subject.oid.should == 23
101
+ end
102
+ it 'should return the simple name' do
103
+ subject.name.should == 'int4'
104
+ end
105
+ it 'should return a simple fqname' do
106
+ subject.fqname.should == 'int4'
107
+ end
108
+ it { should be_numeric }
109
+ it { should_not be_temporal }
110
+ it { should_not be_array }
111
+ it 'should have an array type' do
112
+ subject.array_type_oid.should_not be_nil
113
+ end
114
+ it 'should cast a string to integer when leaving DB' do
115
+ subject.cast_from_database('3211').should == 3211
116
+ end
117
+ it 'should cast from an integer to string form entering DB' do
118
+ subject.cast_to_database(3211).should == '3211'
119
+ end
120
+ end
121
+
122
+ context 'parsed from all_type_rows' do
123
+ let(:row) { types_by_name['_int4'] }
124
+
125
+ it 'should return the correct OID' do
126
+ subject.oid.should == 1007
127
+ end
128
+ it 'should return the simple name' do
129
+ subject.name.should == '_int4'
130
+ end
131
+ it 'should return a simple fqname' do
132
+ subject.fqname.should == '_int4'
133
+ end
134
+ it { should_not be_numeric }
135
+ it { should_not be_temporal }
136
+ it { should be_array }
137
+ it 'should have an element type' do
138
+ subject.element_type_oid.should == 23
139
+ end
140
+ it 'should cast from string form to array of integers' do
141
+ subject.cast_from_database('{1,1,2,3,5,8}').should == [1,1,2,3,5,8]
142
+ end
143
+ it 'should cast from string form to array of integers' do
144
+ subject.cast_to_database([1,1,2,3,5,8]).should == '{1,1,2,3,5,8}'
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,110 @@
1
+ require 'spec_helper'
2
+ require 'pg_funcall/type_map'
3
+
4
+ #
5
+ # Test the utility class for calling database functions
6
+ #
7
+
8
+ describe PgFuncall::TypeMap do
9
+ subject do
10
+ PgFuncall::TypeMap.fetch(ActiveRecord::Base.connection)
11
+ end
12
+
13
+ before(:all) do
14
+ ActiveRecord::Base.connection.execute <<-SQL
15
+ CREATE OR REPLACE FUNCTION public.dbfspec_textfunc(arg1 text, arg2 text)
16
+ RETURNS text
17
+ LANGUAGE plpgsql
18
+ AS $function$
19
+ BEGIN
20
+ RETURN arg1 || ',' || arg2;
21
+ END;
22
+ $function$;
23
+ SQL
24
+
25
+ end
26
+
27
+ after(:all) do
28
+ ActiveRecord::Base.connection.execute <<-SQL
29
+ DROP FUNCTION IF EXISTS public.dbfspec_textfunc(text, text);
30
+ SQL
31
+ end
32
+
33
+
34
+ context 'creation' do
35
+ it { should be_a(PgFuncall::TypeMap) }
36
+ end
37
+
38
+ context '#resolve of TypeInfo' do
39
+ context 'by name' do
40
+ it 'should return the appropriate type for int4' do
41
+ subject.resolve('int4').should be_a(PgFuncall::TypeInfo)
42
+ subject.resolve('int4').name.should == 'int4'
43
+ end
44
+
45
+ it 'should contain reference to ar_type for Integer' do
46
+ subject.resolve('int4').ar_type.should be_a(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::Integer)
47
+ end
48
+ end
49
+
50
+ context 'by oid' do
51
+ it 'should return the appropriate array type for 17 (bytea)' do
52
+ subject.resolve(17).should be_a(PgFuncall::TypeInfo)
53
+ subject.resolve(17).name.should == 'bytea'
54
+ end
55
+
56
+ it 'should return the appropriate array type for 1007 (int4 array)' do
57
+ typobj = subject.resolve(1007)
58
+ typobj.should be_array
59
+ typobj.element_type_oid.should == 23
60
+ end
61
+
62
+ it 'should contain reference to ar_type for intarray' do
63
+ subject.resolve(1007).ar_type.should be_a(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::Array)
64
+ subject.resolve(1007).ar_type.subtype.should be_a(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::Integer)
65
+ end
66
+ end
67
+ end
68
+
69
+ context 'lookup of AR types' do
70
+ context 'by name' do
71
+ it 'should return the appropriate type for int4' do
72
+ subject.lookup_ar_by_name('int4').should be_a(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::Integer)
73
+ end
74
+ end
75
+
76
+ context 'by oid' do
77
+ it 'should return the appropriate array type for 17 (bytea)' do
78
+ subject.lookup_ar_by_oid(17).should be_a(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::Bytea)
79
+ end
80
+
81
+ it 'should return the appropriate array type for 1007 (int4 array)' do
82
+ typobj = subject.lookup_ar_by_oid(1007)
83
+ typobj.should be_a(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::Array)
84
+ typobj.subtype.should be_a(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::Integer)
85
+ end
86
+ end
87
+ end
88
+
89
+ context 'introspection' do
90
+ subject { PgFuncall.new(ActiveRecord::Base.connection).type_map }
91
+
92
+ context '#function_types' do
93
+ it 'returns expected types for qualified name' do
94
+ types = subject.function_types('public.dbfspec_textfunc')
95
+ types.ret_type.should == 25
96
+ types.arg_sigs.should include([25, 25])
97
+ end
98
+
99
+ it 'returns same types for unqualified name' do
100
+ subject.function_types('public.dbfspec_textfunc').
101
+ should == subject.function_types('dbfspec_textfunc', PgFuncall.default_instance.search_path)
102
+ end
103
+
104
+ it 'throws if non-namespaced function is specified without a search_path' do
105
+ expect { subject.function_types('dbfspec_textfunc', []) }.
106
+ to raise_error
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,20 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ if ENV['COVERAGE'] == 'true'
5
+ require 'simplecov'
6
+ SimpleCov.start
7
+ end
8
+
9
+ require 'yaml'
10
+ require 'active_record'
11
+ configs = YAML.load(File.read("config/database.yml.example"))
12
+ ActiveRecord::Base.establish_connection(configs['test'])
13
+
14
+ require 'pg_funcall'
15
+
16
+ begin
17
+ require 'pry'
18
+ rescue LoadError
19
+ #
20
+ end
metadata ADDED
@@ -0,0 +1,201 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pg_funcall
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Robert Sanders
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pg
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.17.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.17.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: activerecord
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 4.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: 4.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: uuid
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: ipaddr_extensions
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '1.7'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '1.7'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '10.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '10.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: 2.14.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: 2.14.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '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'
125
+ - !ruby/object:Gem::Dependency
126
+ name: wwtd
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ! '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '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'
139
+ description:
140
+ email:
141
+ - robert@curioussquid.com
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - .gitignore
147
+ - .rspec
148
+ - .travis.yml
149
+ - Gemfile
150
+ - Gemfile.lock
151
+ - LICENSE.txt
152
+ - README.md
153
+ - Rakefile
154
+ - config/database.yml
155
+ - config/database.yml.example
156
+ - gemfiles/rails40.gemfile
157
+ - gemfiles/rails40.gemfile.lock
158
+ - gemfiles/rails41.gemfile
159
+ - gemfiles/rails41.gemfile.lock
160
+ - gemfiles/rails42.gemfile
161
+ - gemfiles/rails42.gemfile.lock
162
+ - lib/pg_funcall.rb
163
+ - lib/pg_funcall/ipaddr_monkeys.rb
164
+ - lib/pg_funcall/type_info.rb
165
+ - lib/pg_funcall/type_map.rb
166
+ - lib/pg_funcall/version.rb
167
+ - pg_funcall.gemspec
168
+ - script/shell
169
+ - spec/lib/pg_funcall_spec.rb
170
+ - spec/lib/type_info_spec.rb
171
+ - spec/lib/type_map_spec.rb
172
+ - spec/spec_helper.rb
173
+ homepage: http://github.com/rsanders/pg_funcall
174
+ licenses:
175
+ - MIT
176
+ metadata: {}
177
+ post_install_message:
178
+ rdoc_options: []
179
+ require_paths:
180
+ - lib
181
+ required_ruby_version: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - ! '>='
184
+ - !ruby/object:Gem::Version
185
+ version: '0'
186
+ required_rubygems_version: !ruby/object:Gem::Requirement
187
+ requirements:
188
+ - - ! '>='
189
+ - !ruby/object:Gem::Version
190
+ version: '0'
191
+ requirements: []
192
+ rubyforge_project:
193
+ rubygems_version: 2.4.5
194
+ signing_key:
195
+ specification_version: 4
196
+ summary: Utility class for calling functions defined in a PostgreSQL database.
197
+ test_files:
198
+ - spec/lib/pg_funcall_spec.rb
199
+ - spec/lib/type_info_spec.rb
200
+ - spec/lib/type_map_spec.rb
201
+ - spec/spec_helper.rb