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.
- checksums.yaml +4 -4
- data/bin/sequel +5 -5
- data/lib/sequel/adapters/ado.rb +1 -1
- data/lib/sequel/adapters/amalgalite.rb +34 -8
- data/lib/sequel/adapters/ibmdb.rb +2 -2
- data/lib/sequel/adapters/jdbc/hsqldb.rb +1 -1
- data/lib/sequel/adapters/jdbc/mssql.rb +28 -5
- data/lib/sequel/adapters/jdbc/mysql.rb +1 -1
- data/lib/sequel/adapters/jdbc/postgresql.rb +14 -3
- data/lib/sequel/adapters/jdbc.rb +4 -3
- data/lib/sequel/adapters/mock.rb +1 -1
- data/lib/sequel/adapters/mysql.rb +7 -2
- data/lib/sequel/adapters/mysql2.rb +5 -4
- data/lib/sequel/adapters/postgres.rb +42 -39
- data/lib/sequel/adapters/shared/db2.rb +5 -2
- data/lib/sequel/adapters/shared/mssql.rb +11 -5
- data/lib/sequel/adapters/shared/mysql.rb +2 -2
- data/lib/sequel/adapters/shared/postgres.rb +80 -1028
- data/lib/sequel/adapters/shared/sqlanywhere.rb +0 -32
- data/lib/sequel/adapters/shared/sqlite.rb +3 -3
- data/lib/sequel/adapters/sqlite.rb +13 -9
- data/lib/sequel/adapters/trilogy.rb +2 -1
- data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +1 -1
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +11 -1
- data/lib/sequel/connection_pool/sharded_single.rb +1 -1
- data/lib/sequel/connection_pool/sharded_threaded.rb +7 -5
- data/lib/sequel/connection_pool/sharded_timed_queue.rb +3 -3
- data/lib/sequel/connection_pool/threaded.rb +9 -7
- data/lib/sequel/connection_pool/timed_queue.rb +2 -2
- data/lib/sequel/connection_pool.rb +3 -3
- data/lib/sequel/core.rb +44 -24
- data/lib/sequel/database/connecting.rb +1 -1
- data/lib/sequel/database/features.rb +1 -1
- data/lib/sequel/database/misc.rb +6 -11
- data/lib/sequel/database/query.rb +2 -2
- data/lib/sequel/database/schema_generator.rb +4 -4
- data/lib/sequel/database/schema_methods.rb +2 -2
- data/lib/sequel/database/transactions.rb +5 -7
- data/lib/sequel/dataset/actions.rb +2 -2
- data/lib/sequel/dataset/features.rb +4 -4
- data/lib/sequel/dataset/graph.rb +1 -1
- data/lib/sequel/dataset/misc.rb +3 -3
- data/lib/sequel/dataset/prepared_statements.rb +2 -2
- data/lib/sequel/dataset/query.rb +8 -8
- data/lib/sequel/dataset/sql.rb +32 -13
- data/lib/sequel/dataset.rb +2 -2
- data/lib/sequel/deprecated.rb +2 -2
- data/lib/sequel/exceptions.rb +2 -2
- data/lib/sequel/extensions/_pretty_table.rb +1 -1
- data/lib/sequel/extensions/async_thread_pool.rb +3 -3
- data/lib/sequel/extensions/auto_cast_date_and_time.rb +2 -2
- data/lib/sequel/extensions/blank.rb +2 -2
- data/lib/sequel/extensions/constraint_validations.rb +1 -1
- data/lib/sequel/extensions/core_refinements.rb +7 -10
- data/lib/sequel/extensions/date_arithmetic.rb +1 -1
- data/lib/sequel/extensions/datetime_parse_to_time.rb +2 -2
- data/lib/sequel/extensions/duplicate_columns_handler.rb +1 -3
- data/lib/sequel/extensions/graph_each.rb +1 -1
- data/lib/sequel/extensions/index_caching.rb +1 -1
- data/lib/sequel/extensions/inflector.rb +5 -5
- data/lib/sequel/extensions/is_distinct_from.rb +2 -2
- data/lib/sequel/extensions/lit_require_frozen.rb +20 -4
- data/lib/sequel/extensions/migration.rb +21 -7
- data/lib/sequel/extensions/named_timezones.rb +9 -9
- data/lib/sequel/extensions/pg_array.rb +10 -8
- data/lib/sequel/extensions/pg_array_ops.rb +69 -14
- data/lib/sequel/extensions/pg_auto_parameterize.rb +2 -2
- data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +3 -3
- data/lib/sequel/extensions/pg_enum.rb +2 -2
- data/lib/sequel/extensions/pg_extended_date_support.rb +5 -5
- data/lib/sequel/extensions/pg_extended_integer_support.rb +1 -1
- data/lib/sequel/extensions/pg_hstore.rb +2 -2
- data/lib/sequel/extensions/pg_hstore_ops.rb +5 -5
- data/lib/sequel/extensions/pg_inet.rb +2 -2
- data/lib/sequel/extensions/pg_inet_ops.rb +2 -2
- data/lib/sequel/extensions/pg_interval.rb +6 -6
- data/lib/sequel/extensions/pg_json.rb +4 -4
- data/lib/sequel/extensions/pg_json_ops.rb +15 -13
- data/lib/sequel/extensions/pg_range.rb +6 -6
- data/lib/sequel/extensions/pg_range_ops.rb +7 -7
- data/lib/sequel/extensions/pg_row.rb +4 -4
- data/lib/sequel/extensions/pg_row_ops.rb +6 -6
- data/lib/sequel/extensions/provenance.rb +2 -2
- data/lib/sequel/extensions/query.rb +2 -2
- data/lib/sequel/extensions/s.rb +6 -10
- data/lib/sequel/extensions/schema_dumper.rb +10 -6
- data/lib/sequel/extensions/sequel_4_dataset_methods.rb +2 -0
- data/lib/sequel/extensions/sql_comments.rb +1 -1
- data/lib/sequel/extensions/sql_log_normalizer.rb +1 -1
- data/lib/sequel/extensions/sqlite_json_ops.rb +2 -2
- data/lib/sequel/extensions/string_agg.rb +5 -5
- data/lib/sequel/extensions/symbol_aref.rb +12 -32
- data/lib/sequel/extensions/symbol_aref_refinement.rb +2 -5
- data/lib/sequel/extensions/symbol_as.rb +1 -2
- data/lib/sequel/extensions/symbol_as_refinement.rb +1 -5
- data/lib/sequel/extensions/transaction_connection_validator.rb +1 -1
- data/lib/sequel/model/associations.rb +17 -17
- data/lib/sequel/model/base.rb +18 -15
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/model/plugins.rb +2 -2
- data/lib/sequel/model.rb +2 -2
- data/lib/sequel/plugins/association_pks.rb +1 -1
- data/lib/sequel/plugins/association_proxies.rb +4 -4
- data/lib/sequel/plugins/auto_restrict_eager_graph.rb +2 -0
- data/lib/sequel/plugins/caching.rb +28 -3
- data/lib/sequel/plugins/class_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/column_encryption.rb +10 -10
- data/lib/sequel/plugins/concurrent_eager_loading.rb +2 -2
- data/lib/sequel/plugins/csv_serializer.rb +9 -20
- data/lib/sequel/plugins/deprecated_associations.rb +2 -2
- data/lib/sequel/plugins/eager_each.rb +1 -1
- data/lib/sequel/plugins/finder.rb +1 -1
- data/lib/sequel/plugins/forbid_lazy_load.rb +3 -3
- data/lib/sequel/plugins/insert_conflict.rb +1 -1
- data/lib/sequel/plugins/insert_returning_select.rb +1 -1
- data/lib/sequel/plugins/instance_filters.rb +8 -0
- data/lib/sequel/plugins/instance_hooks.rb +19 -0
- data/lib/sequel/plugins/json_serializer.rb +4 -4
- data/lib/sequel/plugins/lazy_attributes.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +1 -1
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +9 -0
- data/lib/sequel/plugins/optimistic_locking.rb +12 -2
- data/lib/sequel/plugins/optimistic_locking_base.rb +14 -0
- data/lib/sequel/plugins/pg_array_associations.rb +4 -4
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +3 -3
- data/lib/sequel/plugins/pg_eager_any_typed_array.rb +2 -2
- data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +11 -2
- data/lib/sequel/plugins/prepared_statements.rb +2 -2
- data/lib/sequel/plugins/select_on_skipped_update.rb +63 -0
- data/lib/sequel/plugins/serialization.rb +1 -1
- data/lib/sequel/plugins/sharding.rb +1 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +21 -3
- data/lib/sequel/plugins/skip_saving_columns.rb +2 -2
- data/lib/sequel/plugins/split_values.rb +1 -1
- data/lib/sequel/plugins/sql_comments.rb +8 -8
- data/lib/sequel/plugins/subclasses.rb +6 -6
- data/lib/sequel/plugins/subset_conditions.rb +5 -16
- data/lib/sequel/plugins/tactical_eager_loading.rb +1 -1
- data/lib/sequel/plugins/throw_failures.rb +3 -3
- data/lib/sequel/plugins/unused_associations.rb +5 -5
- data/lib/sequel/plugins/validate_associated.rb +7 -1
- data/lib/sequel/plugins/validate_associated_context.rb +52 -0
- data/lib/sequel/plugins/validation_helpers.rb +1 -1
- data/lib/sequel/plugins/xml_serializer.rb +2 -0
- data/lib/sequel/sql.rb +120 -116
- data/lib/sequel/version.rb +1 -1
- 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
|
|
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
|
|
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
|
|
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
|
-
# :
|
|
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
|
-
# :
|
|
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
|
-
# :
|
|
793
|
+
# simplecov:disable
|
|
1578
794
|
auto_increment_key = server_version >= 100002 ? :identity : :serial
|
|
1579
|
-
# :
|
|
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
|
-
# :
|
|
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
|
-
# :
|
|
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
|
-
# :
|
|
1024
|
+
# simplecov:disable
|
|
1819
1025
|
else
|
|
1820
1026
|
Sequel.cast(true, TrueClass)
|
|
1821
|
-
# :
|
|
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
|
-
# :
|
|
1033
|
+
# simplecov:disable
|
|
1828
1034
|
else
|
|
1829
1035
|
Sequel.cast(true, TrueClass)
|
|
1830
|
-
# :
|
|
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
|
-
# :
|
|
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
|
-
# :
|
|
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
|
-
# :
|
|
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
|
-
# :
|
|
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
|
-
# :
|
|
1166
|
+
# simplecov:disable
|
|
1961
1167
|
if server_version > 100000
|
|
1962
|
-
# :
|
|
1168
|
+
# simplecov:enable
|
|
1963
1169
|
ds = ds.select_append{pg_attribute[:attidentity]}
|
|
1964
1170
|
|
|
1965
|
-
# :
|
|
1171
|
+
# simplecov:disable
|
|
1966
1172
|
if server_version > 120000
|
|
1967
|
-
# :
|
|
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
|
-
|
|
2380
|
-
|
|
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
|
|
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
|
-
# :
|
|
1937
|
+
# simplecov:disable
|
|
2862
1938
|
if server_version >= 90600
|
|
2863
|
-
# :
|
|
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
|
-
# :
|
|
2028
|
+
# simplecov:disable
|
|
2953
2029
|
:local if server_version >= 90400
|
|
2954
|
-
# :
|
|
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
|
-
# :
|
|
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
|
-
# :
|
|
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
|
|
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
|
-
# :
|
|
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
|
-
# :
|
|
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
|
|
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
|
-
|
|
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
|
-
# :
|
|
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
|
-
# :
|
|
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
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
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
|
-
#
|
|
3050
|
+
# Only include the primary table in the main update clause
|
|
3999
3051
|
def update_table_sql(sql)
|
|
4000
3052
|
sql << ' '
|
|
4001
|
-
|
|
3053
|
+
source_list_append(sql, @opts[:from][0..0])
|
|
4002
3054
|
end
|
|
4003
3055
|
end
|
|
4004
3056
|
end
|