Class: Sequel::Postgres::PGArray::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/sequel/extensions/pg_array.rb

Overview

PostgreSQL array parser that handles both text and numeric input. Because PostgreSQL arrays can contain objects that can be literalized in any number of ways, it is not possible to make a fully generic parser.

This parser is very simple and unoptimized, but should still be O(n) where n is the length of the input string.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source, converter = nil) ⇒ Parser

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.



187
188
189
190
191
192
193
194
195
# File 'lib/sequel/extensions/pg_array.rb', line 187

def initialize(source, converter=nil)
  @source = source
  @source_length = source.length
  @converter = converter 
  @pos = -1
  @entries = []
  @recorded = ""
  @dimension = 0
end

Instance Attribute Details

#posObject (readonly)

Returns the value of attribute pos.



181
182
183
# File 'lib/sequel/extensions/pg_array.rb', line 181

def pos
  @pos
end

Instance Method Details

#new_entry(include_empty = false) ⇒ Object

Take the buffer of recorded characters and add it to the array of entries, and use a new buffer for recorded characters.



216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/sequel/extensions/pg_array.rb', line 216

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
    @entries.push(entry)
    @recorded = ""
  end
end

#next_charObject

Return 2 objects, whether the next character in the input was escaped with a backslash, and what the next character is.



199
200
201
202
203
204
205
206
207
# File 'lib/sequel/extensions/pg_array.rb', line 199

def next_char
  @pos += 1
  if (c = @source[@pos..@pos]) == BACKSLASH
    @pos += 1
    [true, @source[@pos..@pos]]
  else
    [false, c]
  end
end

#parse(nested = false) ⇒ Object

Parse the input character by character, returning an array of parsed (and potentially converted) objects.

Raises:



231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/sequel/extensions/pg_array.rb', line 231

def parse(nested=false)
  # quote sets whether we are inside of a quoted string.
  quote = false
  until @pos >= @source_length
    escaped, char = next_char
    if char == OPEN_BRACE && !quote
      @dimension += 1
      if (@dimension > 1)
        # Multi-dimensional array encounter, use a subparser
        # to parse the next level down.
        subparser = self.class.new(@source[@pos..-1], @converter)
        @entries.push(subparser.parse(true))
        @pos += subparser.pos - 1
      end
    elsif char == CLOSE_BRACE && !quote
      @dimension -= 1
      if (@dimension == 0)
        new_entry
        # Exit early if inside a subparser, since the
        # text after parsing the current level should be
        # ignored as it is handled by the parent parser.
        return @entries if nested
      end
    elsif char == QUOTE && !escaped
      # If already inside the quoted string, this is the
      # ending quote, so add the entry.  Otherwise, this
      # is the opening quote, so set the quote flag.
      new_entry(true) if quote
      quote = !quote
    elsif char == COMMA && !quote
      # If not inside a string and a comma occurs, it indicates
      # the end of the entry, so add the entry.
      new_entry
    else
      # Add the character to the recorded character buffer.
      record(char)
    end
  end
  raise Sequel::Error, "array dimensions not balanced" unless @dimension == 0
  @entries
end

#record(c) ⇒ Object

Add a new character to the buffer of recorded characters.



210
211
212
# File 'lib/sequel/extensions/pg_array.rb', line 210

def record(c)
  @recorded << c
end