Module: StickyElephant::PostgresProtocol

Included in:
PostgresSimulator
Defined in:
lib/sticky_elephant/postgres_protocol.rb

Constant Summary collapse

READY_FOR_QUERY_STATUSES =
{ idle: 'I', transaction: 'T', failed: 'E' }.freeze
COMMAND_COMPLETE_COMMANDS =
%i(insert delete update select move fetch copy create).freeze

Instance Method Summary collapse

Instance Method Details

#command_complete(sym, num) ⇒ Object



15
16
17
18
19
20
21
22
23
24
# File 'lib/sticky_elephant/postgres_protocol.rb', line 15

def command_complete(sym, num)
  unless COMMAND_COMPLETE_COMMANDS.include?(sym)
    raise ArgumentError.new("#{sym} not in #{COMMAND_COMPLETE_COMMANDS}")
  end
  sym = :select if sym == :create
  (
   ["C".ord ] +
   with_length("#{sym.to_s.upcase} #{num}\x00")
  ).pack("C*")
end

#data_row(*rows) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/sticky_elephant/postgres_protocol.rb', line 26

def data_row(*rows)
  results_block = rows.flat_map do |row|
    (int32_bytes(row.length) + row.bytes)
  end

  (
    [ "D".ord ] +
    with_length(
      int16_bytes(rows.count) +
      results_block
    )
  ).pack("C*")
end

#int16_bytes(num) ⇒ Object



69
70
71
# File 'lib/sticky_elephant/postgres_protocol.rb', line 69

def int16_bytes(num)
  [num].pack("n").unpack("C*")
end

#int32_bytes(num) ⇒ Object



65
66
67
# File 'lib/sticky_elephant/postgres_protocol.rb', line 65

def int32_bytes(num)
  [num].pack("N").unpack("C*")
end

#ready_for_query(sym) ⇒ Object



4
5
6
7
8
9
10
11
12
# File 'lib/sticky_elephant/postgres_protocol.rb', line 4

def ready_for_query(sym)
  unless READY_FOR_QUERY_STATUSES.include?(sym)
    raise ArgumentError.new("#{sym} not in #{READY_FOR_QUERY_STATUSES}")
  end
  (
    [ 'Z'.ord ] +
    with_length(READY_FOR_QUERY_STATUSES.fetch(sym))
  ).pack('C*')
end

#row_description(*rows) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/sticky_elephant/postgres_protocol.rb', line 40

def row_description(*rows)
  fields_block = rows.map do |row|
    row + "\x00" +    # str   Field name
      ("\x00" * 4) + # int32 If column of specific table, object ID of table;  else zero.
      ("\x00" * 2) + # int16 If column of specific table, attribute# of column; else zero.
      ("\x00\x00\x00\x19") + # int32 Object ID of field's data type
      ("\xFF\xFF") + # int16 Data type size
      ("\xFF\xFF\xFF\xFF") + # int32 Type modifier
      ("\x00\x00")   # int16 Format code: 0 for text, 1 for binary
  end.join.bytes
  num_fields = int16_bytes(rows.count)
  (
    ['T'.ord ] + # byte - message
    with_length(num_fields + fields_block)
  ).pack("C*")
end

#with_length(obj) ⇒ Object

Raises:

  • (ArgumentError)


57
58
59
60
61
62
63
# File 'lib/sticky_elephant/postgres_protocol.rb', line 57

def with_length(obj)
  bytes = obj.respond_to?(:bytes) ? obj.bytes : obj
  raise ArgumentError.new("Must be an array or respond to #bytes") unless bytes.is_a?(Array)

  length = 4 + bytes.size
  int32_bytes(length) + bytes
end