sequel 4.23.0 → 4.24.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +26 -0
  3. data/Rakefile +1 -1
  4. data/doc/release_notes/4.24.0.txt +99 -0
  5. data/doc/sql.rdoc +10 -1
  6. data/lib/sequel/adapters/jdbc.rb +7 -0
  7. data/lib/sequel/adapters/jdbc/cubrid.rb +1 -1
  8. data/lib/sequel/adapters/jdbc/db2.rb +1 -1
  9. data/lib/sequel/adapters/jdbc/derby.rb +1 -1
  10. data/lib/sequel/adapters/jdbc/h2.rb +1 -1
  11. data/lib/sequel/adapters/jdbc/hsqldb.rb +1 -1
  12. data/lib/sequel/adapters/jdbc/mssql.rb +1 -1
  13. data/lib/sequel/adapters/jdbc/mysql.rb +2 -2
  14. data/lib/sequel/adapters/jdbc/oracle.rb +1 -1
  15. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +1 -1
  16. data/lib/sequel/adapters/jdbc/sqlite.rb +1 -1
  17. data/lib/sequel/adapters/postgres.rb +14 -6
  18. data/lib/sequel/adapters/shared/mssql.rb +1 -1
  19. data/lib/sequel/core.rb +12 -1
  20. data/lib/sequel/database/connecting.rb +1 -2
  21. data/lib/sequel/extensions/pg_inet_ops.rb +200 -0
  22. data/lib/sequel/plugins/association_pks.rb +63 -18
  23. data/lib/sequel/plugins/auto_validations.rb +43 -9
  24. data/lib/sequel/plugins/class_table_inheritance.rb +236 -179
  25. data/lib/sequel/plugins/update_refresh.rb +26 -1
  26. data/lib/sequel/plugins/validation_helpers.rb +7 -2
  27. data/lib/sequel/version.rb +1 -1
  28. data/spec/adapters/oracle_spec.rb +1 -1
  29. data/spec/adapters/postgres_spec.rb +61 -0
  30. data/spec/core_extensions_spec.rb +5 -1
  31. data/spec/extensions/association_pks_spec.rb +73 -1
  32. data/spec/extensions/auto_validations_spec.rb +34 -0
  33. data/spec/extensions/class_table_inheritance_spec.rb +58 -54
  34. data/spec/extensions/pg_inet_ops_spec.rb +101 -0
  35. data/spec/extensions/spec_helper.rb +5 -5
  36. data/spec/extensions/update_refresh_spec.rb +12 -0
  37. data/spec/extensions/validation_helpers_spec.rb +7 -0
  38. data/spec/integration/plugin_test.rb +48 -13
  39. metadata +6 -4
  40. data/lib/sequel/adapters/db2.rb +0 -229
  41. data/lib/sequel/adapters/dbi.rb +0 -102
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b30c79c77e61381e85de13c0490b3e5cba437b25
4
- data.tar.gz: daf911babab2bc31fb6e255d0a0219a4536f373f
3
+ metadata.gz: 1ce66a463879671227d5446f7e224b1610bccd9f
4
+ data.tar.gz: e16b849b789b960f5c6d86dd7049a61ebe42c169
5
5
  SHA512:
6
- metadata.gz: b360c247c80f905380b13ac37ff319339127a09860ddcf13288378be326f8dea51c0e56b9880ae0f488253f32e46bf0752d5b4bf4abe4bd7f9200ddcbe563702
7
- data.tar.gz: 15a84132c8caa90c4dad81998a6a060f931cd2bc77145345e5de5cadbf378c545b3e7f8bbab1a0900341be5a6dd1cf0e9121d35bfea5cfeb85f9ac45a6f42bf0
6
+ metadata.gz: 3ac3191f57bffb08c000deef706301c4b6628cb707ef9f870df162d7d55d3ed21982f931c3b9bbc3658cf4a693e7aa2b45d8a3dd1c62a0345d9d2d88dd7dc391
7
+ data.tar.gz: d05096b10746ea930ecd79f8cde66e295b9b5e99002c64df479369473a1bb603b36c9a69ce2462fecd33c1dc3217705bac651d590dca4c58a85edd44b1c515b3
data/CHANGELOG CHANGED
@@ -1,3 +1,29 @@
1
+ === 4.24.0 (2015-07-01)
2
+
3
+ * Allow class_table_inheritance plugin to support subclasses that don't add additional columns (QuinnHarris, jeremyevans) (#1030)
4
+
5
+ * Add :columns option to update_refresh plugin, specifying the columns to include in the RETURNING clause (celsworth) (#1029)
6
+
7
+ * Use column symbol key for auto validation unique errors if the unique index is on a single column (jeremyevans)
8
+
9
+ * Allow :timeout option to Database#listen in the postgres adapter to be a callable object (celsworth) (#1028)
10
+
11
+ * Add pg_inet_ops extension, for DSL support for PostgreSQL inet/cidr operators and functions (celsworth, jeremyevans) (#1024)
12
+
13
+ * Support :*_opts options in auto_validations plugin, for setting options for the underlying validation methods (celsworth, jeremyevans) (#1026)
14
+
15
+ * Support :delay_pks association option in association_pks to delay setting of associated_pks until after saving (jeremyevans)
16
+
17
+ * Make jdbc subadapters work if they issue queries while the subadapter is being loaded (jeremyevans) (#1022)
18
+
19
+ * Handle 64-bit auto incrementing primary keys in jdbc subadapters (DougEverly) (#1018, #1019)
20
+
21
+ * Remove the deprecated db2 and dbi adapters (jeremyevans)
22
+
23
+ * Make auto_validation plugin use :from=>:values option to setup validations on the underlying columns (jeremyevans)
24
+
25
+ * Add :from=>:values option to validation_helpers methods, for getting values from the values hash instead of a method call (jeremyevans)
26
+
1
27
  === 4.23.0 (2015-06-01)
2
28
 
3
29
  * Make dataset.call_sproc(:insert) work in the jdbc adapter (flash-gordon) (#1013)
data/Rakefile CHANGED
@@ -86,7 +86,7 @@ run_spec = proc do |patterns|
86
86
  lib_dir = File.join(File.dirname(File.expand_path(__FILE__)), 'lib')
87
87
  rubylib = ENV['RUBYLIB']
88
88
  ENV['RUBYLIB'] ? (ENV['RUBYLIB'] += ":#{lib_dir}") : (ENV['RUBYLIB'] = lib_dir)
89
- if RUBY_PLATFORM =~ /mingw32/
89
+ if RUBY_PLATFORM =~ /mingw32/ || RUBY_DESCRIPTION =~ /windows/i
90
90
  patterns = patterns.split.map{|pat| Dir[pat].to_a}.flatten.join(' ')
91
91
  end
92
92
  sh "#{FileUtils::RUBY} -e \"ARGV.each{|f| require f}\" #{patterns}"
@@ -0,0 +1,99 @@
1
+ = New Features
2
+
3
+ * A pg_inet_ops extension has been added, for DSL support for
4
+ calling PostgreSQL inet functions and operators. Example:
5
+
6
+ r = Sequel.pg_inet_op(:inet)
7
+
8
+ ~r # ~inet
9
+ r & :other # inet & other
10
+ r | :other # inet | other
11
+ r << :other # inet << other
12
+ r >> :other # inet >> other
13
+
14
+ r.contained_by(:other) # inet << other
15
+ r.contained_by_or_equals(:other) # inet <<= other
16
+ r.contains(:other) # inet >> other
17
+ r.contains_or_equals(:other) # inet >>= other
18
+ r.contains_or_contained_by(:other) # inet && other
19
+
20
+ r.abbrev # abbrev(inet)
21
+ r.broadcast # broadcast(inet)
22
+ r.family # family(inet)
23
+ r.host # host(inet)
24
+ r.hostmask # hostmask(inet)
25
+ r.masklen # masklen(inet)
26
+ r.netmask # netmask(inet)
27
+ r.network # network(inet)
28
+ r.set_masklen(16) # set_masklen(inet, 16)
29
+ r.text # text(inet)
30
+
31
+ * The association_pks plugin now supports a :delay_pks association
32
+ option. When set to true, this makes the methods created by the
33
+ plugin usable on new objects, by delaying the saving of the
34
+ associated pks until after the new object has been saved. When
35
+ set to :always, this also changes the behavior of the methods
36
+ for existing objects, so that nothing is persisted until the
37
+ object has been saved. Example:
38
+
39
+ Album.plugin :association_pks
40
+ Album.many_to_many :tags, :delay_pks=>true
41
+
42
+ album = Album.new(:tag_pks=>[1,2,3]) # No database query
43
+ album.save # Queries to insert album, and then update albums_tags
44
+
45
+ * The class_table_inheritance plugin now supports subclasses that
46
+ don't require additional columns, and therefore do not need to
47
+ join to additional tables. It now loads the
48
+ single_table_inheritance plugin and supports options that were
49
+ previously only supported by single_table_inheritance, such as the
50
+ :key_map and :key_chooser options.
51
+
52
+ * The validation_helpers plugin now supports a :from=>:values option
53
+ in the validation methods, which will take the value directly from
54
+ the values hash instead of calling the related method. This
55
+ allows validation_helpers to differentiate between validations on
56
+ underlying database column and validations on the model.
57
+
58
+ The auto_validations plugin has been modified to use this feature,
59
+ since all validations it generates are for validations on the
60
+ underlying database columns.
61
+
62
+ * The auto_validations plugin now supports options to pass to each
63
+ of the underlying validation methods:
64
+
65
+ Sequel::Model.plugin :auto_validations,
66
+ :unique_opts=>{:only_if_modified=>true}
67
+
68
+ In addition to :unique_opts, there is support for :not_null_opts
69
+ (for NOT NULL columns without a default), :explicit_not_null_opts
70
+ (for NOT NULL columns with a default), :max_length_opts, and
71
+ :schema_types_opts.
72
+
73
+ * The update_refresh plugin now accepts a :columns option, which
74
+ specifies the columns to refresh. This option is currently only
75
+ respected if the related dataset supports RETURNING.
76
+
77
+ * The :timeout option to Database#listen in the postgres adapter can
78
+ now be a callable object, previously it had to be Numeric. This
79
+ allows you to dynamically change the timeout based on current
80
+ application state.
81
+
82
+ = Other Improvements
83
+
84
+ * The uniqueness validations added by the auto_validations plugin now
85
+ use a symbol key in the related Errors instance if the underlying
86
+ index was on a single column. Previously, the uniqueness
87
+ validations for a single column would use an array key in the
88
+ related Errors instance.
89
+
90
+ * The jdbc subadapters now correctly handle 64-bit autoincrementing
91
+ primary keys.
92
+
93
+ * The jdbc subadapters now work correctly if they issue queries while
94
+ the subadapter is being loaded. This can happen in the
95
+ jdbc/postgresql adapter if the pg_hstore extension is used.
96
+
97
+ = Backwards Compatibility
98
+
99
+ * The deprecated db2 and dbi adapters have been removed.
data/doc/sql.rdoc CHANGED
@@ -237,6 +237,15 @@ If the database supports schema qualified functions, Sequel can handle them by c
237
237
  DB[:albums].select{schema__function.function(col, 2, "a")}
238
238
  # SELECT schema.function(col, 2, 'a') FROM albums
239
239
 
240
+ === Portable/Emulated Functions
241
+
242
+ Sequel offers some support for portable SQL functions, allowing you to call standard SQL functions, where Sequel will emulate support on databases that lack native support.
243
+ Some examples are:
244
+
245
+ Sequel.char_length(:column) # char_length(column)
246
+ Sequel.extract(:year, :column) # extract(year FROM column)
247
+ Sequel.trim(:column) # trim(column)
248
+
240
249
  === Equality Operator (=)
241
250
 
242
251
  Sequel uses hashes to specify equality:
@@ -506,7 +515,7 @@ Note that using +ilike+ with a regular expression will always make the regexp ca
506
515
 
507
516
  === Order Specifications (ASC, DESC)
508
517
 
509
- Sequel supports specifying ascending or descending order using the asc+ and +desc+ method on most Sequel-specific expression objects:
518
+ Sequel supports specifying ascending or descending order using the +asc+ and +desc+ method on most Sequel-specific expression objects:
510
519
 
511
520
  Sequel.expr(:column).asc # "column" ASC
512
521
  Sequel.expr(:column).qualify(:table).desc # "table"."column" DESC
@@ -354,6 +354,7 @@ module Sequel
354
354
  raise(Error, "No connection string specified") unless uri
355
355
 
356
356
  resolved_uri = jndi? ? get_uri_from_jndi : uri
357
+ setup_type_convertor_map_early
357
358
 
358
359
  @driver = if (match = /\Ajdbc:([^:]+)/.match(resolved_uri)) && (prok = Sequel::Database.load_adapter(match[1].to_sym, :map=>DATABASE_SETUP, :subdir=>'jdbc'))
359
360
  prok.call(self)
@@ -640,7 +641,13 @@ module Sequel
640
641
  h[:table_schem] == 'INFORMATION_SCHEMA'
641
642
  end
642
643
 
644
+ # Called after loading subadapter-specific code, overridable by subadapters.
643
645
  def setup_type_convertor_map
646
+ end
647
+
648
+ # Called before loading subadapter-specific code, necessary so that subadapter initialization code
649
+ # that runs queries works correctly. This cannot be overriding in subadapters,
650
+ def setup_type_convertor_map_early
644
651
  @type_convertor_map = TypeConvertor::MAP.merge(Java::JavaSQL::Types::TIMESTAMP=>timestamp_convertor)
645
652
  @basic_type_convertor_map = TypeConvertor::BASIC_MAP
646
653
  end
@@ -30,7 +30,7 @@ module Sequel
30
30
  rs = stmt.getGeneratedKeys
31
31
  begin
32
32
  if rs.next
33
- rs.getInt(1)
33
+ rs.getLong(1)
34
34
  end
35
35
  rescue NativeException
36
36
  nil
@@ -66,7 +66,7 @@ module Sequel
66
66
  sql = IDENTITY_VAL_LOCAL
67
67
  rs = log_yield(sql){stmt.executeQuery(sql)}
68
68
  rs.next
69
- rs.getInt(1)
69
+ rs.getLong(1)
70
70
  end
71
71
  end
72
72
 
@@ -131,7 +131,7 @@ module Sequel
131
131
  sql = 'SELECT IDENTITY_VAL_LOCAL() FROM sysibm.sysdummy1'
132
132
  rs = log_yield(sql){stmt.executeQuery(sql)}
133
133
  rs.next
134
- rs.getInt(1)
134
+ rs.getLong(1)
135
135
  end
136
136
  end
137
137
 
@@ -130,7 +130,7 @@ module Sequel
130
130
  sql = 'SELECT IDENTITY();'
131
131
  rs = log_yield(sql){stmt.executeQuery(sql)}
132
132
  rs.next
133
- rs.getInt(1)
133
+ rs.getLong(1)
134
134
  end
135
135
  end
136
136
 
@@ -101,7 +101,7 @@ module Sequel
101
101
  sql = 'CALL IDENTITY()'
102
102
  rs = log_yield(sql){stmt.executeQuery(sql)}
103
103
  rs.next
104
- rs.getInt(1)
104
+ rs.getLong(1)
105
105
  end
106
106
  end
107
107
 
@@ -22,7 +22,7 @@ module Sequel
22
22
  sql = opts[:prepared] ? ATAT_IDENTITY : SCOPE_IDENTITY
23
23
  rs = log_yield(sql){stmt.executeQuery(sql)}
24
24
  rs.next
25
- rs.getInt(1)
25
+ rs.getLong(1)
26
26
  end
27
27
  end
28
28
 
@@ -46,7 +46,7 @@ module Sequel
46
46
  rs = stmt.getGeneratedKeys
47
47
  begin
48
48
  if rs.next
49
- rs.getInt(1)
49
+ rs.getLong(1)
50
50
  else
51
51
  0
52
52
  end
@@ -57,7 +57,7 @@ module Sequel
57
57
  statement(conn) do |st|
58
58
  rs = st.executeQuery(LAST_INSERT_ID)
59
59
  rs.next
60
- rs.getInt(1)
60
+ rs.getLong(1)
61
61
  end
62
62
  end
63
63
  end
@@ -72,7 +72,7 @@ module Sequel
72
72
  begin
73
73
  rs = log_yield(sql){stmt.executeQuery(sql)}
74
74
  rs.next
75
- rs.getInt(1)
75
+ rs.getLong(1)
76
76
  rescue java.sql.SQLException
77
77
  nil
78
78
  end
@@ -51,7 +51,7 @@ module Sequel
51
51
  sql = LAST_INSERT_ID
52
52
  rs = log_yield(sql){stmt.executeQuery(sql)}
53
53
  rs.next
54
- rs.getInt(1)
54
+ rs.getLong(1)
55
55
  end
56
56
  end
57
57
 
@@ -51,7 +51,7 @@ module Sequel
51
51
  statement(conn) do |stmt|
52
52
  rs = stmt.executeQuery(LAST_INSERT_ROWID)
53
53
  rs.next
54
- rs.getInt(1)
54
+ rs.getLong(1)
55
55
  end
56
56
  end
57
57
 
@@ -439,14 +439,16 @@ module Sequel
439
439
  # :after_listen :: An object that responds to +call+ that is called with the underlying connection after the LISTEN
440
440
  # statement is sent, but before the connection starts waiting for notifications.
441
441
  # :loop :: Whether to continually wait for notifications, instead of just waiting for a single
442
- # notification. If this option is given, a block must be provided. If this object responds to call, it is
442
+ # notification. If this option is given, a block must be provided. If this object responds to +call+, it is
443
443
  # called with the underlying connection after each notification is received (after the block is called).
444
444
  # If a :timeout option is used, and a callable object is given, the object will also be called if the
445
445
  # timeout expires. If :loop is used and you want to stop listening, you can either break from inside the
446
446
  # block given to #listen, or you can throw :stop from inside the :loop object's call method or the block.
447
447
  # :server :: The server on which to listen, if the sharding support is being used.
448
- # :timeout :: How long to wait for a notification, in seconds (can provide a float value for
449
- # fractional seconds). If not given or nil, waits indefinitely.
448
+ # :timeout :: How long to wait for a notification, in seconds (can provide a float value for fractional seconds).
449
+ # If this object responds to +call+, it will be called and should return the number of seconds to wait.
450
+ # If the loop option is also specified, the object will be called on each iteration to obtain a new
451
+ # timeout value. If not given or nil, waits indefinitely.
450
452
  #
451
453
  # This method is only supported if pg is used as the underlying ruby driver. It returns the
452
454
  # channel the notification was sent to (as a string), unless :loop was used, in which case it returns nil.
@@ -465,19 +467,25 @@ module Sequel
465
467
  conn.execute(sql)
466
468
  end
467
469
  opts[:after_listen].call(conn) if opts[:after_listen]
468
- timeout = opts[:timeout] ? [opts[:timeout]] : []
470
+ timeout = opts[:timeout]
471
+ if timeout
472
+ timeout_block = timeout.respond_to?(:call) ? timeout : proc{timeout}
473
+ end
474
+
469
475
  if l = opts[:loop]
470
476
  raise Error, 'calling #listen with :loop requires a block' unless block
471
477
  loop_call = l.respond_to?(:call)
472
478
  catch(:stop) do
473
479
  loop do
474
- conn.wait_for_notify(*timeout, &block)
480
+ t = timeout_block ? [timeout_block.call] : []
481
+ conn.wait_for_notify(*t, &block)
475
482
  l.call(conn) if loop_call
476
483
  end
477
484
  end
478
485
  nil
479
486
  else
480
- conn.wait_for_notify(*timeout, &block)
487
+ t = timeout_block ? [timeout_block.call] : []
488
+ conn.wait_for_notify(*t, &block)
481
489
  end
482
490
  ensure
483
491
  conn.execute("UNLISTEN *")
@@ -37,7 +37,7 @@ module Sequel
37
37
  # Execute the given stored procedure with the given name.
38
38
  #
39
39
  # Options:
40
- # :args :: Arguments to stored procedure. For named argumetns, this should be a
40
+ # :args :: Arguments to stored procedure. For named arguments, this should be a
41
41
  # hash keyed by argument named. For unnamed arguments, this should be an
42
42
  # array. Output parameters to the function are specified using :output.
43
43
  # You can also name output parameters and provide a type by using an
data/lib/sequel/core.rb CHANGED
@@ -84,11 +84,22 @@ module Sequel
84
84
  # DB = Sequel.connect('postgres://user:password@host:port/database_name')
85
85
  # DB = Sequel.connect('sqlite:///blog.db', :max_connections=>10)
86
86
  #
87
+ # You can also pass a single options hash:
88
+ #
89
+ # DB = Sequel.connect(:adapter=>'sqlite', :database=>'./blog.db')
90
+ #
87
91
  # If a block is given, it is passed the opened +Database+ object, which is
88
92
  # closed when the block exits. For example:
89
93
  #
90
94
  # Sequel.connect('sqlite://blog.db'){|db| puts db[:users].count}
91
- #
95
+ #
96
+ # If a block is not given, a reference to this database will be held in
97
+ # <tt>Sequel::DATABASES</tt> until it is removed manually. This is by
98
+ # design, and used by <tt>Sequel::Model</tt> to pick the default
99
+ # database. It is recommended to pass a block if you do not want the
100
+ # resulting Database object to remain in memory until the process
101
+ # terminates.
102
+ #
92
103
  # For details, see the {"Connecting to a Database" guide}[rdoc-ref:doc/opening_databases.rdoc].
93
104
  # To set up a master/slave or sharded database connection, see the {"Master/Slave Databases and Sharding" guide}[rdoc-ref:doc/sharding.rdoc].
94
105
  def self.connect(*args, &block)
@@ -6,7 +6,7 @@ module Sequel
6
6
  # ---------------------
7
7
 
8
8
  # Array of supported database adapters
9
- ADAPTERS = %w'ado amalgalite cubrid db2 dbi do firebird ibmdb informix jdbc mock mysql mysql2 odbc oracle postgres sqlanywhere sqlite swift tinytds'.collect(&:to_sym)
9
+ ADAPTERS = %w'ado amalgalite cubrid do firebird ibmdb informix jdbc mock mysql mysql2 odbc oracle postgres sqlanywhere sqlite swift tinytds'.collect(&:to_sym)
10
10
 
11
11
  @single_threaded = false
12
12
 
@@ -42,7 +42,6 @@ module Sequel
42
42
  else
43
43
  uri = URI.parse(conn_string)
44
44
  scheme = uri.scheme
45
- scheme = :dbi if scheme =~ /\Adbi-/
46
45
  c = adapter_class(scheme)
47
46
  uri_options = c.send(:uri_to_options, uri)
48
47
  uri.query.split('&').collect{|s| s.split('=')}.each{|k,v| uri_options[k.to_sym] = v if k && !k.empty?} unless uri.query.to_s.strip.empty?
@@ -0,0 +1,200 @@
1
+ # The pg_inet_ops extension adds support to Sequel's DSL to make
2
+ # it easier to call PostgreSQL inet functions and operators.
3
+ #
4
+ # To load the extension:
5
+ #
6
+ # Sequel.extension :pg_inet_ops
7
+ #
8
+ # The most common usage is passing an expression to Sequel.pg_inet_op:
9
+ #
10
+ # r = Sequel.pg_inet_op(:inet)
11
+ #
12
+ # Also, on most Sequel expression objects, you can call the pg_inet
13
+ # method:
14
+ #
15
+ # r = Sequel.expr(:ip).pg_inet
16
+ #
17
+ # If you have loaded the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
18
+ # or you have loaded the core_refinements extension
19
+ # and have activated refinements for the file, you can also use Symbol#pg_inet:
20
+ #
21
+ # r = :inet.pg_inet
22
+ #
23
+ # This creates a Sequel::Postgres::InetOp object that can be used
24
+ # for easier querying:
25
+ #
26
+ # ~r # ~inet
27
+ # r & other # inet & other
28
+ # r | other # inet | other
29
+ # r << :other # inet << other
30
+ # r >> :other # inet >> other
31
+ #
32
+ # r.contained_by(:other) # inet << other
33
+ # r.contained_by_or_equals(:other) # inet <<= other
34
+ # r.contains(:other) # inet >> other
35
+ # r.contains_or_equals(:other) # inet >>= other
36
+ # r.contains_or_contained_by(:other) # inet && other
37
+ #
38
+ # r.abbrev # abbrev(inet)
39
+ # r.broadcast # broadcast(inet)
40
+ # r.family # family(inet)
41
+ # r.host # host(inet)
42
+ # r.hostmask # hostmask(inet)
43
+ # r.masklen # masklen(inet)
44
+ # r.netmask # netmask(inet)
45
+ # r.network # network(inet)
46
+ # r.set_masklen(16) # set_masklen(inet, 16)
47
+ # r.text # text(inet)
48
+ #
49
+ # If a String or IPAddr instance is passed to Sequel.pg_inet_op, it will automatically
50
+ # be cast to +inet+. To treat the object as a +cidr+, you must cast it before passing
51
+ # it to Sequel.pg_inet_op:
52
+ #
53
+ # r = Sequel.pg_inet_op(Sequel.cast('1.2.3.4', :cidr))
54
+ #
55
+ # See the PostgreSQL network function and operator documentation for more
56
+ # details on what these functions and operators do.
57
+
58
+ require 'ipaddr'
59
+
60
+ module Sequel
61
+ module Postgres
62
+ # The InetOp class is a simple container for a single object that
63
+ # defines methods that yield Sequel expression objects representing
64
+ # PostgreSQL inet operators and functions.
65
+ #
66
+ # Most methods in this class are defined via metaprogramming, see
67
+ # the pg_inet_ops extension documentation for details on the API.
68
+ class InetOp < Sequel::SQL::Wrapper
69
+ include Sequel::SQL::BitwiseMethods
70
+
71
+ # For String and IPAddr instances, wrap them in a cast to inet,
72
+ # to avoid ambiguity issues when calling operator methods.
73
+ def initialize(v)
74
+ case v
75
+ when ::Sequel::LiteralString
76
+ # nothing
77
+ when String, IPAddr
78
+ v = Sequel.cast(v, :inet)
79
+ end
80
+ super
81
+ end
82
+
83
+ OPERATORS = {
84
+ :contained_by_or_equals => ["(".freeze, " <<= ".freeze, ")".freeze].freeze,
85
+ :contains_or_equals => ["(".freeze, " >>= ".freeze, ")".freeze].freeze,
86
+ :contains_or_contained_by => ["(".freeze, " && ".freeze, ")".freeze].freeze,
87
+ }.freeze
88
+
89
+ OPERATORS.keys.each do |f|
90
+ class_eval("def #{f}(v) Sequel::SQL::BooleanExpression.new(:NOOP, operator(:#{f}, v)) end", __FILE__, __LINE__)
91
+ end
92
+
93
+ %w'<< >>'.each do |f|
94
+ class_eval("def #{f}(v) Sequel::SQL::BooleanExpression.new(:NOOP, super) end", __FILE__, __LINE__)
95
+ end
96
+
97
+ %w'& | +'.each do |f|
98
+ class_eval("def #{f}(v) self.class.new(super) end", __FILE__, __LINE__)
99
+ end
100
+
101
+ %w'abbrev host text'.each do |f|
102
+ class_eval("def #{f}() Sequel::SQL::StringExpression.new(:NOOP, function(:#{f})) end", __FILE__, __LINE__)
103
+ end
104
+
105
+ %w'family masklen'.each do |f|
106
+ class_eval("def #{f}() Sequel::SQL::NumericExpression.new(:NOOP, function(:#{f})) end", __FILE__, __LINE__)
107
+ end
108
+
109
+ %w'broadcast hostmask netmask network'.each do |f|
110
+ class_eval("def #{f}() self.class.new(function(:#{f})) end", __FILE__, __LINE__)
111
+ end
112
+
113
+ # Return the receiver.
114
+ def pg_inet
115
+ self
116
+ end
117
+
118
+ # Return an expression for the bitwise NOT of the receiver
119
+ def ~
120
+ self.class.new(super)
121
+ end
122
+
123
+ # Return an expression for the subtraction of the argument from the receiver
124
+ def -(v)
125
+ case v
126
+ when Integer
127
+ self.class.new(super)
128
+ else
129
+ Sequel::SQL::NumericExpression.new(:NOOP, super)
130
+ end
131
+ end
132
+
133
+ # Return an expression for the calling of the set_masklen function with the receiver and the given argument
134
+ def set_masklen(v)
135
+ self.class.new(Sequel::SQL::Function.new(:set_masklen, self, v))
136
+ end
137
+
138
+ alias contained_by <<
139
+ alias contains >>
140
+
141
+ undef_method :*, :/
142
+
143
+ private
144
+
145
+ # Handle PostgreSQL specific operator types
146
+ def operator(type, other)
147
+ Sequel::SQL::PlaceholderLiteralString.new(OPERATORS[type], [value, other])
148
+ end
149
+
150
+ # Return a function called with the receiver.
151
+ def function(name)
152
+ Sequel::SQL::Function.new(name, self)
153
+ end
154
+ end
155
+
156
+ module InetOpMethods
157
+ # Wrap the receiver in an InetOp so you can easily use the PostgreSQL
158
+ # inet functions and operators with it.
159
+ def pg_inet
160
+ InetOp.new(self)
161
+ end
162
+ end
163
+ end
164
+
165
+ module SQL::Builders
166
+ # Return the expression wrapped in the Postgres::InetOp.
167
+ def pg_inet_op(v)
168
+ case v
169
+ when Postgres::InetOp
170
+ v
171
+ else
172
+ Postgres::InetOp.new(v)
173
+ end
174
+ end
175
+ end
176
+
177
+ class SQL::GenericExpression
178
+ include Sequel::Postgres::InetOpMethods
179
+ end
180
+
181
+ class LiteralString
182
+ include Sequel::Postgres::InetOpMethods
183
+ end
184
+ end
185
+
186
+ # :nocov:
187
+ if Sequel.core_extensions?
188
+ class Symbol
189
+ include Sequel::Postgres::InetOpMethods
190
+ end
191
+ end
192
+
193
+ if defined?(Sequel::CoreRefinements)
194
+ module Sequel::CoreRefinements
195
+ refine Symbol do
196
+ include Sequel::Postgres::InetOpMethods
197
+ end
198
+ end
199
+ end
200
+ # :nocov: