class Sequel::Postgres::PGArray::Parser

  1. lib/sequel/extensions/pg_array.rb
Superclass: StringScanner

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.

Methods

Public Class

  1. new

Public Instance

  1. new_entry
  2. parse

Public Class methods

new(source, converter=nil)

Set the source for the input, and any converter callable to call with objects to be created. For nested parsers the source may contain text after the end current parse, which will be ignored.

[show source]
    # File lib/sequel/extensions/pg_array.rb
336 def initialize(source, converter=nil)
337   super(source)
338   @converter = converter 
339   @stack = [[]]
340   @encoding = string.encoding
341   @recorded = String.new.force_encoding(@encoding)
342 end

Public Instance methods

new_entry(include_empty=false)

Take the buffer of recorded characters and add it to the array of entries, and use a new buffer for recorded characters.

[show source]
    # File lib/sequel/extensions/pg_array.rb
346 def new_entry(include_empty=false)
347   if !@recorded.empty? || include_empty
348     entry = @recorded
349     if entry == 'NULL' && !include_empty
350       entry = nil
351     elsif @converter
352       entry = @converter.call(entry)
353     end
354     @stack.last.push(entry)
355     @recorded = String.new.force_encoding(@encoding)
356   end
357 end
parse()

Parse the input character by character, returning an array of parsed (and potentially converted) objects.

[show source]
    # File lib/sequel/extensions/pg_array.rb
361 def parse
362   raise Sequel::Error, "invalid array, empty string" if eos?
363   raise Sequel::Error, "invalid array, doesn't start with {" unless scan(/((\[\d+:\d+\])+=)?\{/)
364 
365   # :nocov:
366   while !eos?
367   # :nocov:
368     char = scan(/[{}",]|[^{}",]+/)
369     if char == ','
370       # Comma outside quoted string indicates end of current entry
371       new_entry
372     elsif char == '"'
373       raise Sequel::Error, "invalid array, opening quote with existing recorded data" unless @recorded.empty?
374       # :nocov:
375       while true
376       # :nocov:
377         char = scan(/["\\]|[^"\\]+/)
378         if char == '\\'
379           @recorded << getch
380         elsif char == '"'
381           n = peek(1)
382           raise Sequel::Error, "invalid array, closing quote not followed by comma or closing brace" unless n == ',' || n == '}'
383           break
384         else
385           @recorded << char
386         end
387       end
388       new_entry(true)
389     elsif char == '{'
390       raise Sequel::Error, "invalid array, opening brace with existing recorded data" unless @recorded.empty?
391 
392       # Start of new array, add it to the stack
393       new = []
394       @stack.last << new
395       @stack << new
396     elsif char == '}'
397       # End of current array, add current entry to the current array
398       new_entry
399 
400       if @stack.length == 1
401         raise Sequel::Error, "array parsing finished without parsing entire string" unless eos?
402 
403         # Top level of array, parsing should be over.
404         # Pop current array off stack and return it as result
405         return @stack.pop
406       else
407         # Nested array, pop current array off stack
408         @stack.pop
409       end
410     else
411       # Add the character to the recorded character buffer.
412       @recorded << char
413     end
414   end
415 
416   raise Sequel::Error, "array parsing finished with array unclosed"
417 end