pg_conn 0.24.0 → 0.26.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/TODO +5 -0
  3. data/lib/pg_conn/version.rb +1 -1
  4. data/lib/pg_conn.rb +75 -13
  5. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 45c913cadea7c545637f0291133fd43f727beef5efe726377c406e720c105d7d
4
- data.tar.gz: 25ed1737f4bba574d02c7d1e1d823957de723f86e2eeca94f9ea8ef6160c191e
3
+ metadata.gz: 4148bbd8c21613249beed07d5248aa71780a8805881afc94899f9f29cd2d452d
4
+ data.tar.gz: 21bea1c8c108a4a135eb1d6936a56995b457db0e8192a17b745d0b3dd1676846
5
5
  SHA512:
6
- metadata.gz: 696866896b4bea3ebec5313398f580581627535ccf7fca01f94f6f7e9a6198ceff7173b81d21d3725d4d7f0ac7118428a0eab2a098d3f360913926c46d460eaf
7
- data.tar.gz: de5d2541d1384bfa7721f7ec3274f1a232b97d9bc08791f6f5a3c5783b19d5a8d65ac25d7d37cea0e47e27fc4391dad4eb0f15f96584875e0ed526d98bb1a520
6
+ metadata.gz: 7cca5aea976d949607b1650e8f00347a22be14907c8296a26379cd804a51f5610bb9786bc21b3b9317496a00ef135564033f276d5e3300dbd4d133b056835a79
7
+ data.tar.gz: 8bcf303b9712c1e6de69c301115c88a53d908aad90c8bce6b8e73e912d6b710772fb88a6bb191bc34142ca29f016845bfbc035cda4670c91d5e3d407ce82907e
data/TODO CHANGED
@@ -1,4 +1,9 @@
1
1
  TODO
2
+ o Add a <fetch>! method
3
+ value? 0 or 1
4
+ value 1
5
+ values 0 or n
6
+ values! 1 or more
2
7
 
3
8
  o Instrumentation of connection object
4
9
 
@@ -1,3 +1,3 @@
1
1
  module PgConn
2
- VERSION = "0.24.0"
2
+ VERSION = "0.26.0"
3
3
  end
data/lib/pg_conn.rb CHANGED
@@ -269,8 +269,8 @@ module PgConn
269
269
  #
270
270
  # The :elem_type option can be a postgres type name (String or Symbol) or
271
271
  # an array of type names. It is used as the required explicit element
272
- # type when the argument is an empty array. The element types shoud be in
273
- # the same order as the array arguments. Nested arrays is not supported
272
+ # type when the argument is an empty array. It is not needed if the array
273
+ # is guaranteed to be non-empty. Nested arrays are not supported
274
274
  #
275
275
  def quote_value(value, elem_type: nil)
276
276
  case value
@@ -294,19 +294,62 @@ module PgConn
294
294
 
295
295
  # Quote values and concatenate them using ',' as separator
296
296
  def quote_values(values, elem_type: nil)
