sequel 5.107.0 → 5.109.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 (147) hide show
  1. checksums.yaml +4 -4
  2. data/bin/sequel +5 -5
  3. data/lib/sequel/adapters/ado.rb +1 -1
  4. data/lib/sequel/adapters/amalgalite.rb +34 -8
  5. data/lib/sequel/adapters/ibmdb.rb +2 -2
  6. data/lib/sequel/adapters/jdbc/hsqldb.rb +1 -1
  7. data/lib/sequel/adapters/jdbc/mssql.rb +28 -5
  8. data/lib/sequel/adapters/jdbc/mysql.rb +1 -1
  9. data/lib/sequel/adapters/jdbc/postgresql.rb +14 -3
  10. data/lib/sequel/adapters/jdbc.rb +4 -3
  11. data/lib/sequel/adapters/mock.rb +1 -1
  12. data/lib/sequel/adapters/mysql.rb +7 -2
  13. data/lib/sequel/adapters/mysql2.rb +5 -4
  14. data/lib/sequel/adapters/postgres.rb +42 -39
  15. data/lib/sequel/adapters/shared/db2.rb +5 -2
  16. data/lib/sequel/adapters/shared/mssql.rb +11 -5
  17. data/lib/sequel/adapters/shared/mysql.rb +2 -2
  18. data/lib/sequel/adapters/shared/postgres.rb +80 -1028
  19. data/lib/sequel/adapters/shared/sqlanywhere.rb +0 -32
  20. data/lib/sequel/adapters/shared/sqlite.rb +3 -3
  21. data/lib/sequel/adapters/sqlite.rb +13 -9
  22. data/lib/sequel/adapters/trilogy.rb +2 -1
  23. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +1 -1
  24. data/lib/sequel/adapters/utils/mysql_mysql2.rb +11 -1
  25. data/lib/sequel/connection_pool/sharded_single.rb +1 -1
  26. data/lib/sequel/connection_pool/sharded_threaded.rb +7 -5
  27. data/lib/sequel/connection_pool/sharded_timed_queue.rb +3 -3
  28. data/lib/sequel/connection_pool/threaded.rb +9 -7
  29. data/lib/sequel/connection_pool/timed_queue.rb +2 -2
  30. data/lib/sequel/connection_pool.rb +3 -3
  31. data/lib/sequel/core.rb +44 -24
  32. data/lib/sequel/database/connecting.rb +1 -1
  33. data/lib/sequel/database/features.rb +1 -1
  34. data/lib/sequel/database/misc.rb +6 -11
  35. data/lib/sequel/database/query.rb +2 -2
  36. data/lib/sequel/database/schema_generator.rb +4 -4
  37. data/lib/sequel/database/schema_methods.rb +2 -2
  38. data/lib/sequel/database/transactions.rb +5 -7
  39. data/lib/sequel/dataset/actions.rb +2 -2
  40. data/lib/sequel/dataset/features.rb +4 -4
  41. data/lib/sequel/dataset/graph.rb +1 -1
  42. data/lib/sequel/dataset/misc.rb +3 -3
  43. data/lib/sequel/dataset/prepared_statements.rb +2 -2
  44. data/lib/sequel/dataset/query.rb +8 -8
  45. data/lib/sequel/dataset/sql.rb +32 -13
  46. data/lib/sequel/dataset.rb +2 -2
  47. data/lib/sequel/deprecated.rb +2 -2
  48. data/lib/sequel/exceptions.rb +2 -2
  49. data/lib/sequel/extensions/_pretty_table.rb +1 -1
  50. data/lib/sequel/extensions/async_thread_pool.rb +3 -3
  51. data/lib/sequel/extensions/auto_cast_date_and_time.rb +2 -2
  52. data/lib/sequel/extensions/blank.rb +2 -2
  53. data/lib/sequel/extensions/constraint_validations.rb +1 -1
  54. data/lib/sequel/extensions/core_refinements.rb +7 -10
  55. data/lib/sequel/extensions/date_arithmetic.rb +1 -1
  56. data/lib/sequel/extensions/datetime_parse_to_time.rb +2 -2
  57. data/lib/sequel/extensions/duplicate_columns_handler.rb +1 -3
  58. data/lib/sequel/extensions/graph_each.rb +1 -1
  59. data/lib/sequel/extensions/index_caching.rb +1 -1
  60. data/lib/sequel/extensions/inflector.rb +5 -5
  61. data/lib/sequel/extensions/is_distinct_from.rb +2 -2
  62. data/lib/sequel/extensions/lit_require_frozen.rb +20 -4
  63. data/lib/sequel/extensions/migration.rb +21 -7
  64. data/lib/sequel/extensions/named_timezones.rb +9 -9
  65. data/lib/sequel/extensions/pg_array.rb +10 -8
  66. data/lib/sequel/extensions/pg_array_ops.rb +69 -14
  67. data/lib/sequel/extensions/pg_auto_parameterize.rb +2 -2
  68. data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +3 -3
  69. data/lib/sequel/extensions/pg_enum.rb +2 -2
  70. data/lib/sequel/extensions/pg_extended_date_support.rb +5 -5
  71. data/lib/sequel/extensions/pg_extended_integer_support.rb +1 -1
  72. data/lib/sequel/extensions/pg_hstore.rb +2 -2
  73. data/lib/sequel/extensions/pg_hstore_ops.rb +5 -5
  74. data/lib/sequel/extensions/pg_inet.rb +2 -2
  75. data/lib/sequel/extensions/pg_inet_ops.rb +2 -2
  76. data/lib/sequel/extensions/pg_interval.rb +6 -6
  77. data/lib/sequel/extensions/pg_json.rb +4 -4
  78. data/lib/sequel/extensions/pg_json_ops.rb +15 -13
  79. data/lib/sequel/extensions/pg_range.rb +6 -6
  80. data/lib/sequel/extensions/pg_range_ops.rb +7 -7
  81. data/lib/sequel/extensions/pg_row.rb +4 -4
  82. data/lib/sequel/extensions/pg_row_ops.rb +6 -6
  83. data/lib/sequel/extensions/provenance.rb +2 -2
  84. data/lib/sequel/extensions/query.rb +2 -2
  85. data/lib/sequel/extensions/s.rb +6 -10
  86. data/lib/sequel/extensions/schema_dumper.rb +10 -6
  87. data/lib/sequel/extensions/sequel_4_dataset_methods.rb +2 -0
  88. data/lib/sequel/extensions/sql_comments.rb +1 -1
  89. data/lib/sequel/extensions/sql_log_normalizer.rb +1 -1
  90. data/lib/sequel/extensions/sqlite_json_ops.rb +2 -2
  91. data/lib/sequel/extensions/string_agg.rb +5 -5
  92. data/lib/sequel/extensions/symbol_aref.rb +12 -32
  93. data/lib/sequel/extensions/symbol_aref_refinement.rb +2 -5
  94. data/lib/sequel/extensions/symbol_as.rb +1 -2
  95. data/lib/sequel/extensions/symbol_as_refinement.rb +1 -5
  96. data/lib/sequel/extensions/transaction_connection_validator.rb +1 -1
  97. data/lib/sequel/model/associations.rb +17 -17
  98. data/lib/sequel/model/base.rb +18 -15
  99. data/lib/sequel/model/inflections.rb +1 -1
  100. data/lib/sequel/model/plugins.rb +2 -2
  101. data/lib/sequel/model.rb +2 -2
  102. data/lib/sequel/plugins/association_pks.rb +1 -1
  103. data/lib/sequel/plugins/association_proxies.rb +4 -4
  104. data/lib/sequel/plugins/auto_restrict_eager_graph.rb +2 -0
  105. data/lib/sequel/plugins/caching.rb +28 -3
  106. data/lib/sequel/plugins/class_table_inheritance.rb +1 -1
  107. data/lib/sequel/plugins/column_encryption.rb +10 -10
  108. data/lib/sequel/plugins/concurrent_eager_loading.rb +2 -2
  109. data/lib/sequel/plugins/csv_serializer.rb +9 -20
  110. data/lib/sequel/plugins/deprecated_associations.rb +2 -2
  111. data/lib/sequel/plugins/eager_each.rb +1 -1
  112. data/lib/sequel/plugins/finder.rb +1 -1
  113. data/lib/sequel/plugins/forbid_lazy_load.rb +3 -3
  114. data/lib/sequel/plugins/insert_conflict.rb +1 -1
  115. data/lib/sequel/plugins/insert_returning_select.rb +1 -1
  116. data/lib/sequel/plugins/instance_filters.rb +8 -0
  117. data/lib/sequel/plugins/instance_hooks.rb +19 -0
  118. data/lib/sequel/plugins/json_serializer.rb +4 -4
  119. data/lib/sequel/plugins/lazy_attributes.rb +1 -1
  120. data/lib/sequel/plugins/many_through_many.rb +1 -1
  121. data/lib/sequel/plugins/mssql_optimistic_locking.rb +9 -0
  122. data/lib/sequel/plugins/optimistic_locking.rb +12 -2
  123. data/lib/sequel/plugins/optimistic_locking_base.rb +14 -0
  124. data/lib/sequel/plugins/pg_array_associations.rb +4 -4
  125. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +3 -3
  126. data/lib/sequel/plugins/pg_eager_any_typed_array.rb +2 -2
  127. data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +11 -2
  128. data/lib/sequel/plugins/prepared_statements.rb +2 -2
  129. data/lib/sequel/plugins/select_on_skipped_update.rb +63 -0
  130. data/lib/sequel/plugins/serialization.rb +1 -1
  131. data/lib/sequel/plugins/sharding.rb +1 -1
  132. data/lib/sequel/plugins/single_table_inheritance.rb +21 -3
  133. data/lib/sequel/plugins/skip_saving_columns.rb +2 -2
  134. data/lib/sequel/plugins/split_values.rb +1 -1
  135. data/lib/sequel/plugins/sql_comments.rb +8 -8
  136. data/lib/sequel/plugins/subclasses.rb +6 -6
  137. data/lib/sequel/plugins/subset_conditions.rb +5 -16
  138. data/lib/sequel/plugins/tactical_eager_loading.rb +1 -1
  139. data/lib/sequel/plugins/throw_failures.rb +3 -3
  140. data/lib/sequel/plugins/unused_associations.rb +5 -5
  141. data/lib/sequel/plugins/validate_associated.rb +7 -1
  142. data/lib/sequel/plugins/validate_associated_context.rb +52 -0
  143. data/lib/sequel/plugins/validation_helpers.rb +1 -1
  144. data/lib/sequel/plugins/xml_serializer.rb +2 -0
  145. data/lib/sequel/sql.rb +120 -116
  146. data/lib/sequel/version.rb +1 -1
  147. metadata +5 -3
