sqlpostgres 1.2.6 → 1.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.
Files changed (62) hide show
  1. data/Changelog.md +18 -0
  2. data/Gemfile +2 -0
  3. data/Gemfile.lock +12 -0
  4. data/README.rdoc +5 -2
  5. data/Rakefile +5 -24
  6. data/VERSION +1 -1
  7. data/lib/sqlpostgres/Connection.rb +8 -3
  8. data/lib/sqlpostgres/Cursor.rb +2 -2
  9. data/lib/sqlpostgres/Insert.rb +1 -1
  10. data/lib/sqlpostgres/PgBit.rb +1 -1
  11. data/lib/sqlpostgres/PgBox.rb +1 -1
  12. data/lib/sqlpostgres/PgCidr.rb +1 -1
  13. data/lib/sqlpostgres/PgCircle.rb +1 -1
  14. data/lib/sqlpostgres/PgInet.rb +1 -1
  15. data/lib/sqlpostgres/PgInterval.rb +1 -1
  16. data/lib/sqlpostgres/PgLineSegment.rb +1 -1
  17. data/lib/sqlpostgres/PgMacAddr.rb +1 -1
  18. data/lib/sqlpostgres/PgPath.rb +1 -1
  19. data/lib/sqlpostgres/PgPoint.rb +1 -1
  20. data/lib/sqlpostgres/PgPolygon.rb +1 -1
  21. data/lib/sqlpostgres/PgTime.rb +1 -1
  22. data/lib/sqlpostgres/PgTimeWithTimeZone.rb +1 -1
  23. data/lib/sqlpostgres/PgTimestamp.rb +1 -1
  24. data/lib/sqlpostgres/PgTwoPoints.rb +1 -1
  25. data/lib/sqlpostgres/PgWrapper.rb +1 -1
  26. data/lib/sqlpostgres/Select.rb +25 -25
  27. data/lib/sqlpostgres/Translate.rb +7 -29
  28. data/lib/sqlpostgres/Update.rb +1 -1
  29. data/rake_tasks/db.rake +17 -0
  30. data/rake_tasks/default.rake +1 -0
  31. data/rake_tasks/jeweler.rake +18 -0
  32. data/rake_tasks/test.rake +2 -0
  33. data/rake_tasks/test_spec.rake +3 -0
  34. data/rake_tasks/test_unit.rake +4 -0
  35. data/spec/Translate_spec.rb +533 -0
  36. data/spec/config/.gitignore +1 -0
  37. data/spec/config/config.yml +10 -0
  38. data/spec/config/database.yml.template +6 -0
  39. data/spec/connection_spec.rb +515 -0
  40. data/spec/cursor_spec.rb +288 -0
  41. data/spec/lib/database_config.rb +33 -0
  42. data/spec/lib/database_server.rb +42 -0
  43. data/spec/lib/postgres_template.rb +60 -0
  44. data/spec/lib/target_database_servers.rb +55 -0
  45. data/spec/lib/temporary_table.rb +45 -0
  46. data/spec/lib/test_config.rb +24 -0
  47. data/spec/lib/test_connection.rb +29 -0
  48. data/spec/lib/test_database.rb +57 -0
  49. data/spec/roundtrip_spec.rb +582 -0
  50. data/spec/spec_helper.rb +10 -0
  51. data/spec/support/all_characters.rb +18 -0
  52. data/spec/support/clear_default_connection.rb +5 -0
  53. data/spec/support/temporary_table.rb +24 -0
  54. data/spec/support/test_connections.rb +10 -0
  55. data/sqlpostgres.gemspec +35 -4
  56. data/test/Connection.test.rb +7 -5
  57. data/test/Select.test.rb +1 -1
  58. data/test/TestConfig.rb +9 -0
  59. data/test/TestUtil.rb +17 -3
  60. metadata +66 -9
  61. data/test/Translate.test.rb +0 -354
  62. data/test/roundtrip.test.rb +0 -565
data/Changelog.md ADDED
@@ -0,0 +1,18 @@
1
+ ### 1.3.0
2
+
3
+ Enhancements
4
+
5
+ * Support Postgresql 9
6
+ * Some tests converted to rspec
7
+ * Connection can set client encoding
8
+ * More adaptable configuration for databases to run tests against
9
+
10
+ ### 1.2.6
11
+
12
+ Bug fixes
13
+
14
+ * DateTime objects store their full precision
15
+
16
+ ### 1.2.4
17
+
18
+ * First public release
data/Gemfile CHANGED
@@ -4,5 +4,7 @@ gem 'pg', '~> 0.13.2'
4
4
 
