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