@@ -204,12 +204,12 @@ module Sequel
204
204
  @in = v
205
205
  end
206
206
 
207
- # Assumes hash partitioning, sets the modulus for this parition.
207
+ # Assumes hash partitioning, sets the modulus for this partition.
208
208
  def modulus(v)
209
209
  @modulus = v
210
210
  end
211
211
 
212
- # Assumes hash partitioning, sets the remainder for this parition.
212
+ # Assumes hash partitioning, sets the remainder for this partition.
213
213
  def remainder(v)
214
214
  @remainder = v
215
215
  end
@@ -256,564 +256,6 @@ module Sequel
256
256
  end
257
257
  end
258
258
 
259
- module PropertyGraph
260
- # Base class for all Generator DSL classes. This uses a design where
261
- # The DSL class is only used for the evaluation of the block, and new
262
- # returns a frozen struct.
263
- class Generator
264
- # Instead of returning the Generator instance, return a frozen struct
265
- # with data from the generator. This prevents accidentally calling the
266
- # generator methods, and makes it possible for the generator class and
267
- # result class to use the same method name in two different ways, with
268
- # the generator setting data and the frozen struct method returning it.
269
- # The frozen struct classes use the constant Data under each generator
270
- # subclass.
271
- def self.new(*args, &block)
272
- super(*args, &block).data
273
- end
274
-
275
- # Base class for Vertex and Edge.
276
- class Element < self
277
- Data = Struct.new(:name, :key, :labels)
278
-
279
- # +name+ specifies the name of the vertex or edge. It can be an
280
- # SQL::AliasedExpression to use an alias. Options:
281
- # :properties :: Specifies fixed properties for the vertex or edge.
282
- # If this is given, you cannot use the label method
283
- # inside the block.
284
- def initialize(name, opts=OPTS, &block)
285
- @name = name
286
- @labels = []
287
- if opts.key?(:properties)
288
- @labels << [nil, opts[:properties]].freeze
289
- @labels.freeze
290
- end
291
- instance_exec(&block) if block
292
- @labels.freeze
293
- freeze
294
- end
295
-
296
- def data
297
- Data.new(@name, @key, @labels).freeze
298
- end
299
-
300
- # Set the column(s) to use for the KEY clause, which are the columns
301
- # that uniquely identify rows in the table:
302
- #
303
- # key(:id)
304
- # # KEY (id)
305
- #
306
- # key([:id1, :id2])
307
- # # KEY (id1, id2)
308
- def key(columns)
309
- @key = Array(columns)
310
- end
311
-
312
- # Add a label and properties for the label for this vertex/edge.
313
- # A vertex or edge can have multiple labels with separate properties,
314
- # if it wasn't created with fixed properties. The +name+ argument
315
- # specifies the label name. The +properties+ argument specifies the
316
- # properties:
317
- # nil, :all :: PROPERTIES ALL COLUMNS
318
- # false, :none, [] :: NO PROPERTIES
319
- # Array :: Array of specific properties. Each element should be a Symbol,
320
- # SQL::Identifier, or SQL::AliasedExpression.
321
- #
322
- # label(:label_name)
323
- # # LABEL label_name PROPERTIES ALL COLUMNS
324
- #
325
- # label(:label_name, [])
326
- # # LABEL label_name NO PROPERTIES
327
- #
328
- # label(:label_name, [:c, Sequel[:b].as(:d)], Sequel[:e])
329
- # # LABEL label_name PROPERTIES (c, b AS d, e)
330
- def label(name, properties=:all)
331
- if @labels.frozen?
332
- raise Error, "cannot specify label for property graph vertex or edge with fixed properties"
333
- end
334
- @labels << [name, properties].freeze
335
- nil
336
- end
337
- end
338
-
339
- # Vertex is used for the block passed to Create#vertex, used to configure
340
- # vertices in the property graph. It doesn't have any additional behavior
341
- # compared to the Element class, so this is an alias instead of a subclass.
342
- Vertex = Element
343
-
344
- # Target is used for the block passed to Edge#source and Edge#destination,
345
- # used to configure the source and destination of property graph edges.
346
- class Target < self
347
- Data = Struct.new(:name, :key, :references)
348
-
349
- # +name+ specifies the name of the source or destination.
350
- def initialize(name, &block)
351
- @name = name
352
- @key = nil
353
- @references = nil
354
- instance_exec(&block) if block
355
- freeze
356
- end
357
-
358
- def data
359
- Data.new(@name, @key, @references).freeze
360
- end
361
-
362
- # Set the column(s) to use for the KEY clause, which are the columns
363
- # in the edge table that reference columns in the source or destination.
364
- # Should be combined with #references to specify the columns being
365
- # referenced.
366
- #
367
- # key(:vertex_id)
368
- # # KEY (vertex_id)
369
- #
370
- # key([:vertex_id1, :vertex_id2])
371
- # # KEY (vertex_id1, vertex_id2)
372
- def key(keys)
373
- @key = Array(keys)
374
- end
375
-
376
- # Set the column(s) to use for the REFERENCES clause, which are the columns
377
- # in the source or destination table that are referenced by the edge table.
378
- # Should be combined with #key to specify the columns doing the referencing.
379
- #
380
- # references(:id)
381
- # # REFERENCES (id)
382
- #
383
- # references([:id1, :id2])
384
- # # REFERENCES (id1, id2)
385
- def references(refs)
386
- @references = Array(refs)
387
- end
388
- end
389
-
390
- # Edge is used for block passed to Create#edge, used to configure edges
391
- # in the property graph.
392
- class Edge < Element
393
- Data = Struct.new(:name, :key, :labels, :source, :destination)
394
-
395
- # In addition to inherited behavior, raises an error if a block
396
- # is not passed or source or destination is not called in the block.
397
- def initialize(name, opts=OPTS, &block)
398
- super
399
-
400
- unless @source && @destination
401
- raise Error, "source and/or destination not defined for property graph edge"
402
- end
403
- end
404
-
405
- def data
406
- Data.new(@name, @key, @labels, @source, @destination).freeze
407
- end
408
-
409
- # Specify the source for the edge, with block evaluted by Target.
410
- def source(name, &block)
411
- raise Error, "cannot specify multiple sources for a property graph edge" if @source
412
- @source = Target.new(name, &block)
413
- end
414
-
415
- # Specify the destination for the edge, with block evaluted by Target.
416
- def destination(name, &block)
417
- raise Error, "cannot specify multiple destinations for a property graph edge" if @destination
418
- @destination = Target.new(name, &block)
419
- end
420
- end
421
-
422
- # Create is used to evaluate the block given to DatabaseMethods#create_property_graph,
423
- # used to specify the vertices and edges in the property graph.
424
- class Create < self
425
- Data = Struct.new(:vertices, :edges)
426
-
427
- def initialize(&block)
428
- @vertices = []
429
- @edges = []
430
- instance_exec(&block)
431
- @vertices.freeze
432
- @edges.freeze
433
- freeze
434
- end
435
-
436
- def data
437
- Data.new(@vertices, @edges).freeze
438
- end
439
-
440
- # Adds a vertex to the property graph, with the block evaluted by Vertex.
441
- def vertex(name, opts=OPTS, &block)
442
- @vertices << Vertex.new(name, opts, &block)
443
- end
444
-
445
- # Adds an edge to the property graph, with the block evaluted by Edge.
446
- def edge(name, opts=OPTS, &block)
447
- @edges << Edge.new(name, opts, &block)
448
- end
449
- end
450
-
451
- # AlterElement is used to evaluate the block passed to
452
- # Alter#alter_vertex_table and Alter#alter_edge_table.
453
- class AlterElement < self
454
- # +kind+ is +:vertex+ or +:edge+. +name+ is the alias of the
455
- # vertex or edge table to alter.
456
- def initialize(kind, name, &block)
457
- @kind = kind
458
- @name = name
459
- @labels = []
460
- @operations = []
461
- instance_exec(&block)
462
-
463
- # All labels added via #add_label are combined into a single
464
- # ADD LABEL operation, as PostgreSQL supports adding multiple
465
- # labels in a single ALTER ... ADD LABEL statement.
466
- unless @labels.empty?
467
- @operations << {:op=>:add_label, :kind=>kind, :name=>name, :labels=>@labels.freeze}
468
- end
469
-
470
- @operations.each(&:freeze)
471
- @operations.freeze
472
- freeze
473
- end
474
-
475
- def data
476
- @operations
477
- end
478
-
479
- # Add a label (and optional properties) to the vertex/edge table.
480
- # Takes the same arguments as Element#label. Can be called multiple
481
- # times to add multiple labels.
482
- #
483
- # add_label(:l)
484
- # # ADD LABEL l PROPERTIES ALL COLUMNS
485
- def add_label(name, properties=:all)
486
- @labels << [name, properties].freeze
487
- nil
488
- end
489
-
490
- # Remove a label from the vertex/edge table. Options:
491
- # :cascade :: Use CASCADE to drop dependent objects.
492
- #
493
- # drop_label(:l)
494
- # # DROP LABEL l
495
- def drop_label(name, opts=OPTS)
496
- @operations << {:op=>:drop_label, :kind=>@kind, :name=>@name, :label=>name, :cascade=>opts[:cascade]}
497
- nil
498
- end
499
-
500
- # Add properties to an existing label on the vertex/edge table.
501
- # +properties+ is an expression, or array of expressions, the same
502
- # as the explicit array form of the +properties+ argument to
503
- # Element#label.
504
- #
505
- # add_properties(:l, [:c1, Sequel[:c2].as(:c3)])
506
- # # ALTER LABEL l ADD PROPERTIES (c1, c2 AS c3)
507
- def add_properties(label, properties)
508
- @operations << {:op=>:add_properties, :kind=>@kind, :name=>@name, :label=>label, :properties=>Array(properties)}
509
- nil
510
- end
511
-
512
- # Remove properties from an existing label on the vertex/edge table.
513
- # +properties+ is a column name, or array of column names. Options:
514
- # :cascade :: Use CASCADE to drop dependent objects.
515
- #
516
- # drop_properties(:l, [:c1])
517
- # # ALTER LABEL l DROP PROPERTIES (c1)
518
- def drop_properties(label, properties, opts=OPTS)
519
- @operations << {:op=>:drop_properties, :kind=>@kind, :name=>@name, :label=>label, :properties=>Array(properties), :cascade=>opts[:cascade]}
520
- nil
521
- end
522
- end
523
-
524
- # Alter is used to evaluate the block given to DatabaseMethods#alter_property_graph,
525
- # used to specify changes to an existing property graph.
526
- class Alter < self
527
- def initialize(&block)
528
- @operations = []
529
- instance_exec(&block)
530
-
531
- @operations.each do |op|
532
- case op[:op]
533
- when :add_vertex_tables, :add_edge_tables
534
- op[:tables].freeze
535
- end
536
- op.freeze
537
- end
538
- @operations.freeze
539
- freeze
540
- end
541
-
542
- def data
543
- @operations
544
- end
545
-
546
- # Add a vertex to the property graph, with the block used to configure the
547
- # vertex.
548
- #
549
- # alter_property_graph.add_vertex(:v)
550
- # # ADD VERTEX TABLES (v)
551
- def add_vertex(name, opts=OPTS, &block)
552
- add_tables_operation(:add_vertex_tables) << Vertex.new(name, opts, &block)
553
- nil
554
- end
555
-
556
- # Add an edge to the property graph, with the block used to configure the edge.
557
- #
558
- # alter_property_graph.add_edge(:e){source :v1; destination :v2}
559
- # # ADD EDGE TABLES (e SOURCE v1 DESTINATION v2)
560
- def add_edge(name, opts=OPTS, &block)
561
- add_tables_operation(:add_edge_tables) << Edge.new(name, opts, &block)
562
- nil
563
- end
564
-
565
- # Remove vertex tables (referenced by their aliases) from the
566
- # property graph. +aliases+ can be a single alias or an array.
567
- # Options:
568
- # :cascade :: Use CASCADE instead of the default RESTRICT.
569
- #
570
- # alter_property_graph.drop_vertex_tables([:v1, :v2])
571
- # # DROP VERTEX TABLES (v1, v2)
572
- def drop_vertex_tables(aliases, opts=OPTS)
573
- @operations << {:op=>:drop_vertex_tables, :aliases=>Array(aliases), :cascade=>opts[:cascade]}
574
- nil
575
- end
576
-
577
- # Remove edge tables (referenced by their aliases) from the property
578
- # graph. See #drop_vertex_tables.
579
- #
580
- # alter_property_graph.drop_edge_tables([:e1, :e2])
581
- # # DROP EDGE TABLES (e1, e2)
582
- def drop_edge_tables(aliases, opts=OPTS)
583
- @operations << {:op=>:drop_edge_tables, :aliases=>Array(aliases), :cascade=>opts[:cascade]}
584
- nil
585
- end
586
-
587
- # Modify an existing vertex table (referenced by its alias).
588
- #
589
- # alter_property_graph.alter_vertex_table(:v){add_label :l}
590
- # # ALTER VERTEX TABLE v ADD LABEL l PROPERTIES ALL COLUMNS
591
- def alter_vertex_table(name, &block)
592
- @operations.concat(AlterElement.new(:vertex, name, &block))
593
- nil
594
- end
595
-
596
- # Modify an existing edge table (referenced by its alias).
597
- #
598
- # alter_property_graph.alter_edge_table(:e, properties: :none){drop_label :l}
599
- # # ALTER VERTEX TABLE e DROP LABEL l
600
- def alter_edge_table(name, &block)
601
- @operations.concat(AlterElement.new(:edge, name, &block))
602
- nil
603
- end
604
-
605
- # Change the owner of the property graph. +new_owner+ is usually a
606
- # Symbol or SQL::Identifier for the role name, but can be
607
- # <tt>Sequel.lit('CURRENT_USER')</tt> or
608
- # <tt>Sequel.lit('SESSION_USER')</tt>.
609
- #
610
- # alter_property_graph.owner_to(:new_owner)
611
- # # OWNER TO new_owner
612
- def set_owner(new_owner)
613
- @operations << {:op=>:set_owner, :owner=>new_owner}
614
- nil
615
- end
616
-
617
- private
618
-
619
- # Internals of add_vertex and add_edge.
620
- def add_tables_operation(op_name)
621
- unless op = @operations.find{|o| o[:op] == op_name}
622
- @operations << (op = {:op=>op_name, :tables=>[]})
623
- end
624
- op[:tables]
625
- end
626
- end
627
- end
628
-
629
- # Represents a GRAPH_TABLE expression, used to query a property graph
630
- # via graph pattern matching. This is used in place of a table name
631
- # expression or dataset in a SELECT query. These are created by calling
632
- # #graph_table on the related Database object.
633
- #
634
- # Table uses a method chaining design, similar to Dataset, where methods
635
- # return modified frozen copies of the object.
636
- class Table
637
- include SQL::AliasMethods
638
-
639
- # Internal struct for a single element (vertex or edge) in the graph pattern:
640
- # +type+ :: Either :vertex or :edge.
641
- # +marker+ :: Connector string to use for the element (empty for initial vertex).
642
- # +label+ :: Label restriction symbol or SQL::Identifier for the element, if any.
643
- # Can be an array or set to match multiple labels.
644
- # +var+ :: Graph pattern variable symbol for the element, if any.
645
- # +where+ :: WHERE condition for the element, if any.
646
- Element = Struct.new(:type, :marker, :label, :var, :where) do
647
- # Method used to create elements, used instead of new
648
- # to ensure that the returned elements are frozen.
649
- def self.create(type, marker, label, opts)
650
- case label
651
- when Array, Set
652
- label = label.dup.freeze unless label.frozen?
653
- end
654
-
655
- case where = opts[:where]
656
- when Hash, Array
657
- where = SQL::BooleanExpression.from_value_pairs(where)
658
- end
659
-
660
- new(type, marker, label, opts[:var], where).freeze
661
- end
662
-
663
- private_class_method :new
664
- end
665
- private_constant :Element
666
-
667
- # The name of the property graph the table is querying.
668
- attr_reader :name
669
-
670
- # A frozen array of Element instances, representing the vertices and
671
- # edges in the graph pattern.
672
- attr_reader :elements
673
-
674
- # A frozen array of the columns used in the COLUMNS clause (aliased
675
- # as columns_used, as #columns is used to modify the columns).
676
- attr_reader :columns
677
- alias columns_used columns
678
-
679
- # Create a new Table with the given +graph_name+, with +initial_vertex_label+
680
- # and +initial_vertex_opts+ being used to create the initial vertex.
681
- # See Table#link for which options are supported for the initial vertex.
682
- def self.create(graph_name, initial_vertex_label, initial_vertex_opts)
683
- vertex = Element.create(:vertex, "", initial_vertex_label, initial_vertex_opts)
684
- new(graph_name, [vertex].freeze, [].freeze)
685
- end
686
-
687
- def initialize(name, elements, columns)
688
- @name = name
689
- @elements = elements
690
- @columns = columns
691
- freeze
692
- end
693
-
694
- # Return a modified copy with an element added using a bidirectional link
695
- # (<tt>-</tt> in the graph pattern).
696
- # +label+ specifies the label restriction for the element. This can be
697
- # nil for no label restriction, or an array or set to restrict to the
698
- # given labels.
699
- #
700
- # Options supported:
701
- # +:var+ :: Specifies a graph pattern variable name for the element,
702
- # usable in the WHERE or COLUMNS clauses.
703
- # +:vertex+ :: Specifies that the element being linked to is a vertex.
704
- # This allows for direct vertex<->vertex linking, instead of
705
- # the default vertex<->edge<->vertex linking.
706
- # +:where+ :: An expression to use for the WHERE clause for the element.
707
- #
708
- # DB.graph_table(:gn, :v).link(:e)
709
- # # GRAPH_TABLE (gn MATCH (IS v)-[IS e])
710
- def link(label, opts=OPTS)
711
- append_element('-', label, opts)
712
- end
713
-
714
- # Similar to #link, but uses a directed link from the previous element
715
- # to the new element (<tt>-></tt> in the graph pattern). Accepts same
716
- # arguments and options as #link.
717
- #
718
- # DB.graph_table(:gn, :v).to(:e)
719
- # # GRAPH_TABLE (gn MATCH (IS v)->[IS e])
720
- def to(label, opts=OPTS)
721
- append_element('->', label, opts)
722
- end
723
-
724
- # Similar to #link, but uses a directed link from the new element
725
- # to the previous element (<tt><-</tt> in the graph pattern). Accepts
726
- # same arguments and options as #link.
727
- #
728
- # DB.graph_table(:gn, :v).from(:e)
729
- # # GRAPH_TABLE (gn MATCH (IS v)<-[IS e])
730
- def from(label, opts=OPTS)
731
- append_element('<-', label, opts)
732
- end
733
-
734
- # Return a modifies copy that uses the given columns. A graph table
735
- # must have a least one column set before it is used in a query.
736
- #
737
- # DB.graph_table(:gn, :v).columns(:a, Sequel[:b].as(:c))
738
- # # GRAPH_TABLE (gn MATCH (IS v) COLUMNS (a, b AS c))
739
- def columns(*cols)
740
- self.class.new(@name, @elements, cols.freeze)
741
- end
742
-
743
- # Return a modified copy that adds the given columns to the existing
744
- # list of columns for the graph table.
745
- def add_columns(*cols)
746
- columns(*@columns, *cols)
747
- end
748
-
749
- # Append the SQL for the GRAPH_TABLE expression to the given SQL string.
750
- # Requires graph table have at least one column set.
751
- def sql_literal_append(ds, sql)
752
- if @columns.empty?
753
- raise Error, "cannot use graph_table in a query if it does not return any columns"
754
- end
755
- if @elements.last.type == :edge
756
- raise Error, "cannot use graph_table in a query if the last element is an edge"
757
- end
758
-
759
- sql << "GRAPH_TABLE ("
760
- ds.literal_append(sql, @name)
761
- sql << " MATCH "
762
-
763
- @elements.each do |element|
764
- marker = element.marker
765
- var = element.var
766
- label = element.label
767
- where = element.where
768
- vertex = element.type == :vertex
769
-
770
- sql << marker
771
- sql << (vertex ? '(' : '[')
772
-
773
- ds.literal_append(sql, var) if var
774
- if label
775
- sql << (var ? " IS " : "IS ")
776
- if label.is_a?(Array)
777
- label_sep = ""
778
- label.each do |l|
779
- sql << label_sep
780
- label_sep = "|" if label_sep.empty?
781
- ds.literal_append(sql, l)
782
- end
783
- else
784
- ds.literal_append(sql, label)
785
- end
786
- end
787
-
788
- if where
789
- sql << ((var || label) ? " WHERE " : "WHERE ")
790
- ds.literal_append(sql, where)
791
- end
792
-
793
- sql << (vertex ? ')' : ']')
794
- end
795
-
796
- sql << " COLUMNS "
797
- ds.literal_append(sql, @columns)
798
- sql << ")"
799
- end
800
-
801
- private
802
-
803
- # Internals of #link, #to, and #from.
804
- def append_element(marker, label, opts)
805
- node_type = if opts[:vertex]
806
- :vertex
807
- else
808
- @elements.last.type == :vertex ? :edge : :vertex
809
- end
810
-
811
- element = Element.create(node_type, marker, label, opts)
812
- self.class.new(@name, (@elements.dup << element).freeze, @columns)
813
- end
814
- end
815
- end
816
-
817
259
  # Error raised when Sequel determines a PostgreSQL exclusion constraint has been violated.
818
260
  class ExclusionConstraintViolation < Sequel::ConstraintViolation; end
819
261
 
@@ -896,64 +338,6 @@ module Sequel
896
338
  add_conversion_proc(oid, block)
897
339
  end
898
340
 
899
- # Alter the property graph with the given +name+, supported on PostgreSQL 19+.
900
- # The block uses a DSL, evaluated by PropertyGraph::Generator::Alter. Example:
901
- #
902
- # DB.alter_property_graph(:my_graph) do
903
- # # PropertyGraph::Generator::Alter
904
- # add_vertex :companies2
905
- # # ALTER PROPERTY GRAPH "my_graph" ADD VERTEX TABLES ("companies2")
906
- #
907
- # add_edge :works_at2 do
908
- # # PropertyGraph::Generator::Edge
909
- # source :people
910
- # destination :companies2
911
- # end
912
- # # ALTER PROPERTY GRAPH "my_graph" ADD EDGE TABLES
913
- # # ("works_at2" SOURCE "people" DESTINATION "companies2")
914
- #
915
- # drop_vertex_tables [:p2], cascade: true
916
- # # ALTER PROPERTY GRAPH "my_graph" DROP VERTEX TABLES ("p2") CASCADE
917
- #
918
- # drop_edge_tables :e2
919
- # # ALTER PROPERTY GRAPH "my_graph" DROP EDGE TABLES ("e2")
920
- #
921
- # alter_vertex_table :companies do
922
- # # PropertyGraph::Generator::AlterElement
923
- # add_label :public_company, [:name, :symbol]
924
- # # ALTER PROPERTY GRAPH "my_graph" ALTER VERTEX TABLE "companies"
925
- # # ADD LABEL "public_company" PROPERTIES ("name", "symbol")
926
- #
927
- # drop_label :private_company
928
- # # ALTER PROPERTY GRAPH "my_graph" ALTER VERTEX TABLE "companies"
929
- # # DROP LABEL "private_company"
930
- #
931
- # add_properties :company, :revenue
932
- # # ALTER PROPERTY GRAPH "my_graph" ALTER VERTEX TABLE "companies"
933
- # # ALTER LABEL "company" ADD PROPERTIES ("revenue")
934
- #
935
- # drop_properties :company, :internal_id, cascade: true
936
- # # ALTER PROPERTY GRAPH "my_graph" ALTER VERTEX TABLE "companies"
937
- # # ALTER LABEL "company" DROP PROPERTIES ("internal_id") CASCADE
938
- # end
939
- #
940
- # alter_edge_table :works_at do
941
- # # PropertyGraph::Generator::AlterElement
942
- # add_label :employment
943
- # end
944
- # # ALTER PROPERTY GRAPH "my_graph" ALTER EDGE TABLE "works_at"
945
- # # ADD LABEL "employment" PROPERTIES ALL COLUMNS
946
- #
947
- # owner_to :new_owner
948
- # # ALTER PROPERTY GRAPH "my_graph" OWNER TO "new_owner"
949
- # end
950
- def alter_property_graph(name, &block)
951
- PropertyGraph::Generator::Alter.new(&block).each do |op|
952
- execute_ddl(alter_property_graph_op_sql(name, op).freeze)
953
- end
954
- nil
955
- end
956
-
957
341
  def commit_prepared_transaction(transaction_id, opts=OPTS)
958
342
  run("COMMIT PREPARED #{literal(transaction_id)}".freeze, opts)
959
343
  end
@@ -962,7 +346,7 @@ module Sequel
962
346
  # Keys are CHECK constraint name symbols. Values are hashes with the following keys:
963
347
  # :definition :: An SQL fragment for the definition of the constraint
964
348
  # :columns :: An array of column symbols for the columns referenced in the constraint,
965
- # can be an empty array if the database cannot deteremine the column symbols.
349
+ # can be an empty array if the database cannot determine the column symbols.
966
350
  def check_constraints(table)
967
351
  m = output_identifier_meth
968
352
 
@@ -1083,67 +467,6 @@ module Sequel
1083
467
  self << create_language_sql(name, opts).freeze
1084
468
  end
1085
469
 
1086
- # Create a property graph in the database, supported on PostgreSQL 19+.
1087
- #
1088
- # Arguments:
1089
- # name :: Name of the property graph
1090
- # opts :: options hash:
1091
- # :temp :: Create the property graph as a temporary property graph.
1092
- #
1093
- # The block uses a DSL, with classes under PropertyGraph::Generator:
1094
- #
1095
- # DB.create_property_graph(:my_graph) do
1096
- # # PropertyGraph::Generator::Create
1097
- # vertex :people
1098
- #
1099
- # vertex Sequel.as(:people, :p), properties: []
1100
- #
1101
- # vertex Sequel.as(:companies, :c) do
1102
- # # PropertyGraph::Generator::Vertex
1103
- # key :id
1104
- # label :company
1105
- # label :c, [:name, (Sequel[:revenue] / 1000).as(:revenue_thousands)]
1106
- # end
1107
- #
1108
- # edge :works_at do
1109
- # # PropertyGraph::Generator::Edge
1110
- # source :people
1111
- # destination :c
1112
- # end
1113
- #
1114
- # edge Sequel.as(:employment, :e) do
1115
- # source :people do
1116
- # # PropertyGraph::Generator::Target
1117
- # key :person_id
1118
- # references :id
1119
- # end
1120
- # destination :c do
1121
- # # PropertyGraph::Generator::Target
1122
- # key :company_id
1123
- # references :id
1124
- # end
1125
- # label :employment
1126
- # end
1127
- # end
1128
- # # CREATE PROPERTY GRAPH "my_graph"
1129
- # # VERTEX TABLES (
1130
- # # "people",
1131
- # # "people" AS "p" NO PROPERTIES,
1132
- # # "companies" AS "c" KEY ("id")
1133
- # # LABEL "company" PROPERTIES ALL COLUMNS
1134
- # # LABEL "c" PROPERTIES ("name", ("revenue" / 1000) AS "revenue_thousands"))
1135
- # # EDGE TABLES (
1136
- # # "works_at"
1137
- # # SOURCE "people"
1138
- # # DESTINATION "c",
1139
- # # "employment" AS "e"
1140
- # # SOURCE KEY ("person_id") REFERENCES "people" ("id")
1141
- # # DESTINATION KEY ("company_id") REFERENCES "c" ("id")
1142
- # # LABEL "employment" PROPERTIES ALL COLUMNS)
1143
- def create_property_graph(name, opts=OPTS, &block)
1144
- execute_ddl(create_property_graph_sql(name, PropertyGraph::Generator::Create.new(&block), opts))
1145
- end
1146
-
1147
470
  # Create a schema in the database. Arguments:
1148
471
  # name :: Name of the schema (e.g. admin)
1149
472
  # opts :: options hash:
@@ -1241,15 +564,6 @@ module Sequel
1241
564
  self << drop_language_sql(name, opts).freeze
1242
565
  end
1243
566
 
1244
- # Drops a property graph from the database. Arguments:
1245
- # name :: name of the property graph to drop
1246
- # opts :: options hash:
1247
- # :cascade :: Drop other objects depending on this property_graph.
1248
- # :if_exists :: Don't raise an error if the property graph doesn't exist.
1249
- def drop_property_graph(name, opts=OPTS)
1250
- self << drop_property_graph_sql(name, opts).freeze
1251
- end
1252
-
1253
567
  # Drops a schema from the database. Arguments:
1254
568
  # name :: name of the schema to drop
1255
569
  # opts :: options hash:
@@ -1337,82 +651,6 @@ module Sequel
1337
651
  super
1338
652
  end
1339
653
 
1340
- # Return a PropertyGraph::Table instance for a property graph search
1341
- # (a GRAPH_TABLE clause for a SELECT query). Supported on PostgreSQL 19+.
1342
- #
1343
- # Arguments:
1344
- # +property_graph_name+ :: The property graph to query
1345
- # +initial_vertex_label+ :: The label restriction for the initial vertex for the
1346
- # graph pattern (can be nil for no label, or an array
1347
- # or set for restricting to one of multiple labels).
1348
- # +initial_vertex_opts+ :: The options for the initial vertex, see
1349
- # PropertyGraph::Table#link for available options.
1350
- #
1351
- # The returned instance should be further modified by calling methods on it,
1352
- # using a similar approach to how datasets work, where the methods return a
1353
- # modified copy of the receiver. The available methods:
1354
- #
1355
- # link :: Add a bidirectional link to a new element (vertex or edge)
1356
- # to :: Add a directional link from the last element to the new element
1357
- # from :: Add a direciton link from the new element to last element
1358
- # columns :: Replace the columns the graph table returns
1359
- # add_columns :: Append to the columns the graph table returns.
1360
- #
1361
- # See PropertyGraph::Table for the details of these methods and the arguments
1362
- # and options they support. Note that for a graph table to be usable in a query,
1363
- # it must return at least one column, and the last element in the graph pattern
1364
- # must be a vertex.
1365
- #
1366
- # gt = DB.graph_table(:pgn, :iv)
1367
- # # Not yet usable, does not return any columns
1368
- #
1369
- # # Set columns for graph table
1370
- # gt = gt.columns(:c, Sequel[1].as(:d))
1371
- # # GRAPH_TABLE ("pgn" MATCH (IS "iv") COLUMNS ("c", 1 AS "d"))
1372
- #
1373
- # # Adds directional link to edge, since last (initial) element was a vertex
1374
- # gt = gt.link(:e1)
1375
- # # GRAPH_TABLE ("pgn" MATCH (IS "iv")-[IS "e1"] COLUMNS ("c", 1 AS "d"))
1376
- #
1377
- # # Adds directional link from edge to vertex, since last element was an edge
1378
- # gt = gt.to(:v2)
1379
- # # GRAPH_TABLE ("pgn" MATCH (IS "iv")-[IS "e1"]->(IS "v2") COLUMNS ("c", 1 AS "d"))
1380
- #
1381
- # # Adds bidirection link from vertex to vertex (overriding the default)
1382
- # gt = gt.link(:v3, vertex: true)
1383
- # # GRAPH_TABLE ("pgn" MATCH (IS "iv")-[IS "e1"]->(IS "v2")-(IS "v3") COLUMNS ("c", 1 AS "d"))
1384
- #
1385
- # # Adds directional link from new edge to last vertex, since last element was an vertex.
1386
- # # Sets graph pattern variable name and uses it in a WHERE clause for the added element.
1387
- # gt = gt.from(:e2, var: :a2, where: {Sequel[:a2][:c] => 1})
1388
- # # GRAPH_TABLE ("pgn" MATCH (IS "iv")-[IS "e1"]->(IS "v2")-(IS "v3")
1389
- # # <-["a2" IS "e2" WHERE ("a2"."c" = 1)] COLUMNS ("c", 1 AS "d"))
1390
- #
1391
- # # Can use nil as a label for no label restriction, both with and without a variable name
1392
- # gt = gt.to(nil).to(nil, var: :a3)
1393
- # # GRAPH_TABLE ("pgn" MATCH (IS "iv")-[IS "e1"]->(IS "v2")-(IS "v3")
1394
- # # <-["a2" IS "e2" WHERE ("a2"."c" = 1)]->[]->("a3") COLUMNS ("c", 1 AS "d"))
1395
- #
1396
- # # Can restrict to a one of a set of labels
1397
- # gt = gt.from([:x, :y], var: :a6)
1398
- # # GRAPH_TABLE ("pgn" MATCH (IS "iv")-[IS "e1"]->(IS "v2")-(IS "v3")
1399
- # # <-["a2" IS "e2" WHERE ("a2"."c" = 1)]->[]->("a3")->["a6" IS "x"|"y"] COLUMNS ("c", 1 AS "d"))
1400
- #
1401
- # # Add column(s) to the graph table
1402
- # gt = gt.add_columns(:y)
1403
- # # GRAPH_TABLE ("pgn" MATCH (IS "iv")-[IS "e1"]->(IS "v2")-(IS "v3")
1404
- # # <-["a2" IS "e2" WHERE ("a2"."c" = 1)]->[]->("a3")->["a6" IS "x"|"y"]
1405
- # # COLUMNS ("c", 1 AS "d", "y"))
1406
- #
1407
- # DB.from(gt)
1408
- # # SELECT * FROM GRAPH_TABLE (...)
1409
- #
1410
- # DB.from(:x).cross_join(gt)
1411
- # # SELECT * FROM "x" CROSS JOIN GRAPH_TABLE (...)
1412
- def graph_table(property_graph_name, initial_vertex_label, initial_vertex_opts=OPTS)
1413
- PropertyGraph::Table.create(property_graph_name, initial_vertex_label, initial_vertex_opts)
1414
- end
1415
-
1416
654
  # Immediately apply deferrable constraints.
1417
655
  #
1418
656
  # :constraints :: An identifier of the constraint, or an array of
@@ -1503,28 +741,6 @@ module Sequel
1503
741
  Sequel.synchronize{@primary_key_sequences[quoted_table] = value} if value
1504
742
  end
1505
743
 
1506
- # Array of symbols specifying property graphs in the current database.
1507
- # The dataset used is yielded to the block if one is provided,
1508
- # otherwise, an array of symbols of property graph names is returned.
1509
- # Supported on PostgreSQL 19+, will be an empty array on lower versions.
1510
- #
1511
- # Options:
1512
- # :qualify :: Return the property graph names as Sequel::SQL::QualifiedIdentifier
1513
- # instances, using the schema the property graph is located in as the qualifier.
1514
- # :schema :: The schema to search
1515
- # :server :: The server to use
1516
- def property_graphs(opts=OPTS, &block)
1517
- pg_class_relname('g', opts, &block)
1518
- end
1519
-
1520
- # Rename a property graph.
1521
- #
1522
- # DB.rename_property_graph(:x, :y)
1523
- # # ALTER PROPERTY GRAPH x RENAME TO y
1524
- def rename_property_graph(old_name, new_name)
1525
- execute_ddl("ALTER PROPERTY GRAPH #{literal(old_name)} RENAME TO #{literal(new_name)}".freeze)
1526
- end
1527
-
1528
744
  # Rename a schema in the database. Arguments:
1529
745
  # name :: Current name of the schema
1530
746
  # opts :: New name for the schema
@@ -1556,12 +772,12 @@ module Sequel
1556
772
  seq_ds = metadata_dataset.from(:pg_sequence).where(:seqrelid=>regclass_oid(LiteralString.new(seq.freeze)))
1557
773
  increment_by = :seqincrement
1558
774
  min_value = :seqmin
1559
- # :nocov:
775
+ # simplecov:disable
1560
776
  else
1561
777
  seq_ds = metadata_dataset.from(LiteralString.new(seq))
1562
778
  increment_by = :increment_by
1563
779
  min_value = :min_value
1564
- # :nocov:
780
+ # simplecov:enable
1565
781
  end
1566
782
 
1567
783
  get{setval(seq, db[table].select(coalesce(max(pk)+seq_ds.select(increment_by), seq_ds.select(min_value))), false)}
@@ -1574,9 +790,9 @@ module Sequel
1574
790
  # PostgreSQL uses SERIAL psuedo-type instead of AUTOINCREMENT for
1575
791
  # managing incrementing primary keys.
1576
792
  def serial_primary_key_options
1577
- # :nocov:
793
+ # simplecov:disable
1578
794
  auto_increment_key = server_version >= 100002 ? :identity : :serial
1579
- # :nocov:
795
+ # simplecov:enable
1580
796
  {:primary_key => true, auto_increment_key => true, :type=>Integer}
1581
797
  end
1582
798
 
@@ -1588,16 +804,6 @@ module Sequel
1588
804
  @server_version = swallow_database_error{ds.with_sql("SELECT CAST(current_setting('server_version_num') AS integer) AS v").single_value} || 0
1589
805
  end
1590
806
 
1591
- # Change the schema for a property graph. Options:
1592
- # :if_exists :: Use the IF EXISTS clause to not raise an error if the
1593
- # property graph does not exist.
1594
- #
1595
- # DB.set_property_graph_schema(:x, :y)
1596
- # # ALTER PROPERTY GRAPH x SET SCHEMA y
1597
- def set_property_graph_schema(old_name, new_name, opts=OPTS)
1598
- execute_ddl("ALTER PROPERTY GRAPH#{" IF EXISTS" if opts[:if_exists]} #{literal(old_name)} SET SCHEMA #{literal(new_name)}".freeze)
1599
- end
1600
-
1601
807
  # PostgreSQL supports CREATE TABLE IF NOT EXISTS on 9.1+
1602
808
  def supports_create_table_if_not_exists?
1603
809
  server_version >= 90100
@@ -1773,12 +979,12 @@ module Sequel
1773
979
  if server_version >= 90500
1774
980
  cpos = Sequel.expr{array_position(co[:conkey], ctable[:attnum])}
1775
981
  rpos = Sequel.expr{array_position(co[:confkey], rtable[:attnum])}
1776
- # :nocov:
982
+ # simplecov:disable
1777
983
  else
1778
984
  range = 0...32
1779
985
  cpos = Sequel.expr{SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(co[:conkey], [x]), x]}, 32, ctable[:attnum])}
1780
986
  rpos = Sequel.expr{SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(co[:confkey], [x]), x]}, 32, rtable[:attnum])}
1781
- # :nocov:
987
+ # simplecov:enable
1782
988
  end
1783
989
 
1784
990
  ds = metadata_dataset.
@@ -1815,19 +1021,19 @@ module Sequel
1815
1021
  def _add_validated_enforced_constraint_columns(ds)
1816
1022
  validated_cond = if server_version >= 90100
1817
1023
  Sequel[:convalidated]
1818
- # :nocov:
1024
+ # simplecov:disable
1819
1025
  else
1820
1026
  Sequel.cast(true, TrueClass)
1821
- # :nocov:
1027
+ # simplecov:enable
1822
1028
  end
1823
1029
  ds = ds.select_append(validated_cond.as(:validated))
1824
1030
 
1825
1031
  enforced_cond = if server_version >= 180000
1826
1032
  Sequel[:conenforced]
1827
- # :nocov:
1033
+ # simplecov:disable
1828
1034
  else
1829
1035
  Sequel.cast(true, TrueClass)
1830
- # :nocov:
1036
+ # simplecov:enable
1831
1037
  end
1832
1038
  ds = ds.select_append(enforced_cond.as(:enforced))
1833
1039
 
@@ -1839,11 +1045,11 @@ module Sequel
1839
1045
  @_indexes_ds ||= begin
1840
1046
  if server_version >= 90500
1841
1047
  order = [Sequel[:indc][:relname], Sequel.function(:array_position, Sequel[:ind][:indkey], Sequel[:att][:attnum])]
1842
- # :nocov:
1048
+ # simplecov:disable
1843
1049
  else
1844
1050
  range = 0...32
1845
1051
  order = [Sequel[:indc][:relname], SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(Sequel[:ind][:indkey], [x]), x]}, 32, Sequel[:att][:attnum])]
1846
- # :nocov:
1052
+ # simplecov:enable
1847
1053
  end
1848
1054
 
1849
1055
  attnums = SQL::Function.new(:ANY, Sequel[:ind][:indkey])
@@ -1861,10 +1067,10 @@ module Sequel
1861
1067
  order(*order).
1862
1068
  select{[indc[:relname].as(:name), ind[:indisunique].as(:unique), att[:attname].as(:column), con[:condeferrable].as(:deferrable)]}
1863
1069
 
1864
- # :nocov:
1070
+ # simplecov:disable
1865
1071
  ds = ds.where(:indisready=>true) if server_version >= 80300
1866
1072
  ds = ds.where(:indislive=>true) if server_version >= 90300
1867
- # :nocov:
1073
+ # simplecov:enable
1868
1074
 
1869
1075
  ds
1870
1076
  end
@@ -1957,14 +1163,14 @@ module Sequel
1957
1163
  where{pg_attribute[:attnum] > 0}.
1958
1164
  order{pg_attribute[:attnum]}
1959
1165
 
1960
- # :nocov:
1166
+ # simplecov:disable
1961
1167
  if server_version > 100000
1962
- # :nocov:
1168
+ # simplecov:enable
1963
1169
  ds = ds.select_append{pg_attribute[:attidentity]}
1964
1170
 
1965
- # :nocov:
1171
+ # simplecov:disable
1966
1172
  if server_version > 120000
1967
- # :nocov:
1173
+ # simplecov:enable
1968
1174
  ds = ds.select_append{Sequel.~(pg_attribute[:attgenerated]=>'').as(:generated)}
1969
1175
  end
1970
1176
  end
@@ -1998,62 +1204,6 @@ module Sequel
1998
1204
  raise e unless /canceling statement due to (?:statement|lock) timeout/ =~ e.message
1999
1205
  end
2000
1206
 
2001
- # SQL statement for a single ALTER PROPERTY GRAPH operation.
2002
- def alter_property_graph_op_sql(name, op)
2003
- sql = String.new << "ALTER PROPERTY GRAPH " << quote_schema_table(name) << " "
2004
-
2005
- case op_type = op[:op]
2006
- when :add_vertex_tables
2007
- sql << "ADD VERTEX TABLES (" <<
2008
- op[:tables].map do |vertex|
2009
- create_property_graph_table_sql(vertex) <<
2010
- create_property_graph_labels_sql(vertex.labels)
2011
- end.join(', ') << ")"
2012
- when :add_edge_tables
2013
- sql << "ADD EDGE TABLES (" <<
2014
- op[:tables].map do |edge|
2015
- create_property_graph_table_sql(edge) <<
2016
- " SOURCE " << create_property_graph_edge_side_sql(edge.source) <<
2017
- " DESTINATION " << create_property_graph_edge_side_sql(edge.destination) <<
2018
- create_property_graph_labels_sql(edge.labels)
2019
- end.join(', ') << ")"
2020
- when :drop_vertex_tables, :drop_edge_tables
2021
- sql << (op_type == :drop_vertex_tables ? "DROP VERTEX TABLES " : "DROP EDGE TABLES ") <<
2022
- literal(op[:aliases])
2023
- when :add_label
2024
- sql << alter_property_graph_element_table_sql(op)
2025
- op[:labels].each do |label_name, properties|
2026
- sql << " ADD LABEL " << quote_identifier(label_name) <<
2027
- create_property_graph_properties_clause_sql(properties)
2028
- end
2029
- when :drop_label
2030
- sql << alter_property_graph_element_table_sql(op) <<
2031
- " DROP LABEL " << quote_identifier(op[:label])
2032
- when :add_properties
2033
- sql << alter_property_graph_element_table_sql(op) <<
2034
- " ALTER LABEL " << quote_identifier(op[:label]) << " ADD PROPERTIES " <<
2035
- literal(op[:properties])
2036
- when :drop_properties
2037
- sql << alter_property_graph_element_table_sql(op) <<
2038
- " ALTER LABEL " << quote_identifier(op[:label]) << " DROP PROPERTIES " <<
2039
- literal(op[:properties])
2040
- else # when :set_owner
2041
- sql << "OWNER TO " << literal(op[:owner])
2042
- end
2043
-
2044
- case op_type
2045
- when :drop_vertex_tables, :drop_edge_tables, :drop_label, :drop_properties
2046
- sql << " CASCADE" if op[:cascade]
2047
- end
2048
-
2049
- sql
2050
- end
2051
-
2052
- # SQL fragment for the ALTER PROPERTY GRAPH ALTER {VERTEX|EDGE} TABLE prefix
2053
- def alter_property_graph_element_table_sql(op)
2054
- "ALTER #{op[:kind] == :vertex ? 'VERTEX' : 'EDGE'} TABLE #{quote_identifier(op[:name])}"
2055
- end
2056
-
2057
1207
  def alter_table_add_column_sql(table, op)