5
5
  group :development do
6
6
  gem 'jeweler', '~> 1.8.4'
7
+ gem 'memoizer', '~> 1.0.1'
7
8
  gem 'rake', '~> 10.0.3'
9
+ gem 'rspec', '~> 2.12.0'
8
10
  end
data/Gemfile.lock CHANGED
@@ -1,6 +1,7 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
+ diff-lcs (1.1.3)
4
5
  git (1.2.5)
5
6
  jeweler (1.8.4)
6
7
  bundler (~> 1.0)
@@ -8,15 +9,26 @@ GEM
8
9
  rake
9
10
  rdoc
10
11
  json (1.7.6)
12
+ memoizer (1.0.1)
11
13
  pg (0.13.2)
12
14
  rake (10.0.3)
13
15
  rdoc (3.12)
14
16
  json (~> 1.4)
17
+ rspec (2.12.0)
18
+ rspec-core (~> 2.12.0)
19
+ rspec-expectations (~> 2.12.0)
20
+ rspec-mocks (~> 2.12.0)
21
+ rspec-core (2.12.2)
22
+ rspec-expectations (2.12.1)
23
+ diff-lcs (~> 1.1.3)
24
+ rspec-mocks (2.12.1)
15
25
 
16
26
  PLATFORMS
17
27
  ruby
18
28
 
19
29
  DEPENDENCIES
20
30
  jeweler (~> 1.8.4)
31
+ memoizer (~> 1.0.1)
21
32
  pg (~> 0.13.2)
22
33
  rake (~> 10.0.3)
34
+ rspec (~> 2.12.0)
data/README.rdoc CHANGED
@@ -47,8 +47,7 @@ The tests are known to pass in MRI 1.8.7 and MRI 1.9.3
47
47
 
48
48
  == POSTGRES VERSIONS
49
49
 
50
- This library works with Postgres 1.8. It does not yet fully support
51
- Postgres 1.9.
50
+ This library works with Postgres 1.8 and Postgres 1.9.
52
51
 
53
52
  == ENCODINGS
54
53
 
@@ -57,3 +56,7 @@ This library only works properly with the SQL-ASCII encoding.
57
56
  == WHOAMI
58
57
 
59
58
  Wayne Conrad <wconrad@yagni.com>
59
+
60
+ == CONTRIBUTORS
61
+
62
+ Sam Kellogg <sam@nickstoys.com>
data/Rakefile CHANGED
@@ -1,8 +1,8 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require 'rubygems'
4
-
5
4
  require 'bundler'
5
+
6
6
  begin
7
7
  Bundler.setup(:default, :development)
8
8
  rescue Bundler::BundlerError => e
@@ -10,28 +10,9 @@ rescue Bundler::BundlerError => e
10
10
  $stderr.puts 'Run `bundle install` to install missing gems'
11
11
  exit e.status_code
12
12
  end
13
- require 'rake'
14
13
 
15
- require 'jeweler'
16
- Jeweler::Tasks.new do |gem|
17
- # gem is a Gem::Specification... see
18
- # http://docs.rubygems.org/read/chapter/20 for more options
19
- gem.name = 'sqlpostgres'
20
- gem.homepage = 'http://github.com/wconrad/sqlpostgres'
21
- gem.license = 'MIT'
22
- gem.summary = %Q{library for postgresql queries}
23
- gem.description =
24
- ('A mini-language for building and executing SQL statements '\
25
- 'against a postgresql database. This is a very old library, '\
26
- 'pre-dating active record and lacking many of its refinments. '\
27
- 'New projects will probably not want to use it.')
28
- gem.email = 'wconrad@yagni.com'
29
- gem.authors = ['Wayne Conrad']
30
- # dependencies defined in Gemfile
31
- end
32
- Jeweler::RubygemsDotOrgTasks.new
14
+ $:.unshift(File.dirname(__FILE__) + '/lib')
15
+ Dir['rake_tasks/**/*.rake'].sort.each { |path| load path }
33
16
 
34
- desc "Run Tests"
35
- task :test do
36
- system 'test/test'
37
- end
17
+ require File.expand_path('spec/lib/target_database_servers',
18
+ File.dirname(__FILE__))
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.6
1
+ 1.3.0
@@ -83,6 +83,8 @@ module SqlPostgres
83
83
  # to nil.
84
84
  # 'password'::
85
85
  # Password. nil, the default, means no password.
86
+ # 'encoding'::
87
+ # Client encoding.
86
88
  #
