├── spec
├── files
│ ├── empty_migration_folder
│ │ └── .gitkeep
│ ├── empty_migration
│ │ ├── 002_create_nodes.rb
│ │ ├── 003_3_create_users.rb
│ │ └── 001_create_sessions.rb
│ ├── bad_up_migration
│ │ ├── 002_create_alt_advanced.rb
│ │ └── 001_create_alt_basic.rb
│ ├── bad_timestamped_migrations
│ │ ├── 1273253853_3_create_users.rb
│ │ ├── 1273253851_create_nodes.rb
│ │ └── 1273253849_create_sessions.rb
│ ├── reversible_migrations
│ │ ├── 004_reversible.rb
│ │ ├── 002_reversible.rb
│ │ ├── 003_reversible.rb
│ │ ├── 001_reversible.rb
│ │ ├── 006_reversible.rb
│ │ ├── 005_reversible.rb
│ │ └── 007_reversible.rb
│ ├── transaction_unspecified_migrations
│ │ ├── 002_create_basic.rb
│ │ └── 001_create_alt_basic.rb
│ ├── bad_down_migration
│ │ ├── 001_create_alt_basic.rb
│ │ └── 002_create_alt_advanced.rb
│ ├── double_migration
│ │ ├── 003_3_create_users.rb
│ │ ├── 001_create_sessions.rb
│ │ └── 002_create_nodes.rb
│ ├── integer_migrations
│ │ ├── 003_3_create_users.rb
│ │ ├── 002_create_nodes.rb
│ │ └── 001_create_sessions.rb
│ ├── transaction_specified_migrations
│ │ ├── 002_create_basic.rb
│ │ └── 001_create_alt_basic.rb
│ ├── timestamped_migrations
│ │ ├── 1273253853_3_create_users.rb
│ │ ├── 1273253851_create_nodes.rb
│ │ └── 1273253849_create_sessions.rb
│ ├── convert_to_timestamp_migrations
│ │ ├── 003_3_create_users.rb
│ │ ├── 002_create_nodes.rb
│ │ ├── 001_create_sessions.rb
│ │ ├── 1273253850_create_artists.rb
│ │ └── 1273253852_create_albums.rb
│ ├── duplicate_integer_migrations
│ │ ├── 001_create_alt_basic.rb
│ │ └── 001_create_alt_advanced.rb
│ ├── missing_integer_migrations
│ │ ├── 001_create_alt_basic.rb
│ │ └── 003_create_alt_advanced.rb
│ ├── duplicate_timestamped_migrations
│ │ ├── 1273253853_create_users.rb
│ │ ├── 1273253853_create_nodes.rb
│ │ └── 1273253849_create_sessions.rb
│ ├── missing_timestamped_migrations
│ │ ├── 1273253853_3_create_users.rb
│ │ └── 1273253849_create_sessions.rb
│ ├── uppercase_timestamped_migrations
│ │ ├── 1273253853_3_CREATE_USERS.RB
│ │ ├── 1273253851_CREATE_NODES.RB
│ │ └── 1273253849_CREATE_SESSIONS.RB
│ ├── interleaved_timestamped_migrations
│ │ ├── 1273253853_3_create_users.rb
│ │ ├── 1273253851_create_nodes.rb
│ │ ├── 1273253852_create_albums.rb
│ │ ├── 1273253849_create_sessions.rb
│ │ └── 1273253850_create_artists.rb
│ ├── missing_integer_migrations_missing_last_version
│ │ └── 001_create_alt_basic.rb
│ └── unused_associations
│ │ ├── tua.rb
│ │ └── run_tua.rb
├── bin_shim
├── core_spec.rb
├── model_spec.rb
├── plugin_spec.rb
├── core_model_spec.rb
├── model_no_assoc_spec.rb
├── adapter_spec.rb
├── spec_config.rb.example
├── core
│ ├── version_spec.rb
│ └── spec_helper.rb
├── extensions
│ ├── error_splitter_spec.rb
│ ├── dataset_run_spec.rb
│ ├── symbol_as_refinement_spec.rb
│ ├── singular_table_names_spec.rb
│ ├── skip_create_refresh_spec.rb
│ ├── unlimited_update_spec.rb
│ ├── exclude_or_null_spec.rb
│ ├── stdio_logger_spec.rb
│ ├── integer64_spec.rb
│ ├── auto_cast_date_and_time_spec.rb
│ ├── after_initialize_spec.rb
│ ├── symbol_aref_refinement_spec.rb
│ ├── columns_updated_spec.rb
│ ├── constant_sql_override_spec.rb
│ ├── freeze_datasets_spec.rb
│ ├── pg_loose_count_spec.rb
│ ├── validation_contexts_spec.rb
│ ├── current_datetime_timestamp_spec.rb
│ ├── pg_timestamptz_spec.rb
│ ├── auto_restrict_eager_graph_spec.rb
│ ├── error_sql_spec.rb
│ ├── looser_typecasting_spec.rb
│ ├── select_remove_spec.rb
│ ├── pg_extended_integer_support_spec.rb
│ ├── accessed_columns_spec.rb
│ ├── async_thread_pool_plugin_spec.rb
│ ├── single_statement_dataset_destroy_spec.rb
│ ├── split_array_nil_spec.rb
│ ├── boolean_subsets_spec.rb
│ └── inverted_subsets_spec.rb
├── visibility_checking.rb
├── model
│ ├── exceptions_spec.rb
│ └── spec_helper.rb
├── deprecation_helper.rb
├── async_spec_helper.rb
├── sequel_coverage.rb
└── visibility_checking_after_hook.rb
├── lib
├── sequel.rb
└── sequel
│ ├── adapters
│ ├── postgresql.rb
│ ├── odbc
│ │ ├── db2.rb
│ │ └── oracle.rb
│ ├── utils
│ │ ├── columns_limit_1.rb
│ │ ├── unmodified_identifiers.rb
│ │ ├── replace.rb
│ │ └── split_alter_table.rb
│ └── jdbc
│ │ ├── mssql.rb
│ │ └── jtds.rb
│ ├── extensions
│ ├── from_block.rb
│ ├── freeze_datasets.rb
│ ├── no_auto_literal_strings.rb
│ ├── _model_constraint_validations.rb
│ ├── symbol_as.rb
│ ├── sql_expr.rb
│ ├── fiber_concurrency.rb
│ ├── _model_pg_row.rb
│ ├── symbol_as_refinement.rb
│ ├── pretty_table.rb
│ ├── integer64.rb
│ ├── blank.rb
│ ├── pg_loose_count.rb
│ ├── symbol_aref_refinement.rb
│ ├── set_literalizer.rb
│ ├── dataset_run.rb
│ ├── any_not_empty.rb
│ ├── looser_typecasting.rb
│ ├── virtual_row_method_block.rb
│ ├── symbol_aref.rb
│ ├── datetime_parse_to_time.rb
│ ├── empty_array_consider_nulls.rb
│ ├── string_date_time.rb
│ ├── s.rb
│ ├── stdio_logger.rb
│ └── round_timestamps.rb
│ ├── plugins
│ ├── before_after_save.rb
│ ├── unlimited_update.rb
│ ├── after_initialize.rb
│ ├── singular_table_names.rb
│ ├── skip_create_refresh.rb
│ ├── inspect_pk.rb
│ ├── columns_updated.rb
│ ├── empty_failure_backtraces.rb
│ └── async_thread_pool.rb
│ ├── version.rb
│ ├── model
│ └── dataset_module.rb
│ ├── connection_pool
│ └── single.rb
│ ├── database.rb
│ └── dataset
│ ├── deprecated_singleton_class_methods.rb
│ └── dataset_module.rb
├── www
├── public
│ ├── images
│ │ ├── favicon.ico
│ │ ├── sequel-button.png
│ │ └── transparent-background.svg
│ └── css
│ │ ├── development.css
│ │ ├── documentation.css
│ │ ├── plugins.css
│ │ └── links.css
└── make_www.rb
├── .gitignore
├── .github
└── ISSUE_TEMPLATE
│ └── config.yml
├── doc
├── release_notes
│ ├── 5.48.0.txt
│ ├── 5.28.0.txt
│ ├── 5.30.0.txt
│ ├── 5.39.0.txt
│ ├── 5.27.0.txt
│ ├── 5.60.0.txt
│ ├── 5.71.0.txt
│ ├── 5.55.0.txt
│ ├── 5.65.0.txt
│ ├── 5.29.0.txt
│ ├── 5.33.0.txt
│ ├── 5.69.0.txt
│ ├── 5.13.0.txt
│ ├── 5.66.0.txt
│ ├── 5.19.0.txt
│ ├── 5.57.0.txt
│ ├── 5.53.0.txt
│ ├── 5.41.0.txt
│ ├── 5.1.0.txt
│ ├── 4.6.0.txt
│ ├── 5.92.0.txt
│ ├── 5.79.0.txt
│ ├── 5.17.0.txt
│ ├── 5.38.0.txt
│ ├── 5.25.0.txt
│ ├── 5.54.0.txt
│ ├── 5.97.0.txt
│ ├── 5.81.0.txt
│ ├── 5.58.0.txt
│ ├── 4.5.0.txt
│ ├── 5.67.0.txt
│ ├── 5.84.0.txt
│ ├── 5.37.0.txt
│ ├── 5.45.0.txt
│ ├── 4.16.0.txt
│ ├── 5.6.0.txt
│ ├── 5.2.0.txt
│ ├── 4.3.0.txt
│ ├── 4.30.0.txt
│ ├── 5.87.0.txt
│ ├── 5.44.0.txt
│ ├── 1.0.txt
│ ├── 5.74.0.txt
│ ├── 4.18.0.txt
│ ├── 5.26.0.txt
│ ├── 4.29.0.txt
│ ├── 5.40.0.txt
│ ├── 3.22.0.txt
│ ├── 5.63.0.txt
│ ├── 3.20.0.txt
│ ├── 5.96.0.txt
│ ├── 5.72.0.txt
│ ├── 4.17.0.txt
│ ├── 5.34.0.txt
│ ├── 5.70.0.txt
│ ├── 5.75.0.txt
│ ├── 5.80.0.txt
│ └── 5.22.0.txt
├── mssql_stored_procedures.rdoc
└── thread_safety.rdoc
├── MIT-LICENSE
└── sequel.gemspec
/spec/files/empty_migration_folder/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/files/empty_migration/002_create_nodes.rb:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/bin_shim:
--------------------------------------------------------------------------------
1 | load(File.join(Dir.pwd, 'bin/sequel'))
2 |
--------------------------------------------------------------------------------
/spec/core_spec.rb:
--------------------------------------------------------------------------------
1 | Dir['./spec/core/*_spec.rb'].each{|f| require f}
2 |
--------------------------------------------------------------------------------
/spec/model_spec.rb:
--------------------------------------------------------------------------------
1 | Dir['./spec/model/*_spec.rb'].each{|f| require f}
2 |
--------------------------------------------------------------------------------
/spec/plugin_spec.rb:
--------------------------------------------------------------------------------
1 | Dir['./spec/extensions/*_spec.rb'].each{|f| require f}
2 |
--------------------------------------------------------------------------------
/lib/sequel.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | require_relative 'sequel/model'
4 |
--------------------------------------------------------------------------------
/spec/core_model_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative 'core_spec'
2 | require_relative 'model_spec'
3 |
--------------------------------------------------------------------------------
/lib/sequel/adapters/postgresql.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | require_relative 'postgres'
4 |
--------------------------------------------------------------------------------
/spec/files/bad_up_migration/002_create_alt_advanced.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | up{get(:asdfassfd)}
3 | end
4 |
--------------------------------------------------------------------------------
/www/public/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeremyevans/sequel/HEAD/www/public/images/favicon.ico
--------------------------------------------------------------------------------
/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | up{get(:asdfsadfas)}
3 | end
4 |
--------------------------------------------------------------------------------
/www/public/images/sequel-button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeremyevans/sequel/HEAD/www/public/images/sequel-button.png
--------------------------------------------------------------------------------
/lib/sequel/extensions/from_block.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | Sequel::Database.register_extension(:from_block){}
4 |
--------------------------------------------------------------------------------
/spec/model_no_assoc_spec.rb:
--------------------------------------------------------------------------------
1 | Dir['./spec/model/*_spec.rb'].delete_if{|f| f =~ /association|eager_loading/}.each{|f| require f}
2 |
--------------------------------------------------------------------------------
/spec/files/reversible_migrations/004_reversible.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | change do
3 | rename_table :a, :b
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/freeze_datasets.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | Sequel::Database.register_extension(:freeze_datasets){}
4 |
--------------------------------------------------------------------------------
/spec/files/reversible_migrations/002_reversible.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | change do
3 | add_column :a, :b, String
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/spec/files/reversible_migrations/003_reversible.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | change do
3 | rename_column :a, :b, :c
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/spec/files/reversible_migrations/001_reversible.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | change do
3 | create_table(:a){Integer :a}
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/spec/files/transaction_unspecified_migrations/002_create_basic.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | change{create_table(:sm){Integer :smc1}}
3 | end
4 |
--------------------------------------------------------------------------------
/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | change{create_table(:sm11111){Integer :smc1}}
3 | end
4 |
--------------------------------------------------------------------------------
/spec/files/bad_down_migration/001_create_alt_basic.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | up{create_table(:sm11111){Integer :smc1}}
3 | down{get(:asdfsadfsa)}
4 | end
5 |
--------------------------------------------------------------------------------
/spec/files/double_migration/003_3_create_users.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | up{create_table(:sm3333){Integer :smc3}}
3 | down{drop_table(:sm3333)}
4 | end
5 |
--------------------------------------------------------------------------------
/spec/files/empty_migration/003_3_create_users.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | up{create_table(:sm3333){Integer :smc3}}
3 | down{drop_table(:sm3333)}
4 | end
5 |
--------------------------------------------------------------------------------
/spec/files/integer_migrations/003_3_create_users.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | up{create_table(:sm3333){Integer :smc3}}
3 | down{drop_table(:sm3333)}
4 | end
5 |
--------------------------------------------------------------------------------
/spec/files/transaction_specified_migrations/002_create_basic.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | no_transaction
3 | change{create_table(:sm){Integer :smc1}}
4 | end
5 |
--------------------------------------------------------------------------------
/www/public/css/development.css:
--------------------------------------------------------------------------------
1 | section.development {
2 | background-color: #FFF;
3 | border-radius: 12px;
4 | box-shadow: 0 24px 64px rgba(0,0,0,.15);
5 | }
6 |
--------------------------------------------------------------------------------
/spec/files/bad_up_migration/001_create_alt_basic.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | up{create_table(:sm11111){Integer :smc1}}
3 | down{drop_table(:sm11111)}
4 | end
5 |
--------------------------------------------------------------------------------
/spec/files/bad_down_migration/002_create_alt_advanced.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | up{create_table(:sm22222){Integer :smc2}}
3 | down{drop_table(:sm22222)}
4 | end
5 |
--------------------------------------------------------------------------------
/spec/files/timestamped_migrations/1273253853_3_create_users.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | up{create_table(:sm3333){Integer :smc3}}
3 | down{drop_table(:sm3333)}
4 | end
5 |
--------------------------------------------------------------------------------
/spec/files/transaction_specified_migrations/001_create_alt_basic.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | transaction
3 | change{create_table(:sm11111){Integer :smc1}}
4 | end
5 |
--------------------------------------------------------------------------------
/lib/sequel/plugins/before_after_save.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | module Sequel
4 | module Plugins
5 | module BeforeAfterSave
6 | end
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | up{create_table(:sm3333){Integer :smc3}}
3 | down{drop_table(:sm3333)}
4 | end
5 |
--------------------------------------------------------------------------------
/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | up{create_table(:sm11111){Integer :smc1}}
3 | down{drop_table(:sm11111)}
4 | end
5 |
--------------------------------------------------------------------------------
/spec/files/missing_integer_migrations/001_create_alt_basic.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | up{create_table(:sm11111){Integer :smc1}}
3 | down{drop_table(:sm11111)}
4 | end
5 |
--------------------------------------------------------------------------------
/spec/files/missing_integer_migrations/003_create_alt_advanced.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | up{create_table(:sm33333){Integer :smc3}}
3 | down{drop_table(:sm33333)}
4 | end
5 |
--------------------------------------------------------------------------------
/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | up{create_table(:sm33333){Integer :smc3}}
3 | down{drop_table(:sm33333)}
4 | end
5 |
--------------------------------------------------------------------------------
/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | up{create_table(:sm3333){Integer :smc3}}
3 | down{drop_table(:sm3333)}
4 | end
5 |
--------------------------------------------------------------------------------
/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | up{create_table(:sm3333){Integer :smc3}}
3 | down{drop_table(:sm3333)}
4 | end
5 |
--------------------------------------------------------------------------------
/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | up{create_table(:sm3333){Integer :smc3}}
3 | down{drop_table(:sm3333)}
4 | end
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.lock
2 | *.rbc
3 | *.swp
4 | /coverage
5 | /rdoc
6 | /sequel-*.gem
7 | /spec/bin-sequel-*
8 | /spec/spec_config.rb
9 | /www/public/*.html
10 | /www/public/rdoc*
11 |
--------------------------------------------------------------------------------
/spec/adapter_spec.rb:
--------------------------------------------------------------------------------
1 | if !ARGV.empty? && ARGV.first != 'none'
2 | require_relative "adapters/#{ARGV.first}_spec"
3 | end
4 | Dir['./spec/integration/*_test.rb'].each{|f| require f}
5 |
--------------------------------------------------------------------------------
/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | up{create_table(:sm3333){Integer :smc3}}
3 | down{drop_table(:sm3333)}
4 | end
5 |
--------------------------------------------------------------------------------
/spec/spec_config.rb.example:
--------------------------------------------------------------------------------
1 | # Custom setup for the adapter/integration specs
2 | # ENV['SEQUEL_INTEGRATION_URL'] = 'sqlite:/'
3 | # ENV['SEQUEL_POSTGRES_URL'] = 'postgres://localhost/test'
4 |
--------------------------------------------------------------------------------
/spec/files/missing_integer_migrations_missing_last_version/001_create_alt_basic.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | up{create_table(:sm11111){Integer :smc1}}
3 | down{drop_table(:sm11111)}
4 | end
5 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/no_auto_literal_strings.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | Sequel::Database.register_extension(:no_auto_literal_strings){}
4 | Sequel::Dataset.register_extension(:no_auto_literal_strings){}
5 |
--------------------------------------------------------------------------------
/spec/files/integer_migrations/002_create_nodes.rb:
--------------------------------------------------------------------------------
1 | Class.new(Sequel::Migration) do
2 | def up
3 | create_table(:sm2222){Integer :smc2}
4 | end
5 |
6 | def down
7 | drop_table(:sm2222)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/double_migration/001_create_sessions.rb:
--------------------------------------------------------------------------------
1 | class CreateSessions < Sequel::Migration
2 | def up
3 | create_table(:sm1111){Integer :smc1}
4 | end
5 |
6 | def down
7 | drop_table(:sm1111)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/empty_migration/001_create_sessions.rb:
--------------------------------------------------------------------------------
1 | class CreateSessions < Sequel::Migration
2 | def up
3 | create_table(:sm1111){Integer :smc1}
4 | end
5 |
6 | def down
7 | drop_table(:sm1111)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/integer_migrations/001_create_sessions.rb:
--------------------------------------------------------------------------------
1 | class CreateSessions < Sequel::Migration
2 | def up
3 | create_table(:sm1111){Integer :smc1}
4 | end
5 |
6 | def down
7 | drop_table(:sm1111)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb:
--------------------------------------------------------------------------------
1 | Class.new(Sequel::Migration) do
2 | def up
3 | create_table(:sm2222){Integer :smc2}
4 | end
5 |
6 | def down
7 | drop_table(:sm2222)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb:
--------------------------------------------------------------------------------
1 | Class.new(Sequel::Migration) do
2 | def up
3 | create_table(:sm2222){Integer :smc2}
4 | end
5 |
6 | def down
7 | drop_table(:sm2222)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/timestamped_migrations/1273253851_create_nodes.rb:
--------------------------------------------------------------------------------
1 | Class.new(Sequel::Migration) do
2 | def up
3 | create_table(:sm2222){Integer :smc2}
4 | end
5 |
6 | def down
7 | drop_table(:sm2222)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb:
--------------------------------------------------------------------------------
1 | class CreateSessions < Sequel::Migration
2 | def up
3 | create_table(:sm1111){Integer :smc1}
4 | end
5 |
6 | def down
7 | get(:asdfsadfas)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb:
--------------------------------------------------------------------------------
1 | class CreateSessions < Sequel::Migration
2 | def up
3 | create_table(:sm1111){Integer :smc1}
4 | end
5 |
6 | def down
7 | drop_table(:sm1111)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb:
--------------------------------------------------------------------------------
1 | Class.new(Sequel::Migration) do
2 | def up
3 | create_table(:sm2222){Integer :smc2}
4 | end
5 |
6 | def down
7 | drop_table(:sm2222)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb:
--------------------------------------------------------------------------------
1 | Class.new(Sequel::Migration) do
2 | def up
3 | create_table(:sm2222){Integer :smc2}
4 | end
5 |
6 | def down
7 | drop_table(:sm2222)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/reversible_migrations/006_reversible.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | change do
3 | create_table(:c) do
4 | primary_key :id
5 | end
6 | alter_table(:b) do
7 | add_foreign_key :f, :c
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/spec/files/timestamped_migrations/1273253849_create_sessions.rb:
--------------------------------------------------------------------------------
1 | class CreateSessions < Sequel::Migration
2 | def up
3 | create_table(:sm1111){Integer :smc1}
4 | end
5 |
6 | def down
7 | drop_table(:sm1111)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB:
--------------------------------------------------------------------------------
1 | Class.new(Sequel::Migration) do
2 | def up
3 | create_table(:sm2222){Integer :smc2}
4 | end
5 |
6 | def down
7 | drop_table(:sm2222)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb:
--------------------------------------------------------------------------------
1 | class CreateArtists < Sequel::Migration
2 | def up
3 | create_table(:sm1122){Integer :smc12}
4 | end
5 |
6 | def down
7 | drop_table(:sm1122)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb:
--------------------------------------------------------------------------------
1 | class CreateAlbums < Sequel::Migration
2 | def up
3 | create_table(:sm2233){Integer :smc23}
4 | end
5 |
6 | def down
7 | drop_table(:sm2233)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb:
--------------------------------------------------------------------------------
1 | class CreateAlbums < Sequel::Migration
2 | def up
3 | create_table(:sm2233){Integer :smc23}
4 | end
5 |
6 | def down
7 | drop_table(:sm2233)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb:
--------------------------------------------------------------------------------
1 | class CreateSessions < Sequel::Migration
2 | def up
3 | create_table(:sm1111){Integer :smc1}
4 | end
5 |
6 | def down
7 | drop_table(:sm1111)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/reversible_migrations/005_reversible.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | change do
3 | alter_table(:b) do
4 | add_column :d, String
5 | end
6 | alter_table(:b) do
7 | rename_column :d, :e
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb:
--------------------------------------------------------------------------------
1 | class CreateSessions < Sequel::Migration
2 | def up
3 | create_table(:sm1111){Integer :smc1}
4 | end
5 |
6 | def down
7 | drop_table(:sm1111)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb:
--------------------------------------------------------------------------------
1 | class CreateSessions < Sequel::Migration
2 | def up
3 | create_table(:sm1111){Integer :smc1}
4 | end
5 |
6 | def down
7 | drop_table(:sm1111)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb:
--------------------------------------------------------------------------------
1 | class CreateArtists < Sequel::Migration
2 | def up
3 | create_table(:sm1122){Integer :smc12}
4 | end
5 |
6 | def down
7 | drop_table(:sm1122)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB:
--------------------------------------------------------------------------------
1 | class CreateSessions < Sequel::Migration
2 | def up
3 | create_table(:sm1111){Integer :smc1}
4 | end
5 |
6 | def down
7 | drop_table(:sm1111)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/files/reversible_migrations/007_reversible.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | change do
3 | create_table(:d) do
4 | primary_key :id
5 | end
6 | alter_table(:b) do
7 | add_foreign_key :g, :d, :foreign_key_constraint_name=>:b_f_foo
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/www/public/images/transparent-background.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Questions or Feature Requests
4 | url: https://github.com/jeremyevans/sequel/discussions/new?category=general
5 | about: If you aren't sure what you are reporting is a bug in Sequel, open a discussion post instead of an issue.
6 |
--------------------------------------------------------------------------------
/lib/sequel/adapters/odbc/db2.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | require_relative '../shared/db2'
4 |
5 | Sequel.synchronize do
6 | Sequel::ODBC::DATABASE_SETUP[:db2] = proc do |db|
7 | db.extend ::Sequel::DB2::DatabaseMethods
8 | db.extend_datasets ::Sequel::DB2::DatasetMethods
9 | end
10 | end
11 |
12 |
--------------------------------------------------------------------------------
/lib/sequel/adapters/odbc/oracle.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | require_relative '../shared/oracle'
4 |
5 | Sequel.synchronize do
6 | Sequel::ODBC::DATABASE_SETUP[:oracle] = proc do |db|
7 | db.extend ::Sequel::Oracle::DatabaseMethods
8 | db.extend_datasets ::Sequel::Oracle::DatasetMethods
9 | end
10 | end
11 |
12 |
--------------------------------------------------------------------------------
/spec/files/double_migration/002_create_nodes.rb:
--------------------------------------------------------------------------------
1 | Class.new(Sequel::Migration) do
2 | def up
3 | create_table(:sm2222){Integer :smc2}
4 | end
5 |
6 | def down
7 | drop_table(:sm2222)
8 | end
9 | end
10 |
11 | Class.new(Sequel::Migration) do
12 | def up
13 | create_table(:sm2443){Integer :smc2}
14 | end
15 |
16 | def down
17 | drop_table(:sm2443)
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/www/public/css/documentation.css:
--------------------------------------------------------------------------------
1 | section.documentation {
2 | background-color: #FFF;
3 | border-radius: 12px;
4 | box-shadow: 0 24px 64px rgba(0,0,0,.15);
5 | }
6 |
7 | ul.release-notes {
8 | font-family: var(--font-monospace);
9 | display: flex;
10 | flex-direction: column;
11 | gap: 8px;
12 | font-size: 14px;
13 | color: #ccc;
14 | list-style: none;
15 | margin-top: 8px;
16 | margin-bottom: 16px;
17 | padding: 0;
18 | }
19 |
20 | ul.release-notes__li {
21 | list-style: none;
22 | }
23 |
--------------------------------------------------------------------------------
/spec/core/version_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "Sequel.version" do
4 | it "should be in the form X.Y.Z with all being numbers" do
5 | Sequel.version.must_match(/\A\d+\.\d+\.\d+\z/)
6 | end
7 |
8 | it "MAJOR/MINOR/TINY/VERSION_NUMBER should be integers" do
9 | Sequel::MAJOR.must_be_kind_of(Integer)
10 | Sequel::MINOR.must_be_kind_of(Integer)
11 | Sequel::TINY.must_be_kind_of(Integer)
12 | Sequel::VERSION_NUMBER.must_be_kind_of(Integer)
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/spec/extensions/error_splitter_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "Sequel::Plugins::ErrorSplitter" do
4 | before do
5 | @c = Class.new(Sequel::Model)
6 | @c.plugin :error_splitter
7 | @m = @c.new
8 | def @m.validate
9 | errors.add([:a, :b], 'is bad')
10 | end
11 | end
12 |
13 | it "should split errors for multiple columns and assign them to each column" do
14 | @m.valid?.must_equal false
15 | @m.errors.must_equal(:a=>['is bad'], :b=>['is bad'])
16 | end
17 | end
18 |
19 |
--------------------------------------------------------------------------------
/www/make_www.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'erb'
3 | $: << File.join(File.dirname(__FILE__), '..','lib', 'sequel')
4 | require 'version'
5 | Dir.chdir(File.dirname(__FILE__))
6 | erb = ERB.new(File.read('layout.html.erb'))
7 | Dir['pages/*.html.erb'].each do |page|
8 | public_loc = "#{page.gsub(/\Apages\//, 'public/').sub('.erb', '')}"
9 | content = content = ERB.new(File.read(page)).result(binding)
10 | title = title = File.basename(page.sub('.html.erb', ''))
11 | File.open(public_loc, 'wb'){|f| f.write(erb.result(binding))}
12 | end
13 |
--------------------------------------------------------------------------------
/spec/extensions/dataset_run_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "dataset_run extension" do
4 | it "#run should run the SQL on the database" do
5 | db = Sequel.mock
6 | db["SQL with ?", "placeholder"].extension(:dataset_run).run.must_be_nil
7 | db.sqls.must_equal ["SQL with 'placeholder'"]
8 | end
9 |
10 | it "#run should respect current server" do
11 | db = Sequel.mock(:servers=>{:a=>{}})
12 | db["SQL with ?", "placeholder"].extension(:dataset_run).server(:a).run.must_be_nil
13 | db.sqls.must_equal ["SQL with 'placeholder' -- a"]
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/doc/release_notes/5.48.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * A Sequel::Database#like_without_collate accessor has been added on
4 | Microsoft SQL Server, which avoids using the COLLATE clause for
5 | LIKE expressions. This can speed up query performance significantly.
6 |
7 | * A private Sequel::Model::Errors#full_message method has been added
8 | to make it easier to support internationalization for Sequel::Model
9 | error messages.
10 |
11 | = Other Improvements
12 |
13 | * The association reflection tracking in the unused_associations
14 | plugin now works correctly when combining coverage runs.
15 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/_model_constraint_validations.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | module Sequel
4 | module Plugins
5 | module ConstraintValidations
6 | module DatabaseMethods
7 | # A hash of validation method call metadata for all tables in the database.
8 | # The hash is keyed by table name string and contains arrays of validation
9 | # method call arrays.
10 | attr_accessor :constraint_validations
11 | end
12 | end
13 | end
14 |
15 | Database.register_extension(:_model_constraint_validations, Plugins::ConstraintValidations::DatabaseMethods)
16 | end
17 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/symbol_as.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # The symbol_as extension adds Symbol#as, for creating
4 | # Sequel::SQL::AliasedExpression objects. It's
5 | # designed as a shortcut so that instead of:
6 | #
7 | # Sequel[:column].as(:alias)
8 | #
9 | # you can just write:
10 | #
11 | # :column.as(:alias)
12 | #
13 | # To load the extension:
14 | #
15 | # Sequel.extension :symbol_as
16 | #
17 | # If you are using Ruby 2+, and you would like to use refinements, there
18 | # is a refinement version of this in the symbol_as_refinement extension.
19 |
20 | #
21 | class Symbol
22 | include Sequel::SQL::AliasMethods
23 | end
24 |
--------------------------------------------------------------------------------
/spec/extensions/symbol_as_refinement_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | if (RUBY_VERSION >= '2.0.0' && RUBY_ENGINE == 'ruby') || (RUBY_VERSION >= '2.3.0' && RUBY_ENGINE == 'jruby')
4 | Sequel.extension :symbol_as_refinement
5 | using Sequel::SymbolAs
6 |
7 | describe "symbol_as_refinement extension" do
8 | before do
9 | @db = Sequel.mock
10 | end
11 |
12 | it "Symbol#as should create aliased expression" do
13 | @db.literal(:x.as(:y)).must_equal "x AS y"
14 | end
15 |
16 | it "Symbol#as should create aliased expression with columns" do
17 | @db.literal(:x.as(:y, [:c1, :c2])).must_equal "x AS y(c1, c2)"
18 | end
19 | end
20 | end
21 |
22 |
--------------------------------------------------------------------------------
/doc/release_notes/5.28.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * An any_not_empty extension has been added, for making Dataset#any?
4 | without a block be the same as !empty?. This can result in a
5 | much faster database query.
6 |
7 | * An exclude_or_null extension has been added, adding a
8 | Dataset#exclude_or_null method that returns rows where the given
9 | expression is false or NULL. This extension is supported on
10 | PostgreSQL, SQLite, MySQL, H2, and HSQLDB.
11 |
12 | = Other Improvements
13 |
14 | * When using the jdbc/postgresql adapter, calling with_fetch_size
15 | on a dataset will emit a warning. This is because the driver
16 | will ignore the setting.
17 |
--------------------------------------------------------------------------------
/spec/extensions/singular_table_names_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "singular_table_names plugin" do
4 | before do
5 | @c = Class.new(Sequel::Model)
6 | @c.plugin :singular_table_names
7 | end
8 | after do
9 | Object.send(:remove_const, :Foo)
10 | end
11 |
12 | it "should use the singular form of model name for table name" do
13 | class ::Foo < @c; end
14 | Foo.table_name.must_equal :foo
15 | end
16 |
17 | it "should handle namespaced models using single form of last component of model name" do
18 | module ::Foo; end
19 | class Foo::Bar < @c; end
20 | Foo::Bar.table_name.must_equal :bar
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/spec/extensions/skip_create_refresh_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "Sequel::Plugins::SkipCreateRefresh" do
4 | it "should skip the refresh after saving a new object" do
5 | c = Class.new(Sequel::Model(:a))
6 | c.columns :id, :x
7 | c.dataset = c.dataset.with_autoid(2)
8 | c.db.reset
9 | c.create(:x=>1)
10 | c.db.sqls.must_equal ['INSERT INTO a (x) VALUES (1)', 'SELECT * FROM a WHERE id = 2']
11 |
12 | c.dataset = c.dataset.with_autoid(2)
13 | c.plugin :skip_create_refresh
14 | c.db.reset
15 | c.create(:x=>3).values.must_equal(:id=>2, :x=>3)
16 | c.db.sqls.must_equal ['INSERT INTO a (x) VALUES (3)']
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/lib/sequel/adapters/utils/columns_limit_1.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | module Sequel
4 | class Dataset
5 | module ColumnsLimit1
6 | COLUMNS_CLONE_OPTIONS = {:distinct => nil, :limit => 1, :offset=>nil, :where=>nil, :having=>nil, :order=>nil, :row_proc=>nil, :graph=>nil, :eager_graph=>nil}.freeze
7 |
8 | # Use a limit of 1 instead of a limit of 0 when
9 | # getting the columns.
10 | def columns!
11 | ds = clone(COLUMNS_CLONE_OPTIONS)
12 | ds.each{break}
13 |
14 | if cols = ds.cache[:_columns]
15 | self.columns = cols
16 | else
17 | []
18 | end
19 | end
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/sql_expr.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # The sql_expr extension adds the sql_expr method to every object, which
4 | # returns an wrapped object that works nicely with Sequel's DSL by calling
5 | # Sequel.expr:
6 | #
7 | # 1.sql_expr < :a # 1 < a
8 | # false.sql_expr & :a # FALSE AND a
9 | # true.sql_expr | :a # TRUE OR a
10 | # ~nil.sql_expr # NOT NULL
11 | # "a".sql_expr + "b" # 'a' || 'b'
12 | #
13 | # To load the extension:
14 | #
15 | # Sequel.extension :sql_expr
16 |
17 | #
18 | class Object
19 | # Return the object wrapper in an appropriate Sequel expression object.
20 | def sql_expr
21 | Sequel[self]
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/doc/release_notes/5.30.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * Sequel now supports generated columns on SQLite 3.31+ using the
4 | :generated_always_as and :generated_type options. Example:
5 |
6 | DB.create_table(:table) do
7 | primary_key :id
8 | Numeric :amount, null: false
9 | Numeric :tax, null: false
10 | Numeric :total, generated_always_as: (Sequel[:amount] + :tax)
11 | end
12 |
13 | = Other Improvements
14 |
15 | * The Database#transaction :before_retry option is now called before
16 | retrying the transaction even when the :num_retries option is set
17 | to nil.
18 |
19 | * The gem no longer ships with specs and older release notes, reducing
20 | the gem size by over 40%.
21 |
--------------------------------------------------------------------------------
/spec/extensions/unlimited_update_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "Sequel::Plugins::UnlimitedUpdate" do
4 | before do
5 | @db = Sequel.mock(:host=>'mysql', :numrows=>1)
6 | @db.extend_datasets{def quote_identifiers?; false end}
7 | @c = Class.new(Sequel::Model(@db[:test]))
8 | @c.columns :id, :name
9 | @o = @c.load(:id=>1, :name=>'a')
10 | @db.sqls
11 | end
12 |
13 | it "should remove limit from update dataset" do
14 | @o.save
15 | @db.sqls.must_equal ["UPDATE test SET name = 'a' WHERE (id = 1) LIMIT 1"]
16 |
17 | @c.plugin :unlimited_update
18 | @o.save
19 | @db.sqls.must_equal ["UPDATE test SET name = 'a' WHERE (id = 1)"]
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/spec/visibility_checking.rb:
--------------------------------------------------------------------------------
1 | require 'visibility_checker'
2 | changes = VISIBILITY_CHANGES = []
3 | Minitest.after_run do
4 | if defined?(DB)
5 | [DB.singleton_class, DB.dataset.singleton_class].each do |c|
6 | VISIBILITY_CHANGES.concat(VisibilityChecker.visibility_changes(c).map{|v| [v, c.inspect]})
7 | end
8 | end
9 |
10 | changes.uniq!{|v,| v}
11 | changes.map! do |v, caller|
12 | "#{caller}: #{v.new_visibility} method #{v.overridden_by}##{v.method} overrides #{v.original_visibility} method in #{v.defined_in}"
13 | end
14 | changes.sort!
15 | if changes.empty?
16 | puts "No visibility changes"
17 | else
18 | puts "Visibility changes:"
19 | puts(*changes)
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/doc/release_notes/5.39.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * On Microsoft SQL Server, the :clustered option is now supported
4 | for primary key and unique constraints. You can use a true value
5 | for CLUSTERED and a false value for NONCLUSTERED.
6 |
7 | = Other Improvements
8 |
9 | * Partitioned tables are now included in the result of
10 | Database#tables on PostgreSQL.
11 |
12 | * alter_table set_column_allow_null no longer drops the size of
13 | binary columns on Microsoft SQL Server.
14 |
15 | * In the tree plugin, the roots_dataset method now works correctly
16 | with queries using joins by qualifying the parent column.
17 |
18 | * A fork safety guide has been added, discussing fork safety issues
19 | when using Sequel.
20 |
--------------------------------------------------------------------------------
/spec/extensions/exclude_or_null_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "exclude_or_null extension" do
4 | before do
5 | @ds = Sequel.mock[:t].extension(:exclude_or_null)
6 | end
7 |
8 | it "#exclude_or_null should add WHERE condition where a is false or NULL" do
9 | @ds.exclude_or_null(:a).sql.must_equal "SELECT * FROM t WHERE NOT coalesce(a, 'f')"
10 | end
11 |
12 | it "#exclude_or_null_having should add HAVING condition where a is false or NULL" do
13 | @ds.exclude_or_null_having(:a).sql.must_equal "SELECT * FROM t HAVING NOT coalesce(a, 'f')"
14 | end
15 |
16 | it "should not effect normal exclude" do
17 | @ds.exclude(:a).sql.must_equal "SELECT * FROM t WHERE NOT a"
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/spec/extensions/stdio_logger_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | require 'stringio'
4 |
5 | describe "stdio_logger extension: Sequel::StdioLogger" do
6 | before do
7 | Sequel.extension :stdio_logger
8 | @output = StringIO.new
9 | @logger = Sequel::StdioLogger.new(@output)
10 | end
11 |
12 | it "#debug should not log" do
13 | @logger.debug("foo").must_be_nil
14 | @output.rewind
15 | @output.read.must_equal ''
16 | end
17 |
18 | [:info, :warn, :error].each do |level|
19 | it "##{level} should log message with given level" do
20 | @logger.send(level, "foo").must_be_nil
21 | @output.rewind
22 | @output.read.must_match(/ #{level.to_s.upcase}: foo\n\z/)
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/fiber_concurrency.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # The fiber_concurrency extension changes the default concurrency
4 | # primitive in Sequel to be Fiber.current instead of Thread.current.
5 | # This is the value used in various hash keys to implement safe
6 | # concurrency (thread-safe concurrency by default, fiber-safe
7 | # concurrency with this extension. It can be enabled via:
8 | #
9 | # Sequel.extension :fiber_concurrency
10 | #
11 | # Related module: Sequel::FiberConcurrency
12 |
13 | require 'fiber'
14 |
15 | module Sequel
16 | module FiberConcurrency
17 | # Make the current concurrency primitive be Fiber.current.
18 | def current
19 | Fiber.current
20 | end
21 | end
22 |
23 | extend FiberConcurrency
24 | end
25 |
--------------------------------------------------------------------------------
/lib/sequel/adapters/utils/unmodified_identifiers.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | module Sequel
4 | module UnmodifiedIdentifiers
5 | module DatabaseMethods
6 | private
7 |
8 | # Databases that use this module for unquoted identifiers to lowercase.
9 | def folds_unquoted_identifiers_to_uppercase?
10 | false
11 | end
12 | end
13 |
14 | module DatasetMethods
15 | private
16 |
17 | # Turn the given symbol/string into a symbol, keeping the current case.
18 | def output_identifier(v)
19 | v == '' ? :untitled : v.to_sym
20 | end
21 |
22 | # Turn the given symbol/string into a string, keeping the current case.
23 | def input_identifier(v)
24 | v.to_s
25 | end
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/spec/model/exceptions_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe Sequel::MassAssignmentRestriction, "#create" do
4 | it "should set model attr" do
5 | model_cls = Class.new
6 |
7 | model = model_cls.new
8 | err = Sequel::MassAssignmentRestriction.create("method foo doesn't exist", model, "foo")
9 | err.message.must_include("method foo doesn't exist for class ")
10 | err.model.must_equal(model)
11 | err.column.must_equal("foo")
12 |
13 | def model_cls.inspect; 'TestModel' end
14 | model = model_cls.new
15 | err = Sequel::MassAssignmentRestriction.create("method foo doesn't exist", model, "foo")
16 | err.message.must_equal("method foo doesn't exist for class TestModel")
17 | err.model.must_equal(model)
18 | err.column.must_equal("foo")
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/doc/release_notes/5.27.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * Sequel::DEFAULT has been added a constant for the DEFAULT expression,
4 | useful in inserts and especially updates:
5 |
6 | DB[:a].where(:id=>1).update(:b=>Sequel::DEFAULT)
7 | # UPDATE "a" SET "b" = DEFAULT WHERE "id" = 1
8 |
9 | * SQL::Function#filter for filtered aggregate functions is now
10 | supported on all databases. On databases not supporting it natively
11 | (all except PostgreSQL 9.4+ and SQLite 3.30+), a CASE statement is
12 | used to emulate the support.
13 |
14 | = Other Improvements
15 |
16 | * NULLS FIRST/LAST is now used without emulation on SQLite 3.30+.
17 |
18 | * The pg_enum extension now works correctly on PostgreSQL 8.3-9.0.
19 |
20 | * Postgres::ArrayOp#join in the pg_array_ops extension now works
21 | correctly on PostgreSQL <9.1.
22 |
--------------------------------------------------------------------------------
/lib/sequel/plugins/unlimited_update.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | module Sequel
4 | module Plugins
5 | # The unlimited_update plugin is designed to work around a
6 | # MySQL warning in replicated environments, which occurs if
7 | # you issue an UPDATE with a LIMIT clause.
8 | #
9 | # Usage:
10 | #
11 | # # Make all model subclass not use a limit for update
12 | # Sequel::Model.plugin :unlimited_update
13 | #
14 | # # Make the Album class not use a limit for update
15 | # Album.plugin :unlimited_update
16 | module UnlimitedUpdate
17 | module InstanceMethods
18 | private
19 |
20 | # Use an unlimited dataset for updates.
21 | def _update_dataset
22 | super.unlimited
23 | end
24 | end
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/spec/deprecation_helper.rb:
--------------------------------------------------------------------------------
1 | Sequel::Deprecation.backtrace_filter = lambda{|line, lineno| lineno < 4 || line =~ /_spec\.rb/}
2 |
3 | class Minitest::HooksSpec
4 | def self.deprecated(a, &block)
5 | it("#{a} (deprecated)") do
6 | deprecated{instance_exec(&block)}
7 | end
8 | end
9 |
10 | def deprecated
11 | output = Sequel::Deprecation.output
12 | Sequel::Deprecation.output = nil
13 | yield
14 | ensure
15 | Sequel::Deprecation.output = output
16 | end
17 |
18 | def self.with_symbol_splitting(a, &block)
19 | it("#{a}, with symbol splitting enabled") do
20 | with_symbol_splitting{instance_exec(&block)}
21 | end
22 | end
23 |
24 | def with_symbol_splitting
25 | Sequel.split_symbols = true
26 | yield
27 | ensure
28 | Sequel.split_symbols = false
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/spec/extensions/integer64_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "integer64 extension" do
4 | before do
5 | @db = Sequel.mock.extension(:integer64)
6 | end
7 |
8 | it "should use bigint as default integer type" do
9 | @db.create_table(:t){Integer :a; column :b, Integer}
10 | @db.sqls.must_equal ['CREATE TABLE t (a bigint, b bigint)']
11 | end
12 |
13 | it "should use bigint as default type for primary_key and foreign_key" do
14 | @db.create_table(:t){primary_key :id; foreign_key :t_id, :t}
15 | @db.sqls.must_equal ['CREATE TABLE t (id bigint PRIMARY KEY AUTOINCREMENT, t_id bigint REFERENCES t)']
16 | end
17 |
18 | it "should use bigint when casting" do
19 | @db.get(Sequel.cast('a', Integer))
20 | @db.sqls.must_equal ["SELECT CAST('a' AS bigint) AS v LIMIT 1"]
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/lib/sequel/version.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | module Sequel
4 | # The major version of Sequel. Only bumped for major changes.
5 | MAJOR = 5
6 |
7 | # The minor version of Sequel. Bumped for every non-patch level
8 | # release, generally around once a month.
9 | MINOR = 99
10 |
11 | # The tiny version of Sequel. Usually 0, only bumped for bugfix
12 | # releases that fix regressions from previous versions.
13 | TINY = 0
14 |
15 | # The version of Sequel you are using, as a string (e.g. "2.11.0")
16 | VERSION = [MAJOR, MINOR, TINY].join('.').freeze
17 |
18 | # The version of Sequel you are using, as a number (2.11.0 -> 20110)
19 | VERSION_NUMBER = MAJOR*10000 + MINOR*10 + TINY
20 |
21 | # The version of Sequel you are using, as a string (e.g. "2.11.0")
22 | def self.version
23 | VERSION
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/spec/extensions/auto_cast_date_and_time_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "auto_cast_date_and_time extension" do
4 | before do
5 | @db = Sequel.mock.extension :auto_cast_date_and_time
6 | end
7 |
8 | it "should automatically cast Time instances" do
9 | @db.literal(Time.local(2000)).must_equal "TIMESTAMP '2000-01-01 00:00:00.000000'"
10 | end
11 |
12 | it "should automatically cast DateTime instances" do
13 | @db.literal(DateTime.new(2000)).must_equal "TIMESTAMP '2000-01-01 00:00:00.000000'"
14 | end
15 |
16 | it "should automatically cast SQLTime instances" do
17 | @db.literal(Sequel::SQLTime.create(10, 20, 30)).must_equal "TIME '10:20:30.000000'"
18 | end
19 |
20 | it "should automatically cast Date instances" do
21 | @db.literal(Date.new(2000)).must_equal "DATE '2000-01-01'"
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/spec/async_spec_helper.rb:
--------------------------------------------------------------------------------
1 | class Minitest::Spec
2 | if ENV['SEQUEL_ASYNC_THREAD_POOL'] || ENV['SEQUEL_ASYNC_THREAD_POOL_PREEMPT'] || ENV['SEQUEL_EAGER_ASYNC']
3 | use_async = true
4 | if ENV['SEQUEL_ASYNC_THREAD_POOL_PREEMPT']
5 | ::DB.opts[:preempt_async_thread] = true
6 | end
7 | ::DB.opts[:num_async_threads] = 12
8 | ::DB.extension :async_thread_pool
9 |
10 | if ENV['SEQUEL_EAGER_ASYNC']
11 | Sequel::Model.plugin :concurrent_eager_loading, :always=>true
12 | end
13 | end
14 |
15 | if use_async && DB.pool.pool_type == :threaded && (!DB.opts[:max_connections] || DB.opts[:max_connections] >= 4)
16 | def async?
17 | true
18 | end
19 |
20 | def wait
21 | yield.tap{}
22 | end
23 | else
24 | def async?
25 | false
26 | end
27 |
28 | def wait
29 | yield
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/spec/core/spec_helper.rb:
--------------------------------------------------------------------------------
1 | if ENV['COVERAGE']
2 | require_relative "../sequel_coverage"
3 | SimpleCov.sequel_coverage(:filter=>%r{lib/sequel/(\w+\.rb|(dataset|database|model|connection_pool)/\w+\.rb|adapters/mock\.rb)\z})
4 | end
5 |
6 | $:.unshift(File.join(File.dirname(File.expand_path(__FILE__)), "../../lib/"))
7 | require_relative "../../lib/sequel/core"
8 |
9 | ENV['MT_NO_PLUGINS'] = '1' # Work around stupid autoloading of plugins
10 | gem 'minitest'
11 | require 'minitest/global_expectations/autorun'
12 | require 'minitest/hooks/default'
13 |
14 | require_relative '../deprecation_helper'
15 |
16 | if ENV['SEQUEL_COLUMNS_INTROSPECTION']
17 | Sequel.extension :columns_introspection
18 | Sequel::Database.extension :columns_introspection
19 | require_relative '../../lib/sequel/adapters/mock'
20 | Sequel::Mock::Dataset.send(:include, Sequel::ColumnsIntrospection)
21 | end
22 |
--------------------------------------------------------------------------------
/lib/sequel/adapters/jdbc/mssql.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | require_relative '../shared/mssql'
4 |
5 | module Sequel
6 | module JDBC
7 | module MSSQL
8 | module DatabaseMethods
9 | include Sequel::MSSQL::DatabaseMethods
10 |
11 | private
12 |
13 | # Get the last inserted id using SCOPE_IDENTITY().
14 | def last_insert_id(conn, opts=OPTS)
15 | statement(conn) do |stmt|
16 | sql = opts[:prepared] ? 'SELECT @@IDENTITY' : 'SELECT SCOPE_IDENTITY()'
17 | rs = log_connection_yield(sql, conn){stmt.executeQuery(sql)}
18 | rs.next
19 | rs.getLong(1)
20 | end
21 | end
22 |
23 | # Primary key indexes appear to start with pk__ on MSSQL
24 | def primary_key_index_re
25 | /\Apk__/i
26 | end
27 | end
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/_model_pg_row.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | module Sequel
4 | module Plugins
5 | module PgRow
6 | module DatabaseMethods
7 | # Handle Sequel::Model instances in bound variables.
8 | def bound_variable_arg(arg, conn)
9 | case arg
10 | when Sequel::Model
11 | "(#{arg.values.values_at(*arg.columns).map{|v| bound_variable_array(v)}.join(',')})"
12 | else
13 | super
14 | end
15 | end
16 |
17 | # If a Sequel::Model instance is given, return it as-is
18 | # instead of attempting to convert it.
19 | def row_type(db_type, v)
20 | if v.is_a?(Sequel::Model)
21 | v
22 | else
23 | super
24 | end
25 | end
26 | end
27 | end
28 | end
29 |
30 | Database.register_extension(:_model_pg_row, Plugins::PgRow::DatabaseMethods)
31 | end
32 |
--------------------------------------------------------------------------------
/spec/extensions/after_initialize_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "Sequel::Plugins::AfterInitialize" do
4 | before do
5 | @db = Sequel.mock(:host=>'mysql', :numrows=>1)
6 | @c = Class.new(Sequel::Model(@db[:test]))
7 | @c.class_eval do
8 | columns :id, :name
9 | plugin :after_initialize
10 | def after_initialize
11 | self.name *= 2
12 | self.id *= 3 if id
13 | end
14 | end
15 | end
16 |
17 | it "should have after_initialize hook be called for new objects" do
18 | @c.new(:name=>'foo').values.must_equal(:name=>'foofoo')
19 | end
20 |
21 | it "should have after_initialize hook be called for objects loaded from the database" do
22 | @c.call(:id=>1, :name=>'foo').values.must_equal(:id=>3, :name=>'foofoo')
23 | end
24 |
25 | it "should not allow .call to be called without arguments" do
26 | proc{@c.call}.must_raise ArgumentError
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/spec/extensions/symbol_aref_refinement_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | if (RUBY_VERSION >= '2.0.0' && RUBY_ENGINE == 'ruby') || (RUBY_VERSION >= '2.3.0' && RUBY_ENGINE == 'jruby')
4 | Sequel.extension :symbol_aref_refinement
5 | using Sequel::SymbolAref
6 |
7 | describe "symbol_aref_refinement extension" do
8 | before do
9 | @db = Sequel.mock
10 | end
11 |
12 | it "Symbol#[] should create qualified identifier if given a symbol" do
13 | @db.literal(:x[:y]).must_equal "x.y"
14 | end
15 |
16 | it "Symbol#[] should create qualified identifier if given an identifier" do
17 | @db.literal(:x[Sequel[:y]]).must_equal "x.y"
18 | end
19 |
20 | it "Symbol#[] should create qualified identifier if given a qualified identifier" do
21 | @db.literal(:x[:y[:z]]).must_equal "x.y.z"
22 | end
23 |
24 | it "should not affect other arguments to Symbol#[]" do
25 | :x[0].must_equal "x"
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/doc/release_notes/5.60.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * The date_arithmetic extension now supports arbitrary expressions
4 | as interval values on PostgreSQL 9.4+. Previously, only integers
5 | were supported for the interval values.
6 |
7 | = Other Improvements
8 |
9 | * Most Kernel#respond_to? calls have been converted to equivalent
10 | defined? calls for better performance. defined? is a keyword
11 | and is about 50% faster for the same behavior.
12 |
13 | * The is_distinct_from extension now supports the IS DISTINCT FROM
14 | syntax natively on SQLite 3.39+, instead of emulating it.
15 |
16 | * HAVING without GROUP BY is now supported on SQLite 3.39+.
17 |
18 | * Coverage testing has been significantly expanded. Previously,
19 | the core, model, plugin, and extension code had 100% line/branch
20 | coverage. 100% line/branch coverage has been added for the
21 | core extensions, bin/sequel, and the postgres adapter with the
22 | pg driver.
23 |
--------------------------------------------------------------------------------
/doc/release_notes/5.71.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * A pg_xmin_optimistic_locking plugin has been added. This plugin
4 | uses PostgreSQL's xmin system column to implement optimistic
5 | locking. The xmin system column is automatically updated whenever
6 | the database row is updated. You can load this plugin into a
7 | base model and have all models that subclass from it use optimistic
8 | locking, without needing any user-defined lock columns.
9 |
10 | = Other Improvements
11 |
12 | * set_column_allow_null is now a reversible migration method inside
13 | alter_table blocks.
14 |
15 | * The use of ILIKE no longer forces the ESCAPE clause on PostgreSQL,
16 | which allows the use of ILIKE ANY and other constructions. There
17 | is no need to use the ESCAPE clause with ILIKE, because the value
18 | Sequel uses is PostgreSQL's default.
19 |
20 | * The xid PostgreSQL type is now recognized as an integer type in the
21 | jdbc/postgresql adapter.
22 |
--------------------------------------------------------------------------------
/doc/release_notes/5.55.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * An auto_restrict_eager_graph plugin has been added for automatically
4 | disallowing the use of eager_graph with associations using blocks but
5 | lacking graph_* options. This can prevent potentionally invalid usage,
6 | as the restrictions added by the block are not used by eager_graph.
7 |
8 | * The sqlite adapter now supports the :setup_regexp_function
9 | Database option. This option will define a REGEXP function in the
10 | database that will allow regexp support in queries, such as:
11 |
12 | DB[:table].where(column: /(some|pattern)/)
13 |
14 | Note that this creates a Ruby Regexp object per column value tested,
15 | so it isn't the most optimal approach.
16 |
17 | = Other Improvements
18 |
19 | * Calling dataset aggregate methods such as #max on a model dataset now
20 | works correctly. Previously, it could fail if called enough times to
21 | optimize using a placeholder literalizer.
22 |
--------------------------------------------------------------------------------
/doc/release_notes/5.65.0.txt:
--------------------------------------------------------------------------------
1 | = Improvements
2 |
3 | * The pg_auto_parameterize extension now uses a modified placeholder
4 | literalizer for speeding up the generation of SQL queries in the same
5 | cases where a standard dataset would use a placeholder literalizer.
6 | This can provide a 4% speedup for simple queries, with greater
7 | speedups for more complex queries.
8 |
9 | * Database#indexes now returns indexes for partitioned tables on
10 | PostgreSQL 11+.
11 |
12 | * MySQL versions not supporting CHECK constraints no longer include
13 | :min_value/:max_value schema entries for decimal/numeric columns.
14 |
15 | = Backwards Compatibility
16 |
17 | * The Dataset::PlaceholderLiterlizer::Record.loader API has changed,
18 | it now accepts the Dataset::PlaceholderLiterlizer class to use as
19 | the first argument. This makes it easier to create
20 | Dataset::PlaceholderLiterlizer subclasses, such as the one now used
21 | by the pg_auto_parameterize extension.
22 |
--------------------------------------------------------------------------------
/doc/release_notes/5.29.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * An empty_failure_backtraces plugin has been added for using empty
4 | backtraces for ValidationFailed and HookFailed exceptions. In many
5 | cases, these exceptions are automatically handled (e.g. web form
6 | submission handling to display appropriate error pages), and using
7 | empty backtraces is 10-15x faster on JRuby 9.2.7.0+.
8 |
9 | * Dataset#json_serializer_opts has been added to the json_serializer
10 | plugin. This allows setting default options on a per-Dataset basis
11 | for all Dataset#to_json calls.
12 |
13 | = Other Improvements
14 |
15 | * Another disconnect error is now recognized in the tinytds adapter.
16 |
17 | * Using Sequel with the the CRuby master branch (what will be Ruby 3)
18 | now works by supporting a second argument for
19 | Dataset#initialize_clone.
20 |
21 | * Sequel now avoids a warning in verbose mode when using the postgres
22 | adapter, a recent version of ruby-pg, and bound variables.
23 |
--------------------------------------------------------------------------------
/doc/release_notes/5.33.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * Custom join types are now supported on a per-association basis when
4 | using eager_graph/association_join. This builds on the previous
5 | support for custom aliases, using Sequel::SQL::AliasedExpression:
6 |
7 | class Artist < Sequel::Model; end
8 | class Album < Sequel::Model; end
9 | class Track < Sequel::Model; end
10 | Artist.one_to_many :albums
11 | Album.one_to_many :tracks
12 | Artist.eager_graph(
13 | Sequel[:albums].as(:a, join_type: :inner) =>
14 | Sequel[:tracks].as(:t, join_type: :left)
15 | )
16 |
17 | * A Database#current_timestamp_utc accessor has been added on SQLite.
18 | Setting this to true will keep CURRENT_TIMESTAMP, CURRENT_TIME, and
19 | CURRENT_DATE in UTC instead of converting them to localtime.
20 |
21 | = Other Improvements
22 |
23 | * The smallserial PostgreSQL type is now recognized and Sequel will
24 | not try to mark smallserial columns as identity columns.
25 |
--------------------------------------------------------------------------------
/www/public/css/plugins.css:
--------------------------------------------------------------------------------
1 | section.plugins {
2 | background-color: #FFF;
3 | border-radius: 12px;
4 | box-shadow: 0 24px 64px rgba(0,0,0,.15);
5 | }
6 |
7 | code.plugins__code {
8 | background-color: #eaeaea;
9 | border-radius: 4px;
10 | padding: 2px 4px;
11 | }
12 |
13 | div.plugins__sidebar {
14 | display: grid;
15 | grid-template-columns: 1fr 4fr;
16 | margin-top: var(--gap);
17 | border-top: 1px solid var(--border);
18 | }
19 | @media (max-width: 1200px) {
20 | div.plugins__sidebar {
21 | grid-template-columns: 1fr;
22 | }
23 | }
24 |
25 | aside.plugins__sidebar-aside {
26 | position: sticky;
27 | top: 0;
28 | max-height: 100vh;
29 | border-right: 1px solid var(--border);
30 | padding-bottom: var(--gap);
31 | padding-top: var(--gap);
32 | padding-left: var(--gap);
33 | padding-right: var(--gap);
34 | }
35 | @media (max-width: 1200px) {
36 | aside.plugins__sidebar-aside {
37 | position: inherit;
38 | border-right: none;
39 | border-bottom: 1px solid var(--border);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/spec/extensions/columns_updated_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "Sequel::Plugins::ColumnsUpdated" do
4 | before do
5 | @c = Class.new(Sequel::Model(DB[:items].with_autoid(13)))
6 | @c.columns :id, :x, :y
7 | @c.plugin :columns_updated
8 | end
9 |
10 | it "should make hash used for updating available in columns_updated until after hooks finish running" do
11 | res = nil
12 | @c.send(:define_method, :after_save){res = columns_updated}
13 | o = @c.new(:x => 1, :y => nil)
14 | o[:x] = 2
15 | o.save
16 | res.must_be_nil
17 | o.after_save
18 | res.must_be_nil
19 |
20 | o = @c.load(:id => 23,:x => 1, :y => nil)
21 | o[:x] = 2
22 | o.save
23 | res.must_equal(:x=>2, :y=>nil)
24 | o.after_save
25 | res.must_be_nil
26 |
27 | o = @c.load(:id => 23,:x => 2, :y => nil)
28 | o[:x] = 2
29 | o[:y] = 22
30 | o.save(:columns=>:x)
31 | res.must_equal(:x=>2)
32 | o.after_save
33 | res.must_be_nil
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/lib/sequel/adapters/utils/replace.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | module Sequel
4 | class Dataset
5 | module Replace
6 | # Execute a REPLACE statement on the database (deletes any duplicate
7 | # rows before inserting).
8 | def replace(*values)
9 | execute_insert(replace_sql(*values))
10 | end
11 |
12 | # SQL statement for REPLACE
13 | def replace_sql(*values)
14 | clone(:replace=>true).insert_sql(*values)
15 | end
16 |
17 | # Replace multiple rows in a single query.
18 | def multi_replace(*values)
19 | clone(:replace=>true).multi_insert(*values)
20 | end
21 |
22 | # Databases using this module support REPLACE.
23 | def supports_replace?
24 | true
25 | end
26 |
27 | private
28 |
29 | # If this is an replace instead of an insert, use replace instead
30 | def insert_insert_sql(sql)
31 | sql << (@opts[:replace] ? 'REPLACE' : 'INSERT')
32 | end
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/doc/release_notes/5.69.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * An adapter has been added for the trilogy MySQL driver. One large
4 | advantage over mysql2 is that trilogy does not require any MySQL
5 | client libraries installed on the machine. The trilogy adapter
6 | has basically the same issues/skipped specs as the mysql2 adapter,
7 | but it also does not support an application_timezone different
8 | than the database_timezone.
9 |
10 | * Model dataset modules now have a model accessor, allowing for
11 | code such as:
12 |
13 | class Foo < Sequel::Model
14 | dataset_module do
15 | where :kept, Sequel[model.table_name][:discarded_at] => nil
16 | end
17 | end
18 |
19 | = Improvements
20 |
21 | * The mysql adapter now works with ruby-mysql 4 (the pure-ruby
22 | MySQL driver). Note that multi-results support does not work
23 | with ruby-mysql 4 (it doesn't work with mysql2, trilogy, or
24 | other Sequel adapters in general).
25 |
26 | * Warnings for unsupported flags are now avoided on ruby-mysql 3.
27 |
--------------------------------------------------------------------------------
/spec/extensions/constant_sql_override_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "constant_sql_override extension" do
4 | before do
5 | @db = Sequel.mock.extension(:constant_sql_override)
6 | end
7 |
8 | it 'overrides configured constants' do
9 | @db.set_constant_sql(Sequel::CURRENT_TIMESTAMP, "CURRENT TIMESTAMP AT TIME ZONE 'UTC'")
10 | @db[:tbl].where(foo: Sequel::CURRENT_TIMESTAMP).first
11 | @db.sqls.must_equal ["SELECT * FROM tbl WHERE (foo = CURRENT TIMESTAMP AT TIME ZONE 'UTC') LIMIT 1"]
12 | end
13 |
14 | it 'does not change behavior for unconfigured constants' do
15 | @db[:tbl].where(foo: Sequel::CURRENT_TIMESTAMP).first
16 | @db.sqls.must_equal ["SELECT * FROM tbl WHERE (foo = CURRENT_TIMESTAMP) LIMIT 1"]
17 | end
18 |
19 | it 'freezes the constant_sqls hash when frozen' do
20 | @db.freeze
21 | @db.constant_sqls.frozen?.must_equal true
22 | proc{@db.set_constant_sql(Sequel::CURRENT_TIMESTAMP, "CURRENT TIMESTAMP AT TIME ZONE 'UTC'")}.must_raise RuntimeError
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/spec/extensions/freeze_datasets_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "freeze_datasets extension" do
4 | before do
5 | @db = Sequel.mock.extension(:freeze_datasets)
6 | end
7 |
8 | it "should freeze datasets by default" do
9 | @db.dataset.frozen?.must_equal true
10 | @db.fetch('SQL').frozen?.must_equal true
11 | @db.from(:table).frozen?.must_equal true
12 | @db[:table].frozen?.must_equal true
13 | end
14 |
15 | it "should have dataset#dup return frozen dataset" do
16 | @db.dataset.dup.frozen?.must_equal true
17 | end
18 |
19 | it "should cache Database#from calls with single symbol tables" do
20 | @db.from(:foo).must_be_same_as @db.from(:foo)
21 | @db.from(Sequel[:foo]).wont_be_same_as @db.from(Sequel[:foo])
22 | end
23 |
24 | it "should clear Database#from cache when modifying the schema" do
25 | ds = @db.from(:foo)
26 | ds.columns(:foo, :bar)
27 | @db[:foo].columns.must_equal [:foo, :bar]
28 | @db.create_table!(:foo){Integer :x}
29 | @db[:foo].columns.wont_equal [:foo, :bar]
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/doc/release_notes/5.13.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * A constant_sql_override Database extension has been added, allowing
4 | for overriding the SQL used by constants such as
5 | Sequel::CURRENT_TIMESTAMP. This can be used to force
6 | CURRENT_TIMESTAMP to be literalized at a particular time zone:
7 |
8 | DB.extension :constant_sql_override
9 | DB.set_constant_sql(Sequel::CURRENT_TIMESTAMP,
10 | "CURRENT_TIMESTAMP AT TIME ZONE 'UTC'")
11 |
12 | * Prepared statements now support the :single_value type, which
13 | returns the first column value in the dataset.
14 |
15 | prep_stmt = DB[:table].select(:column).prepare(:single_value, :ps)
16 | prep_stmt.call
17 | # PREPARE ps AS SELECT column FROM table LIMIT 1;
18 | # EXECUTE ps;
19 | # => 42
20 |
21 | = Other Improvements
22 |
23 | * Dataset#from_self will no longer use a cached dataset if any options
24 | are given, as that can result in incorrect behavior.
25 |
26 | * Model.all in the static_cache plugin now accepts a block, mirroring
27 | the API when the static_cache plugin is not used.
28 |
--------------------------------------------------------------------------------
/doc/release_notes/5.66.0.txt:
--------------------------------------------------------------------------------
1 | = Improvements
2 |
3 | * Dataset#empty? now correctly handles datasets using custom SQL or
4 | Dataset#values where the first value in the first row is NULL.
5 |
6 | * Dataset#count without an argument or block now works correctly on
7 | Microsoft SQL Server when using custom SQL that uses ORDER BY.
8 |
9 | * Dataset#count now works correctly for datasets using Dataset#values.
10 |
11 | * Sequel now recognizes an additional SQLite constraint violation
12 | error that occurs with recent versions of amalgalite.
13 |
14 | * Dataset#values will now raise an exception when called with an empty
15 | array. Previously, an exception would not be raised until the query
16 | was sent to the database.
17 |
18 | = Backwards Compatibility
19 |
20 | * The changes to make Dataset#empty? and #count work with custom SQL
21 | on Microsoft SQL Server now result in running the custom SQL, which
22 | could result in worse performance than in previous versions. You can
23 | wrap such datasets with Dataset#from_self manually to restore the
24 | previous behavior.
25 |
--------------------------------------------------------------------------------
/doc/release_notes/5.19.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * A Database#rename_enum_value method has been added to the pg_enum
4 | extension. It is supported on PostgreSQL 10+:
5 |
6 | DB.rename_enum_value(:enum_type, 'old_name', 'new_name')
7 |
8 | = Other Improvements
9 |
10 | * The performance of row fetching and type conversion in the
11 | sqlanywhere adapter has been improved.
12 |
13 | * The performance of row fetching in the sqlite adapter has been
14 | improved.
15 |
16 | * Calling Database#drop_table now drops any constraint validations
17 | metadata for the table if using the constraint_validations
18 | extension. However, modifying the table using Database#alter_table
19 | does not affect the constraint validations metadata.
20 |
21 | * The sqlite adapter when used with ruby-sqlite3 1.4.0+ now uses
22 | SQLite extended result codes for a more accurate determination of
23 | specific database errors types.
24 |
25 | * Performance for typecasting to decimal and floats has been improved
26 | slightly.
27 |
28 | * Performance when merging hashes has been improved slightly.
29 |
--------------------------------------------------------------------------------
/doc/release_notes/5.57.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * An is_distinct_from extension has been added with support for the
4 | SQL IS DISTINCT FROM operator. This operator is similar to the
5 | not equals operator, except in terms of NULL handling. It returns
6 | true if only one side is NULL, and false if both sides are NULL.
7 | You can call is_distinct_from on Sequel itself or on Sequel objects:
8 |
9 | Sequel.is_distinct_from(:column_a, :column_b)
10 | Sequel[:column_a].is_distinct_from(:column_b)
11 | # (column_a IS DISTINCT FROM column_b)
12 |
13 | On databases not supporting IS DISTINCT FROM, support is emulated
14 | using a CASE statement.
15 |
16 | * Column definitions on MySQL can use the :on_update_current_timestamp
17 | option for ON UPDATE CURRENT_TIMESTAMP, which creates a column that
18 | will automatically have its value set to CURRENT_TIMESTAMP on every
19 | update.
20 |
21 | * Database#create_function on PostgreSQL now supports a :parallel
22 | option to set the thread safety of the funciton. The value should
23 | be :safe, :unsafe, or :restricted.
24 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/symbol_as_refinement.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # The symbol_as_refinement extension adds a refinement that makes
4 | # Symbol#as return Sequel::SQL::AliasedExpression instances. It's
5 | # designed as a shortcut so that instead of:
6 | #
7 | # Sequel[:column].as(:alias) # column AS alias
8 | #
9 | # you can just write:
10 | #
11 | # :column.as(:alias) # column AS alias
12 | #
13 | # To load the extension:
14 | #
15 | # Sequel.extension :symbol_as_refinement
16 | #
17 | # To enable the refinement for the current file:
18 | #
19 | # using Sequel::SymbolAs
20 | #
21 | # If you would like this extension to be enabled globally instead
22 | # of as a refinement, use the symbol_as extension.
23 | #
24 | # Related module: Sequel::SymbolAs
25 |
26 | # :nocov:
27 | raise(Sequel::Error, "Refinements require ruby 2.0.0 or greater") unless RUBY_VERSION >= '2.0.0'
28 | # :nocov:
29 |
30 | module Sequel::SymbolAs
31 | refine Symbol do
32 | def as(aliaz, columns=nil)
33 | Sequel::SQL::AliasedExpression.new(self, aliaz, columns)
34 | end
35 | end
36 | end
37 |
38 |
--------------------------------------------------------------------------------
/doc/release_notes/5.53.0.txt:
--------------------------------------------------------------------------------
1 | = Improvements
2 |
3 | * The jdbc/h2 subadapter now supports H2 version 2.0. It continues to
4 | support H2 versions 1.3 and 1.4.
5 |
6 | * The mysql2 adapter's prepared statement support now reuses existing
7 | native prepared statements, instead of only binding variables on
8 | newly prepared statements. This was the intended behavior
9 | previously, and should result in increased performance in cases
10 | where preparing a query takes significant time.
11 |
12 | * The subclasses plugin now ignores an existing Class#subclasses
13 | method if it is defined in Ruby. This fixes cases where usage of
14 | ActiveSupport would break the subclasses plugin.
15 |
16 | * Database#call_sproc in the jdbc adapter will now always close the
17 | prepared call it creates. Before, if there was an exception raised
18 | when setting the arguments for the prepared call, the prepared call
19 | would not be closed.
20 |
21 | * A more appropriate error is now issued if you try to use the
22 | column_encryption plugin to encrypt a column without setting up an
23 | encryption key.
24 |
--------------------------------------------------------------------------------
/doc/release_notes/5.41.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * The validation methods added by the validation_helpers plugin now
4 | support the :skip_invalid option, which will not add a validation
5 | error on a column if it already has a validation error. This can
6 | be useful if you want to avoid having duplicate errors.
7 |
8 | * The auto_validations plugin now supports a :skip_invalid plugin
9 | option, which will pass the :skip_invalid option when calling
10 | validation methods.
11 |
12 | = Other Improvements
13 |
14 | * The :adder, :remover, and :clearer association options now
15 | support keyword arguments in Ruby 2.7+.
16 |
17 | * In the pg_interval extension, Sequel now uses the same number of
18 | seconds per month and seconds per year as active_support. It
19 | originally used the same number, but active_support changed the
20 | values in active_support 5.1. Sequel now uses the active_support
21 | values if they are available.
22 |
23 | * When adding a String column on PostgreSQL, an explicit text: true
24 | option now takes precedence over an explicit :size option, as it
25 | does in Sequel's default behavior.
26 |
--------------------------------------------------------------------------------
/spec/extensions/pg_loose_count_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "pg_loose_count extension" do
4 | before do
5 | @db = Sequel.mock(:host=>'postgres', :fetch=>{:v=>1}).extension(:pg_loose_count)
6 | @db.extend_datasets{def quote_identifiers?; false end}
7 | end
8 |
9 | it "should add loose_count method getting fast count for entire table using table statistics" do
10 | @db.loose_count(:a).must_equal 1
11 | @db.sqls.must_equal ["SELECT CAST(reltuples AS integer) AS v FROM pg_class WHERE (oid = CAST(CAST('a' AS regclass) AS oid)) LIMIT 1"]
12 | end
13 |
14 | it "should support schema qualified tables" do
15 | @db.loose_count(Sequel[:a][:b]).must_equal 1
16 | @db.sqls.must_equal ["SELECT CAST(reltuples AS integer) AS v FROM pg_class WHERE (oid = CAST(CAST('a.b' AS regclass) AS oid)) LIMIT 1"]
17 | end
18 |
19 | with_symbol_splitting "should support schema qualified table symbols" do
20 | @db.loose_count(:a__b).must_equal 1
21 | @db.sqls.must_equal ["SELECT CAST(reltuples AS integer) AS v FROM pg_class WHERE (oid = CAST(CAST('a.b' AS regclass) AS oid)) LIMIT 1"]
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/doc/release_notes/5.1.0.txt:
--------------------------------------------------------------------------------
1 | = Improvements
2 |
3 | * Database#copy_into in the jdbc/postgresql adapter now works
4 | correctly when using multibyte characters in strings.
5 |
6 | * The alter_table add_foreign_key method is now reversible when the
7 | :foreign_key_constraint_name option is used.
8 |
9 | * The jdbc/h2 and jdbc/hsqldb adapters now respect the
10 | :foreign_key_constraint_name option.
11 |
12 | * Calling Model.freeze on an already frozen model no longer raises
13 | an error.
14 |
15 | * An unnecessary database query is now avoided when loading the
16 | pg_inet extension when the pg_array extension is already loaded.
17 |
18 | * A better exception message is now used when migrating with an
19 | empty migration directory.
20 |
21 | = Backwards Compatibility
22 |
23 | * Model.allowed_columns has been removed. Use the whitelist_security
24 | plugin if you want to call it.
25 |
26 | * Model use_after_commit_rollback class and instance accessors have
27 | been removed.
28 |
29 | * Support for the Model#_before_validation method has been removed.
30 |
31 | * The private Model.plugin_module_defined? method has been removed.
32 |
--------------------------------------------------------------------------------
/MIT-LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2007-2008 Sharon Rosner
2 | Copyright (c) 2008-2023 Jeremy Evans
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to
6 | deal in the Software without restriction, including without limitation the
7 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 | sell copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 | THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/doc/release_notes/4.6.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * Database#call_mssql_sproc is now available for calling
4 | stored procedures on Microsoft SQL Server, including the use
5 | of output parameters.
6 |
7 | * The Database#{commit,rollback}_prepared_transaction methods now
8 | support a :server option for the server on which to operate.
9 |
10 | = Other Improvements
11 |
12 | * On Microsoft SQL Server 2012, the native OFFSET/FETCH support
13 | is now used for offsets, instead of emulating support via the
14 | ROW_NUMBER window function.
15 |
16 | * Eager loading is now skipped when doing eager(...).naked.all on
17 | a model dataset, instead of raising an error. This can fix issues
18 | when the eager_each plugin is used.
19 |
20 | * A couple additional disconnection errors are now detected in the
21 | jdbc/postgresql adapter.
22 |
23 | * The tinytds adapter now handles returning rows when the fields
24 | are not immediately available.
25 |
26 | * RuntimeErrors raised by oci8 are now handled correctly in the
27 | oracle adapter.
28 |
29 | * Sequel's specs now work with RSpec 3, while still running
30 | correctly on RSpec 1.3 and 2.
31 |
--------------------------------------------------------------------------------
/doc/release_notes/5.92.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * Objects that respond to sql_literal_append or sql_literal to
4 | support custom literalization in Sequel datasets can now also
5 | implement the sql_literal_allow_caching? method. If the object
6 | responds to the method and it returns true, then Sequel will
7 | still allow caching of the Dataset's SQL (this is disabled by
8 | default as Sequel cannot be sure that the literalization will
9 | not change between calls).
10 |
11 | * Model.qualified_primary_key has been added, which returns an
12 | SQL::QualifiedIdentifier with the model's primary key, or an
13 | array of SQL::QualifiedIdentifier objects if the model uses a
14 | composite primary key.
15 |
16 | * set_column_not_null is now a reversible method in migrations.
17 |
18 | = Other Improvements
19 |
20 | * The Model dataset paged_each method and the dataset methods in
21 | the paged_operations plugin now automatically use a qualified
22 | primary key instead of an unqualified primary key if the dataset
23 | is joined.
24 |
25 | * Module temporary names when using Ruby 3.5 are now consistent
26 | with Ruby 3.3 and 3.4.
27 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/pretty_table.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # The pretty_table extension adds Sequel::Dataset#print and the
4 | # Sequel::PrettyTable class for creating nice-looking plain-text
5 | # tables. Example:
6 | #
7 | # +--+-------+
8 | # |id|name |
9 | # |--+-------|
10 | # |1 |fasdfas|
11 | # |2 |test |
12 | # +--+-------+
13 | #
14 | # You can load this extension into specific datasets:
15 | #
16 | # ds = DB[:table]
17 | # ds = ds.extension(:pretty_table)
18 | #
19 | # Or you can load it into all of a database's datasets, which
20 | # is probably the desired behavior if you are using this extension:
21 | #
22 | # DB.extension(:pretty_table)
23 | #
24 | # Related module: Sequel::DatasetPrinter
25 |
26 | #
27 | module Sequel
28 | extension :_pretty_table
29 |
30 | module DatasetPrinter
31 | # Pretty prints the records in the dataset as plain-text table.
32 | def print(*cols)
33 | ds = naked
34 | rows = ds.all
35 | Sequel::PrettyTable.print(rows, cols.empty? ? ds.columns : cols)
36 | end
37 | end
38 |
39 | Dataset.register_extension(:pretty_table, DatasetPrinter)
40 | end
41 |
--------------------------------------------------------------------------------
/lib/sequel/model/dataset_module.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | module Sequel
4 | class Model
5 | # This Module subclass is used by Model.dataset_module
6 | # to add dataset methods to classes. In addition to the
7 | # methods offered by Dataset::DatasetModule, it also
8 | # automatically creates class methods for public dataset
9 | # methods.
10 | class DatasetModule < Dataset::DatasetModule
11 | # The model class related to this dataset module.
12 | attr_reader :model
13 |
14 | # Store the model related to this dataset module.
15 | def initialize(model)
16 | @model = model
17 | end
18 |
19 | # Alias for where.
20 | def subset(name, *args, &block)
21 | where(name, *args, &block)
22 | end
23 |
24 | private
25 |
26 | # Add a class method to the related model that
27 | # calls the dataset method of the same name.
28 | def method_added(meth)
29 | @model.send(:def_model_dataset_method, meth) if public_method_defined?(meth)
30 | super
31 | end
32 | end
33 |
34 | @dataset_module_class = DatasetModule
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/doc/release_notes/5.79.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * Dataset#select_prepend has been added for prepending to the
4 | currently selected columns:
5 |
6 | DB[:table].select_prepend(:column)
7 | # SELECT column, table.*
8 |
9 | As not all databases support "SELECT column, *", select_prepend
10 | qualifies wildcard selections to all tables referenced in the
11 | query.
12 |
13 | The only reason to use select_prepend is if you want the hashes
14 | returned by Sequel to be in a specific order. Otherwise, it is
15 | better to use select_append.
16 |
17 | * On PostgreSQL, Sequel now supports an :unlogged_tables_default
18 | Database option, which will default created tables to be UNLOGGED.
19 | This can be useful to speedup testing in some cases, but it should
20 | never be used in cases where data integrity is important.
21 |
22 | = Other Improvements
23 |
24 | * On PostgreSQL, Database#create_or_replace_view now supports the
25 | :materialized option. This allows for dropping an existing
26 | materialized view and creating a new one with the same name
27 | (PostgreSQL does not have native support for replacing materialized
28 | views).
29 |
--------------------------------------------------------------------------------
/doc/release_notes/5.17.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * An instance-level skip_auto_validations method has been added to
4 | the auto_validations plugin, allowing you to skip all or specific
5 | types of auto validations inside the block:
6 |
7 | model_instance.skip_auto_validations(:unique) do
8 | puts model_instance.valid?
9 | end
10 |
11 | * A Database :preconnect_extensions option has been added. This
12 | option is similar to :extensions, but the extensions are loaded
13 | before the :preconnect option is processed. This allows you to
14 | use the server_logging extension with the :preconnect option.
15 |
16 | * For specifying custom table aliases when using eager_graph and
17 | association_join, you can now use:
18 |
19 | Sequel[:association].as(:table_alias)
20 |
21 | in addition to:
22 |
23 | Sequel.as(:association, :table_alias)
24 |
25 | = Other Improvements
26 |
27 | * The ado/mssql adapter now retrieves the number of deleted or
28 | updated rows for a query without issuing a separate query.
29 |
30 | * Sequel now avoids the use of Proc.new with an implicit block, as
31 | that feature will be deprecated starting in Ruby 2.7.
32 |
--------------------------------------------------------------------------------
/spec/sequel_coverage.rb:
--------------------------------------------------------------------------------
1 | require 'simplecov'
2 |
3 | def SimpleCov.sequel_coverage(opts = {})
4 | start do
5 | enable_coverage :branch
6 | command_name SEQUEL_COVERAGE unless SEQUEL_COVERAGE == "1"
7 | add_filter{|f| f.filename.match(%r{\A#{Regexp.escape(File.dirname(__FILE__))}/})}
8 |
9 | if ENV['SEQUEL_MERGE_COVERAGE']
10 | filter = %r{bin/sequel\z|lib/sequel/(\w+\.rb|(dataset|database|model|connection_pool|extensions|plugins)/\w+\.rb|adapters/(mock|(shared/)?postgres)\.rb)\z}
11 | add_filter{|src| src.filename !~ filter}
12 | elsif opts[:filter]
13 | add_filter{|src| src.filename !~ opts[:filter]}
14 | end
15 |
16 | if opts[:subprocesses]
17 | enable_for_subprocesses true
18 | ENV['COVERAGE'] = 'subprocess'
19 | ENV['RUBYOPT'] = "#{ENV['RUBYOPT']} -r ./spec/sequel_coverage"
20 | elsif SEQUEL_COVERAGE == 'subprocess'
21 | command_name "bin-#{$$}"
22 | self.print_error_status = false
23 | formatter SimpleCov::Formatter::SimpleFormatter
24 | end
25 | end
26 | end
27 |
28 | SEQUEL_COVERAGE = ENV.delete('COVERAGE')
29 |
30 | if SEQUEL_COVERAGE == 'subprocess'
31 | SimpleCov.sequel_coverage
32 | end
33 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/integer64.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # The integer64 extension changes the default type used for Integer
4 | # to be the same type as used for :Bignum. In general, this means that
5 | # instead of Integer resulting in a 32-bit database integer type, it will
6 | # result in a 64-bit database integer type. This affects the default
7 | # type used for primary_key and foreign_key when using the schema
8 | # modification methods.
9 | #
10 | # Note that it doesn't make sense to use this extension on SQLite, since
11 | # the integer type will automatically handle 64-bit integers, and it treats
12 | # the integer type specially when the column is also the primary key.
13 | #
14 | # To load the extension into the database:
15 | #
16 | # DB.extension :integer64
17 | #
18 | # Related module: Sequel::Integer64
19 |
20 | #
21 | module Sequel
22 | module Integer64
23 | private
24 |
25 | # Use same type as used for :Bignum by default for generic integer value.
26 | def type_literal_generic_integer(column)
27 | type_literal_generic_bignum_symbol(column)
28 | end
29 | end
30 |
31 | Database.register_extension(:integer64, Integer64)
32 | end
33 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/blank.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # The blank extension adds the blank? method to all objects (e.g. Object#blank?).
4 | #
5 | # To load the extension:
6 | #
7 | # Sequel.extension :blank
8 |
9 | [FalseClass, Object, NilClass, Numeric, String, TrueClass].each do |klass|
10 | # :nocov:
11 | if klass.method_defined?(:blank?)
12 | klass.send(:alias_method, :blank?, :blank?)
13 | end
14 | # :nocov:
15 | end
16 |
17 | class FalseClass
18 | # false is always blank
19 | def blank?
20 | true
21 | end
22 | end
23 |
24 | class Object
25 | # Objects are blank if they respond true to empty?
26 | def blank?
27 | respond_to?(:empty?) && empty?
28 | end
29 | end
30 |
31 | class NilClass
32 | # nil is always blank
33 | def blank?
34 | true
35 | end
36 | end
37 |
38 | class Numeric
39 | # Numerics are never blank (not even 0)
40 | def blank?
41 | false
42 | end
43 | end
44 |
45 | class String
46 | # Strings are blank if they are empty or include only whitespace
47 | def blank?
48 | strip.empty?
49 | end
50 | end
51 |
52 | class TrueClass
53 | # true is never blank
54 | def blank?
55 | false
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/doc/release_notes/5.38.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * The jdbc/mysql adapter now supports the newer
4 | com.mysql.cj.jdbc.Driver driver. The adapter will still attempt to
5 | load the older com.mysql.jdbc.Driver if the com.mysql.cj.jdbc.Driver
6 | is not found.
7 |
8 | = Other Improvements
9 |
10 | * When testing a connection after creating a new Database instance
11 | raises an exception, the Database instance is removed from
12 | Sequel::DATABASES.
13 |
14 | * The single_table_inheritance and prepared_statements plugins now
15 | work correctly if loaded into the same class.
16 |
17 | * Database connect and disconnect errors are no longer swallowed when
18 | calling Database#create_or_replace_view, Database#server_version
19 | on PostgreSQL, or Database#create_table* on Oracle.
20 |
21 | = Backwards Compatibility
22 |
23 | * Previously, instantiating a new Database instance directly using
24 | Sequel::Database.new did not test the connection by default. That
25 | was instead handled by Sequel::Database.connect. The test
26 | connection now happens inside Database#initialize. This should only
27 | affect backwards compatibility for code that is calling
28 | Sequel::Database.new directly.
29 |
--------------------------------------------------------------------------------
/spec/extensions/validation_contexts_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "Sequel::Plugins::ValidationHelpers" do
4 | before do
5 | @c = Class.new(Sequel::Model(:foo))
6 | @c.class_eval do
7 | columns :a, :b, :c
8 | plugin :validation_contexts
9 | def validate
10 | errors.add(:a, 'bad') if a == 1 && validation_context == :create
11 | errors.add(:b, 'bad') if b == 2 && validation_context == :update
12 | errors.add(:c, 'bad') if c == 3 && validation_context == :foo
13 | end
14 | end
15 | end
16 |
17 | it "should support :validation_context option to valid?" do
18 | @c.new(:c=>3).valid?.must_equal true
19 | @c.new(:c=>3).valid?(:validation_context=>:foo).must_equal false
20 | end
21 |
22 | it "should support :validation_context option to save?" do
23 | @c.new(:c=>3).save
24 | proc{@c.new(:c=>3).save(:validation_context=>:foo)}.must_raise Sequel::ValidationFailed
25 | end
26 |
27 | it "should raise error if using a validation context on a frozen model instance" do
28 | @c.new(:c=>3).freeze.valid?.must_equal true
29 | proc{@c.new(:c=>3).freeze.valid?(:validation_context=>:foo)}.must_raise RuntimeError, TypeError
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/lib/sequel/plugins/after_initialize.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | module Sequel
4 | module Plugins
5 | # Adds an after_initialize hook to models, called after initializing
6 | # both new objects and ones loaded from the database.
7 | #
8 | # Usage:
9 | #
10 | # # Make all model subclasses support the after_initialize hook
11 | # Sequel::Model.plugin :after_initialize
12 | #
13 | # # Make the Album class support the after_initialize hook
14 | # Album.plugin :after_initialize
15 | module AfterInitialize
16 | module ClassMethods
17 | # Call after_initialize for model objects loaded from the database.
18 | def call(_)
19 | v = super
20 | v.after_initialize
21 | v
22 | end
23 | end
24 |
25 | module InstanceMethods
26 | # Call after_initialize for new model objects.
27 | def initialize(h={})
28 | super
29 | after_initialize
30 | end
31 |
32 | # An empty after_initialize hook, so that plugins that use this
33 | # can always call super to get the default behavior.
34 | def after_initialize
35 | end
36 | end
37 | end
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/spec/files/unused_associations/tua.rb:
--------------------------------------------------------------------------------
1 | class TUA < Sequel::Model
2 | many_to_one :a1, :key=>:t_id, :class=>self, :is_used=>!!ENV['A1_IS_USED']
3 | one_to_many :a2s, :key=>:t_id, :class=>self
4 | one_to_one :a3, :key=>:t_id, :class=>self
5 | a4s_opts = {:right_key=>:t_id, :left_key=>:t_id, :class=>self}
6 | include(a4s_opts[:methods_module] = Module.new) if ENV['A4S_METHODS_MODULE']
7 | a4s_opts[:read_only] = true if ENV['A4S_READ_ONLY']
8 | if ENV['A4S_NO_METHODS']
9 | a4s_opts[:no_dataset_method] = a4s_opts[:no_association_method] = true
10 | a4s_opts[:adder] = a4s_opts[:remover] = a4s_opts[:clearer] = nil
11 | end
12 | many_to_many :a4s, a4s_opts
13 | one_through_one :a5, :right_key=>:t_id, :left_key=>:t_id, :class=>self, :is_used=>!!ENV['A5_IS_USED']
14 | one_to_many :a6s, :key=>:t_id, :class=>self, :is_used=>!!ENV['A6S_IS_USED']
15 |
16 | O = load(:id=>1, :t_id=>2)
17 |
18 | class SC < self
19 | many_to_one :a7, :key=>:t_id, :class=>self
20 |
21 | O = load(:id=>1, :t_id=>2)
22 | end
23 | end
24 |
25 | # Class with no associations
26 | class TUA2 < Sequel::Model
27 | end
28 |
29 | # Anonymous class with associations
30 | Class.new(Sequel::Model(DB[:tuas])) do
31 | many_to_one :a1, :key=>:t_id, :class=>self
32 | end
33 |
--------------------------------------------------------------------------------
/lib/sequel/plugins/singular_table_names.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | module Sequel
4 | module Plugins
5 | # The singular_table_names plugin changes the default
6 | # table names for subclasses to not assume a plural version.
7 | # By default, Sequel assumes table names for models use
8 | # the plural versions.
9 | #
10 | # Note that this plugin only affects subclasses of the
11 | # class it is loaded into, it does not affect the
12 | # current class. So it only makes sense to load this
13 | # into Sequel::Model itself, or a subclass of Sequel::Model
14 | # that is created via Class.new.
15 | #
16 | # Usage:
17 | #
18 | # # Don't assume pluralized table names
19 | # Sequel::Model.plugin :singular_table_names
20 | module SingularTableNames
21 | module ClassMethods
22 | # Returns the implicit table name for the model class, which is the demodulized,
23 | # underscored, name of the class.
24 | #
25 | # Artist.implicit_table_name # => :artist
26 | # Foo::ArtistAlias.implicit_table_name # => :artist_alias
27 | def implicit_table_name
28 | underscore(demodulize(name)).to_sym
29 | end
30 | end
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/spec/extensions/current_datetime_timestamp_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "current_datetime_timestamp extension" do
4 | before do
5 | @ds = Sequel.mock[:table].extension(:current_datetime_timestamp)
6 | end
7 | after do
8 | Sequel.datetime_class = Time
9 | end
10 |
11 | it "should have current_timestamp respect Sequel.datetime_class" do
12 | t = Sequel::Dataset.new(nil).current_datetime
13 | t.must_be_kind_of(Time)
14 | (Time.now - t < 0.1).must_equal true
15 |
16 | Sequel.datetime_class = DateTime
17 | t = Sequel::Dataset.new(nil).current_datetime
18 | t.must_be_kind_of(DateTime)
19 | (DateTime.now - t < (0.1/86400)).must_equal true
20 | end
21 |
22 | it "should have current_timestamp value be literalized as CURRENT_TIMESTAMP" do
23 | @ds.literal(@ds.current_datetime).must_equal 'CURRENT_TIMESTAMP'
24 | Sequel.datetime_class = DateTime
25 | @ds.literal(@ds.current_datetime).must_equal 'CURRENT_TIMESTAMP'
26 | end
27 |
28 |
29 | it "should have other Date/Time values literalized normally" do
30 | t = Time.at(1594239778).getutc
31 | @ds.literal(t).must_equal "'2020-07-08 20:22:58.000000'"
32 | @ds.literal(t.to_datetime).must_equal "'2020-07-08 20:22:58.000000'"
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/lib/sequel/adapters/jdbc/jtds.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | Sequel::JDBC.load_driver('Java::NetSourceforgeJtdsJdbc::Driver', :JTDS)
4 | require_relative 'mssql'
5 |
6 | module Sequel
7 | module JDBC
8 | Sequel.synchronize do
9 | DATABASE_SETUP[:jtds] = proc do |db|
10 | db.extend(Sequel::JDBC::JTDS::DatabaseMethods)
11 | db.extend_datasets Sequel::MSSQL::DatasetMethods
12 | db.send(:set_mssql_unicode_strings)
13 | Java::NetSourceforgeJtdsJdbc::Driver
14 | end
15 | end
16 |
17 | module JTDS
18 | module DatabaseMethods
19 | include Sequel::JDBC::MSSQL::DatabaseMethods
20 |
21 | private
22 |
23 | # JTDS exception handling with SQLState is less accurate than with regexps.
24 | def database_exception_use_sqlstates?
25 | false
26 | end
27 |
28 | def disconnect_error?(exception, opts)
29 | super || exception.message =~ /\AInvalid state, the Connection object is closed\.\z/
30 | end
31 |
32 | # Handle nil values by using setNull with the correct parameter type.
33 | def set_ps_arg_nil(cps, i)
34 | cps.setNull(i, cps.getParameterMetaData.getParameterType(i))
35 | end
36 | end
37 | end
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/doc/release_notes/5.25.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * An association_multi_add_remove plugin has been added. This plugin
4 | adds a shortcut for adding or removing multiple associated objects
5 | in a single method call:
6 |
7 | Artist.plugin :association_multi_add_remove
8 | Artist.many_to_one :albums
9 | Artist[1].add_albums([Album[2], Album[3]])
10 | Artist[1].remove_albums([Album[4], Album[5]])
11 |
12 | It also offers a setter method, which will add and remove associated
13 | objects as necessary:
14 |
15 | Artist[1].albums = [Album[3], Album[4]]
16 |
17 | = Other Improvements
18 |
19 | * The sharding plugin now integrates with the server_block extension.
20 | This makes it so if you retrieve a model instance inside a
21 | with_server block, saving the model instance will save it back to
22 | the shard from which it was retrieved.
23 |
24 | * Setting a default for a column on Microsoft SQL Server now works
25 | correctly if the column already has a default.
26 |
27 | * Sequel::SQL::NumericMethods#coerce no longer raises NoMethodError
28 | if the super method is not defined. This fixes some cases when
29 | comparing Date/DateTime instances to Sequel objects.
30 |
31 | * The csv_serializer plugin now avoids keyword argument separation
32 | issues on Ruby 2.7+.
33 |
--------------------------------------------------------------------------------
/doc/release_notes/5.54.0.txt:
--------------------------------------------------------------------------------
1 | = New Feature
2 |
3 | * An enum plugin has been added. This plugin allows you to create
4 | model-level enums, giving names to underlying values of a column.
5 | For example:
6 |
7 | Album.plugin :enum
8 | Album.enum :status_id, good: 1, bad: 2
9 |
10 | Adds Album#good! and Album#bad! for changing the status_id to 1 or
11 | 2 respectively. It adds Album#good? and Album#bad? for checking
12 | whether the status_id is 1 or 2 respectively. It overrides
13 | Album#status_id to return :good or :bad instead of 1 or 2,
14 | respectively, and overrides Album#status_id= to accept :good or
15 | :bad instead of 1 or 2 respectively.
16 |
17 | Additionally, it adds good and bad dataset methods for filtering
18 | the model's dataset to records where status_id is 1 or 2
19 | respectively. It also adds not_good and not_bad dataset methods
20 | for filtering the model's dataset to records where status_id is not
21 | 1 or not 2 respectively.
22 |
23 | You can use :prefix and :suffix options when calling enum to
24 | add a prefix or suffix to the method names created. You can
25 | set the :override_accessors option to false to not override
26 | the accessor methods for the column, and set the :dataset_methods
27 | option to false to not add dataset methods.
28 |
--------------------------------------------------------------------------------
/doc/release_notes/5.97.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * A deprecated_associations plugin has been added, which supports
4 | warning if a deprecated association is used:
5 |
6 | Album.plugin :deprecated_associations
7 | Album.many_to_one :artist, deprecated: true
8 | album = Album[1]
9 |
10 | # Warnings for all of the following calls
11 | album.artist
12 | album.artist_dataset
13 | album.artist = Artist[2]
14 | Album.association_reflection(:artist)
15 | Album.eager(:artist)
16 | Album.eager_graph(:artist)
17 | Album.where(artist: Artist[1]).all
18 |
19 | You can customize the behavior using the :raise, :deduplicate,
20 | and :backtrace plugin options.
21 |
22 | * Database#rename_schema has been added on PostgreSQL to support
23 | renaming schemas.
24 |
25 | = Other Improvements
26 |
27 | * Database#drop_schema on PostgreSQL now clears all cached schema
28 | information.
29 |
30 | * Postgres::PGRange#inspect in the pg_range extension now provides
31 | more friendly output:
32 |
33 | Sequel::Postgres::PGRange.from_range(1...3, :int4).inspect
34 | # => "#"
35 |
36 | * BigDecimal typcasting when using the looser_typecasting extension
37 | now works as expected when using newer bigdecimal gem with
38 | Ruby < 2.4.
39 |
--------------------------------------------------------------------------------
/spec/visibility_checking_after_hook.rb:
--------------------------------------------------------------------------------
1 | require_relative "visibility_checking"
2 | model_subclasses = []
3 |
4 | [Sequel::Database, Sequel::Dataset, Sequel::Model, Sequel::Model.singleton_class].each do |c|
5 | VISIBILITY_CHANGES.concat(VisibilityChecker.visibility_changes(c).map{|v| [v, c.inspect]})
6 | end
7 |
8 | Sequel::Model.singleton_class.class_eval do
9 | prepend(Module.new do
10 | private
11 | define_method(:inherited) do |sc|
12 | model_subclasses << sc
13 | super(sc)
14 | end
15 | end)
16 | end
17 |
18 | Minitest::HooksSpec.class_eval do
19 | after do
20 | path, lineno = method(@NAME).source_location
21 | check = []
22 | Sequel::DATABASES.each do |db|
23 | check.push(db.singleton_class)
24 | check.push(db.dataset.singleton_class)
25 | end
26 | Sequel::DATABASES.clear
27 |
28 | subclasses = model_subclasses.dup
29 | model_subclasses.clear
30 | check.concat(subclasses)
31 | check.concat(subclasses.map(&:singleton_class))
32 | check.concat(subclasses.map{|c| c.dataset.singleton_class if c.instance_variable_get(:@dataset)})
33 |
34 | check.each do |c|
35 | next unless c
36 | VISIBILITY_CHANGES.concat(VisibilityChecker.visibility_changes(c).map{|v| [v, "#{path}:#{lineno}"]})
37 | end
38 | end
39 | end
40 |
41 |
--------------------------------------------------------------------------------
/spec/extensions/pg_timestamptz_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "pg_timestamptz extension" do
4 | before do
5 | @db = Sequel.mock(:host=>'postgres').extension :pg_timestamptz
6 | end
7 |
8 | it "should use timestamptz as default timestamp type" do
9 | @db.create_table(:t){Time :t; DateTime :tz; Time :ot, :only_time=>true}
10 | @db.sqls.must_equal ['CREATE TABLE "t" ("t" timestamptz, "tz" timestamptz, "ot" time)']
11 | end
12 |
13 | it "should automatically cast Time and DateTime instances using TIMESTAMP WITH TIME ZONE when using auto_cast_date_and_time " do
14 | t = Time.utc(2000)
15 | dt = DateTime.new(2000)
16 | expected = "TIMESTAMP WITH TIME ZONE '2000-01-01 00:00:00.000000+0000'"
17 |
18 | @db.timezone = :utc
19 | @db.extension :auto_cast_date_and_time
20 | @db.literal(t).must_equal expected
21 | @db.literal(dt).must_equal expected
22 |
23 | db = Sequel.mock(:host=>'postgres').extension :auto_cast_date_and_time
24 | db.extension :pg_timestamptz
25 | db.literal(t).must_equal expected
26 | db.literal(dt).must_equal expected
27 | end
28 |
29 | it "should use timestamptz when casting" do
30 | @db.get(Sequel.cast('a', Time))
31 | @db.sqls.must_equal ["SELECT CAST('a' AS timestamptz) AS \"v\" LIMIT 1"]
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/doc/release_notes/5.81.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * A temporarily_release_connection Database extension has been added,
4 | designed for multithreaded transactional testing.
5 |
6 | This allows one thread to start a transaction, and then release
7 | the connection back for usage by the connection pool, so that
8 | other threads can operate on the connection object safely inside
9 | the transaction. This requires the connection pool be limited
10 | to a single connection, to ensure that the released connection
11 | can be reacquired. It's not perfect, because if the connection
12 | is disconnected and removed from the pool while temporarily
13 | released, there is no way to handle that situation correctly.
14 | Example:
15 |
16 | DB.transaction(rollback: :always, auto_savepoint: true) do |conn|
17 | DB.temporarily_release_connection(conn) do
18 | # Other threads can operate on connection safely inside
19 | # the transaction
20 | yield
21 | end
22 | end
23 |
24 | = Other Improvements
25 |
26 | * In the caller_logging and provenance extensions, Ruby internal
27 | caller locations are skipped when trying to locate the appropriate
28 | caller line to include.
29 |
30 | * A couple ignored block warnings in plugin apply methods have been
31 | fixed on Ruby 3.4.
32 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/pg_loose_count.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # The pg_loose_count extension looks at the table statistics
4 | # in the PostgreSQL system tables to get a fast approximate
5 | # count of the number of rows in a given table:
6 | #
7 | # DB.loose_count(:table) # => 123456
8 | #
9 | # It can also support schema qualified tables:
10 | #
11 | # DB.loose_count(Sequel[:schema][:table]) # => 123456
12 | #
13 | # How accurate this count is depends on the number of rows
14 | # added/deleted from the table since the last time it was
15 | # analyzed. If the table has not been vacuumed or analyzed
16 | # yet, this can return 0 or -1 depending on the PostgreSQL
17 | # version in use.
18 | #
19 | # To load the extension into the database:
20 | #
21 | # DB.extension :pg_loose_count
22 | #
23 | # Related module: Sequel::Postgres::LooseCount
24 |
25 | #
26 | module Sequel
27 | module Postgres
28 | module LooseCount
29 | # Look at the table statistics for the given table to get
30 | # an approximate count of the number of rows.
31 | def loose_count(table)
32 | from(:pg_class).where(:oid=>regclass_oid(table)).get(Sequel.cast(:reltuples, Integer))
33 | end
34 | end
35 | end
36 |
37 | Database.register_extension(:pg_loose_count, Postgres::LooseCount)
38 | end
39 |
40 |
--------------------------------------------------------------------------------
/doc/release_notes/5.58.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * Dataset#merge and related #merge_* methods have been added for the
4 | MERGE statement. MERGE is supported on PostgreSQL 15+, Oracle,
5 | Microsoft SQL Server, DB2, H2, HSQLDB, and Derby. You can use MERGE
6 | to insert, update, and/or delete in a single query. You call
7 | the #merge_* methods to setup the MERGE statement, and #merge to
8 | execute it on the database:
9 |
10 | ds = DB[:m1]
11 | merge_using(:m2, i1: :i2).
12 | merge_insert(i1: :i2, a: Sequel[:b]+11).
13 | merge_delete{a > 30}.
14 | merge_update(i1: Sequel[:i1]+:i2+10, a: Sequel[:a]+:b+20)
15 |
16 | ds.merge
17 | # MERGE INTO m1 USING m2 ON (i1 = i2)
18 | # WHEN NOT MATCHED THEN INSERT (i1, a) VALUES (i2, (b + 11))
19 | # WHEN MATCHED AND (a > 30) THEN DELETE
20 | # WHEN MATCHED THEN UPDATE SET i1 = (i1 + i2 + 10), a = (a + b + 20)
21 |
22 | On PostgreSQL, the following additional MERGE related methods are
23 | available:
24 |
25 | * #merge_do_nothing_when_matched
26 | * #merge_do_nothing_when_not_matched
27 |
28 | * A :disable_split_materialized Database option is now supported on
29 | MySQL. This disables split_materialized support in the optimizer,
30 | working around a bug in MariaDB 10.5+ that causes failures in
31 | Sequel's association tests.
32 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/symbol_aref_refinement.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # The symbol_aref_refinement extension adds a refinement that makes
4 | # Symbol#[] support Symbol, #Sequel::SQL::Indentifier, and
5 | # Sequel::SQL::QualifiedIdentifier instances, returning appropriate
6 | # Sequel::SQL::QualifiedIdentifier instances. It's designed as a
7 | # shortcut so that instead of:
8 | #
9 | # Sequel[:table][:column] # table.column
10 | #
11 | # you can just write:
12 | #
13 | # :table[:column] # table.column
14 | #
15 | # To load the extension:
16 | #
17 | # Sequel.extension :symbol_aref_refinement
18 | #
19 | # To enable the refinement for the current file:
20 | #
21 | # using Sequel::SymbolAref
22 | #
23 | # If you would like this extension to be enabled globally instead
24 | # of as a refinement, use the symbol_aref extension.
25 | #
26 | # Related module: Sequel::SymbolAref
27 |
28 | # :nocov:
29 | raise(Sequel::Error, "Refinements require ruby 2.0.0 or greater") unless RUBY_VERSION >= '2.0.0'
30 | # :nocov:
31 |
32 | module Sequel::SymbolAref
33 | refine Symbol do
34 | def [](v)
35 | case v
36 | when Symbol, Sequel::SQL::Identifier, Sequel::SQL::QualifiedIdentifier
37 | Sequel::SQL::QualifiedIdentifier.new(self, v)
38 | else
39 | super
40 | end
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/doc/release_notes/4.5.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * An mssql_optimistic_locking plugin has been added. This is similar
4 | to the regular optimistic_locking plugin, but instead of using an
5 | integer lock column, it uses a timestamp/rowversion lock column.
6 |
7 | * Database#create_table with the :temp=>true option on PostgreSQL now
8 | supports an :on_commit option. This option can be set to :drop or
9 | :delete_rows to either drop or empty the temporary table on
10 | transaction commit.
11 |
12 | = Other Improvements
13 |
14 | * Dataset#insert no longer errors on PostgreSQL if the related table
15 | is a placeholder literal string.
16 |
17 | * Unique constraints are now copied when emulating alter_table
18 | operations on SQLite.
19 |
20 | * Clob column values are no longer returned as SQL::Blob instances
21 | by the db2 and ibmdb adapters unless use_clob_as_blob is true.
22 |
23 | * SQL::Blob objects now work correctly as prepared statement
24 | arguments in the jdbc/db2 adapter if use_clob_as_blob is false.
25 |
26 | = Backwards Compatibility
27 |
28 | * The Model.primary_key array for models with composite keys is now
29 | frozen.
30 |
31 | * On DB2, use_clob_as_blob now defaults to false instead of true.
32 |
33 | * Sequel no longer uses RubyForge. The Sequel website is now located
34 | at http://sequel.jeremyevans.net.
35 |
--------------------------------------------------------------------------------
/doc/release_notes/5.67.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * A set_literalizer extension has been added, for treating Set
4 | instances in datasets similar to Array instances:
5 |
6 | DB.extension :set_literalizer
7 | DB[:table].where(column: Set.new([1, 2, 3]))
8 | # SELECT FROM table WHERE (column IN (1, 2, 3))
9 |
10 | = Improvements
11 |
12 | * Sequel now avoids the use of singleton classes for datasets on Ruby
13 | 2.4+, instead creating a regular subclass whenever a dataset would
14 | be extended via #extension or #with_extend. This significantly
15 | improves performance, up to 20-40% for common dataset usage,
16 | because it avoids creating new singleton classes for every dataset
17 | clone, and it allows for cached method lookup.
18 |
19 | * Database#tables and #views now support a :qualify option on Microsoft
20 | SQL Server to returned qualified identifiers.
21 |
22 | * The schema_dumper extension can now dump tables in non-default schemas
23 | when using Microsoft SQL Server.
24 |
25 | * The schema_dumper extension now correctly dumps string column sizes
26 | when using Microsoft SQL Server.
27 |
28 | = Backwards Compatibility
29 |
30 | * Calling Sequel::Dataset.register_extension where the second argument
31 | is not a module now issues a deprecation warning. Support for this
32 | will be removed in Sequel 6.
33 |
--------------------------------------------------------------------------------
/doc/release_notes/5.84.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * The pg_json_ops extension now supports the json_exists, json_value,
4 | and json_query functions added in PostgreSQL 17:
5 |
6 | Sequel.extension :pg_json_ops
7 | j = Sequel.pg_json_op(:jsonb_column)
8 | j.exists('$.foo') # json_exists(jsonb_column, '$.foo')
9 | j.value('$.foo') # json_value(jsonb_column, '$.foo')
10 | j.query('$.foo') # json_query(jsonb_column, '$.foo')
11 |
12 | j.exists('$.foo', passing: {a: 1}) # json_exists(jsonb_column, '$.foo' PASSING 1 AS a)
13 | j.value('$.foo', returning: Time) # json_value(jsonb_column, '$.foo' RETURNING timestamp)
14 | j.query('$.foo', wrapper: true) # json_query(jsonb_column, '$.foo' WITH WRAPPER)
15 |
16 | All clauses supported by PostgreSQL 17 are supported via options
17 | (supported options differ per method):
18 |
19 | * :on_error : ON ERROR
20 | * :on_empty : ON EMPTY
21 | * :passing : PASSING
22 | * :returning : RETURNING
23 | * :wrapper : WITH WRAPPER | OMIT QUOTES
24 |
25 | * On SQLite, Database#create_table now supports a :using option to
26 | create a virtual table:
27 |
28 | DB.create_table(:t, using: 'fts5(email)')
29 | # CREATE VIRTUAL TABLE t USING fts5(email)
30 |
31 | = Other Improvements
32 |
33 | * The gem size has been reduced 25% by removing documentation.
34 |
--------------------------------------------------------------------------------
/www/public/css/links.css:
--------------------------------------------------------------------------------
1 | section.links {
2 | background-color: #FFF;
3 | border-radius: 12px;
4 | box-shadow: 0 24px 64px rgba(0,0,0,.15);
5 | }
6 |
7 | ul.assets {
8 | display: grid;
9 | grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
10 | gap: calc(var(--gap) / 2);
11 | list-style: none;
12 | padding: 0;
13 | margin: calc(var(--gap) / 2) var(--gap);
14 | }
15 | @media (max-width: 640px) {
16 | ul.assets {
17 | grid-template-columns: 1fr;
18 | }
19 | }
20 |
21 | li.assets__item {
22 | display: grid;
23 | grid-template-rows: auto max-content;
24 | border-radius: 8px;
25 | border: 1px solid var(--border);
26 | }
27 |
28 | a.assets__container {
29 | display: flex;
30 | align-items: center;
31 | justify-content: center;
32 | padding: var(--gap) 32px;
33 | box-sizing: border-box;
34 | background-image: url("../images/transparent-background.svg");
35 | background-size: 32px;
36 | }
37 |
38 | @media (max-width: 480px) {
39 | img.assets__img {
40 | width: 80%;
41 | }
42 | }
43 |
44 | p.assets__description {
45 | border-top: 1px solid var(--border);
46 | background-color: #f4f4f4;
47 | margin: 0;
48 | padding: 12px 16px;
49 | font-size: 12px;
50 | text-align: center;
51 | border-radius: 0 0 8px 8px;
52 | color: #666;
53 | }
54 |
55 | a.parens:before {
56 | content: "(";
57 | }
58 | a.parens:after {
59 | content: ")";
60 | }
61 |
--------------------------------------------------------------------------------
/doc/release_notes/5.37.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * Model#column_previously_was and #column_previously_changed? have
4 | been added to the dirty plugin, for getting the previous values
5 | of the column before saving and for whether there were changes
6 | before saving.
7 |
8 | Model#column_previously_changed? accepts :from and :to options
9 | to allow you to more easily determine if the value changed from
10 | and/or to specific values.
11 |
12 | This information was previously obtainable via
13 | Model#previous_changes, but these new methods offer a friendlier
14 | interface.
15 |
16 | * Postgres::PGRow::{Array,Hash}Row#op has been added to the
17 | pg_row_ops extension if the pg_row extension is loaded. This
18 | is similar to how the pg_array_ops, pg_hstore_ops, and
19 | pg_json_ops and #op method to their objects. This makes it
20 | easier to perform row operations on literal rows.
21 |
22 | = Other Improvements
23 |
24 | * The schema_dumper extension now supports more unsigned numeric
25 | types, such as "decimal(7,2) unsigned" and "real unsigned".
26 |
27 | * IntegerMigrator now raises an Migrator::Error if attempting to
28 | migrate down when there are migration files missing and needed for
29 | the down migration. Previously, IntegerMigrator would not raise an
30 | exception and would make no database changes in this case.
31 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/set_literalizer.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # The set_literalizer extension should no longer be used, as Sequel
4 | # now supports Set values by default. For backwards compatibility
5 | # the set_literalizer extension will treat a set that contains only
6 | # 2 element arrays as a condition specifier (matching the behavior
7 | # for arrays where all elements are 2 element arrays). This is not
8 | # compatible with Sequel's current default behavior. If you are
9 | # relying on this behavior, it is recommended you convert the set
10 | # to an array.
11 | #
12 | # Related module: Sequel::Dataset::SetLiteralizer
13 |
14 | module Sequel
15 | # SEQUEL6: Remove
16 | Sequel::Deprecation.deprecate("The set_literalizer extension", "Sequel now supports set literalization by default")
17 |
18 | class Dataset
19 | module SetLiteralizer
20 | private
21 |
22 | # Allow using sets as condition specifiers.
23 | def filter_expr(expr = nil, &block)
24 | if expr.is_a?(Set)
25 | expr
26 | else
27 | super
28 | end
29 | end
30 |
31 | # Literalize Set instances by converting the set to array.
32 | def literal_set_append(sql, v)
33 | literal_append(sql, v.to_a)
34 | end
35 | end
36 |
37 | register_extension(:set_literalizer, SetLiteralizer)
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/doc/release_notes/5.45.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * A auto_validations_constraint_validations_presence_message plugin
4 | has been added that provides integration for the auto_validations
5 | and constraint_validations plugin in the following conditions:
6 |
7 | * The column has a NOT NULL constraint
8 | * The column has a presence constraint validation with both
9 | the :message and :allow_nil options used.
10 |
11 | In this case, when saving a nil value in the column, the plugin
12 | will make it so the more specific message from the presence
13 | constraint validation is used, instead of the generic message
14 | from auto_validations.
15 |
16 | = Other Improvements
17 |
18 | * On SQLite 3.35.0+, Sequel now uses ALTER TABLE DROP COLUMN for
19 | dropping columns, instead of emulating the dropped column by
20 | recreating the table.
21 |
22 | * The Dataset#with :materialized option is now supported on SQLite
23 | 3.35.0+ for specifying whether common table expressions should be
24 | materialized.
25 |
26 | * The odbc adapter now correct handles boolean columns with NULL
27 | values. Previously, such values were returned as false instead
28 | of nil.
29 |
30 | = Backwards Compatibility
31 |
32 | * The change to use ALTER TABLE DROP COLUMN on SQLite 3.35.0+ can
33 | cause backwards compatibility issues if SQLite 3.35.0+ does
34 | not allow dropping the column.
35 |
--------------------------------------------------------------------------------
/doc/release_notes/4.16.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * Model#qualified_pk_hash has been added, which is similar to
4 | Model#pk_hash, but uses qualified keys.
5 |
6 | * Dataset#distinct now accepts a virtual row block.
7 |
8 | * Database#drop_table with :foreign=>true option now drops foreign
9 | tables on PostgreSQL. Database#create_table with :foreign option
10 | is now reversible on PostgreSQL.
11 |
12 | = Other Improvements
13 |
14 | * Sequel::Model.cache_associations = false now skips the database's
15 | schema cache when loading the schema for a model. This fixes
16 | some issues in environments that use code reloading.
17 |
18 | * Database#create_table? and #create_join_table? no longer use
19 | IF NOT EXISTS if indexes are being created.
20 |
21 | * Model.primary_key_hash and .qualified_primary_key_hash have been
22 | optimized.
23 |
24 | * validates_unique in the validation_helpers plugin now uses a
25 | qualified primary key if the model's dataset is joined. This fixes
26 | a case when the auto_validations and class_table_inheritance
27 | plugins are used together.
28 |
29 | * Disconnect errors are now recognized in the postgres adapter when
30 | SSL is used for connecting.
31 |
32 | * Empty string default values are no longer converted to nil default
33 | values on MySQL.
34 |
35 | * Database#foreign_key_list now works correctly on Microsoft SQL
36 | Server 2005.
37 |
--------------------------------------------------------------------------------
/doc/release_notes/5.6.0.txt:
--------------------------------------------------------------------------------
1 | = Improvements
2 |
3 | * Running migrations using one of the included migrators on separate
4 | Database objects in separate threads simultaneously is now
5 | supported. Previously, the migrators were not thread-safe.
6 |
7 | * On Ruby 2.5+, :db_type entries in the schema hashes are now deduped
8 | for a slight memory savings when using many columns with the same
9 | database type.
10 |
11 | * The schema_caching extension now freezes string values in the
12 | resulting hashes, just as the default schema parsing code started
13 | doing in 5.5.0.
14 |
15 | * The schema_caching extension now supports the :callable_default
16 | schema values used by the pg_json, pg_array, and pg_hstore
17 | extensions, by removing the entry before caching and resetting it
18 | after restoring the cache.
19 |
20 | * Identifier mangling rules are now respected when renaming columns on
21 | Microsoft SQL Server.
22 |
23 | = Backwards Compatibility
24 |
25 | * The migrator internals were modified in order to support
26 | thread-safety. The private Migrator#remove_migration_classes
27 | method has been removed, and #load_migration_file now returns the
28 | migration object/class instead of populating Migration.descendants.
29 | Migration.descendants is now only used for temporary storage, and
30 | will no longer contain all migration objects/classes used by the
31 | migrator.
32 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/dataset_run.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # The dataset_run extension is designed for cases where you want
4 | # to use dataset methods to build a query, but want to run that
5 | # query without returning a result. The most common need would
6 | # be to easily use placeholders in an SQL string, which Database#run
7 | # does not support directly.
8 | #
9 | # You can load this extension into specific datasets:
10 | #
11 | # ds = DB["GRANT SELECT ON ? TO ?", :table, :user]
12 | # ds = ds.extension(:dataset_run)
13 | # ds.run
14 | #
15 | # Or you can load it into all of a database's datasets, which
16 | # is probably the desired behavior if you are using this extension:
17 | #
18 | # DB.extension(:dataset_run)
19 | # DB["GRANT SELECT ON ? TO ?", :table, :user].run
20 | #
21 | # Related module: Sequel::DatasetRun
22 |
23 | #
24 | module Sequel
25 | module DatasetRun
26 | # Run the dataset's SQL on the database. Returns NULL. This is
27 | # useful when you want to run SQL without returning a result.
28 | #
29 | # DB["GRANT SELECT ON ? TO ?", :table, :user].run
30 | # # GRANT SELECT ON "table" TO "user"
31 | def run
32 | if server = @opts[:server]
33 | db.run(sql, :server=>server)
34 | else
35 | db.run(sql)
36 | end
37 | end
38 | end
39 |
40 | Dataset.register_extension(:dataset_run, DatasetRun)
41 | end
42 |
--------------------------------------------------------------------------------
/doc/mssql_stored_procedures.rdoc:
--------------------------------------------------------------------------------
1 | = Stored Procedures in MSSQL
2 |
3 | This guide documents the workaround implemented to allow executing stored procedures
4 | in MSSQL, as well as getting the value of output variables.
5 |
6 | == Simple Execution
7 |
8 | The following stored procedure is used as an example:
9 |
10 | CREATE PROCEDURE dbo.SequelTest(
11 | @Input varchar(25),
12 | @Output int OUTPUT
13 | )
14 | AS
15 | SET @Output = LEN(@Input)
16 | RETURN 0
17 |
18 | Execute it as follows:
19 |
20 | DB.call_mssql_sproc(:SequelTest, {args: ['Input String', :output]})
21 |
22 | Use the +:output+ symbol to denote an output variable. The result will contain a
23 | hash of the output variables, as well as the result code and number of affected rows:
24 |
25 | {:result => 0, :numrows => 1, :var1 => "1"}
26 |
27 | Output variables will be strings by default. To specify their type, include the
28 | SQL type:
29 |
30 | DB.call_mssql_sproc(:SequelTest, {args: ['Input String', [:output, 'int']]})
31 |
32 | Result:
33 |
34 | {:result => 0, :numrows => 1, :var1 => 1}
35 |
36 | Output variables will be named +var#{n}+ where n is their zero indexed position
37 | in the parameter list. To name the output variable, include their name:
38 |
39 | DB.call_mssql_sproc(:SequelTest, {args: ['Input String', [:output, nil, 'Output']]})
40 |
41 | Result:
42 |
43 | {:result => 0, :numrows => 1, :output => "1"}
44 |
--------------------------------------------------------------------------------
/spec/extensions/auto_restrict_eager_graph_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "auto_restrict_eager_graph plugin" do
4 | before do
5 | @db = Sequel.mock
6 | @c = Class.new(Sequel::Model(@db[:items]))
7 | @c.plugin :auto_restrict_eager_graph
8 | end
9 |
10 | it "should restrict eager_graph for associations with blocks without :graph_* options" do
11 | @c.many_to_one :cs, :class=>@c do |ds| ds.where(:x) end
12 | proc{@c.eager_graph(:cs)}.must_raise Sequel::Error
13 | end
14 |
15 | it "should not restrict eager_graph for associations without blocks" do
16 | @c.many_to_one :cs, :class=>@c
17 | @c.eager_graph(:cs).sql.must_equal "SELECT * FROM items LEFT OUTER JOIN items AS cs ON (cs.id = items.cs_id)"
18 | end
19 |
20 | it "should not restrict eager_graph for associations with :graph_* options" do
21 | @c.many_to_one :cs, :class=>@c, :graph_conditions=>{:x=>true} do |ds| ds.where(:x) end
22 | @c.eager_graph(:cs).sql.must_equal "SELECT * FROM items LEFT OUTER JOIN items AS cs ON ((cs.id = items.cs_id) AND (cs.x IS TRUE))"
23 | end
24 |
25 | it "should not restrict eager_graph for associations with :allow_eager_graph option" do
26 | @c.many_to_one :cs, :class=>@c, :allow_eager_graph=>true do |ds| ds.where(:x) end
27 | @c.eager_graph(:cs).sql.must_equal "SELECT * FROM items LEFT OUTER JOIN items AS cs ON (cs.id = items.cs_id)"
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/lib/sequel/plugins/skip_create_refresh.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | module Sequel
4 | module Plugins
5 | # The skip_create_refresh plugin skips the
6 | # refresh after saving a new model object. Sequel does the
7 | # refresh by default to make sure all columns are populated, which is
8 | # necessary so that database defaults work correctly.
9 | #
10 | # This plugin is mostly for performance reasons where you
11 | # want to save the cost of select statement after the insert,
12 | # but it could also help cases where records are not
13 | # immediately available for selection after insertion.
14 | #
15 | # Note that Sequel by default does not attempt to refresh records when
16 | # updating existing model objects, only when inserting new
17 | # model objects.
18 | #
19 | # Usage:
20 | #
21 | # # Make all model subclass instances skip refreshes when saving
22 | # # (called before loading subclasses)
23 | # Sequel::Model.plugin :skip_create_refresh
24 | #
25 | # # Make the Album class skip refreshes when saving
26 | # Album.plugin :skip_create_refresh
27 | module SkipCreateRefresh
28 | module InstanceMethods
29 | private
30 | # Do nothing instead of refreshing the record inside of save.
31 | def _save_refresh
32 | nil
33 | end
34 | end
35 | end
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/lib/sequel/plugins/inspect_pk.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | module Sequel
4 | module Plugins
5 | # The inspect_pk plugin includes the pk right next to the
6 | # model name in inspect, allowing for easily copying and
7 | # pasting to retrieve a copy of the object:
8 | #
9 | # Album.with_pk(1).inspect
10 | # # default: #
11 | # # with inspect_pk: #
12 | #
13 | # Usage:
14 | #
15 | # # Make all model instances include pk in inspect output
16 | # Sequel::Model.plugin :inspect_pk
17 | #
18 | # # Make Album instances include pk in inspect output
19 | # Album.plugin :inspect_pk
20 | module InspectPk
21 | module InstanceMethods
22 | private
23 |
24 | # The primary key value to include in the inspect output, if any.
25 | # For composite primary keys, this only includes a value if all
26 | # fields are present.
27 | def inspect_pk
28 | if primary_key && (pk = self.pk) && (!(Array === pk) || pk.all?)
29 | pk
30 | end
31 | end
32 |
33 | # Include the instance's primary key in the output.
34 | def inspect_prefix
35 | if v = inspect_pk
36 | "#{super}[#{v.inspect}]"
37 | else
38 | super
39 | end
40 | end
41 | end
42 | end
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/lib/sequel/plugins/columns_updated.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | module Sequel
4 | module Plugins
5 | # The columns_updated plugin stores the columns hash used in the
6 | # UPDATE query when saving the instance, and makes it available
7 | # in the after_update and after_save hooks via the +columns_updated+
8 | # accessor. The data is cleared before returning from +save+.
9 | #
10 | # Usage:
11 | #
12 | # # Make all model subclasses store the columns hash used for updating
13 | # Sequel::Model.plugin :columns_updated
14 | #
15 | # # Make the Album class store the columns hash used for updating
16 | # Album.plugin :columns_updated
17 | module ColumnsUpdated
18 | module InstanceMethods
19 | private
20 |
21 | # The hash used for updating records. This should only be called
22 | # in the after_update and after_save hooks.
23 | attr_reader :columns_updated
24 |
25 | # Store the hash used for updating the record, so it can be accessed
26 | # in the after_hooks.
27 | def _update_columns(columns_updated)
28 | @columns_updated = columns_updated
29 | super
30 | end
31 |
32 | # Unset the updated columns hash before returning from save.
33 | def _save(opts)
34 | super
35 | ensure
36 | @columns_updated = nil
37 | end
38 | end
39 | end
40 | end
41 | end
42 |
43 |
--------------------------------------------------------------------------------
/doc/release_notes/5.2.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * A pg_extended_date_support extension has been added. This
4 | extension adds support for infinite and BC dates/timestamps on
5 | PostgreSQL.
6 |
7 | The postgres adapter already had a convert_infinite_timestamps
8 | setting, but it wasn't supported in the jdbc/postgresql adapter
9 | and it didn't handle BC dates/timestamps. Setting a non-default
10 | convert_infinite_timestamps setting in the postgres adapter will
11 | now automatically load the extension for backwards compatibility.
12 |
13 | The pg_extended_date_support extension by default just fixes the
14 | handling of BC dates/timestamps. To get it to handle infinite
15 | timestamps, you need to choose the appropriate setting for your
16 | application:
17 |
18 | DB.extension :pg_extended_date_support
19 | DB.convert_infinite_timestamps = :string # or :float or :nil
20 |
21 | This extension also enables the handling of timezone offsets
22 | with seconds, which is not natively supported by ruby's Time
23 | class in ruby <2.5.
24 |
25 | = Improvements
26 |
27 | * The jdbc/mysql adapter now handles smallint unsigned and
28 | integer unsigned column types where the value for the column
29 | is outside of the range of a Java short or integer.
30 |
31 | * Sequel::Model.inherited no longer modifies an existing @dataset
32 | instance variable if one has already been set. This fixes a
33 | regression that was introduced in Sequel 5.0.0.
34 |
--------------------------------------------------------------------------------
/lib/sequel/plugins/empty_failure_backtraces.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | module Sequel
4 | module Plugins
5 | # The empty_failure_backtraces plugin uses empty backtraces when raising HookFailed and ValidationFailed
6 | # exceptions. This can be significantly faster, and if you are using these exceptions for
7 | # flow control, you do not need the backtraces. This plugin is about 10% faster on CRuby
8 | # and 10-15x faster on JRuby 9.2.7.0+. This does not have an effect on JRuby <9.2.7.0.
9 | #
10 | # Usage:
11 | #
12 | # # Make all model subclass instances use empty backtraces for HookFailed
13 | # # and ValidationFailed exceptions (called before loading subclasses)
14 | # Sequel::Model.plugin :empty_failure_backtraces
15 | #
16 | # # Make the Album class use empty backtraces for HookFailed and ValidationFailed exceptions
17 | # Album.plugin :empty_failure_backtraces
18 | module EmptyFailureBacktraces
19 | module InstanceMethods
20 | private
21 |
22 | # Use empty backtrace for HookFailed exceptions.
23 | def hook_failed_error(msg)
24 | e = super
25 | e.set_backtrace([])
26 | e
27 | end
28 |
29 | # Use empty backtrace for ValidationFailed exceptions.
30 | def validation_failed_error
31 | e = super
32 | e.set_backtrace([])
33 | e
34 | end
35 | end
36 | end
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/doc/release_notes/4.3.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * The tree and rcte_tree plugins now support composite keys.
4 |
5 | * An error_sql Database extension has been added. This extension
6 | adds the DatabaseError#sql method, which should return the
7 | database query that caused the error. This is useful for
8 | drivers that don't include the SQL used as part of the error
9 | message.
10 |
11 | = Other Improvements
12 |
13 | * Empty blobs are now literalized correctly on MySQL.
14 |
15 | * Empty arrays are now literalized correctly on PostgreSQL <8.4.
16 |
17 | * In the pagination extension, Dataset#page_count is now 1 even if
18 | the dataset is empty. This fixes issues with last_page? and
19 | page_range returning bad values for empty datasets.
20 |
21 | * In the pagination extension, calling Dataset#each_page without a
22 | block now returns an Enumerator.
23 |
24 | * Dataset#qualify and Sequel.delay now work together, qualifying
25 | the object returned by the delayed evaluation.
26 |
27 | * Migrator.migrator_class is now a public method.
28 |
29 | * The PostgreSQL citext type is now recognized as a string.
30 |
31 | * Another disconnect error is now recognized in the jdbc/as400
32 | adapter.
33 |
34 | * Guides about using and creating Sequel extensions and model
35 | plugins have been added.
36 |
37 | = Backwards Compatibility
38 |
39 | * If you were expecting Dataset#page_count on a empty paginated
40 | dataset to return 0, you need to update your code.
41 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/any_not_empty.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # The any_not_empty extension changes the behavior of Dataset#any?
4 | # if called without a block. By default, this method uses the
5 | # standard Enumerable behavior of enumerating results and seeing
6 | # if any result is not false or nil. With this extension, it
7 | # just checks whether the dataset is empty. This approach can
8 | # be much faster if the dataset is currently large.
9 | #
10 | # DB[:table].any?
11 | # # SELECT * FROM table
12 | #
13 | # DB[:table].extension(:any_not_empty).any?
14 | # # SELECT 1 as one FROM table LIMIT 1
15 | #
16 | # You can load this extension into specific datasets:
17 | #
18 | # ds = DB[:table]
19 | # ds = ds.extension(:any_not_empty)
20 | #
21 | # Or you can load it into all of a database's datasets, which
22 | # is probably the desired behavior if you are using this extension:
23 | #
24 | # DB.extension(:any_not_empty)
25 | #
26 | # Note that this can result in any? returning a different result if
27 | # the dataset has a row_proc that can return false or nil.
28 | #
29 | # Related module: Sequel::AnyNotEmpty
30 |
31 | #
32 | module Sequel
33 | module AnyNotEmpty
34 | # If a block is not given, return whether the dataset is not empty.
35 | def any?(*a)
36 | if !a.empty? || defined?(yield)
37 | super
38 | else
39 | !empty?
40 | end
41 | end
42 | end
43 |
44 | Dataset.register_extension(:any_not_empty, AnyNotEmpty)
45 | end
46 |
--------------------------------------------------------------------------------
/lib/sequel/plugins/async_thread_pool.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | module Sequel
4 | extension 'async_thread_pool'
5 |
6 | module Plugins
7 | # The async_thread_pool plugin makes it slightly easier to use the async_thread_pool
8 | # Database extension with models. It makes Model.async return an async dataset for the
9 | # model, and support async behavior for #destroy, #with_pk, and #with_pk! for model
10 | # datasets:
11 | #
12 | # # Will load the artist with primary key 1 asynchronously
13 | # artist = Artist.async.with_pk(1)
14 | #
15 | # You must load the async_thread_pool Database extension into the Database object the
16 | # model class uses in order for async behavior to work.
17 | #
18 | # Usage:
19 | #
20 | # # Make all model subclass datasets support support async class methods and additional
21 | # # async dataset methods
22 | # Sequel::Model.plugin :async_thread_pool
23 | #
24 | # # Make the Album class support async class method and additional async dataset methods
25 | # Album.plugin :async_thread_pool
26 | module AsyncThreadPool
27 | module ClassMethods
28 | Plugins.def_dataset_methods(self, :async)
29 | end
30 |
31 | module DatasetMethods
32 | [:destroy, :with_pk, :with_pk!].each do |meth|
33 | ::Sequel::Database::AsyncThreadPool::DatasetMethods.define_async_method(self, meth)
34 | end
35 | end
36 | end
37 | end
38 | end
39 |
40 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/looser_typecasting.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # The LooserTypecasting extension loosens the default database typecasting
4 | # for the following types:
5 | #
6 | # :float :: use to_f instead of Float()
7 | # :integer :: use to_i instead of Integer()
8 | # :decimal :: use 0.0 for unsupported strings
9 | # :string :: silently allow hash and array conversion to string
10 | #
11 | # This also removes bytesize checks for string inputs for float, integer
12 | # and decimal conversions.
13 | #
14 | # To load the extension into the database:
15 | #
16 | # DB.extension :looser_typecasting
17 | #
18 | # Related module: Sequel::LooserTypecasting
19 |
20 | #
21 | module Sequel
22 | module LooserTypecasting
23 | private
24 |
25 | # Typecast the value to a Float using to_f instead of Kernel.Float
26 | def typecast_value_float(value)
27 | value.to_f
28 | end
29 |
30 | # Typecast the value to an Integer using to_i instead of Kernel.Integer
31 | def typecast_value_integer(value)
32 | value.to_i
33 | end
34 |
35 | # Typecast the value to an String using to_s instead of Kernel.String
36 | def typecast_value_string(value)
37 | value.to_s
38 | end
39 |
40 | # Typecast invalid BigDecimal to 0.0.
41 | def _typecast_value_string_to_decimal(value)
42 | BigDecimal(value)
43 | rescue
44 | BigDecimal('0.0')
45 | end
46 | end
47 |
48 | Database.register_extension(:looser_typecasting, LooserTypecasting)
49 | end
50 |
51 |
--------------------------------------------------------------------------------
/spec/extensions/error_sql_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "error_sql extension" do
4 | before do
5 | @db = Sequel.mock(:fetch=>proc{|sql| @db.synchronize{|c| @db.log_connection_yield(sql, c){raise StandardError}}}).extension(:error_sql)
6 | end
7 |
8 | it "should have Sequel::DatabaseError#sql give the SQL causing the error" do
9 | @db["SELECT"].all rescue (e = $!)
10 | e.sql.must_equal "SELECT"
11 | end
12 |
13 | it "should include connection information in SQL information if logging connection info" do
14 | @db.log_connection_info = true
15 | @db["SELECT"].all rescue (e = $!)
16 | e.sql.must_match(/\A\(conn: -?\d+\) SELECT\z/)
17 | end
18 |
19 | it "should include arguments in SQL information if given" do
20 | @db["SELECT"].with_fetch(proc{|sql| @db.synchronize{|c| @db.log_connection_yield(sql, c, [1, 2]){raise StandardError}}}).all rescue (e = $!)
21 | e.sql.must_equal "SELECT; [1, 2]"
22 | end
23 |
24 | it "should have Sequel::DatabaseError#sql give the SQL causing the error when using a logger" do
25 | l = Object.new
26 | def l.method_missing(*) end
27 | @db.loggers = [l]
28 | @db["SELECT"].all rescue (e = $!)
29 | e.sql.must_equal "SELECT"
30 | end
31 |
32 | it "should have Sequel::DatabaseError#sql be nil if there is no wrapped exception" do
33 | @db["SELECT"].with_fetch(proc{|sql| @db.log_connection_yield(sql, nil){raise Sequel::DatabaseError}}).all rescue (e = $!)
34 | e.sql.must_be_nil
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/spec/files/unused_associations/run_tua.rb:
--------------------------------------------------------------------------------
1 | $:.unshift(File.expand_path('../../../lib', File.dirname(__FILE__)))
2 | require 'json'
3 | require 'coverage'
4 |
5 | Coverage.start(methods: true)
6 |
7 | require 'sequel'
8 | DB = Sequel.mock(:columns=>[:id, :t_id], :fetch=>{:id=>1, :t_id=>2}, :numrows=>1)
9 |
10 | opts = ENV['PLUGIN_OPTS'] ? Sequel.parse_json(ENV['PLUGIN_OPTS']).transform_keys(&:to_sym) : {}
11 | Sequel::Model.plugin :unused_associations, opts
12 |
13 | require_relative 'tua'
14 |
15 | eval($stdin.read)
16 |
17 | begin
18 | cov_data = if ENV['NO_COVERAGE_RESULT']
19 | Sequel::Model.update_associations_coverage
20 | else
21 | Sequel::Model.update_associations_coverage(coverage_result: Coverage.result)
22 | end
23 |
24 | data = if ENV['NO_COVERAGE_DATA']
25 | Sequel::Model.update_unused_associations_data
26 | elsif ENV['KEEP_COVERAGE']
27 | Sequel::Model.update_unused_associations_data(:keep_coverage=>true)
28 | else
29 | Sequel::Model.update_unused_associations_data(coverage_data: cov_data)
30 | end
31 |
32 | result = if ENV['NO_DATA']
33 | [Sequel::Model.unused_associations.sort,
34 | Sequel::Model.unused_association_options.sort]
35 | else
36 | [Sequel::Model.unused_associations(unused_associations_data: data).sort,
37 | Sequel::Model.unused_association_options(unused_associations_data: data).sort]
38 | end
39 | rescue => e
40 | result = "#{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
41 | end
42 |
43 | print Sequel.object_to_json(result)
44 |
--------------------------------------------------------------------------------
/lib/sequel/connection_pool/single.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | # This is the fastest connection pool, since it isn't a connection pool at all.
4 | # It is just a wrapper around a single connection that uses the connection pool
5 | # API.
6 | class Sequel::SingleConnectionPool < Sequel::ConnectionPool
7 | def initialize(db, opts=OPTS)
8 | super
9 | @conn = []
10 | end
11 |
12 | # Yield the connection if one has been made.
13 | def all_connections
14 | yield @conn.first unless @conn.empty?
15 | end
16 |
17 | # Disconnect the connection from the database.
18 | def disconnect(opts=nil)
19 | return unless c = @conn.first
20 | disconnect_connection(c)
21 | @conn.clear
22 | nil
23 | end
24 |
25 | # Yield the connection to the block.
26 | def hold(server=nil)
27 | unless c = @conn.first
28 | @conn.replace([c = make_new(:default)])
29 | end
30 | yield c
31 | rescue Sequel::DatabaseDisconnectError, *@error_classes => e
32 | disconnect if disconnect_error?(e)
33 | raise
34 | end
35 |
36 | # The SingleConnectionPool always has a maximum size of 1.
37 | def max_size
38 | 1
39 | end
40 |
41 | def pool_type
42 | :single
43 | end
44 |
45 | # The SingleConnectionPool always has a size of 1 if connected
46 | # and 0 if not.
47 | def size
48 | @conn.empty? ? 0 : 1
49 | end
50 |
51 | private
52 |
53 | # Make sure there is a valid connection.
54 | def preconnect(concurrent = nil)
55 | hold{}
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/doc/release_notes/4.30.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * Overriding the :limit and :eager_limit_strategy association options
4 | can now be done on a per-call basis when eager loading, by using an
5 | eager block callback and setting the :eager_limit or
6 | :eager_limit_strategy dataset options. Example:
7 |
8 | Album.eager(:tracks=>proc{|ds| ds.clone(:eager_limit=>5)}).all
9 |
10 | * Dataset#insert_conflict and #insert_ignore have been added on
11 | SQLite, adding support for the INSERT OR ... SQL syntax:
12 |
13 | DB[:table].insert_ignore.insert(:a=>1, :b=>2)
14 | # INSERT OR IGNORE INTO TABLE (a, b) VALUES (1, 2)
15 |
16 | DB[:table].insert_conflict(:replace).insert(:a=>1, :b=>2)
17 | # INSERT OR REPLACE INTO TABLE (a, b) VALUES (1, 2)
18 |
19 | * An identifier_columns plugin has been added, which allows
20 | Sequel::Model#save to work when column names contain double
21 | underscores.
22 |
23 | = Other Improvements
24 |
25 | * IPv6 addresses can now be used in connection URLs when using
26 | ruby 1.9.3+.
27 |
28 | * The :db_type entries in column schema hashes now include sizes
29 | for string and decimal types on DB2 and when using the jdbc
30 | adapter's generic schema parsing.
31 |
32 | * Database#row_type in the pg_row extension now handles different
33 | formats of specifying schema qualified types. So a row type
34 | registered via :schema__type can be found using
35 | Sequel.qualify(:schema, :type).
36 |
37 | * Another disconnect error is recognized in the tinytds adapter.
38 |
--------------------------------------------------------------------------------
/lib/sequel/database.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | module Sequel
4 | # Hash of adapters that have been used. The key is the adapter scheme
5 | # symbol, and the value is the Database subclass.
6 | ADAPTER_MAP = {}
7 |
8 | # Hash of shared adapters that have been registered. The key is the
9 | # adapter scheme symbol, and the value is the Sequel module containing
10 | # the shared adapter.
11 | SHARED_ADAPTER_MAP = {}
12 |
13 | # Array of all databases to which Sequel has connected. If you are
14 | # developing an application that can connect to an arbitrary number of
15 | # databases, delete the database objects from this (or use the :keep_reference
16 | # Database option or a block when connecting) or they will not get
17 | # garbage collected.
18 | DATABASES = []
19 |
20 | # A Database object represents a virtual connection to a database.
21 | # The Database class is meant to be subclassed by database adapters in order
22 | # to provide the functionality needed for executing queries.
23 | class Database
24 | OPTS = Sequel::OPTS
25 | end
26 |
27 | require_relative "database/connecting"
28 | require_relative "database/dataset"
29 | require_relative "database/dataset_defaults"
30 | require_relative "database/logging"
31 | require_relative "database/features"
32 | require_relative "database/misc"
33 | require_relative "database/query"
34 | require_relative "database/transactions"
35 | require_relative "database/schema_generator"
36 | require_relative "database/schema_methods"
37 | end
38 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/virtual_row_method_block.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # These modifies virtual row blocks so that you can pass a block
4 | # when calling a method to change the behavior. It only exists
5 | # for backwards compatibility with previous Sequel versions, and
6 | # is not recommended for new applications.
7 | #
8 | # To load the extension:
9 | #
10 | # Sequel.extension :virtual_row_method_block
11 |
12 | #
13 | module Sequel
14 | module SQL
15 | class VirtualRow < BasicObject
16 | include(Module.new do
17 | Sequel.set_temp_name(self){"Sequel::SQL:VirtualRow::_MethodBlockMethodMissing"}
18 | # Handle blocks passed to methods and change the behavior.
19 | def method_missing(m, *args, &block)
20 | if block
21 | if args.empty?
22 | Function.new(m)
23 | else
24 | case args.shift
25 | when :*
26 | Function.new(m, *args).*
27 | when :distinct
28 | Function.new(m, *args).distinct
29 | when :over
30 | opts = args.shift || OPTS
31 | f = Function.new(m, *::Kernel.Array(opts[:args]))
32 | f = f.* if opts[:*]
33 | f.over(opts)
34 | else
35 | Kernel.raise(Error, 'unsupported VirtualRow method argument used with block')
36 | end
37 | end
38 | else
39 | super
40 | end
41 | end
42 | end)
43 | end
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/symbol_aref.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # The symbol_aref extension makes Symbol#[] support Symbol,
4 | # Sequel::SQL::Indentifier, and Sequel::SQL::QualifiedIdentifier instances,
5 | # returning appropriate Sequel::SQL::QualifiedIdentifier instances. It's
6 | # designed as a shortcut so that instead of:
7 | #
8 | # Sequel[:table][:column] # table.column
9 | #
10 | # you can just write:
11 | #
12 | # :table[:column] # table.column
13 | #
14 | # To load the extension:
15 | #
16 | # Sequel.extension :symbol_aref
17 | #
18 | # If you are using Ruby 2+, and you would like to use refinements, there
19 | # is a refinement version of this in the symbol_aref_refinement extension.
20 | #
21 | # Related module: Sequel::SymbolAref
22 |
23 | if RUBY_VERSION >= '2.0'
24 | module Sequel::SymbolAref
25 | def [](v)
26 | case v
27 | when Symbol, Sequel::SQL::Identifier, Sequel::SQL::QualifiedIdentifier
28 | Sequel::SQL::QualifiedIdentifier.new(self, v)
29 | else
30 | super
31 | end
32 | end
33 | end
34 |
35 | class Symbol
36 | prepend Sequel::SymbolAref
37 | end
38 | # :nocov:
39 | else
40 | class Symbol
41 | if method_defined?(:[])
42 | alias_method :aref_before_sequel, :[]
43 | end
44 |
45 | def [](v)
46 | case v
47 | when Symbol, Sequel::SQL::Identifier, Sequel::SQL::QualifiedIdentifier
48 | Sequel::SQL::QualifiedIdentifier.new(self, v)
49 | else
50 | aref_before_sequel(v)
51 | end
52 | end
53 | end
54 | end
55 | # :nocov:
56 |
--------------------------------------------------------------------------------
/doc/release_notes/5.87.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * Column schema hashes on MySQL and PostgreSQL now include the
4 | comment on the column in the :comment entry.
5 |
6 | * An inspect_pk plugin has been added, which makes the inspect output
7 | include the primary key next to the class name, so that you can
8 | copy and paste the inspect output to return the model object:
9 |
10 | Album.with_pk(1).inspect
11 | # default: #
12 | # with inspect_pk: #
13 |
14 | * A pg_schema_caching extension has been added. This builds on top
15 | of the schema_caching extension, and handles OIDs for custom types.
16 |
17 | Type OIDs are included in column schema hashes on PostgreSQL. The
18 | OIDs are static for built-in types, but dynamic for custom types.
19 | The pg_schema_caching extension will perform a query to get the
20 | type OIDs for the custom types after loading the cached schema.
21 |
22 | = Other Improvements
23 |
24 | * Database#extension and Dataset#extension no longer attempt to
25 | require the extension file if the extension has already been
26 | registered. This is how model plugins work, and makes it easier
27 | for applications to use custom extensions without messing with the
28 | load path.
29 |
30 | * When using the pg_auto_parameterize extension, and using
31 | Dataset#no_auto_parameterize, Dataset#import is no longer limited to
32 | inserting 40 rows at a time.
33 |
34 | * The trilogy adapter now treats all database errors with code 1205 as
35 | Sequel::DatabaseLockTimeout.
36 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/datetime_parse_to_time.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # This switches the default parsing of strings into Time values
4 | # from using Time.parse to using DateTime.parse.to_time. This
5 | # fixes issues when the times being parsed have no timezone
6 | # information, the implicit timezone for the Database instance
7 | # is set to +:utc+, and the timestamps being used include values
8 | # not valid in the local timezone, such as during a daylight
9 | # savings time switch.
10 | #
11 | # To load the extension:
12 | #
13 | # Sequel.extension :datetime_parse_to_time
14 |
15 | #
16 | module Sequel::DateTimeParseToTime
17 | private
18 |
19 | # Use DateTime.parse.to_time to do the conversion if the input a string and is assumed to
20 | # be in UTC and there is no offset information in the string.
21 | def convert_input_timestamp(v, input_timezone)
22 | if v.is_a?(String) && datetime_class == Time && input_timezone == :utc && !_date_parse(v).has_key?(:offset)
23 | # :nocov:
24 | # Whether this is fully branch covered depends on the order in which the specs are run.
25 | v = handle_date_parse_input(v) if respond_to?(:handle_date_parse_input, true)
26 | # :nocov:
27 | t = DateTime.parse(v).to_time
28 | case application_timezone
29 | when nil, :local
30 | t = t.localtime
31 | end
32 | t
33 | else
34 | super
35 | end
36 | rescue => e
37 | raise convert_exception_class(e, Sequel::InvalidValue)
38 | end
39 | end
40 |
41 | Sequel.extend(Sequel::DateTimeParseToTime)
42 |
--------------------------------------------------------------------------------
/spec/extensions/looser_typecasting_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "LooserTypecasting Extension" do
4 | before do
5 | @db = Sequel.mock
6 | def @db.supports_schema_parsing?() true end
7 | def @db.schema(*args)
8 | [[:id, {}], [:z, {:type=>:float}], [:b, {:type=>:integer}], [:d, {:type=>:decimal}], [:s, {:type=>:string}]]
9 | end
10 | @c = Class.new(Sequel::Model(@db[:items]))
11 | @db.extension(:looser_typecasting)
12 | @c.instance_eval do
13 | @columns = [:id, :b, :z, :d, :s]
14 | def columns; @columns; end
15 | end
16 | end
17 |
18 | it "should not raise errors for invalid strings in integer columns" do
19 | @c.new(:b=>'a').b.must_equal 0
20 | @c.new(:b=>'a').b.must_be_kind_of(Integer)
21 | end
22 |
23 | it "should not raise errors for invalid strings in float columns" do
24 | @c.new(:z=>'a').z.must_equal 0.0
25 | @c.new(:z=>'a').z.must_be_kind_of(Float)
26 | end
27 |
28 | it "should not raise errors for hash or array input to string columns" do
29 | @c.new(:s=>'a').s.must_equal 'a'
30 | @c.new(:s=>[]).s.must_be_kind_of(String)
31 | @c.new(:s=>{}).s.must_be_kind_of(String)
32 | end
33 |
34 | it "should not raise errors for invalid strings in decimal columns" do
35 | @c.new(:d=>'a').d.must_equal 0.0
36 | @c.new(:d=>'a').d.must_be_kind_of(BigDecimal)
37 | end
38 |
39 | it "should not affect conversions of other types in decimal columns" do
40 | @c.new(:d=>1).d.must_equal 1
41 | @c.new(:d=>1).d.must_be_kind_of(BigDecimal)
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/doc/release_notes/5.44.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * A concurrent_eager_loading plugin has been added. This plugin
4 | builds on top of the async_thread_pool Database extension and
5 | allows eager loading multiple associations concurrently in
6 | separate threads. With this plugin, you can mark datasets for
7 | concurrent eager loading using eager_load_concurrently:
8 |
9 | Album.eager_load_concurrently.eager(:artist, :genre, :tracks).all
10 |
11 | Datasets that are marked for concurrent eager loading will use
12 | concurrent eager loading if they are eager loading more than one
13 | association. If you would like to make concurrent eager loading
14 | the default, you can load the plugin with the :always option.
15 |
16 | All of the association types that ship with Sequel now support
17 | concurrent eager loading when using this plugin. For custom eager
18 | loaders using the :eager_loader association option, please see the
19 | documentation for the plugin for how to enable custom eager loading
20 | for them.
21 |
22 | = Other Improvements
23 |
24 | * The date_arithmetic extension now handles ActiveSupport::Duration
25 | values with weeks, as well as :weeks as a key in a hash value. Weeks
26 | are converted into 7 days internally.
27 |
28 | * The shared SQLite adapter now emulates the dropping of non-composite
29 | unique constraints. Non-composite unique constraints are now
30 | treated similarly to composite unique constraints, in that dropping
31 | any unique constraints on a table will drop all unique constraints
32 | on that table.
33 |
--------------------------------------------------------------------------------
/doc/release_notes/1.0.txt:
--------------------------------------------------------------------------------
1 | === New code organization
2 |
3 | Sequel is now divided into two parts: sequel_core and sequel_model.
4 | These two parts are distributed as two separate gems. The sequel gem
5 | bundles sequel_core and sequel_model together. If you don't use
6 | Sequel::Model in your code, you can just install and use sequel_core.
7 |
8 | === New model hooks implementation
9 |
10 | The hooks implementation have been rewritten from scratch, is much
11 | more robust and offers a few new features:
12 |
13 | * More ways to define hooks: hooks can now be defined by supplying a
14 | block or a method name, or by overriding the hook instance method.
15 |
16 | * Inheritable hooks: Hooks can now be inherited, which means that you
17 | can define general hooks in a model superclass, and use them in
18 | subclasses. You can also define global hooks on Sequel::Model that
19 | will be invoked for all model classes.
20 |
21 | * Hook chains can be broken by returning false from within the hook.
22 |
23 | * New after_initialize hook, invoked after instance initialization.
24 |
25 | * The hook invocation order can no longer be changed. Hooks are
26 | invoked in order of definition, from the top of the class hierarchy
27 | (that is, from Sequel::Model) down to the specific class.
28 |
29 | === Miscellanea
30 |
31 | * Removed deprecated adapter stubs, and all other deprecations in both
32 | sequel_core and sequel_model.
33 |
34 | * Fixed String#to_time to raise error correctly for invalid time
35 | stamps.
36 |
37 | * Fixed error behavior when parse_tree or ruby2ruby are not available.
38 |
39 |
--------------------------------------------------------------------------------
/spec/extensions/select_remove_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "Dataset#select_remove" do
4 | before do
5 | @d = Sequel.mock.from(:test).extension(:select_remove)
6 | @d.columns :a, :b, :c
7 | end
8 |
9 | it "should remove columns from the selected columns" do
10 | @d.sql.must_equal 'SELECT * FROM test'
11 | @d.select_remove(:a).sql.must_equal 'SELECT b, c FROM test'
12 | @d.select_remove(:b).sql.must_equal 'SELECT a, c FROM test'
13 | @d.select_remove(:c).sql.must_equal 'SELECT a, b FROM test'
14 | end
15 |
16 | it "should work correctly if there are already columns selected" do
17 | d = @d.select(:a, :b, :c)
18 | d.columns :a, :b, :c
19 | d.select_remove(:c).sql.must_equal 'SELECT a, b FROM test'
20 | end
21 |
22 | it "should have no effect if the columns given are not currently selected" do
23 | @d.select_remove(:d).sql.must_equal 'SELECT a, b, c FROM test'
24 | end
25 |
26 | it "should handle expressions where Sequel can't determine the alias by itself" do
27 | d = @d.select(:a, Sequel.function(:b), Sequel.as(:c, :b))
28 | d.columns :a, :"b()", :b
29 | d.select_remove(:"b()").sql.must_equal 'SELECT a, c AS b FROM test'
30 | end
31 |
32 | it "should remove expressions if given exact expressions" do
33 | d = @d.select(:a, Sequel.function(:b), Sequel.as(:c, :b))
34 | d.columns :a, :"b()", :b
35 | d.select_remove(Sequel.function(:b)).sql.must_equal 'SELECT a, c AS b FROM test'
36 | d.select_remove(Sequel.as(:c, :b)).sql.must_equal 'SELECT a, b() FROM test'
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/doc/release_notes/5.74.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * Sequel.migration blocks now support a revert method, which reverts
4 | the changes in the block on up, and applies them on down. So if
5 | you have a migration such as:
6 |
7 | Sequel.migration do
8 | change do
9 | create_table :table do
10 | # ...
11 | end
12 | end
13 | end
14 |
15 | and you later want to add a migration that drops the table, you
16 | can use:
17 |
18 | Sequel.migration do
19 | revert do
20 | create_table :table do
21 | # ...
22 | end
23 | end
24 | end
25 |
26 | This will drop the table when migrating up, and create a table
27 | with the given schema when migrating down.
28 |
29 | * is_json and is_not_json methods have been added to the pg_json_ops
30 | extension, for the IS [NOT] JSON operator supported in PostgreSQL
31 | 16+. These were previously added in Sequel 5.59.0, and removed
32 | in Sequel 5.61.0 as support was removed in PostgreSQL 15 beta 4.
33 | PostgreSQL 16 shipped with support for them, so support has been
34 | recommitted to Sequel.
35 |
36 | = Other Improvements
37 |
38 | * SQLite generated columns now show up in Database#schema when using
39 | SQLite 3.37+.
40 |
41 | * Sequel now attempts to avoid an infinite loop in pathlogical cases
42 | in the jdbc adapter, where the exception cause chain has a loop.
43 | Additionally, if an exception is already recognized as a disconnect,
44 | or an exception already responds to a getSQLState method, Sequel no
45 | longer looks at the causes of the exception.
46 |
--------------------------------------------------------------------------------
/spec/extensions/pg_extended_integer_support_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "pg_extended_integer_support extension" do
4 | before do
5 | @db = Sequel.mock(:host=>'postgres').extension(:pg_extended_integer_support)
6 | end
7 |
8 | it "should literalize integers out of range using single quotes by default" do
9 | @db.literal(2**63).must_equal "'9223372036854775808'"
10 | end
11 |
12 | it "should literalize integers out of range without quotes when configured with :raw strategy" do
13 | @db.dataset.integer_outside_bigint_range_strategy(:raw).literal(2**63).must_equal "9223372036854775808"
14 | end
15 |
16 | it "should raise for integers out of range when configured with :raise strategy" do
17 | ds = @db.dataset.integer_outside_bigint_range_strategy(:raise)
18 | proc{ds.literal(2**63)}.must_raise Sequel::InvalidValue
19 | end
20 |
21 | it "should raise for integers out of range when configured with :quote strategy" do
22 | @db.dataset.integer_outside_bigint_range_strategy(:quote).literal(2**63).must_equal "'9223372036854775808'"
23 | end
24 |
25 | it "should respect :integer_outside_bigint_range_strategy Database option for strategy" do
26 | @db.opts[:integer_outside_bigint_range_strategy] = :raw
27 | @db.literal(2**63).must_equal "9223372036854775808"
28 |
29 | @db.opts[:integer_outside_bigint_range_strategy] = :quote
30 | @db.literal(2**63).must_equal "'9223372036854775808'"
31 |
32 | @db.opts[:integer_outside_bigint_range_strategy] = :raise
33 | proc{@db.literal(2**63)}.must_raise Sequel::InvalidValue
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/empty_array_consider_nulls.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # This changes Sequel's literalization of IN/NOT IN with an empty
4 | # array value to consider NULL values if one of the referenced
5 | # columns is NULL:
6 | #
7 | # DB[:test].where(name: [])
8 | # # SELECT * FROM test WHERE (name != name)
9 | # DB[:test].exclude(name: [])
10 | # # SELECT * FROM test WHERE (name = name)
11 | #
12 | # This works for sets in addition to arrays:
13 | #
14 | # DB[:test].where(name: Set[])
15 | # # SELECT * FROM test WHERE (name != name)
16 | # DB[:test].exclude(name: Set[])
17 | # # SELECT * FROM test WHERE (name = name)
18 | #
19 | # The default Sequel behavior is to ignore NULLs, as the above
20 | # query is not generally optimized well by databases.
21 | #
22 | # You can load this extension into specific datasets:
23 | #
24 | # ds = DB[:table]
25 | # ds = ds.extension(:empty_array_consider_nulls)
26 | #
27 | # Or you can load it into all of a database's datasets, which
28 | # is probably the desired behavior if you are using this extension:
29 | #
30 | # DB.extension(:empty_array_consider_nulls)
31 | #
32 | # Related module: Sequel::EmptyArrayConsiderNulls
33 |
34 | #
35 | module Sequel
36 | module EmptyArrayConsiderNulls
37 | # Use an expression that returns NULL if the column value is NULL.
38 | def empty_array_value(op, cols)
39 | c = Array(cols)
40 | SQL::BooleanExpression.from_value_pairs(c.zip(c), :AND, op == :IN)
41 | end
42 |
43 | end
44 |
45 | Dataset.register_extension(:empty_array_consider_nulls, EmptyArrayConsiderNulls)
46 | end
47 |
--------------------------------------------------------------------------------
/spec/model/spec_helper.rb:
--------------------------------------------------------------------------------
1 | $:.unshift(File.join(File.dirname(File.expand_path(__FILE__)), "../../lib/"))
2 | require_relative "../../lib/sequel"
3 |
4 | Sequel::Deprecation.backtrace_filter = lambda{|line, lineno| lineno < 4 || line =~ /_spec\.rb/}
5 |
6 | ENV['MT_NO_PLUGINS'] = '1' # Work around stupid autoloading of plugins
7 | gem 'minitest'
8 | require 'minitest/global_expectations/autorun'
9 | require 'minitest/hooks/default'
10 |
11 | require_relative '../deprecation_helper'
12 |
13 | class << Sequel::Model
14 | attr_writer :db_schema
15 | alias orig_columns columns
16 | def columns(*cols)
17 | return super if cols.empty?
18 | define_method(:columns){cols}
19 | alias_method(:columns, :columns)
20 | @dataset.send(:columns=, cols) if @dataset
21 | def_column_accessor(*cols)
22 | @columns = cols
23 | @db_schema = {}
24 | cols.each{|c| @db_schema[c] = {}}
25 | end
26 | end
27 |
28 | Sequel::DB = nil
29 | Sequel::Model.use_transactions = false
30 | Sequel::Model.cache_anonymous_models = false
31 |
32 | db = Sequel.mock(:fetch=>{:id => 1, :x => 1}, :numrows=>1, :autoid=>proc{|sql| 10})
33 | def db.schema(*) [[:id, {:primary_key=>true}]] end
34 | def db.reset() sqls end
35 | def db.supports_schema_parsing?() true end
36 | Sequel::Model.db = DB = db
37 |
38 | if ENV['SEQUEL_COLUMNS_INTROSPECTION']
39 | Sequel.extension :columns_introspection
40 | Sequel::Database.extension :columns_introspection
41 | Sequel::Mock::Dataset.send(:include, Sequel::ColumnsIntrospection)
42 | end
43 | if ENV['SEQUEL_NO_CACHE_ASSOCIATIONS']
44 | Sequel::Model.cache_associations = false
45 | end
46 |
--------------------------------------------------------------------------------
/doc/release_notes/4.18.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * An :auto_increment key has been added to the schema information for
4 | primary key columns on JDBC, PostgreSQL, MySQL, MSSQL, DB2, and
5 | SQLite. This fixes issues in the schema_dumper extension where
6 | non-auto-incrementing integer primary keys are no longer dumped as
7 | auto-incrementing.
8 |
9 | For adapters that don't have specific support for detecting
10 | auto incrementing primary keys, Sequel now assumes a primary key
11 | is auto incrementing only if it is not a composite primary key
12 | and the type contains int (e.g. int, integer, bigint).
13 |
14 | = Other Improvements
15 |
16 | * Dataset#empty? now ignores any order on the dataset. Previously,
17 | calling empty? on a dataset ordered by an alias in the SELECT list
18 | could raise an exception.
19 |
20 | * Schema qualified tables are now handled correctly in
21 | many_through_many associations.
22 |
23 | * Using a hash as the value for the :eager association option now
24 | works correctly.
25 |
26 | * All PG::ConnectionBad exceptions are now treated as disconnect
27 | errors in the postgres adapter. This should be more robust than
28 | the previous method of trying to recognize disconnect errors by
29 | trying to parse the exception message.
30 |
31 | * Sequel now skips a hash allocation when issuing queries through
32 | datasets if sharding is not used.
33 |
34 | * Sequel no longer uses the JDBC schema parsing in the jdbc/sqlserver
35 | adapter. Instead, it uses the MSSQL schema parsing, which should
36 | be more accurate than the generic JDBC schema parsing.
37 |
--------------------------------------------------------------------------------
/sequel.gemspec:
--------------------------------------------------------------------------------
1 | require File.expand_path("../lib/sequel/version", __FILE__)
2 | SEQUEL_GEMSPEC = Gem::Specification.new do |s|
3 | s.name = 'sequel'
4 | s.version = Sequel.version
5 | s.platform = Gem::Platform::RUBY
6 | s.extra_rdoc_files = ["MIT-LICENSE"]
7 | s.rdoc_options += ["--quiet", "--line-numbers", "--inline-source", '--title', 'Sequel: The Database Toolkit for Ruby', '--main', 'README.rdoc']
8 | s.summary = "The Database Toolkit for Ruby"
9 | s.description = s.summary
10 | s.author = "Jeremy Evans"
11 | s.email = "code@jeremyevans.net"
12 | s.homepage = "https://sequel.jeremyevans.net"
13 | s.license = 'MIT'
14 | s.metadata = {
15 | 'bug_tracker_uri' => 'https://github.com/jeremyevans/sequel/issues',
16 | 'changelog_uri' => 'https://sequel.jeremyevans.net/rdoc/files/CHANGELOG.html',
17 | 'documentation_uri' => 'https://sequel.jeremyevans.net/documentation.html',
18 | 'mailing_list_uri' => 'https://github.com/jeremyevans/sequel/discussions',
19 | 'source_code_uri' => 'https://github.com/jeremyevans/sequel',
20 | }
21 | s.required_ruby_version = ">= 1.9.2"
22 | s.files = %w(MIT-LICENSE bin/sequel) + Dir["lib/**/*.rb"]
23 | s.require_path = "lib"
24 | s.bindir = 'bin'
25 | s.executables << 'sequel'
26 | s.add_dependency "bigdecimal"
27 | s.add_development_dependency "minitest", '>=5.7.0'
28 | s.add_development_dependency "minitest-hooks"
29 | s.add_development_dependency "minitest-global_expectations"
30 | s.add_development_dependency "tzinfo"
31 | s.add_development_dependency "activemodel"
32 | s.add_development_dependency "nokogiri"
33 | end
34 |
--------------------------------------------------------------------------------
/spec/extensions/accessed_columns_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "accessed_columns plugin" do
4 | before do
5 | @db = Sequel.mock(:fetch=>{:name=>'a', :b=>'c'}, :numrows=>1)
6 | @c = Class.new(Sequel::Model(@db[:test]))
7 | @c.columns :name, :b
8 | @c.plugin :accessed_columns
9 | @o = @c.new
10 | end
11 |
12 | it "should record columns accessed" do
13 | @o.accessed_columns.must_equal []
14 | @o.name
15 | @o.accessed_columns.must_equal [:name]
16 | @o.name
17 | @o.accessed_columns.must_equal [:name]
18 | @o.b
19 | @o.accessed_columns.sort_by{|s| s.to_s}.must_equal [:b, :name]
20 | end
21 |
22 | it "should clear accessed columns when refreshing" do
23 | @o.name
24 | @o.refresh
25 | @o.accessed_columns.must_equal []
26 | end
27 |
28 | it "should clear accessed columns when saving" do
29 | @o.name
30 | @o.save
31 | @o.accessed_columns.must_equal []
32 | end
33 |
34 | it "should work when duping and cloning instances" do
35 | o = @o.dup
36 | o.accessed_columns.must_be_empty
37 |
38 | @o.name
39 | o = @o.dup
40 | @o.accessed_columns.must_equal [:name]
41 | o.accessed_columns.must_equal [:name]
42 |
43 | @o.b
44 | @o.accessed_columns.sort_by{|s| s.to_s}.must_equal [:b, :name]
45 | o.accessed_columns.must_equal [:name]
46 | o2 = o.clone
47 | o2.refresh
48 | o.accessed_columns.must_equal [:name]
49 | o2.accessed_columns.must_equal []
50 | end
51 |
52 | it "should not raise exceptions when object is frozen" do
53 | @o.freeze
54 | @o.name
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/doc/release_notes/5.26.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * Support for SQL/JSON path expressions has been added to the
4 | pg_json_ops extension. These are supported in PostgreSQL 12+.
5 | Examples:
6 |
7 | j = Sequel.pg_json_op(:json_column)
8 | j.path_exists('$.foo') # (jsonb_column @? '$.foo')
9 | j.path_match('$.foo') # (jsonb_column @@ '$.foo')
10 | j.path_exists!('$.foo') # jsonb_path_exists(jsonb_column, '$.foo')
11 | j.path_match!('$.foo') # jsonb_path_match(jsonb_column, '$.foo')
12 | j.path_query('$.foo') # jsonb_path_query(jsonb_column, '$.foo')
13 | j.path_query_array('$.foo') # jsonb_path_query_array(jsonb_column, '$.foo')
14 | j.path_query_first('$.foo') # jsonb_path_query_first(jsonb_column, '$.foo')
15 |
16 | * The nested_attributes method in the nested_attributes plugin now
17 | supports a :require_modification option, which can override the
18 | default require_modification setting for the nested objects. This
19 | can be useful to avoid errors if multiple requests are submitted
20 | simultaneously to delete the same nested row.
21 |
22 | = Other Improvements
23 |
24 | * The dirty plugin now works correctly with the typecast_on_load
25 | plugin.
26 |
27 | * Sequel::Postgres::PGRange#hash has been added to the pg_range
28 | extension, allowing PGRange instances to be usable as hash keys.
29 |
30 | * Table aliases are now supported for single table INSERT
31 | statements on PostgreSQL 9.5+, which can make some insert_conflict
32 | usage easier.
33 |
34 | * Two more foreign key constraint violation types are now recognized
35 | on MySQL 8.0.13+.
36 |
--------------------------------------------------------------------------------
/spec/extensions/async_thread_pool_plugin_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative 'spec_helper'
2 |
3 | describe "async_thread_pool plugin" do
4 | before do
5 | @db = Sequel.mock(:extensions=>'async_thread_pool', :fetch=>{:id=>1}, :keep_reference=>false, :num_async_threads=>1, :numrows=>1)
6 | @Album = Class.new(Sequel::Model)
7 | @Album.set_dataset(@db[:albums])
8 | @Album.plugin :async_thread_pool
9 | @db.sqls
10 | end
11 |
12 | it 'should support creating async datasets via Model.async' do
13 | t = Thread.current
14 | t2 = nil
15 |
16 | v = @Album.all{|x| t2 = Thread.current}
17 | (Array === v).must_equal true
18 | v.first.must_be_kind_of @Album
19 | t2.must_equal t
20 |
21 | v = @Album.async.all{|x| t2 = Thread.current}
22 | (Array === v).must_equal false
23 | v.first.must_be_kind_of @Album
24 | t2.wont_be_nil
25 | t2.wont_equal t
26 |
27 | @db.sqls.must_equal ["SELECT * FROM albums", "SELECT * FROM albums"]
28 | end
29 |
30 | it 'should support async versions of destroy' do
31 | @Album.dataset.async.destroy.__value.must_equal 1
32 | @db.sqls.must_equal ["SELECT * FROM albums", "DELETE FROM albums WHERE (id = 1)"]
33 | end
34 |
35 | it 'should support async versions of with_pk' do
36 | @Album.dataset.async.with_pk(1).__value.pk.must_equal 1
37 | @db.sqls.must_equal ["SELECT * FROM albums WHERE (albums.id = 1) LIMIT 1"]
38 | end
39 |
40 | it 'should support async versions of with_pk!' do
41 | @Album.dataset.async.with_pk!(1).__value.pk.must_equal 1
42 | @db.sqls.must_equal ["SELECT * FROM albums WHERE (albums.id = 1) LIMIT 1"]
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/spec/extensions/single_statement_dataset_destroy_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "single_statement_dataset_destroy plugin" do
4 | before do
5 | @db = Sequel.mock(:fetch=>[{:id=>1}, {:id=>3}])
6 | @a = a = []
7 | @class = Class.new(Sequel::Model(@db[:t])) do
8 | plugin :single_statement_dataset_destroy
9 | define_method(:before_destroy){a << :"b#{pk}"; super()}
10 | define_method(:after_destroy){super(); a << :"a#{pk}"}
11 | end
12 | @db.sqls
13 | end
14 |
15 | it "should delete expected rows, running all before hooks first and all after hooks last" do
16 | @db.numrows = 2
17 | @class.dataset.destroy.must_equal 2
18 | @a.must_equal [:b1, :b3, :a1, :a3]
19 | @db.sqls.must_equal ["BEGIN", "SELECT * FROM t", "DELETE FROM t", "COMMIT"]
20 | end
21 |
22 | it "should use default behavior of multiple queries if a custom around_destroy hook is used" do
23 | @class.send(:define_method, :around_destroy){|&b|b.call}
24 | @db.numrows = 1
25 | @class.dataset.destroy.must_equal 2
26 | @a.must_equal [:b1, :a1, :b3, :a3]
27 | @db.sqls.must_equal [
28 | "SELECT * FROM t",
29 | "DELETE FROM t WHERE (id = 1)",
30 | "DELETE FROM t WHERE (id = 3)",
31 | ]
32 | end
33 |
34 | it "should raise and rollback if the dataset is modified during the destroy" do
35 | @db.numrows = 4
36 | proc{@class.dataset.destroy}.must_raise(Sequel::Error).
37 | message.must_equal "dataset changed during destroy, expected rows: 2, actual rows: 4"
38 | @db.sqls.must_equal ["BEGIN", "SELECT * FROM t", "DELETE FROM t", "ROLLBACK"]
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/lib/sequel/dataset/deprecated_singleton_class_methods.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | module Sequel
4 | class Dataset
5 | # This module implements methods to support deprecated use of extensions registered
6 | # not using a module. In such cases, for backwards compatibility, Sequel has to use
7 | # a singleton class for the dataset.
8 | module DeprecatedSingletonClassMethods
9 | # Load the extension into a clone of the receiver.
10 | def extension(*a)
11 | c = _clone(:freeze=>false)
12 | c.send(:_extension!, a)
13 | c.freeze
14 | end
15 |
16 | # Extend the cloned of the receiver with the given modules, instead of the default
17 | # approach of creating a subclass of the receiver's class and including the modules
18 | # into that.
19 | def with_extend(*mods, &block)
20 | c = _clone(:freeze=>false)
21 | c.extend(*mods) unless mods.empty?
22 | c.extend(Sequel.set_temp_name(DatasetModule.new(&block)){"Sequel::Dataset::_DatasetModule(#{block.source_location.join(':')})"}) if block
23 | c.freeze
24 | end
25 |
26 | private
27 |
28 | # Load the extensions into the receiver.
29 | def _extension!(exts)
30 | Sequel.extension(*exts)
31 | exts.each do |ext|
32 | if pr = Sequel.synchronize{EXTENSIONS[ext]}
33 | pr.call(self)
34 | else
35 | raise(Error, "Extension #{ext} does not have specific support handling individual datasets (try: Sequel.extension #{ext.inspect})")
36 | end
37 | end
38 | self
39 | end
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/doc/release_notes/4.29.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * A uuid plugin has now been added. This plugin will automatically
4 | create a uuid for newly created model objects.
5 |
6 | Model.plugin :uuid
7 | Model.create.uuid => # some UUID
8 |
9 | * Model#json_serializer_opts has been added to the json_serializer
10 | plugin, allowing you to override the JSON serialization options
11 | on a per instance basis without passing the options directly
12 | to Model#to_json. This is useful if you are including the model
13 | instance inside another datastructure that will be serialized
14 | to JSON.
15 |
16 | obj.json_serializer_opts(:root => true)
17 | [obj].to_json
18 | # => '[{"obj":{"id":1,"name":"Foo"}}]'
19 |
20 | = Other Improvements
21 |
22 | * The Database#transaction :retry_on option now works when using
23 | savepoints.
24 |
25 | * Calling Database#table_exists? inside a transaction will now use
26 | a savepoint if the database supports it, so that if the table
27 | doesn't exist, it will not affect the state of the transaction.
28 |
29 | * Blobs can now be used as bound variables in the oracle adapter.
30 |
31 | * The sqlanywhere adapter now works with database sharding.
32 |
33 | * The Dataset#full_text_search :rank option has been fixed to order
34 | by rank descending instead of ascending.
35 |
36 | * External adapters that do not support INSERT with DEFAULT VALUES
37 | can now override Dataset#insert_empty_columns_values to set
38 | the columns and values to use for an empty INSERT.
39 |
40 | * External adapters can now implement Dataset#date_add_sql_append
41 | to integrate with the date_arithmetic extension.
42 |
--------------------------------------------------------------------------------
/doc/release_notes/5.40.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * On SQLite 3.33.0+, the UPDATE FROM syntax is now supported. This
4 | allows you to update one table based on a join to another table.
5 | The SQLite syntax is based on the PostgreSQL syntax, and the
6 | Sequel API is the same for both. You need to pass multiple tables
7 | to Dataset#from. The first table is the table to update, and the
8 | remaining tables are used to construct the UPDATE FROM clause:
9 |
10 | DB[:a, :b].where{{a[:c]=>b[:d]}}.update(:e=>'f')
11 | # UPDATE a SET e = 'f' FROM b WHERE (a.c = b.d)
12 |
13 | Unlike PostgreSQL, SQLite does not support the deletion of joined
14 | datasets. Related to this, the following methods for testing
15 | database support for modifying joined datasets have been added:
16 |
17 | * supports_updating_joins?
18 | * supports_deleting_joins?
19 |
20 | = Other Improvements
21 |
22 | * The pg_interval and date_arithmetic extensions now support
23 | ActiveSupport 6.1.
24 |
25 | * Sequel no longer issues method redefinition warnings in verbose
26 | mode. As Ruby 3 has dropped uninitialized instance variable
27 | warnings, Sequel is now verbose warning free on Ruby 3.
28 |
29 | = Backwards Compatibility
30 |
31 | * Trying to truncate or insert into a joined dataset now correctly
32 | raises an exception even if the joined dataset supports updates.
33 |
34 | * The private Dataset#check_modification_allowed! method is now
35 | deprecated, and users (custom adapters) should now switch to one
36 | of the more specific methods introduced in this version:
37 |
38 | * check_insert_allowed!
39 | * check_update_allowed!
40 | * check_delete_allowed!
41 |
--------------------------------------------------------------------------------
/doc/release_notes/3.22.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * Support COLLATE in column definitions. At least MySQL and Microsoft
4 | SQL Server support them, and PostgreSQL 9.1 should as well.
5 |
6 | * When connecting to Microsoft SQL Server, you can use the
7 | mssql_unicode_strings accessor to turn of the default usage
8 | of unicode strings (N'') and use regular strings (''). This
9 | can improve performance, but changes the behavior. It's
10 | set to true by default for backwards compatibility. You can
11 | change it at both the dataset and database level:
12 |
13 | DB.mssql_unicode_strings = false # default for datasets
14 | dataset.mssql_unicode_strings = false # just this dataset
15 |
16 | * In the oracle adapter, if Sequel.application_timezone is :utc, set
17 | the timezone for the connection to use the 00:00 timezone.
18 |
19 | = Other Improvements
20 |
21 | * In the single_table_inheritance plugin, correctly handle a
22 | multi-level class hierarchy so that loading instances from a
23 | middle level of the hierarchy can return instances of subclasses.
24 |
25 | * Don't use a schema when creating a temporary table, even if
26 | default_schema is set.
27 |
28 | * Fix the migrator when a default_schema is used.
29 |
30 | * In the ado adapter, assume a connection to SQL Server if the
31 | :conn_string is given and doesn't indicate Access/Jet.
32 |
33 | * Fix fetching rows in the tinytds adapter when the
34 | identifier_output_method is nil.
35 |
36 | * The tinytds adapter now checks for disconnect errors, but it might
37 | not be reliable until the next release of tiny_tds.
38 |
39 | * The odbc adapter now handles ODBC::Time instances correctly.
40 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/string_date_time.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # The string_date_time extension provides String instance methods
4 | # for converting the strings to a date (e.g. String#to_date), allowing
5 | # for backwards compatibility with legacy Sequel code.
6 | #
7 | # These methods calls +parse+ on the related class, and as such, can
8 | # result in denial of service in older versions of Ruby for large
9 | # untrusted input, and raise exceptions in newer versions of Ruby.
10 | #
11 | # To load the extension:
12 | #
13 | # Sequel.extension :string_date_time
14 |
15 | class String
16 | # Converts a string into a Date object.
17 | def to_date
18 | Date.parse(self, Sequel.convert_two_digit_years)
19 | rescue => e
20 | raise Sequel.convert_exception_class(e, Sequel::InvalidValue)
21 | end
22 |
23 | # Converts a string into a DateTime object.
24 | def to_datetime
25 | DateTime.parse(self, Sequel.convert_two_digit_years)
26 | rescue => e
27 | raise Sequel.convert_exception_class(e, Sequel::InvalidValue)
28 | end
29 |
30 | # Converts a string into a Time or DateTime object, depending on the
31 | # value of Sequel.datetime_class
32 | def to_sequel_time
33 | if Sequel.datetime_class == DateTime
34 | DateTime.parse(self, Sequel.convert_two_digit_years)
35 | else
36 | Sequel.datetime_class.parse(self)
37 | end
38 | rescue => e
39 | raise Sequel.convert_exception_class(e, Sequel::InvalidValue)
40 | end
41 |
42 | # Converts a string into a Time object.
43 | def to_time
44 | Time.parse(self)
45 | rescue => e
46 | raise Sequel.convert_exception_class(e, Sequel::InvalidValue)
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/s.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # The s extension adds Sequel::S, a module containing a private #S
4 | # method that calls Sequel.expr. It's designed as a shortcut so
5 | # that instead of:
6 | #
7 | # Sequel.expr(:column) + 1
8 | # # or
9 | # Sequel.expr{column + 1}
10 | #
11 | # you can just write:
12 | #
13 | # S(:column) + 1
14 | # # or
15 | # S{column + 1}
16 | #
17 | # To load the extension:
18 | #
19 | # Sequel.extension :s
20 | #
21 | # Then you can include the Sequel::S module into whatever classes or
22 | # objects you care about:
23 | #
24 | # Sequel::Model.send(:include, Sequel::S) # available in model instance methods
25 | # Sequel::Model.extend(Sequel::S) # available in model class methods
26 | # Sequel::Dataset.send(:include, Sequel::S) # available in dataset methods
27 | #
28 | # or just into Object if you want it available everywhere:
29 | #
30 | # Object.send(:include, Sequel::S)
31 | #
32 | # If you are using Ruby 2+, and you would like to use refinements, you
33 | # can use Sequel::S as a refinement, in which case the private #S method
34 | # will be available on all objects while the refinement is active.
35 | #
36 | # using Sequel::S
37 | #
38 | # S(:column) + 1
39 | #
40 | # Related module: Sequel::S
41 |
42 |
43 | #
44 | module Sequel::S
45 | private
46 |
47 | # Delegate to Sequel.expr
48 | def S(*a, &block)
49 | Sequel.expr(*a, &block)
50 | end
51 |
52 | # :nocov:
53 | if RUBY_VERSION >= '2.0.0'
54 | include_meth = RUBY_VERSION >= '3.1' ? :import_methods : :include
55 | # :nocov:
56 | refine Object do
57 | send include_meth, Sequel::S
58 | end
59 | end
60 | end
61 |
--------------------------------------------------------------------------------
/doc/release_notes/5.63.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * On Ruby 3.2, the pool_class: :timed_queue Database option can now
4 | be used to use an alternative connection pool that stores
5 | connections in a queue, and uses the new Queue#pop :timeout option
6 | in Ruby 3.2 to implement the pool timeout. This new connection
7 | pool is simpler than the default connection pool. It is not yet
8 | the default connection pool on Ruby 3.2, but it may become the
9 | default in a later version. Users of Ruby 3.2 are encouraged to
10 | try out the pool_class: :timed_queue Database option and provide
11 | feedback on how it works in their application.
12 |
13 | = Other Improvements
14 |
15 | * The tactical_eager_loading plugin now works in combination with the
16 | single_table_inheritance and class_table_inheritance plugins, when
17 | loading an association only defined in a specific subclass.
18 | Previously, eager loading would be skipped in such a case. Now,
19 | an eager load will be attempted for all instances supporting the
20 | association.
21 |
22 | * The validate_associated plugin now avoids database type errors for
23 | non-integer association keys. In cases where the associated object
24 | doesn't have a value for the associated key, and the current object
25 | does not have a key value that can be set in the associated object,
26 | validation errors in the associated object related to the associated
27 | key will be ignored.
28 |
29 | * Thread-keyed connection pool hashes now use compare_by_identity for
30 | better performance.
31 |
32 | * The JRuby workaround in the named_timezones extension is no longer
33 | used on JRuby 9.3.9.0+, as JRuby fixed the related bug.
34 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/stdio_logger.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # The stdio_logger extension exposes a Sequel::StdioLogger class that
4 | # can be used for logging with Sequel, as a minimal alternative to
5 | # the logger library. It exposes debug/info/warn/error methods for the
6 | # different warning levels. The debug method is a no-op, so that setting
7 | # the Database sql_log_level to debug will result in no output for normal
8 | # queries. The info/warn/error methods log the current time, log level,
9 | # and the given message.
10 | #
11 | # To use this extension:
12 | #
13 | # Sequel.extension :stdio_logger
14 | #
15 | # Then you you can use Sequel::StdioLogger to wrap IO objects that you
16 | # would like Sequel to log to:
17 | #
18 | # DB.loggers << Sequel::StdioLogger.new($stdout)
19 | #
20 | # log_file = File.open("db_queries.log", 'a')
21 | # log_file.sync = true
22 | # DB.loggers << Sequel::StdioLogger.new(log_file)
23 | #
24 | # This is implemented as a global extension instead of a Database extension
25 | # because Database loggers must be set before Database extensions are loaded.
26 | #
27 | # Related module: Sequel::StdioLogger
28 |
29 | #
30 | module Sequel
31 | class StdioLogger
32 | def initialize(device)
33 | @device = device
34 | end
35 |
36 | # Do not log debug messages. This is so setting the Database
37 | # sql_log_level to debug will result in no output.
38 | def debug(msg)
39 | end
40 |
41 | [:info, :warn, :error].each do |meth|
42 | define_method(meth) do |msg|
43 | @device.write("#{Time.now.strftime('%F %T')} #{meth.to_s.upcase}: #{msg}\n")
44 | nil
45 | end
46 | end
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/doc/release_notes/3.20.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * The swift adapter now supports an SQLite subadapter. Use the
4 | :db_type => 'sqlite' option when connecting. You can use an
5 | in memory database with the following connection string:
6 |
7 | swift:///?database=:memory:&db_type=sqlite
8 |
9 | * Arbitrary JDBC properties can now be set in the JDBC adapter
10 | using the :jdbc_properties option when connecting. The value
11 | of this option should be a hash where keys and values are JDBC
12 | property keys and values.
13 |
14 | * Basic Microsoft Access support was added to the ado adapter.
15 | The creation of autoincrementing primary key integers now works,
16 | and identifiers are now quoted with [].
17 |
18 | * The Database#indexes method now supports a :partial option when
19 | connecting to MySQL, which makes it include partial indexes (which
20 | are usually excluded).
21 |
22 | = Other Improvements
23 |
24 | * The class_table_inheritance plugin now handles subclass
25 | associations better. Previously, the implicit eager loading code
26 | had issues when you called an association method that only existed
27 | in the subclass.
28 |
29 | * The error message used when a validates_max_length validation is
30 | applied to a nil column value has been improved. You can override
31 | the message yourself using the :nil_message option.
32 |
33 | * The read_timeout and connect_timeout options now work correctly in
34 | the mysql adapter.
35 |
36 | * Another MySQL disconnect error message is now recognized.
37 |
38 | = Backwards Compatibility
39 |
40 | * The swift adapter was upgraded to support swift 0.8.1. Older
41 | versions of swift are no longer supported.
42 |
--------------------------------------------------------------------------------
/doc/release_notes/5.96.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * On PostgreSQL 9.2+, alter_table now supports a rename_constraint
4 | method, to rename an existing constraint:
5 |
6 | DB.alter_table(:table) do
7 | rename_constraint(:old_name, :new_name)
8 | end
9 |
10 | * Virtual generated columns are now supported on PostgreSQL 18+,
11 | using the :generated_always_as and :virtual options. For backwards
12 | compatibility, the default without the :virtual option still
13 | creates a stored generated column. This is unfortunately different
14 | from the PostgreSQL 18+ default, where VIRTUAL is assumed if neither
15 | VIRTUAL nor STORED is specified.
16 |
17 | * The strip_nulls method in the pg_json_ops extension now supports an
18 | :in_arrays option on PostgreSQL 18+, for stripping nulls in json
19 | arrays.
20 |
21 | * The pg_array_ops extension now supports sort and reverse methods,
22 | for the array_sort and array_reverse database functions added in
23 | PostgreSQL 18.
24 |
25 | = Other Improvements
26 |
27 | * When using the pg_range and/or pg_multirange extensions in
28 | conjunction with the the pg_auto_parameterize extension, PostgreSQL
29 | range and multirange types containing non-value expressions will no
30 | longer be automatically parameterized. Note that in order for Sequel
31 | to generate appropriate SQL for range types with a non-value
32 | expressions, the range must have an explicit type, as PostgreSQL
33 | does not offer a function to create an untyped range.
34 |
35 | * A regression in 5.95.0 where the :deferred option would be ignored
36 | for unique and primary key constraints on PostgreSQL has been
37 | fixed (fix originally included in 5.95.1).
38 |
--------------------------------------------------------------------------------
/lib/sequel/dataset/dataset_module.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | module Sequel
4 | class Dataset
5 | # This Module subclass is used by Database#extend_datasets
6 | # and Dataset#with_extend to add dataset methods to classes.
7 | # It adds some helper methods inside the module that can define
8 | # named methods on the dataset instances which do specific actions.
9 | # For example:
10 | #
11 | # DB.extend_datasets do
12 | # order :by_id, :id
13 | # select :with_id_and_name, :id, :name
14 | # where :active, :active
15 | # end
16 | #
17 | # DB[:table].active.with_id_and_name.by_id
18 | # # SELECT id, name FROM table WHERE active ORDER BY id
19 | class DatasetModule < ::Module
20 | meths = (<<-METHS).split.map(&:to_sym)
21 | where exclude exclude_having having
22 | distinct grep group group_and_count group_append
23 | limit offset order order_append order_prepend reverse
24 | select select_all select_append select_group select_prepend server
25 | METHS
26 |
27 | # Define a method in the module
28 | def self.def_dataset_caching_method(mod, meth)
29 | mod.send(:define_method, meth) do |name, *args, &block|
30 | if block
31 | define_method(name){public_send(meth, *args, &block)}
32 | else
33 | key = :"_#{meth}_#{name}_ds"
34 | define_method(name) do
35 | cached_dataset(key){public_send(meth, *args)}
36 | end
37 | end
38 | end
39 | end
40 |
41 | meths.each do |meth|
42 | def_dataset_caching_method(self, meth)
43 | end
44 | end
45 | end
46 | end
47 |
--------------------------------------------------------------------------------
/lib/sequel/adapters/utils/split_alter_table.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 |
3 | module Sequel::Database::SplitAlterTable
4 | private
5 |
6 | # Preprocess the array of operations. If it looks like some operations depend
7 | # on results of earlier operations and may require reloading the schema to
8 | # work correctly, split those operations into separate lists, and between each
9 | # list, remove the cached schema so that the later operations deal with the
10 | # then current table schema.
11 | def apply_alter_table(name, ops)
12 | modified_columns = []
13 | op_groups = [[]]
14 | ops.each do |op|
15 | case op[:op]
16 | when :add_column, :set_column_type, :set_column_null, :set_column_default
17 | if modified_columns.include?(op[:name])
18 | op_groups << []
19 | else
20 | modified_columns << op[:name]
21 | end
22 | when :rename_column
23 | if modified_columns.include?(op[:name]) || modified_columns.include?(op[:new_name])
24 | op_groups << []
25 | end
26 | modified_columns << op[:name] unless modified_columns.include?(op[:name])
27 | modified_columns << op[:new_name] unless modified_columns.include?(op[:new_name])
28 | end
29 | if split_alter_table_op?(op)
30 | op_groups << []
31 | end
32 | op_groups.last << op
33 | end
34 |
35 | op_groups.each do |opgs|
36 | next if opgs.empty?
37 | alter_table_sql_list(name, opgs).each{|sql| execute_ddl(sql)}
38 | remove_cached_schema(name)
39 | end
40 | end
41 |
42 | # Whether the given alter table op should start a new group.
43 | def split_alter_table_op?(op)
44 | false
45 | end
46 | end
47 |
--------------------------------------------------------------------------------
/doc/release_notes/5.72.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * A pg_auto_parameterize_in_array extension has been added, which
4 | handles conversion of IN/NOT IN to = ANY or != ALL for more types.
5 | The pg_auto_parameterize extension only handles integer types by
6 | default, because other types require the pg_array extension. This
7 | new extension adds handling for Float, BigDecimal, Date, Time,
8 | DateTime, Sequel::SQLTime, and Sequel::SQL::Blob types. It can
9 | also handle String types if the :treat_string_list_as_text_array
10 | Database option is present, using the text type for that. Handling
11 | String values as text is not the default because that may cause
12 | issues for some queries.
13 |
14 | = Other Improvements
15 |
16 | * The defaults_setter plugin now does a deep copy of database
17 | default values that are hash/array or delegates to hash/array.
18 | This fixes cases where the database default values are mutated.
19 |
20 | * Sequel now correctly handles infinite and NaN float values used
21 | inside PostgreSQL array bound variables.
22 |
23 | * The data in the cache files used by the schema_caching and
24 | index_caching extensions and static_cache_cache and
25 | pg_auto_constraint_validations plugins are now sorted before the
26 | cache file is saved, increasing consistency between runs.
27 |
28 | * bigdecimal has been added as a dependency. bigdecimal is currently
29 | a default gem in Ruby from 1.9 to 3.2, but it will move to a
30 | bundled gem in Ruby 3.4, and there will be warnings in Ruby 3.3
31 | for cases that will break in Ruby 3.4. Adding bigdecimal as a
32 | dependency should avoid warnings when using bundler in Ruby 3.3,
33 | and should avoid errors in Ruby 3.4.
34 |
--------------------------------------------------------------------------------
/spec/extensions/split_array_nil_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "split_array_nil extension" do
4 | before do
5 | @ds = Sequel.mock[:table].extension(:split_array_nil)
6 | end
7 |
8 | it "should split IN with nil in array into separate OR IS NULL clause" do
9 | @ds.filter(:a=>[1, nil]).sql.must_equal "SELECT * FROM table WHERE ((a IN (1)) OR (a IS NULL))"
10 | end
11 |
12 | it "should split NOT IN with nil in array into separate AND IS NOT NULL clause" do
13 | @ds.exclude(:a=>[1, nil]).sql.must_equal "SELECT * FROM table WHERE ((a NOT IN (1)) AND (a IS NOT NULL))"
14 | end
15 |
16 | it "should not affect other IN/NOT in clauses with arrays" do
17 | @ds.filter(:a=>[1, 2]).sql.must_equal "SELECT * FROM table WHERE (a IN (1, 2))"
18 | @ds.exclude(:a=>[1, 2]).sql.must_equal "SELECT * FROM table WHERE (a NOT IN (1, 2))"
19 | end
20 |
21 | it "should split IN with nil in set into separate OR IS NULL clause" do
22 | @ds.filter(:a=>Set[1, nil]).sql.must_equal "SELECT * FROM table WHERE ((a IN (1)) OR (a IS NULL))"
23 | end
24 |
25 | it "should split NOT IN with nil in set into separate AND IS NOT NULL clause" do
26 | @ds.exclude(:a=>Set[1, nil]).sql.must_equal "SELECT * FROM table WHERE ((a NOT IN (1)) AND (a IS NOT NULL))"
27 | end
28 |
29 | it "should not affect other IN/NOT in clauses with sets" do
30 | @ds.filter(:a=>Set[1, 2]).sql.must_equal "SELECT * FROM table WHERE (a IN (1, 2))"
31 | @ds.exclude(:a=>Set[1, 2]).sql.must_equal "SELECT * FROM table WHERE (a NOT IN (1, 2))"
32 | end
33 |
34 | it "should not affect other types of filters clauses" do
35 | @ds.filter(:a=>1).sql.must_equal "SELECT * FROM table WHERE (a = 1)"
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/doc/release_notes/4.17.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * A :preconnect Database option has been added, for automatically
4 | creating the maximum number of connections to the database on
5 | instantiation. This is useful when there is high latency for
6 | initial connection setup, where Sequel's usual approach of
7 | connecting as needed can cause pauses at runtime.
8 |
9 | * Database#sharded? has been added for checking whether the Database
10 | object uses multiple servers.
11 |
12 | * Dataset#server? has been added, for returning a cloned dataset
13 | associated with the given server/shard if the dataset does not
14 | already have a server set. This returns the receiver if the
15 | server has already been set or the Database is not sharded.
16 |
17 | = Other Improvements
18 |
19 | * Sequel now uses the correct shard when deleting model instances.
20 | Previously, the correct shard was only used in the unoptimized
21 | case, not in the optimized case.
22 |
23 | * Sequel now uses the correct shard when using Dataset#insert_select
24 | on PostgreSQL. This was first broken in the 4.13.0 release.
25 |
26 | * Sequel now correctly handles Sequel::SQL::Blob instances used in
27 | bound variables in the postgres adapter. Previously this resulted
28 | in duplicate apostrophes being used.
29 |
30 | * When using the jdbc/sqlite3 adapter with jdbc-sqlite3 3.8.7, Sequel
31 | now handles date objects and empty blobs correctly, working around
32 | bugs in the driver.
33 |
34 | = Backwards Compatibility
35 |
36 | * In the update_or_create plugin, Model.update_or_create now always
37 | returns the object. Previously it would not return the object if
38 | the object already existed but no updates were necessary.
39 |
--------------------------------------------------------------------------------
/spec/extensions/boolean_subsets_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "boolean_subsets plugin" do
4 | before do
5 | @db = Sequel.mock
6 | def @db.supports_schema_parsing?() true end
7 | def @db.schema(*args)
8 | [[:asdaf9898as, {}], [:active, {:type=>:boolean}]]
9 | end
10 |
11 | @c = Class.new(Sequel::Model(@db[:items]))
12 | @p = proc do
13 | @columns = [:asdaf9898as, :active]
14 | def columns; @columns; end
15 | singleton_class.send(:alias_method, :columns, :columns)
16 | end
17 | @c.instance_eval(&@p)
18 | end
19 |
20 | it "should create subsets only for boolean attributes" do
21 | @c.plugin(:boolean_subsets)
22 | @c.active.sql.must_equal "SELECT * FROM items WHERE (active IS TRUE)"
23 | @c.respond_to?(:asdaf9898as).must_equal false
24 | end
25 |
26 | it "should handle a block passed to the plugin" do
27 | @c.plugin(:boolean_subsets){|c| ["where_#{c}", c]}
28 | @c.where_active.sql.must_equal "SELECT * FROM items WHERE active"
29 | @c.respond_to?(:active).must_equal false
30 | end
31 |
32 | it "should create boolean subsets when set_dataset is called" do
33 | c = Class.new(Sequel::Model(@db))
34 | c.instance_eval(&@p)
35 | c.plugin(:boolean_subsets)
36 | c.respond_to?(:active).must_equal false
37 |
38 | c.set_dataset(@db[:items])
39 | c.active.sql.must_equal "SELECT * FROM items WHERE (active IS TRUE)"
40 | c.respond_to?(:asdaf9898as).must_equal false
41 | end
42 |
43 | it "should handle cases where getting the columns raises an error" do
44 | def @c.columns; raise Sequel::Error end
45 | @c.plugin(:boolean_subsets)
46 | @c.respond_to?(:active).must_equal false
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/doc/release_notes/5.34.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * The association_pks plugin now creates *_pks_dataset methods for
4 | each association. These are similar to the existing *_pks getter
5 | methods, but they return a dataset of the keys instead of the keys
6 | themselves.
7 |
8 | * The association_pks plugin now supports a :cache_pks association
9 | option, which will cache calls to the *_pks getter method. The
10 | default behavior remains that the *_pks getter method only returns
11 | cached values if the *_pks= setter method has been used to set the
12 | values.
13 |
14 | * The *_pks getter methods supported by the association_pks plugin
15 | now support a :refresh option to ignore any cached values, similar
16 | to how the association getter methods work.
17 |
18 | = Other Improvements
19 |
20 | * If trying to disconnect a server that doesn't exist when using a
21 | sharded connection pool, a Sequel::Error is now raised. Previously,
22 | the sharded threaded pool raised a NoMethodError and the sharded
23 | single connection pool did not raise an error.
24 |
25 | * If using the :savepoint option when savepoints are not supported,
26 | a Sequel::InvalidOperation exception is now raised, instead of a
27 | NoMethodError.
28 |
29 | * Calling Dataset#eager_graph with no arguments now returns the
30 | dataset.
31 |
32 | * If not connected to the database, the single connection pool will
33 | not yield any connections to Database#pool.all_connections.
34 |
35 | * Forcing a :ruby eager limit strategy for an association without a
36 | limit or offset now works correctly.
37 |
38 | * Multiple unnecessary conditionals have been removed.
39 |
40 | * Sequel core and model code now have 100% branch coverage.
41 |
--------------------------------------------------------------------------------
/lib/sequel/extensions/round_timestamps.rb:
--------------------------------------------------------------------------------
1 | # frozen-string-literal: true
2 | #
3 | # The round_timestamps extension will automatically round timestamp
4 | # values to the database's supported level of precision before literalizing
5 | # them.
6 | #
7 | # For example, if the database supports millisecond precision, and you give
8 | # it a Time value with microsecond precision, it will round it appropriately:
9 | #
10 | # Time.at(1405341161.917999982833862)
11 | # # default: 2014-07-14 14:32:41.917999
12 | # # with extension: 2014-07-14 14:32:41.918000
13 | #
14 | # The round_timestamps extension correctly deals with databases that support
15 | # millisecond or second precision. In addition to handling Time values, it
16 | # also handles DateTime values and Sequel::SQLTime values (for the TIME type).
17 | #
18 | # To round timestamps for a single dataset:
19 | #
20 | # ds = ds.extension(:round_timestamps)
21 | #
22 | # To round timestamps for all datasets on a single database:
23 | #
24 | # DB.extension(:round_timestamps)
25 | #
26 | # Related module: Sequel::Dataset::RoundTimestamps
27 |
28 | module Sequel
29 | class Dataset
30 | module RoundTimestamps
31 | # Round DateTime values before literalizing
32 | def literal_datetime(v)
33 | super(v + Rational(5, 10**timestamp_precision)/864000)
34 | end
35 |
36 | # Round Sequel::SQLTime values before literalizing
37 | def literal_sqltime(v)
38 | super(v.round(sqltime_precision))
39 | end
40 |
41 | # Round Time values before literalizing
42 | def literal_time(v)
43 | super(v.round(timestamp_precision))
44 | end
45 | end
46 |
47 | register_extension(:round_timestamps, RoundTimestamps)
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/doc/release_notes/5.70.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * A sharded_timed_queue connection pool has been added. This offers
4 | most of the same features as the sharded_threaded connection pool,
5 | but uses the new Queue#pop :timeout features added in Ruby 3.2 to
6 | allow for a simpler and possibly faster and more robust
7 | implementation.
8 |
9 | * If a :pool_class option is not specified when creating a Database,
10 | Sequel will now look at the SEQUEL_DEFAULT_CONNECTION_POOL
11 | environment variable to determine the connection pool class to use.
12 | This allows you to set SEQUEL_DEFAULT_CONNECTION_POOL=timed_queue
13 | on Ruby 3.2 to test with the timed_queue connection pool without
14 | making any code changes. If the :servers Database option is given,
15 | Sequel will automatically use the sharded version of the connection
16 | pool specified by SEQUEL_DEFAULT_CONNECTION_POOL.
17 |
18 | = Other Improvements
19 |
20 | * The connection_validator, connection_expiration, and
21 | async_thread_pool extensions now work with the timed_queue and
22 | sharded_timed_queue connection pools.
23 |
24 | * The sharded_threaded connection pool now disconnects connections
25 | for all specified servers instead of just the last specified server
26 | when using remove_server.
27 |
28 | * The static_cache plugin now recognizes when the forbid_lazy_load
29 | plugin is already loaded, and does not return instances that
30 | forbid lazy load for methods that return a single object, such as
31 | Database.{[],cache_get_pk,first}.
32 |
33 | * Sequel now displays an informative error message if attempting to
34 | load the connection_validator or connection_expiration extensions
35 | when using the single threaded connection pool.
36 |
--------------------------------------------------------------------------------
/doc/thread_safety.rdoc:
--------------------------------------------------------------------------------
1 | = Thread Safety
2 |
3 | Most Sequel usage (and all common Sequel usage) is thread safe by default. Specifically, multiple threads can operate on Database instances, Dataset instances, and Model classes concurrently without problems. In general, Database instance and Model classes are not modified after application startup, and Dataset instances are always frozen.
4 |
5 | == Connection Pool
6 |
7 | In order to allow multiple threads to operate on the same database at the same time, Sequel uses a connection pool. The connection pool is designed so that a thread uses a connection for the minimum amount of time, returning the connection to the pool as soon as it is done using the connection. If a thread requests a connection and the pool does not have an available connection, a new connection will be created. If the maximum number of connections in the pool has already been reached, the thread will block until a connection is available or the connection pool timeout has elapsed (in which case a Sequel::PoolTimeout error will be raised).
8 |
9 | == Exceptions
10 |
11 | This is a small list of things that are specifically non thread-safe. This is not an exhaustive list, there may be cases not mentioned here.
12 |
13 | 1) Model instances: Model instances are not thread-safe unless they are frozen first. Multiple threads should not operate on an unfrozen model instance concurrently.
14 |
15 | 2) Model class modifications: Model class modifications, such as adding associations and loading plugins, are not designed to be thread safe. You should not modify a class in one thread if any other thread can concurrently access it. Model subclassing is designed to be thread-safe, so you create a model subclass in a thread and modify it safely.
16 |
--------------------------------------------------------------------------------
/doc/release_notes/5.75.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * Database#{defer,immediate}_constraints methods have been added on
4 | PostgreSQL for changing handling of deferrable constraints inside
5 | a transaction. defer_constraints sets deferrable constraints to
6 | be deferred (not checked until transaction commit), and
7 | immediate_constraints sets deferrable constraints to be checked
8 | as part of the related query, and any already deferred constraint
9 | checks to be applied immediately. You can pass the :constraints
10 | option to only apply the changes to specific constraints.
11 |
12 | * TimestampMigrator.run_single has been added, to migrate a single
13 | migration up or down.
14 |
15 | = Other Improvements
16 |
17 | * INSERT RETURNING is now supported on MariaDB 10.5+, and used
18 | automatically when saving new model objects. Note that this
19 | is not supported when using the jdbc adapter, because the
20 | jdbc-mysql driver doesn't support it. A jdbc/mariadb adapter
21 | could be added, as it's likely recent versions of the
22 | jdbc-mariadb driver would support it, but the jdbc-mariadb gem
23 | hasn't been updated in over 4 years. Talk to the jdbc-mariadb
24 | gem maintainers if you want to use this feature with the jdbc
25 | adapter.
26 |
27 | * The Dataset#paged_each optimization in the postgres adapter
28 | now respects the :skip_transaction option, making it the
29 | same as the :hold option. Note that this has effects beyond
30 | just skipping the transaction, but non-HOLD cursors are only
31 | supported inside transactions.
32 |
33 | * The any_not_empty? extension's Dataset#any? method now supports
34 | an argument, passing it to Enumerable#any? (which has supported
35 | an argument since Ruby 2.5).
36 |
--------------------------------------------------------------------------------
/doc/release_notes/5.80.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * A provenance dataset extension has been added. This extension makes
4 | SQL queries include a comment describing how the dataset was built.
5 | This can make debugging complex cases significantly easier. Here's
6 | a simple example:
7 |
8 | DB.extension :provenance
9 |
10 | DB[:table].
11 | select(:a).
12 | where{b > 10}.
13 | order(:c).
14 | limit(10)
15 | # SQL:
16 | # SELECT a FROM table WHERE (b > 10) ORDER BY c LIMIT 10 --
17 | # -- Dataset Provenance
18 | # -- Keys:[:from] Source:(eval at bin/sequel:257):2:in `'
19 | # -- Keys:[:select] Source:(eval at bin/sequel:257):3:in `'
20 | # -- Keys:[:where] Source:(eval at bin/sequel:257):4:in `'
21 | # -- Keys:[:order] Source:(eval at bin/sequel:257):5:in `'
22 | # -- Keys:[:limit] Source:(eval at bin/sequel:257):6:in `'
23 |
24 | With the above example, it's obvious how the dataset is created, but
25 | but in real applications, where datasets can be built from multiple
26 | files, seeing where each dataset clone was made can be helpful.
27 |
28 | The source listed will skip locations in the Ruby standard library
29 | as well as Sequel itself. Other locations can be skipped by
30 | providing a Database :provenance_caller_ignore Regexp option:
31 |
32 | DB.opts[:provenance_caller_ignore] = /\/gems\/library_name-/
33 |
34 | = Other Improvements
35 |
36 | * For dataset methods where Sequel can determine that the return
37 | value would be equivalent to the receiver, Sequel now returns the
38 | receiver. This reduces the number of dataset allocations.
39 |
40 | * Sequel now supports Dataset#skip_locked on MariaDB 10.6+.
41 |
--------------------------------------------------------------------------------
/spec/extensions/inverted_subsets_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative "spec_helper"
2 |
3 | describe "Sequel::Plugins::InvertedSubsets" do
4 | it "should name generated dataset module class" do
5 | c = Sequel::Model(:items)
6 | c.plugin :inverted_subsets
7 | c.dataset_module_class.name.must_equal "Sequel::_Model(:items)::@dataset_module_class(InvertedSubsets)"
8 | end if RUBY_VERSION >= '3.3'
9 |
10 | it "should add an inverted subset method which inverts the condition" do
11 | c = Class.new(Sequel::Model(:a))
12 | c.plugin :inverted_subsets
13 | c.dataset_module{subset(:published, :published => true)}
14 | c.not_published.sql.must_equal 'SELECT * FROM a WHERE (published IS NOT TRUE)'
15 | end
16 |
17 | it "should support a configuration block to customise the inverted method name" do
18 | c = Class.new(Sequel::Model(:a))
19 | c.plugin(:inverted_subsets){|name| "exclude_#{name}"}
20 | c.dataset_module{where(:published, :published => true)}
21 | c.exclude_published.sql.must_equal 'SELECT * FROM a WHERE (published IS NOT TRUE)'
22 | end
23 |
24 | it "should chain to existing dataset" do
25 | c = Class.new(Sequel::Model(:a))
26 | c.plugin :inverted_subsets
27 | c.dataset_module{where(:published, :published => true)}
28 | c.where(1=>0).not_published.sql.must_equal 'SELECT * FROM a WHERE ((1 = 0) AND (published IS NOT TRUE))'
29 | end
30 |
31 | it "should work in subclasses" do
32 | c = Class.new(Sequel::Model)
33 | c.plugin(:inverted_subsets){|name| "exclude_#{name}"}
34 | c = Class.new(c)
35 | c.dataset = :a
36 | c.dataset_module{subset(:published, :published => true)}
37 | c.exclude_published.sql.must_equal 'SELECT * FROM a WHERE (published IS NOT TRUE)'
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/doc/release_notes/5.22.0.txt:
--------------------------------------------------------------------------------
1 | = New Features
2 |
3 | * Sequel now supports Ruby 2.7+ startless ranges in filters:
4 |
5 | DB[:table].where(:column=>(..10))
6 | # SELECT * FROM table WHERE (column <= 10)
7 |
8 | DB[:table].where(:column=>(...10))
9 | # SELECT * FROM table WHERE (column < 10)
10 |
11 | It also supports startless, endless ranges in filters, using a
12 | condition that is always true:
13 |
14 | DB[:table].where(:column=>(nil..nil))
15 | # SELECT * FROM table WHERE (1 = 1)
16 |
17 | * Sequel now supports startless ranges in the pg_range extension:
18 |
19 | DB.extension :pg_range
20 |
21 | DB[:table].insert(:column=>(..10))
22 | # INSERT INTO "table" ("column") VALUES ('[,10]') RETURNING "id"
23 |
24 | DB[:table].insert(:column=>(...10))
25 | # INSERT INTO "table" ("column") VALUES ('[,10)') RETURNING "id"
26 |
27 | DB[:table].insert(:column=>(nil..nil))
28 | # INSERT INTO "table" ("column") VALUES ('[,]') RETURNING "id"
29 |
30 | * Sequel now supports a :materialized option in Dataset#with on
31 | PostgreSQL 12+, to control the inlining of common table expressions:
32 |
33 | DB[:t].with(:t, DB[:t2], :materialized=>false)
34 | # WITH "t" AS NOT MATERIALIZED (SELECT * FROM "t2")
35 | # SELECT * FROM "t"
36 |
37 | DB[:t].with(:t, DB[:t2], :materialized=>true)
38 | # WITH "t" AS MATERIALIZED (SELECT * FROM "t2")
39 | # SELECT * FROM "t"
40 |
41 | = Other Improvements
42 |
43 | * Database#primary_key_sequence now works for tables without serial
44 | sequences on PostgreSQL 12+.
45 |
46 | * Dataset#multi_insert and #import with return: :primary_key option
47 | on Microsoft SQL Server now work correctly if the dataset uses
48 | a row_proc (e.g. for model datasets).
49 |
--------------------------------------------------------------------------------