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
315 def initialize(source, converter=nil)
316   super(source)
317   @converter = converter 
318   @stack = [[]]
319   @encoding = string.encoding
320   @recorded = String.new.force_encoding(@encoding)
321 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
325 def new_entry(include_empty=false)
326   if !@recorded.empty? || include_empty
327     entry = @recorded
328     if entry == 'NULL' && !include_empty
329       entry = nil
330     elsif @converter
331       entry = @converter.call(entry)
332     end
333     @stack.last.push(entry)
334     @recorded = String.new.force_encoding(@encoding)
335   end
336 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
340 def parse
341   raise Sequel::Error, "invalid array, empty string" if eos?
342   raise Sequel::Error, "invalid array, doesn't start with {" unless scan(/((\[\d+:\d+\])+=)?\{/)
343 
344   # :nocov:
345   while !eos?
346   # :nocov:
347     char = scan(/[{}",]|[^{}",]+/)
348     if char == ','
349       # Comma outside quoted string indicates end of current entry
350       new_entry
351     elsif char == '"'
352       raise Sequel::Error, "invalid array, opening quote with existing recorded data" unless @recorded.empty?
353       # :nocov:
354       while true
355       # :nocov:
356         char = scan(/["\\]|[^"\\]+/)
357         if char == '\\'
358           @recorded << getch
359         elsif char == '"'
360           n = peek(1)
361           raise Sequel::Error, "invalid array, closing quote not followed by comma or closing brace" unless n == ',' || n == '}'
362           break
363         else
364           @recorded << char
365         end
366       end
367       new_entry(true)
368     elsif char == '{'
369       raise Sequel::Error, "invalid array, opening brace with existing recorded data" unless @recorded.empty?
370 
371       # Start of new array, add it to the stack
372       new = []
373       @stack.last << new
374       @stack << new
375     elsif char == '}'
376       # End of current array, add current entry to the current array
377       new_entry
378 
379       if @stack.length == 1
380         raise Sequel::Error, "array parsing finished without parsing entire string" unless eos?
381 
382         # Top level of array, parsing should be over.
383         # Pop current array off stack and return it as result
384         return @stack.pop
385       else
386         # Nested array, pop current array off stack
387         @stack.pop
388       end
389     else
390       # Add the character to the recorded character buffer.
391       @recorded << char
392     end
393   end
394 
395   raise Sequel::Error, "array parsing finished with array unclosed"
396 end