87
89
  # To wrap an existing connection, pass this argument:
88
90
  #
@@ -107,12 +109,15 @@ module SqlPostgres
107
109
  tty = args['tty'] || ""
108
110
  login = args['login']
109
111
  password = args['password']
112
+ client_encoding = args['encoding']
110
113
  @pgconn = @@pgClass.connect(hostName, port, options, tty, dbName,
111
114
  login, password)
115
+ if client_encoding
116
+ @pgconn.set_client_encoding(client_encoding)
117
+ end
112
118
  end
113
119
  @statement_in_exception = args['statement_in_exception']
114
120
  @statement_in_exception = true if @statement_in_exception.nil?
115
- @pgconn.set_client_encoding("unicode")
116
121
  end
117
122
 
118
123
  # close the connection. If it's already closed, do nothing.
@@ -177,8 +182,8 @@ module SqlPostgres
177
182
  unless column.converter.nil?
178
183
  typeCode = pgresult.ftype(i)
179
184
  value = row[i]
180
- args = [value]
181
- args << typeCode if column.converter.arity == 2
185
+ args = [value, @pgconn]
186
+ args << typeCode if column.converter.arity == 3
182
187
  hash[column.as || column.value] =
183
188
  value && column.converter.call(*args)
184
189
  end
@@ -101,8 +101,8 @@ module SqlPostgres
101
101
  @connection.exec(statement)
102
102
  end
103
103
 
104
- # Close the cursor. Once closed, it may closed or fetched from
105
- # again.
104
+ # Close the cursor. Once closed, it may not be closed or fetched
105
+ # from again.
106
106
 
107
107
  def close
108
108
  statement = "close #{@name}"
@@ -140,7 +140,7 @@ module SqlPostgres
140
140
 
141
141
  def insert_bytea(column, value = :no_value)
142
142
  @columns << column
143
- @values << Translate.escape_bytea(value) unless value == :no_value
143
+ @values << Translate.escape_bytea(value, @connection.pgconn) unless value == :no_value
144
144
  end
145
145
 
146
146
  # Insert into a bytea[] (bytea array) column. You must use this
@@ -1,4 +1,4 @@
1
- require 'sqlpostgres/PgType'
1
+ require File.expand_path('PgType', File.dirname(__FILE__))
2
2
 
3
3
  module SqlPostgres
4
4
 
@@ -1,4 +1,4 @@
1
- require 'sqlpostgres/PgTwoPoints'
1
+ require File.expand_path('PgTwoPoints', File.dirname(__FILE__))
2
2
 
3
3
  module SqlPostgres
4
4
 
@@ -1,4 +1,4 @@
1
- require 'sqlpostgres/PgWrapper'
1
+ require File.expand_path('PgWrapper', File.dirname(__FILE__))
2
2
 
3
3
  module SqlPostgres
4
4
 
@@ -1,4 +1,4 @@
1
- require 'sqlpostgres/PgType'
1
+ require File.expand_path('PgType', File.dirname(__FILE__))
2
2
 
3
3
  module SqlPostgres
4
4
 
@@ -1,4 +1,4 @@
1
- require 'sqlpostgres/PgWrapper'
1
+ require File.expand_path('PgWrapper', File.dirname(__FILE__))
2
2
 
3
3
  module SqlPostgres
4
4
 
@@ -1,4 +1,4 @@
1
- require 'sqlpostgres/PgType'
1
+ require File.expand_path('PgType', File.dirname(__FILE__))
2
2
 
3
3
  module SqlPostgres
4
4
 
@@ -1,4 +1,4 @@
1
- require 'sqlpostgres/PgTwoPoints'
1
+ require File.expand_path('PgTwoPoints', File.dirname(__FILE__))
2
2
 
3
3
  module SqlPostgres
4
4
 
@@ -1,4 +1,4 @@
1
- require 'sqlpostgres/PgWrapper'
1
+ require File.expand_path('PgWrapper', File.dirname(__FILE__))
2
2
 
3
3
  module SqlPostgres
4
4
 
@@ -1,4 +1,4 @@
1
- require 'sqlpostgres/PgType'
1
+ require File.expand_path('PgType', File.dirname(__FILE__))
2
2
 
3
3
  module SqlPostgres
4
4
 
@@ -1,4 +1,4 @@
1
- require 'sqlpostgres/PgType'
1
+ require File.expand_path('PgType', File.dirname(__FILE__))
2
2
 
3
3
  module SqlPostgres