2058
1208
  "ADD COLUMN#{' IF NOT EXISTS' if op[:if_not_exists]} #{column_definition_sql(op)}"
2059
1209
  end
@@ -2111,7 +1261,7 @@ module Sequel
2111
1261
 
2112
1262
  # If the :synchronous option is given and non-nil, set synchronous_commit
2113
1263
  # appropriately. Valid values for the :synchronous option are true,
2114
- # :on, false, :off, :local, and :remote_write.
1264
+ # :on, false, :off, :local, :remote_apply, and :remote_write.
2115
1265
  def begin_new_transaction(conn, opts)
2116
1266
  super
2117
1267
  if opts.has_key?(:synchronous)
@@ -2122,6 +1272,12 @@ module Sequel
2122
1272
  sync = :off
2123
1273
  when nil
2124
1274
  return
1275
+ when :on, :off, :local, :remote_apply, :remote_write
1276
+ nil
1277
+ else
1278
+ # SEQUEL6: raise
1279
+ Sequel::Deprecation.deprecate("Unsupported :synchronous option given to Database#transaction: #{sync.inspect}, this will raise an error in Sequel 6.")
1280
+ return
2125
1281
  end
2126
1282
 
2127
1283
  log_connection_execute(conn, "SET LOCAL synchronous_commit = #{sync}")
@@ -2376,8 +1532,14 @@ module Sequel
2376
1532
  if opts[:options] || opts[:format]
2377
1533
  options = String.new
2378
1534
  options << " ("
2379
- options << "FORMAT #{opts[:format]}" if opts[:format]
2380
- options << "#{', ' if opts[:format]}#{opts[:options]}" if opts[:options]
1535
+ if format = opts[:format]
1536
+ sql_format = format.to_s.downcase
1537
+ unless %w[text csv json binary].freeze.include?(sql_format)
1538
+ raise Error, "unsupported COPY TO format: #{format.inspect}"
1539
+ end
1540
+ options << "FORMAT #{format}"
1541
+ end
1542
+ options << "#{', ' if format}#{opts[:options]}" if opts[:options]
2381
1543
  options << ')'
2382
1544
  end
2383
1545
  table = if table.is_a?(::Sequel::Dataset)
@@ -2447,87 +1609,6 @@ module Sequel
2447
1609
  sql
2448
1610
  end
2449
1611
 
2450
- # SQL statement for creating a property graph.
2451
- def create_property_graph_sql(name, data, opts=OPTS)
2452
- sql = String.new
2453
- sql << "CREATE "
2454
- sql << "TEMPORARY " if opts[:temp]
2455
- sql << "PROPERTY GRAPH "
2456
- sql << quote_schema_table(name)
2457
-
2458
- unless data.vertices.empty?
2459
- sql << " VERTEX TABLES ("
2460
- sql << data.vertices.map do |vertex|
2461
- create_property_graph_table_sql(vertex) <<
2462
- create_property_graph_labels_sql(vertex.labels)
2463
- end.join(', ')
2464
- sql << ")"
2465
- end
2466
-
2467
- unless data.edges.empty?
2468
- sql << " EDGE TABLES ("
2469
- sql << data.edges.map do |edge|
2470
- create_property_graph_table_sql(edge) <<
2471
- " SOURCE " << create_property_graph_edge_side_sql(edge.source) <<
2472
- " DESTINATION " << create_property_graph_edge_side_sql(edge.destination) <<
2473
- create_property_graph_labels_sql(edge.labels)
2474
- end.join(', ')
2475
- sql << ")"
2476
- end
2477
-
2478
- sql
2479
- end
2480
-
2481
- # SQL fragment for the SOURCE or DESTINATION clause of an edge in a property graph.
2482
- def create_property_graph_edge_side_sql(side)
2483
- sql = String.new
2484
- if side.key
2485
- sql << "KEY " << literal(side.key) << " REFERENCES "
2486
- end
2487
- sql << quote_identifier(side.name)
2488
- if side.references
2489
- sql << " " << literal(side.references)
2490
- end
2491
- sql
2492
- end
2493
-
2494
- # SQL fragment for the table name and KEY clause used for vertices and edges in
2495
- # a property graph.
2496
- def create_property_graph_table_sql(element)
2497
- sql = String.new
2498
- sql << literal(element.name)
2499
-
2500
- if key = element.key
2501
- sql << " KEY " << literal(key)
2502
- end
2503
-
2504
- sql
2505
- end
2506
-
2507
- # SQL fragment for the LABEL/PROPERTIES clauses used for vertices and
2508
- # edges in a property graph.
2509
- def create_property_graph_labels_sql(labels)
2510
- labels.map do |name, properties|
2511
- sql = String.new
2512
- sql << " LABEL " << quote_identifier(name) if name
2513
- sql << create_property_graph_properties_clause_sql(properties)
2514
- sql
2515
- end.join
2516
- end
2517
-
2518
- # SQL fragment for the NO PROPERTIES, PROPERTIES ALL COLUMNS, or
2519
- # PROPERTIES (...) clause for a property graph element or label.
2520
- def create_property_graph_properties_clause_sql(properties)
2521
- case properties
2522
- when nil, :all
2523
- " PROPERTIES ALL COLUMNS"
2524
- when false, :none, [].freeze
2525
- " NO PROPERTIES"
2526
- else
2527
- " PROPERTIES #{literal(properties)}"
2528
- end
2529
- end
2530
-
2531
1612
  # SQL for creating a schema.
2532
1613
  def create_schema_sql(name, opts=OPTS)
2533
1614
  "CREATE SCHEMA #{'IF NOT EXISTS ' if opts[:if_not_exists]}#{quote_identifier(name)}#{" AUTHORIZATION #{literal(opts[:owner])}" if opts[:owner]}"
@@ -2554,7 +1635,7 @@ module Sequel
2554
1635
  "#{super}#{create_table_suffix_sql(name, options)}"
2555
1636
  end
2556
1637
 
2557
- # Handle various PostgreSQl specific table extensions such as inheritance,
1638
+ # Handle various PostgreSQL specific table extensions such as inheritance,
2558
1639
  # partitioning, tablespaces, and foreign tables.
2559
1640
  def create_table_suffix_sql(name, options)
2560
1641
  sql = String.new
@@ -2641,11 +1722,6 @@ module Sequel
2641
1722
  "DROP LANGUAGE#{' IF EXISTS' if opts[:if_exists]} #{name}#{' CASCADE' if opts[:cascade]}"
2642
1723
  end
2643
1724
 
2644
- # SQL for dropping a property graph from the database.
2645
- def drop_property_graph_sql(name, opts=OPTS)
2646
- "DROP PROPERTY GRAPH#{' IF EXISTS' if opts[:if_exists]} #{literal(name)}#{' CASCADE' if opts[:cascade]}"
2647
- end
2648
-
2649
1725
  # SQL for dropping a schema from the database.
2650
1726
  def drop_schema_sql(name, opts=OPTS)
2651
1727
  "DROP SCHEMA#{' IF EXISTS' if opts[:if_exists]} #{quote_identifier(name)}#{' CASCADE' if opts[:cascade]}"
@@ -2858,9 +1934,9 @@ module Sequel
2858
1934
  row[:auto_increment] = !!(row[:default] =~ /\A(?:nextval)/i) || identity == 'a' || identity == 'd'
2859
1935
  end
2860
1936
 
2861
- # :nocov:
1937
+ # simplecov:disable
2862
1938
  if server_version >= 90600
2863
- # :nocov:
1939
+ # simplecov:enable
2864
1940
  case row[:oid]
2865
1941
  when 1082
2866
1942
  row[:min_value] = MIN_DATE
@@ -2949,9 +2025,9 @@ module Sequel
2949
2025
 
2950
2026
  # PostgreSQL 9.4+ supports views with check option.
2951
2027
  def view_with_check_option_support
2952
- # :nocov:
2028
+ # simplecov:disable
2953
2029
  :local if server_version >= 90400
2954
- # :nocov:
2030
+ # simplecov:enable
2955
2031
  end
2956
2032
  end
2957
2033
 
@@ -3054,12 +2130,12 @@ module Sequel
3054
2130
  rows[0]
3055
2131
  elsif rows.all?{|row| String === row}
3056
2132
  rows.join("\r\n")
3057
- # :nocov:
2133
+ # simplecov:disable
3058
2134
  else
3059
2135
  # This branch is unreachable in tests, but it seems better to just return
