pg-hstore 1.1.6 → 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. data/lib/pg_hstore.rb +69 -26
  2. metadata +5 -3
@@ -1,19 +1,25 @@
1
1
  module PgHstore
2
2
  SINGLE_QUOTE = "'"
3
+ E_SINGLE_QUOTE = "E'"
3
4
  DOUBLE_QUOTE = '"'
4
- DOLLAR_QUOTE = '$$' # TODO not infallible
5
5
  HASHROCKET = '=>'
6
6
  COMMA = ','
7
+ SLASH = '\\'
8
+
9
+ ESCAPED_CHAR = /\\(.)/
10
+ ESCAPED_SINGLE_QUOTE = '\\\''
11
+ ESCAPED_DOUBLE_QUOTE = '\\"'
12
+ ESCAPED_SLASH = '\\\\'
7
13
 
8
14
  QUOTED_LITERAL = /"[^"\\]*(?:\\.[^"\\]*)*"/
9
15
  UNQUOTED_LITERAL = /[^\s=,][^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
10
16
  LITERAL = /(#{QUOTED_LITERAL}|#{UNQUOTED_LITERAL})/
11
17
  PAIR = /#{LITERAL}\s*=>\s*#{LITERAL}/
12
18
  NULL = /\ANULL\z/i
19
+
13
20
  # set symbolize_keys = false if you want string keys
14
21
  # thanks to https://github.com/engageis/activerecord-postgres-hstore for regexps!
15
22
  def PgHstore.load(hstore, symbolize_keys = true)
16
- hstore = unquote hstore, DOLLAR_QUOTE
17
23
  hstore.scan(PAIR).inject({}) do |memo, (k, v)|
18
24
  k = unescape unquote(k, DOUBLE_QUOTE)
19
25
  k = k.to_sym if symbolize_keys
@@ -23,22 +29,28 @@ module PgHstore
23
29
  end
24
30
  end
25
31
 
26
- # set for_parameter = true if you're using the output for a bind variable
27
- def PgHstore.dump(hash, for_parameter = false)
28
- memo = hash.map do |k, v|
29
- if v.nil?
30
- v = "NULL"
31
- else
32
- v = DOUBLE_QUOTE + escape(v) + DOUBLE_QUOTE
33
- end
34
- k = DOUBLE_QUOTE + escape(k) + DOUBLE_QUOTE
35
- [k, v].join HASHROCKET
36
- end.join COMMA
37
- if for_parameter
38
- memo
39
- else
40
- DOLLAR_QUOTE + memo + DOLLAR_QUOTE
41
- end
32
+ # Serialize a hash to be sent to PostgreSQL as an hstore value.
33
+ #
34
+ # By default, returns a (Postgre)SQL string constant suitable for
35
+ # interpolating directly into a query. With raw_string = true,
36
+ # returns the plain string value suitable for use as a bind variable.
37
+ def PgHstore.dump(hash, raw_string = false)
38
+ # Per http://www.postgresql.org/docs/9.2/static/hstore.html :
39
+ #
40
+ # The text representation of an hstore, used for input and
41
+ # output, includes zero or more 'key => value' pairs separated
42
+ # by commas. [...] Whitespace between pairs or around the =>
43
+ # sign is ignored. Double-quote keys and values [... see
44
+ # escape_nonnull_for_hstore ...]
45
+ #
46
+ # A value (but not a key) can be an SQL NULL. Double-quote the
47
+ # NULL to treat it as the ordinary string "NULL".
48
+ hstore = hash.map do |k, v|
49
+ hstore_k = escape_nonnull_for_hstore(k)
50
+ hstore_v = (v.nil?) ? "NULL" : escape_nonnull_for_hstore(v)
51
+ [hstore_k, hstore_v].join(HASHROCKET)
52
+ end.join(COMMA)
53
+ raw_string ? hstore : as_postgresql_string_constant(hstore)
42
54
  end
43
55
 
44
56
  class << self
@@ -57,16 +69,47 @@ module PgHstore
57
69
  end
58
70
  end
59
71
 
60
- ESCAPED_CHAR = /\\(.)/
61
72
  def PgHstore.unescape(literal)
62
73
  literal.gsub ESCAPED_CHAR, '\1'
63
74
  end
64
-
65
- NON_ESCAPE_SLASH = '\\'
66
- ESCAPED_SLASH = '\\\\'
67
- ESCAPED_DOUBLE_QUOTE = '\"'
68
- def PgHstore.escape(string)
69
- string.to_s.gsub(NON_ESCAPE_SLASH) {ESCAPED_SLASH}.gsub DOUBLE_QUOTE, ESCAPED_DOUBLE_QUOTE
75
+
76
+ # Escape a value as a string to use as an hstore key or value.
77
+ #
78
+ # Per http://www.postgresql.org/docs/9.2/static/hstore.html :
79
+ #
80
+ # Double-quote keys and values that include [stuff]. To include a
81
+ # double quote or a backslash in a key or value, escape it with a
82
+ # backslash.
83
+ #
84
+ # You got it, boss.
85
+ def PgHstore.escape_nonnull_for_hstore(string)
86
+ interior = string.to_s.dup
87
+ interior.gsub!(SLASH) {ESCAPED_SLASH}
88
+ interior.gsub!(DOUBLE_QUOTE, ESCAPED_DOUBLE_QUOTE)
89
+ DOUBLE_QUOTE + interior + DOUBLE_QUOTE
70
90
  end
71
- end
72
91
 
92
+ # Escape a string as a string constant to be used in a SQL query
93
+ # to PostgreSQL.
94
+ #
95
+ # Ideally we would use plain SQL string constants, which are very simple:
96
+ # http://www.postgresql.org/docs/9.2/static/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS
97
+ # Unfortunately PostgreSQL treats these differently depending on the
98
+ # variable standard_conforming_strings, which defaulted to off until 9.1.
99
+ # It doesn't seem possible to generate them correctly for both cases at
100
+ # once, and trying to know the value of that variable and dispatch on it
101
+ # would be awful.
102
+ #
103
+ # Instead, use the slightly more cumbersome "escape" string constants:
104
+ # http://www.postgresql.org/docs/9.2/static/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-ESCAPE
105
+ # They're a little uglier and they're PostgreSQL-specific, but nobody has
106
+ # to see them and this whole module is PostgreSQL-specific. And, crucially,
107
+ # their behavior doesn't vary. Not allowing injection attacks: priceless.
108
+ # We don't use any of the fancy escapes, just neuter any backslashes and quotes.
109
+ def PgHstore.as_postgresql_string_constant(string)
110
+ interior = string.to_s.dup
111
+ interior.gsub!(SLASH) {ESCAPED_SLASH}
112
+ interior.gsub!(SINGLE_QUOTE) {ESCAPED_SINGLE_QUOTE}
113
+ E_SINGLE_QUOTE + interior + SINGLE_QUOTE
114
+ end
115
+ end
metadata CHANGED
@@ -1,16 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg-hstore
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.6
4
+ version: 1.1.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Peter van Hardenberg
9
9
  - Seamus Abshere
10
+ - Greg Price
10
11
  autorequire:
11
12
  bindir: bin
12
13
  cert_chain: []
13
- date: 2013-02-07 00:00:00.000000000 Z
14
+ date: 2013-02-20 00:00:00.000000000 Z
14
15
  dependencies:
15
16
  - !ruby/object:Gem::Dependency
16
17
  name: rspec
@@ -77,6 +78,7 @@ rubyforge_project:
77
78
  rubygems_version: 1.8.25
78
79
  signing_key:
79
80
  specification_version: 3
80
- summary: ''
81
+ summary: postgresql hstore parser/deparser - provides PgHstore.dump and PgHstore.load
82
+ (aka parse)
81
83
  test_files: []
82
84
  has_rdoc: