class Sequel::Postgres::PGRange
:nocov:
Constants
- ENDLESS_RANGE_NOT_SUPPORTED
- STARTLESS_RANGE_NOT_SUPPORTED
Attributes
The beginning of the range. If nil, the range has an unbounded beginning.
The PostgreSQL database type for the range (e.g. 'int4range').
The end of the range. If nil, the range has an unbounded ending.
Public Class Methods
Create an empty PGRange
with the given database type.
# File lib/sequel/extensions/pg_range.rb 333 def self.empty(db_type=nil) 334 new(nil, nil, :empty=>true, :db_type=>db_type) 335 end
Initialize a new PGRange
instance. Accepts the following options:
- :db_type
-
The PostgreSQL database type for the range.
- :empty
-
Whether the range is empty (has no points)
- :exclude_begin
-
Whether the beginning element is excluded from the range.
- :exclude_end
-
Whether the ending element is excluded from the range.
# File lib/sequel/extensions/pg_range.rb 343 def initialize(beg, en, opts=OPTS) 344 @begin = beg 345 @end = en 346 @empty = !!opts[:empty] 347 @exclude_begin = !!opts[:exclude_begin] 348 @exclude_end = !!opts[:exclude_end] 349 @db_type = opts[:db_type] 350 if @empty 351 raise(Error, 'cannot have an empty range with either a beginning or ending') unless @begin.nil? && @end.nil? && opts[:exclude_begin].nil? && opts[:exclude_end].nil? 352 end 353 end
Public Instance Methods
Allow PGRange
values in case statements, where they return true if they are equal to each other using eql?, or if this PGRange
can be converted to a Range
, delegating to that range.
# File lib/sequel/extensions/pg_range.rb 413 def ===(other) 414 if eql?(other) 415 true 416 else 417 if valid_ruby_range? 418 to_range === other 419 else 420 false 421 end 422 end 423 end
Return whether the value is inside the range.
# File lib/sequel/extensions/pg_range.rb 362 def cover?(value) 363 return false if empty? 364 b = self.begin 365 return false if b && b.public_send(exclude_begin? ? :>= : :>, value) 366 e = self.end 367 return false if e && e.public_send(exclude_end? ? :<= : :<, value) 368 true 369 end
Whether this range is empty (has no points). Note that for manually created ranges (ones not retrieved from the database), this will only be true if the range was created using the :empty option.
# File lib/sequel/extensions/pg_range.rb 428 def empty? 429 @empty 430 end
Consider the receiver equal to other PGRange
instances with the same beginning, ending, exclusions, and database type. Also consider it equal to Range
instances if this PGRange
can be converted to a a Range
and those ranges are equal.
# File lib/sequel/extensions/pg_range.rb 375 def eql?(other) 376 case other 377 when PGRange 378 if db_type == other.db_type 379 if empty? 380 other.empty? 381 elsif other.empty? 382 false 383 else 384 [:@begin, :@end, :@exclude_begin, :@exclude_end].all?{|v| instance_variable_get(v) == other.instance_variable_get(v)} 385 end 386 else 387 false 388 end 389 when Range 390 if valid_ruby_range? 391 to_range.eql?(other) 392 else 393 false 394 end 395 else 396 false 397 end 398 end
Whether the beginning element is excluded from the range.
# File lib/sequel/extensions/pg_range.rb 433 def exclude_begin? 434 @exclude_begin 435 end
Whether the ending element is excluded from the range.
# File lib/sequel/extensions/pg_range.rb 438 def exclude_end? 439 @exclude_end 440 end
Make sure equal ranges have the same hash.
# File lib/sequel/extensions/pg_range.rb 402 def hash 403 if @empty 404 @db_type.hash 405 else 406 [@begin, @end, @exclude_begin, @exclude_end, @db_type].hash 407 end 408 end
Append a literalize version of the receiver to the sql.
# File lib/sequel/extensions/pg_range.rb 443 def sql_literal_append(ds, sql) 444 if (s = @db_type) && !empty? 445 sql << s.to_s << "(" 446 ds.literal_append(sql, self.begin) 447 sql << ',' 448 ds.literal_append(sql, self.end) 449 sql << ',' 450 ds.literal_append(sql, "#{exclude_begin? ? "(" : "["}#{exclude_end? ? ")" : "]"}") 451 sql << ")" 452 else 453 ds.literal_append(sql, unquoted_literal(ds)) 454 if s 455 sql << '::' << s.to_s 456 end 457 end 458 end
Return a ruby Range
object for this instance, if one can be created.
# File lib/sequel/extensions/pg_range.rb 464 def to_range 465 return @range if @range 466 raise(Error, "cannot create ruby range for an empty PostgreSQL range") if empty? 467 raise(Error, "cannot create ruby range when PostgreSQL range excludes beginning element") if exclude_begin? 468 # :nocov: 469 raise(Error, "cannot create ruby range when PostgreSQL range has unbounded beginning") if STARTLESS_RANGE_NOT_SUPPORTED && !self.begin 470 raise(Error, "cannot create ruby range when PostgreSQL range has unbounded ending") if ENDLESS_RANGE_NOT_SUPPORTED && !self.end 471 # :nocov: 472 @range = Range.new(self.begin, self.end, exclude_end?) 473 end
Whether the beginning of the range is unbounded.
# File lib/sequel/extensions/pg_range.rb 483 def unbounded_begin? 484 self.begin.nil? && !empty? 485 end
Whether the end of the range is unbounded.
# File lib/sequel/extensions/pg_range.rb 488 def unbounded_end? 489 self.end.nil? && !empty? 490 end
Return a string containing the unescaped version of the range. Separated out for use by the bound argument code.
# File lib/sequel/extensions/pg_range.rb 494 def unquoted_literal(ds) 495 if empty? 496 'empty' 497 else 498 "#{exclude_begin? ? "(" : "["}#{escape_value(self.begin, ds)},#{escape_value(self.end, ds)}#{exclude_end? ? ")" : "]"}" 499 end 500 end
Whether or not this PGRange
is a valid ruby range. In order to be a valid ruby range, it must have a beginning and an ending (no unbounded ranges), and it cannot exclude the beginning element.
# File lib/sequel/extensions/pg_range.rb 478 def valid_ruby_range? 479 !(empty? || exclude_begin? || (STARTLESS_RANGE_NOT_SUPPORTED && !self.begin) || (ENDLESS_RANGE_NOT_SUPPORTED && !self.end)) 480 end
Private Instance Methods
Escape common range types. Instead of quoting, just backslash escape all special characters.
# File lib/sequel/extensions/pg_range.rb 506 def escape_value(k, ds) 507 case k 508 when nil 509 '' 510 when Date, Time 511 ds.literal(k)[1...-1] 512 when Integer, Float 513 k.to_s 514 when BigDecimal 515 k.to_s('F') 516 when LiteralString 517 k 518 when String 519 if k.empty? 520 '""' 521 else 522 k.gsub(/("|,|\\|\[|\]|\(|\))/, '\\\\\1') 523 end 524 else 525 ds.literal(k).gsub(/("|,|\\|\[|\]|\(|\))/, '\\\\\1') 526 end 527 end