sequel 4.23.0 → 4.24.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 (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: