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.

Instance Method Summary collapse

Constructor Details

#initialize(source, converter = nil) ⇒ Parser

Returns a new instance of Parser



300
301
302
303
304
305
306
# File 'lib/sequel/extensions/pg_array.rb', line 300

def initialize(source, converter=nil)
  super(source)
  @converter = converter 
  @stack = [[]]
  @encoding = string.encoding
  @recorded = String.new.force_encoding(@encoding)
end

Instance Method Details

#new_entry(include_empty = false) ⇒ Object



310
311
312
313
314
315
316
317
318
319
320
321
# File 'lib/sequel/extensions/pg_array.rb', line 310

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 = String.new.force_encoding(@encoding)
  end
end

#parseObject

Raises:



325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
# File 'lib/sequel/extensions/pg_array.rb', line 325

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