4
4
 
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "PgType")
1
+ require File.expand_path('PgType', File.dirname(__FILE__))
2
2
 
3
3
  module SqlPostgres
4
4
 
@@ -1,4 +1,4 @@
1
- require 'sqlpostgres/PgType'
1
+ require File.expand_path('PgType', File.dirname(__FILE__))
2
2
 
3
3
  module SqlPostgres
4
4
 
@@ -1,4 +1,4 @@
1
- require 'sqlpostgres/PgType'
1
+ require File.expand_path('PgType', File.dirname(__FILE__))
2
2
 
3
3
  module SqlPostgres
4
4
 
@@ -1,4 +1,4 @@
1
- require 'sqlpostgres/PgType'
1
+ require File.expand_path('PgType', File.dirname(__FILE__))
2
2
 
3
3
  module SqlPostgres
4
4
 
@@ -1,4 +1,4 @@
1
- require 'sqlpostgres/PgType'
1
+ require File.expand_path('PgType', File.dirname(__FILE__))
2
2
 
3
3
  module SqlPostgres
4
4
 
@@ -1,4 +1,4 @@
1
- require 'sqlpostgres/PgType'
1
+ require File.expand_path('PgType', File.dirname(__FILE__))
2
2
 
3
3
  module SqlPostgres
4
4
 
@@ -609,29 +609,29 @@ module SqlPostgres
609
609
 
610
610
  # Converters used to translate strings into Ruby types.
611
611
 
612
- BitConverter = proc { |s| PgBit.from_sql(s) }
613
- BooleanConverter = proc { |s| s == 't' }
614
- BoxConverter = proc { |s| PgBox.from_sql(s) }
615
- ByteaConverter = proc { |s| Translate.unescape_bytea(s) }
616
- CidrConverter = proc { |s| PgCidr.from_sql(s) }
617
- CircleConverter = proc { |s| PgCircle.from_sql(s) }
618
- DateConverter = proc { |s| Translate.sql_to_date(s) }
619
- FloatConverter = proc { |s| s.to_f }
620
- InetConverter = proc { |s| PgInet.from_sql(s) }
621
- IntegerConverter = proc { |s| s.to_i }
622
- IntervalConverter = proc { |s| PgInterval.from_sql(s) }
623
- LsegConverter = proc { |s| PgLineSegment.from_sql(s) }
624
- MacAddrConverter = proc { |s| PgMacAddr.from_sql(s) }
625
- PathConverter = proc { |s| PgPath.from_sql(s) }
626
- PointConverter = proc { |s| PgPoint.from_sql(s) }
627
- PolygonConverter = proc { |s| PgPolygon.from_sql(s) }
628
- QCharConverter = proc { |s| Translate.unescape_qchar(s) }
629
- StringConverter = proc { |s| s }
630
- TimeConverter = proc { |s| PgTime.from_sql(s) }
631
- TimeStringConverter = proc { |s| Time.local(*s.split(/:/)) }
632
- TimeWithTimeZoneConverter = proc { |s| PgTimeWithTimeZone.from_sql(s) }
633
- TimestampConverter = proc { |s| PgTimestamp.from_sql(s) }
634
- TimestampTzConverter = proc { |s| Translate.sql_to_datetime(s) }
612
+ BitConverter = proc { |s, server_version| PgBit.from_sql(s) }
613
+ BooleanConverter = proc { |s, server_version| s == 't' }
614
+ BoxConverter = proc { |s, server_version| PgBox.from_sql(s) }
615
+ ByteaConverter = proc { |s, server_version| Translate.unescape_bytea(s, server_version) }
616
+ CidrConverter = proc { |s, server_version| PgCidr.from_sql(s) }
617
+ CircleConverter = proc { |s, server_version| PgCircle.from_sql(s) }
618
+ DateConverter = proc { |s, server_version| Translate.sql_to_date(s) }
619
+ FloatConverter = proc { |s, server_version| s.to_f }
620
+ InetConverter = proc { |s, server_version| PgInet.from_sql(s) }
621
+ IntegerConverter = proc { |s, server_version| s.to_i }
622
+ IntervalConverter = proc { |s, server_version| PgInterval.from_sql(s) }
623
+ LsegConverter = proc { |s, server_version| PgLineSegment.from_sql(s) }
624
+ MacAddrConverter = proc { |s, server_version| PgMacAddr.from_sql(s) }
625
+ PathConverter = proc { |s, server_version| PgPath.from_sql(s) }
626
+ PointConverter = proc { |s, server_version| PgPoint.from_sql(s) }
627
+ PolygonConverter = proc { |s, server_version| PgPolygon.from_sql(s) }
628
+ QCharConverter = proc { |s, server_version| Translate.unescape_qchar(s) }
629
+ StringConverter = proc { |s, server_version| s }
630
+ TimeConverter = proc { |s, server_version| PgTime.from_sql(s) }
631
+ TimeStringConverter = proc { |s, server_version| Time.local(*s.split(/:/)) }
632
+ TimeWithTimeZoneConverter = proc { |s, server_version| PgTimeWithTimeZone.from_sql(s) }
633
+ TimestampConverter = proc { |s, server_version| PgTimestamp.from_sql(s) }
634
+ TimestampTzConverter = proc { |s, server_version| Translate.sql_to_datetime(s) }
635
635
 
636
636
  # Map each base (non-array) type to a converter.
637
637
 
@@ -705,7 +705,7 @@ module SqlPostgres
705
705
  Types::ARRAY_VARCHAR => Types::VARCHAR,
706
706
  }
707
707
 
708
- AutoConverter = proc { |s, type_code|
708
+ AutoConverter = proc { |s, pgconn, type_code|
709
709
  array_element_type = ARRAY_ELEMENT_TYPES[type_code]
710
710
  if !array_element_type.nil?
711
711
  s = Translate.sql_to_array(s)
@@ -713,7 +713,7 @@ module SqlPostgres
713
713
  end
714
714
  converter = CONVERTERS[type_code] || StringConverter
715
715
  Translate.deep_collect(s) do |e|
716
- converter.call(e)
716
+ converter.call(e, pgconn)
717
717
  end
718
718
  }
719
719
 
@@ -270,45 +270,23 @@ module SqlPostgres
270
270
  # \
271
271
  # \x7f-\xff
272
272
 
273
- def escape_bytea(s)
273
+ def escape_bytea(s, pgconn)
274
274
  return "null" if s.nil?
275
275
  return "default" if s == :default
276
- "E'" + PGconn.escape_bytea(Array(s).join) + "'"
276
+ raise s.inspect if s.is_a?(Array) #DEBUG
277
+ value = "'" + pgconn.escape_bytea(s) + "'"
278
+ value = "E" + value if pgconn.server_version < 9_01_00
279
+ value
277
280
  end
278
281
  module_function :escape_bytea
279
282
 
280
- # Unescape octal escape sequences, turning them back into bytes.
281
-
282
- def unescape_octal_escapes(s)
283
- s.gsub(/\\(\d{3})/) do
284
- $1.oct.chr
285
- end.gsub(/\\\\/, '\\')
286
- end
287
- module_function :unescape_octal_escapes
288
-
289
283
  # Unescape a bytea string read from postgres.
290
284
 
291
- def unescape_bytea(s)
292
- if s.respond_to?(:force_encoding)
293
- s = s.force_encoding("ASCII-8BIT")
294
- end
295
- s.gsub(/\\(\\|[0-3][0-7][0-7])/) do
296
- if $1 == "\\"
297
- "\\"
298
- else
299
- $1.oct.chr
300
- end
301
- end
285
+ def unescape_bytea(s, pgconn)
286
+ pgconn.unescape_bytea(s)
302
287
  end
303
288
  module_function :unescape_bytea
304
289
 
305
- # Unescape a text string read from postges.
306
-
307
- def unescape_text(s)
308
- unescape_bytea(s)
309
- end
310
- module_function :unescape_text
311
-
312
290
  # Convert a time to SQL format, including microseconds:
313
291
  # (YYYY-mm-dd HH:MM:SS.uuuuuu)
314
292
 
@@ -99,7 +99,7 @@ module SqlPostgres
99
99
  #**
100
100
 
101
101
  def set_bytea(column, value)
102
- @set_clauses << [column, Translate.escape_bytea(value)].join(' = ')
102
+ @set_clauses << [column, Translate.escape_bytea(value, @connection.pgconn)].join(' = ')
103
103
  end
104
104
 
105
105
  # Set a column to an array.
@@ -0,0 +1,17 @@
1
+ namespace 'test:db' do
2
+
3
+ def target_database_servers
4
+ TestSupport::TargetDatabaseServers.instance
5
+ end
6
+
7
+ desc 'Create test databases'
8
+ task 'create' do
9
+ target_database_servers.create_databases
10
+ end
11
+
12
+ desc 'Drop test databases'
13
+ task 'drop' do
14
+ target_database_servers.drop_databases
15
+ end
16
+
17
+ end