pg_conn 0.24.0 → 0.26.0

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 (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