Class: Sequel::Postgres::PGArray::Parser

Inherits:
StringScanner
  • Object
show all
Defined in:
lib/sequel/extensions/pg_array.rb

Overview

PostgreSQL array parser that handles PostgreSQL array output format. Note that does not handle all forms out input that PostgreSQL will accept, and it will not raise an error for all forms of invalid input.

Constant Summary collapse

UNQUOTED_RE =
/[{}",]|[^{}",]+/
QUOTED_RE =
/["\\]|[^"\\]+/
NULL_RE =
/NULL",/
OPEN_RE =
/((\[\d+:\d+\])+=)?\{/

Instance Method Summary collapse

Constructor Details

#initialize(source, converter = nil) ⇒ Parser

Returns a new instance of Parser.



424
425
426
427
428
429
430
# File 'lib/sequel/extensions/pg_array.rb', line 424

def initialize(source, converter=nil)
  super(source)
  @converter = converter 
  @stack = [[]]
  @recorded = new_entry_buffer
  #@encoding = string.encoding # SEQUEL5
end

Instance Method Details

#new_entry(include_empty = false) ⇒ Object



434
435
436
437
438
439
440
441
442
443
444
445
# File 'lib/sequel/extensions/pg_array.rb', line 434

def new_entry(include_empty=false)
  if !@recorded.empty? || include_empty
    entry = @recorded
    if entry == 'NULL' && !include_empty
      entry = nil
    elsif @converter
      entry = @converter.call(entry)
    end
    @stack.last.push(entry)
    @recorded = new_entry_buffer
  end
end

#parseObject

Raises:



449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
# File 'lib/sequel/extensions/pg_array.rb', line 449

def parse
  raise Sequel::Error, "invalid array, empty string" if eos?
  raise Sequel::Error, "invalid array, doesn't start with {" unless scan(/((\[\d+:\d+\])+=)?\{/)

  while !eos?
    char = scan(/[{}",]|[^{}",]+/)
    if char == ','
      # Comma outside quoted string indicates end of current entry
      new_entry
    elsif char == '"'
      raise Sequel::Error, "invalid array, opening quote with existing recorded data" unless @recorded.empty?
      while true
        char = scan(/["\\]|[^"\\]+/)
        if char == '\\'
          @recorded << getch
        elsif char == '"'
          n = peek(1)
          raise Sequel::Error, "invalid array, closing quote not followed by comma or closing brace" unless n == ',' || n == '}'
          break
        else
          @recorded << char
        end
      end
      new_entry(true)
    elsif char == '{'
      raise Sequel::Error, "invalid array, opening brace with existing recorded data" unless @recorded.empty?

      # Start of new array, add it to the stack
      new = []
      @stack.last << new
      @stack << new
    elsif char == '}'
      # End of current array, add current entry to the current array
      new_entry

      if @stack.length == 1
        raise Sequel::Error, "array parsing finished without parsing entire string" unless eos?

        # Top level of array, parsing should be over.
        # Pop current array off stack and return it as result
        return @stack.pop
      else
        # Nested array, pop current array off stack
        @stack.pop
      end
    else
      # Add the character to the recorded character buffer.
      @recorded << char
    end
  end

  raise Sequel::Error, "array parsing finished with array unclosed"
end