297
- elem_types = Array(elem_type)
298
- values.map { |value|
297
+ values.map { |value| quote_value(value, elem_type: elem_type) }.join(", ")
298
+ end
299
+
300
+ # Quote an array of values as a tuple. The element types should be in the
301
+ # same order as the array arguments. #quote_tuples is same as #quote_values
302
+ # except the values may have different types (this makes no difference
303
+ # except in the case when the tuple may contain empty array(s))
304
+ def quote_tuple(tuple, elem_types: nil)
305
+ elem_types = Array(elem_types)
306
+ tuple.map { |value|
299
307
  elem_type = value.is_a?(Array) ? elem_types&.shift : nil
300
308
  quote_value(value, elem_type: elem_type)
301
309
  }.join(", ")
302
310
  end
303
311
 
304
- # Quote an array of values as a tuple. Just an alias for #quote_values
305
- def quote_tuple(tuple, elem_type: nil) = quote_values(tuple, elem_type: elem_type)
306
-
307
312
  # Quote an array of tuples
308
- def quote_tuples(tuples, elem_type: nil)
309
- tuples.map { |tuple| "(#{quote_values(tuple, elem_type: elem_type)})" }.join(", ")
313
+ def quote_tuples(tuples, elem_types: nil)
314
+ tuples.map { |tuple| "(#{quote_tuple(tuple, elem_types: elem_types)})" }.join(", ")
315
+ end
316
+
317
+ # Quote a record and cast it into the given type, the type can also be a
318
+ # table or view. 'data' is a hash or struct representation of the record
319
+ #
320
+ # Note that the fields are retrived from the database so this method is not
321
+ # as fast as the other quote-methods. It is however very convenient when
322
+ # you're testing and need a composite type because record-quoting can
323
+ # easily become unwieldly
324
+ def quote_record(schema_name = nil, type, data, elem_types: nil)
325
+ qual_name = [schema_name, type].compact .join('.')
326
+
327
+ fields = self.values(%(
328
+ select attname
329
+ from pg_attribute
330
+ where
331
+ attrelid = '#{qual_name}'::regclass
332
+ and attnum > 0
333
+ and not attisdropped
334
+ order by attnum
335
+ )).map(&:to_sym)
336
+
337
+ values =
338
+ case data
339
+ when Hash; fields.map { |f| data[f] }
340
+ when OpenStruct; fields.map { |f| data.send(f) }
341
+ when Array; data
342
+ else
343
+ raise Error, "Illegal value #{data.inspect}"
344
+ end
345
+
346
+ "(#{quote_tuple(values, elem_types: elem_types)})::#{qual_name}"
347
+ end
348
+
349
+ def quote_records(schema_name = nil, type, datas, elem_types: nil)
350
+ qual_name = [schema_name, type].compact .join('.') + "[]"
351
+ records = datas.map { |data| quote_record(schema_name, type, data, elem_types: elem_types) }
352
+ "array[#{records.join(", ")}]::#{qual_name}"
310
353
  end
311
354
 
312
355
  # :call-seq:
@@ -630,7 +673,10 @@ module PgConn
630
673
  #
631
674
  # There is no variant that takes a single tuple because it would then be
632
675
  # impossible to have array or hash field values
633
- def insert(*args)
676
+ def insert(*args, upsert: nil, **opts)
677
+ # Add options to args except the special :upsert option
678
+ args << opts if !opts.empty?
679
+
634
680
  # Add schema (=nil) if absent
635
681
  args.unshift nil if args.size == 2 || (args.size == 3 && args[1].is_a?(Array))
636
682
 
@@ -648,7 +694,7 @@ module PgConn
648
694
 
649
695
  # Find method and normalize data
650
696
  if data.is_a?(Array) # Array of tuples
651
- method = :values
697
+ method = :values # The pg_conn method when multiple records are inserted
652
698
  if data.empty?
653
699
  return []
654
700
  elsif data.first.is_a?(Array) # Tuple (array) element. Requires the 'fields' argument
@@ -661,21 +707,37 @@ module PgConn
661
707
  raise ArgumentError
662
708
  end
663
709
  elsif data.is_a?(Hash)
664
- method = :value
710
+ method = :value # The pg_conn method when only one record is inserted
665
711
  fields ||= data.keys
666
712
  tuples = [fields.map { |field| data[field] }]
667
713
  else
668
- raise ArgumentError
714
+ raise ArgumentError, "Illegal argument '#{data.inspect}'"
669
715
  end
670
716
 
717
+ # On-conflict clause
718
+ upsert_sql =
719
+ case upsert
720
+ when true; "on conflict do nothing"
721
+ when String; "on conlict #{upsert}"
722
+ when false, nil; ""
723
+ else
724
+ raise ArgumentError, "Illegal value for :upsert option: #{upsert.inspect}"
725
+ end
726
+
671
727
  # Execute SQL statement using either :value or :values depending on data arity
672
728
  self.send method, %(
673
729
  insert into #{table} (#{quote_identifiers(fields)})
674
730
  values #{quote_tuples(tuples)}
731
+ #{upsert_sql}
675
732
  returning id
676
733
  )
677
734
  end
678
735
 
736
+ # Use upsert. Currently on 'on conflict do nothing' is supported
737
+ def upsert(*args)
738
+ insert(*args, upsert: true)
739
+ end
740
+
679
741
  # Update record(s)
680
742
  def update(schema = nil, table, expr, hash)
681
743
  table = [schema, table].compact.join(".")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg_conn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.24.0
4
+ version: 0.26.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Claus Rasmussen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-10-07 00:00:00.000000000 Z
11
+ date: 2024-11-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pg