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
337 def initialize(source, converter=nil)
338   super(source)
339   @converter = converter 
340   @stack = [[]]
341   @encoding = string.encoding
342   @recorded = String.new.force_encoding(@encoding)
343 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
347 def new_entry(include_empty=false)
348   if !@recorded.empty? || include_empty
349     entry = @recorded
350     if entry == 'NULL' && !include_empty
351       entry = nil
352     elsif @converter
353       entry = @converter.call(entry)
354     end
355     @stack.last.push(entry)
356     @recorded = String.new.force_encoding(@encoding)
357   end
358 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
362 def parse
363   raise Sequel::Error, "invalid array, empty string" if eos?
364   raise Sequel::Error, "invalid array, doesn't start with {" unless scan(/((\[\d+:\d+\])+=)?\{/)
365 
366   # simplecov:disable
367   while !eos?
368   # simplecov:enable
369     char = scan(/[{}",]|[^{}",]+/)
370     if char == ','
371       # Comma outside quoted string indicates end of current entry
372       new_entry
373     elsif char == '"'
374       raise Sequel::Error, "invalid array, opening quote with existing recorded data" unless @recorded.empty?
375       # simplecov:disable
376       while true
377       # simplecov:enable
378         char = scan(/["\\]|[^"\\]+/)
379         if char == '\\'
380           @recorded << getch
381         elsif char == '"'
382           n = peek(1)
383           raise Sequel::Error, "invalid array, closing quote not followed by comma or closing brace" unless n == ',' || n == '}'
384           break
385         else
386           @recorded << char
387         end
388       end
389       new_entry(true)
390     elsif char == '{'
391       raise Sequel::Error, "invalid array, opening brace with existing recorded data" unless @recorded.empty?
392 
393       raise Sequel::Error, "cannot parse array with more than 6 dimensions" if @stack.length >= 6
394       # Start of new array, add it to the stack
395       new = []
396       @stack.last << new
397       @stack << new
398     elsif char == '}'
399       # End of current array, add current entry to the current array
400       new_entry
401 
402       if @stack.length == 1
403         raise Sequel::Error, "array parsing finished without parsing entire string" unless eos?
404 
405         # Top level of array, parsing should be over.
406         # Pop current array off stack and return it as result
407         return @stack.pop
408       else
409         # Nested array, pop current array off stack
410         @stack.pop
411       end
412     else
413       # Add the character to the recorded character buffer.
414       @recorded << char
415     end
416   end
417 
418   raise Sequel::Error, "array parsing finished with array unclosed"
419 end