3060
2136
  # all rows than throw in error if this case actually happens.
3061
2137
  rows
3062
- # :nocov:
2138
+ # simplecov:enable
3063
2139
  end
3064
2140
  end
3065
2141
 
@@ -3069,26 +2145,6 @@ module Sequel
3069
2145
  cached_lock_style_dataset(:_for_key_share_ds, :key_share)
3070
2146
  end
3071
2147
 
3072
- # Set FOR PORTION OF clause for UPDATE and DELETE statements.
3073
- # The first argument is the range or multirange column. If two arguments
3074
- # are provided, the second argument is an expression with the same
3075
- # database type as the first argument. If three arguments are provided,
3076
- # the second specifies the inclusive start of the portion to update and the third
3077
- # specifies the exclusive end of portion to update. When using the three argument
3078
- # form, nil can be provided as the second or third argument to have the start or
3079
- # end of the portion be unbounded. Supported on PostgreSQL 19+.
3080
- # Example:
3081
- #
3082
- # DB[:t].for_portion_of(:rc, Sequel.function(:int4range, 1, 2)).update(c: 3)
3083
- # # UPDATE t FOR PORTION OF rc (int4range(1, 2)) SET c = 3
3084
- #
3085
- # DB[:t].for_portion_of(:rc, 1, 2).update(c: 3)
3086
- # # UPDATE t FOR PORTION OF rc FROM 1 TO 2 SET c = 3
3087
- def for_portion_of(column, range, to=(arg_not_given=true))
3088
- range = [range, to].freeze unless arg_not_given
3089
- clone(:for_portion_of => [column, range].freeze)
3090
- end
3091
-
3092
2148
  # Return a cloned dataset which will use FOR NO KEY UPDATE to lock returned rows.
3093
2149
  # This is generally a better choice than using for_update on PostgreSQL, unless
3094
2150
  # you will be deleting the row or modifying a key column. Supported on PostgreSQL 9.3+.
@@ -3181,8 +2237,11 @@ module Sequel
3181
2237
  # Handle uniqueness violations when inserting, by updating the conflicting row, using
3182
2238
  # ON CONFLICT. With no options, uses ON CONFLICT DO NOTHING. Options:
3183
2239
  # :conflict_where :: The index filter, when using a partial index to determine uniqueness.
3184
- # :constraint :: An explicit constraint name, has precendence over :target.
2240
+ # :constraint :: An explicit constraint name, has precedence over :target.
3185
2241
  # :target :: The column name or expression to handle uniqueness violations on.
2242
+ # :select :: Use ON CONFLICT DO SELECT. This will use the dataset's lock style.
2243
+ # You must use #returning on this dataset when using this option.
2244
+ # :select_where :: A WHERE condition to use for the select.
3186
2245
  # :update :: A hash of columns and values to set. Uses ON CONFLICT DO UPDATE.
3187
2246
  # :update_where :: A WHERE condition to use for the update.
3188
2247
  #
@@ -3213,7 +2272,21 @@ module Sequel
3213
2272
  # # INSERT INTO TABLE (a, b) VALUES (1, 2)
3214
2273
  # # ON CONFLICT ON CONSTRAINT table_a_uidx
3215
2274
  # # DO UPDATE SET b = excluded.b WHERE (table.status_id = 1)
2275
+ #
2276
+ # DB[:table].returning(:a).insert_conflict(target: :a, select: true).insert(a: 1, b: 2)
2277
+ # # INSERT INTO TABLE (a, b) VALUES (1, 2)
2278
+ # # ON CONFLICT (a) DO SELECT RETURNING a
2279
+ #
2280
+ # DB[:table].returning(:a).for_update.
2281
+ # insert_conflict(target: :a, select: true, select_where: {Sequel[:excluded][:b] => 3}).
2282
+ # insert(a: 1, b: 2)
2283
+ # # INSERT INTO TABLE (a, b) VALUES (1, 2)
2284
+ # # ON CONFLICT (a) DO SELECT FOR UPDATE WHERE (excluded.b = 3) RETURNING a
3216
2285
  def insert_conflict(opts=OPTS)
2286
+ if opts[:select] && opts[:update]
2287
+ raise Error, "Cannot provide both :select and :update options to insert_conflict"
2288
+ end
2289
+
3217
2290
  clone(:insert_conflict => opts)
3218
2291
  end
3219
2292
 
@@ -3454,14 +2527,14 @@ module Sequel
3454
2527
  server_version >= 90500
3455
2528
  end
3456
2529
 
3457
- # :nocov:
2530
+ # simplecov:disable
3458
2531
 
3459
2532
  # PostgreSQL supports timezones in literal timestamps
3460
2533
  def supports_timestamp_timezones?
3461
2534
  # SEQUEL6: Remove
3462
2535
  true
3463
2536
  end
3464
- # :nocov:
2537
+ # simplecov:enable
3465
2538
 
3466
2539
  # PostgreSQL 8.4+ supports WINDOW clause.
3467
2540
  def supports_window_clause?
@@ -3576,7 +2649,7 @@ module Sequel
3576
2649
  end
3577
2650
 
3578
2651
  # Use from_self for aggregate dataset using VALUES.
3579
- def aggreate_dataset_use_from_self?
2652
+ def aggregate_dataset_use_from_self?
3580
2653
  super || @opts[:values]
3581
2654
  end
3582
2655
 
@@ -3591,11 +2664,10 @@ module Sequel
3591
2664
  "'%Y-%m-%d %H:%M:%S.%6N%z'"
3592
2665
  end
3593
2666
 
3594
- # Only include the primary table in the main delete clause.
3595
- # Support FOR PORTION OF.
2667
+ # Only include the primary table in the main delete clause
3596
2668
  def delete_from_sql(sql)
3597
2669
  sql << ' FROM '
3598
- table_for_portion_of_sql_append(sql)
2670
+ source_list_append(sql, @opts[:from][0..0])
3599
2671
  end
3600
2672
 
3601
2673
  # Use USING to specify additional tables in a delete query
@@ -3638,7 +2710,7 @@ module Sequel
3638
2710
  origin = String.new
3639
2711
  origin << 'EXPLAIN '
3640
2712
 
3641
- # :nocov:
2713
+ # simplecov:disable
3642
2714
  if server_version < 90000
3643
2715
  if opts[:analyze]
3644
2716
  origin << 'ANALYZE '
@@ -3646,7 +2718,7 @@ module Sequel
3646
2718
 
3647
2719
  return origin
3648
2720
  end
3649
- # :nocov:
2721
+ # simplecov:enable
3650
2722
 
3651
2723
  comma = nil
3652
2724
  paren = "("
@@ -3680,32 +2752,6 @@ module Sequel
3680
2752
  origin
3681
2753
  end
3682
2754
 
3683
- # Add FOR PORTION OF SQL if the dataset uses it.
3684
- def table_for_portion_of_sql_append(sql)
3685
- fpo_column, fpo_range = @opts[:for_portion_of]
3686
- if fpo_column
3687
- table, aliaz = split_alias(@opts[:from].first)
3688
- source_list_append(sql, [table])
3689
- sql << ' FOR PORTION OF '
3690
- literal_append(sql, fpo_column)
3691
-
3692
- if fpo_range.is_a?(Array)
3693
- fpo_start, fpo_end = fpo_range
3694
- sql << ' FROM '
3695
- literal_append(sql, fpo_start)
3696
- sql << ' TO '
3697
- literal_append(sql, fpo_end)
3698
- else
3699
- sql << ' ('
3700
- literal_append(sql, fpo_range)
3701
- sql << ')'
3702
- end
3703
- as_sql_append(sql, aliaz) if aliaz
3704
- else
3705
- source_list_append(sql, @opts[:from][0..0])
3706
- end
3707
- end
3708
-
3709
2755
  # Add ON CONFLICT clause if it should be used
3710
2756
  def insert_conflict_sql(sql)
3711
2757
  if opts = @opts[:insert_conflict]
@@ -3726,13 +2772,19 @@ module Sequel
3726
2772
  if values = opts[:update]
3727
2773
  sql << " DO UPDATE SET "
3728
2774
  update_sql_values_hash(sql, values)
3729
- if update_where = opts[:update_where]
3730
- sql << " WHERE "
3731
- literal_append(sql, update_where)
3732
- end
2775
+ where = opts[:update_where]
2776
+ elsif opts[:select]
2777
+ sql << " DO SELECT"
2778
+ select_lock_sql(sql)
2779
+ where = opts[:select_where]
3733
2780
  else
3734
2781
  sql << " DO NOTHING"
3735
2782
  end
2783
+
2784
+ if where
2785
+ sql << " WHERE "
2786
+ literal_append(sql, where)
2787
+ end
3736
2788
  end
3737
2789
  end
3738
2790
 
@@ -3995,10 +3047,10 @@ module Sequel
3995
3047
  join_from_sql(:FROM, sql)
3996
3048
  end
3997
3049
 
3998
- # Support FOR PORTION OF.
3050
+ # Only include the primary table in the main update clause
3999
3051
  def update_table_sql(sql)
4000
3052
  sql << ' '
4001
- table_for_portion_of_sql_append(sql)
3053
+ source_list_append(sql, @opts[:from][0..0])
4002
3054
  end
4003
3055
  end
4004
3056
  end