| Class | Sequel::Postgres::PGArray::Parser |
| In: |
lib/sequel/extensions/pg_array.rb
|
| Parent: | Object |
PostgreSQL array parser that handles all types of input.
This parser is very simple and unoptimized, but should still be O(n) where n is the length of the input string.
| pos | [R] | Current position in the input string. |
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.
# File lib/sequel/extensions/pg_array.rb, line 362
362: def initialize(source, converter=nil)
363: @source = source
364: @source_length = source.length
365: @converter = converter
366: @pos = -1
367: @entries = []
368: @recorded = ""
369: @dimension = 0
370: end
Take the buffer of recorded characters and add it to the array of entries, and use a new buffer for recorded characters.
# File lib/sequel/extensions/pg_array.rb, line 391
391: def new_entry(include_empty=false)
392: if !@recorded.empty? || include_empty
393: entry = @recorded
394: if entry == NULL && !include_empty
395: entry = nil
396: elsif @converter
397: entry = @converter.call(entry)
398: end
399: @entries.push(entry)
400: @recorded = ""
401: end
402: end
Return 2 objects, whether the next character in the input was escaped with a backslash, and what the next character is.
# File lib/sequel/extensions/pg_array.rb, line 374
374: def next_char
375: @pos += 1
376: if (c = @source[@pos..@pos]) == BACKSLASH
377: @pos += 1
378: [true, @source[@pos..@pos]]
379: else
380: [false, c]
381: end
382: end
Parse the input character by character, returning an array of parsed (and potentially converted) objects.
# File lib/sequel/extensions/pg_array.rb, line 406
406: def parse(nested=false)
407: # quote sets whether we are inside of a quoted string.
408: quote = false
409: until @pos >= @source_length
410: escaped, char = next_char
411: if char == OPEN_BRACE && !quote
412: @dimension += 1
413: if (@dimension > 1)
414: # Multi-dimensional array encounter, use a subparser
415: # to parse the next level down.
416: subparser = self.class.new(@source[@pos..-1], @converter)
417: @entries.push(subparser.parse(true))
418: @pos += subparser.pos - 1
419: end
420: elsif char == CLOSE_BRACE && !quote
421: @dimension -= 1
422: if (@dimension == 0)
423: new_entry
424: # Exit early if inside a subparser, since the
425: # text after parsing the current level should be
426: # ignored as it is handled by the parent parser.
427: return @entries if nested
428: end
429: elsif char == QUOTE && !escaped
430: # If already inside the quoted string, this is the
431: # ending quote, so add the entry. Otherwise, this
432: # is the opening quote, so set the quote flag.
433: new_entry(true) if quote
434: quote = !quote
435: elsif char == COMMA && !quote
436: # If not inside a string and a comma occurs, it indicates
437: # the end of the entry, so add the entry.
438: new_entry
439: else
440: # Add the character to the recorded character buffer.
441: record(char)
442: end
443: end
444: raise Sequel::Error, "array dimensions not balanced" unless @dimension == 0
445: @entries
446: end