sequel 3.21.0 → 3.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +1131 -3
- data/MIT-LICENSE +1 -1
- data/README.rdoc +106 -65
- data/Rakefile +59 -27
- data/bin/sequel +50 -26
- data/doc/active_record.rdoc +68 -52
- data/doc/advanced_associations.rdoc +201 -75
- data/doc/association_basics.rdoc +327 -79
- data/doc/bin_sequel.rdoc +144 -0
- data/doc/cheat_sheet.rdoc +21 -21
- data/doc/core_extensions.rdoc +374 -0
- data/doc/dataset_basics.rdoc +10 -10
- data/doc/dataset_filtering.rdoc +54 -42
- data/doc/mass_assignment.rdoc +56 -0
- data/doc/migration.rdoc +89 -557
- data/doc/model_hooks.rdoc +80 -29
- data/doc/object_model.rdoc +576 -0
- data/doc/opening_databases.rdoc +121 -53
- data/doc/prepared_statements.rdoc +41 -15
- data/doc/querying.rdoc +137 -56
- data/doc/reflection.rdoc +36 -10
- data/doc/release_notes/3.22.0.txt +39 -0
- data/doc/release_notes/3.23.0.txt +172 -0
- data/doc/release_notes/3.24.0.txt +420 -0
- data/doc/release_notes/3.25.0.txt +88 -0
- data/doc/release_notes/3.26.0.txt +88 -0
- data/doc/release_notes/3.27.0.txt +82 -0
- data/doc/release_notes/3.28.0.txt +304 -0
- data/doc/release_notes/3.29.0.txt +459 -0
- data/doc/release_notes/3.30.0.txt +135 -0
- data/doc/release_notes/3.31.0.txt +146 -0
- data/doc/release_notes/3.32.0.txt +202 -0
- data/doc/release_notes/3.33.0.txt +157 -0
- data/doc/release_notes/3.34.0.txt +671 -0
- data/doc/release_notes/3.35.0.txt +144 -0
- data/doc/release_notes/3.36.0.txt +245 -0
- data/doc/release_notes/3.37.0.txt +338 -0
- data/doc/release_notes/3.38.0.txt +234 -0
- data/doc/release_notes/3.39.0.txt +237 -0
- data/doc/release_notes/3.40.0.txt +73 -0
- data/doc/release_notes/3.41.0.txt +155 -0
- data/doc/schema_modification.rdoc +585 -0
- data/doc/sharding.rdoc +99 -8
- data/doc/sql.rdoc +154 -112
- data/doc/testing.rdoc +169 -0
- data/doc/thread_safety.rdoc +17 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/validations.rdoc +1 -1
- data/doc/virtual_rows.rdoc +78 -43
- data/lib/sequel/adapters/ado/access.rb +334 -0
- data/lib/sequel/adapters/ado/mssql.rb +18 -12
- data/lib/sequel/adapters/ado.rb +69 -21
- data/lib/sequel/adapters/amalgalite.rb +17 -14
- data/lib/sequel/adapters/cubrid.rb +143 -0
- data/lib/sequel/adapters/db2.rb +178 -85
- data/lib/sequel/adapters/dbi.rb +19 -21
- data/lib/sequel/adapters/do/mysql.rb +17 -11
- data/lib/sequel/adapters/do/postgres.rb +2 -61
- data/lib/sequel/adapters/do/sqlite.rb +0 -10
- data/lib/sequel/adapters/do.rb +20 -39
- data/lib/sequel/adapters/firebird.rb +33 -210
- data/lib/sequel/adapters/ibmdb.rb +452 -0
- data/lib/sequel/adapters/informix.rb +6 -29
- data/lib/sequel/adapters/jdbc/as400.rb +16 -34
- data/lib/sequel/adapters/jdbc/cubrid.rb +52 -0
- data/lib/sequel/adapters/jdbc/db2.rb +78 -0
- data/lib/sequel/adapters/jdbc/derby.rb +325 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
- data/lib/sequel/adapters/jdbc/h2.rb +68 -31
- data/lib/sequel/adapters/jdbc/hsqldb.rb +189 -0
- data/lib/sequel/adapters/jdbc/informix.rb +21 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +40 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
- data/lib/sequel/adapters/jdbc/mysql.rb +16 -28
- data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +77 -52
- data/lib/sequel/adapters/jdbc/progress.rb +21 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
- data/lib/sequel/adapters/jdbc/sqlserver.rb +72 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +308 -114
- data/lib/sequel/adapters/mock.rb +372 -0
- data/lib/sequel/adapters/mysql.rb +130 -230
- data/lib/sequel/adapters/mysql2.rb +64 -63
- data/lib/sequel/adapters/odbc/mssql.rb +17 -9
- data/lib/sequel/adapters/odbc.rb +29 -10
- data/lib/sequel/adapters/openbase.rb +7 -11
- data/lib/sequel/adapters/oracle.rb +364 -57
- data/lib/sequel/adapters/postgres.rb +379 -145
- data/lib/sequel/adapters/shared/access.rb +236 -11
- data/lib/sequel/adapters/shared/cubrid.rb +216 -0
- data/lib/sequel/adapters/shared/db2.rb +353 -0
- data/lib/sequel/adapters/shared/firebird.rb +231 -0
- data/lib/sequel/adapters/shared/informix.rb +53 -0
- data/lib/sequel/adapters/shared/mssql.rb +412 -116
- data/lib/sequel/adapters/shared/mysql.rb +396 -89
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +166 -0
- data/lib/sequel/adapters/shared/oracle.rb +262 -45
- data/lib/sequel/adapters/shared/postgres.rb +688 -279
- data/lib/sequel/adapters/shared/progress.rb +5 -8
- data/lib/sequel/adapters/shared/sqlite.rb +317 -96
- data/lib/sequel/adapters/sqlite.rb +109 -46
- data/lib/sequel/adapters/swift/mysql.rb +10 -12
- data/lib/sequel/adapters/swift/postgres.rb +13 -79
- data/lib/sequel/adapters/swift/sqlite.rb +9 -6
- data/lib/sequel/adapters/swift.rb +31 -27
- data/lib/sequel/adapters/tinytds.rb +177 -25
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +77 -0
- data/lib/sequel/adapters/utils/pg_types.rb +81 -0
- data/lib/sequel/adapters/utils/split_alter_table.rb +36 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
- data/lib/sequel/ast_transformer.rb +194 -0
- data/lib/sequel/connection_pool/sharded_single.rb +23 -13
- data/lib/sequel/connection_pool/sharded_threaded.rb +64 -13
- data/lib/sequel/connection_pool/single.rb +11 -3
- data/lib/sequel/connection_pool/threaded.rb +69 -20
- data/lib/sequel/connection_pool.rb +20 -18
- data/lib/sequel/core.rb +143 -11
- data/lib/sequel/database/connecting.rb +66 -29
- data/lib/sequel/database/dataset.rb +4 -4
- data/lib/sequel/database/dataset_defaults.rb +63 -2
- data/lib/sequel/database/logging.rb +7 -2
- data/lib/sequel/database/misc.rb +192 -51
- data/lib/sequel/database/query.rb +299 -114
- data/lib/sequel/database/schema_generator.rb +103 -36
- data/lib/sequel/database/schema_methods.rb +310 -69
- data/lib/sequel/dataset/actions.rb +344 -90
- data/lib/sequel/dataset/features.rb +101 -8
- data/lib/sequel/dataset/graph.rb +42 -15
- data/lib/sequel/dataset/misc.rb +52 -25
- data/lib/sequel/dataset/mutation.rb +12 -7
- data/lib/sequel/dataset/prepared_statements.rb +68 -30
- data/lib/sequel/dataset/query.rb +322 -68
- data/lib/sequel/dataset/sql.rb +716 -293
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/_pretty_table.rb +83 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +109 -0
- data/lib/sequel/extensions/blank.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +72 -0
- data/lib/sequel/extensions/connection_validator.rb +109 -0
- data/lib/sequel/extensions/constraint_validations.rb +451 -0
- data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +30 -46
- data/lib/sequel/extensions/eval_inspect.rb +173 -0
- data/lib/sequel/extensions/inflector.rb +4 -0
- data/lib/sequel/extensions/looser_typecasting.rb +5 -4
- data/lib/sequel/extensions/migration.rb +100 -11
- data/lib/sequel/extensions/named_timezones.rb +9 -0
- data/lib/sequel/extensions/null_dataset.rb +94 -0
- data/lib/sequel/extensions/pagination.rb +4 -0
- data/lib/sequel/extensions/pg_array.rb +539 -0
- data/lib/sequel/extensions/pg_array_ops.rb +263 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +175 -0
- data/lib/sequel/extensions/pg_hstore.rb +334 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +293 -0
- data/lib/sequel/extensions/pg_inet.rb +113 -0
- data/lib/sequel/extensions/pg_interval.rb +191 -0
- data/lib/sequel/extensions/pg_json.rb +212 -0
- data/lib/sequel/extensions/pg_range.rb +513 -0
- data/lib/sequel/extensions/pg_range_ops.rb +150 -0
- data/lib/sequel/extensions/pg_row.rb +576 -0
- data/lib/sequel/extensions/pg_row_ops.rb +182 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +317 -0
- data/lib/sequel/extensions/pretty_table.rb +17 -72
- data/lib/sequel/extensions/query.rb +8 -4
- data/lib/sequel/extensions/query_literals.rb +79 -0
- data/lib/sequel/extensions/schema_caching.rb +76 -0
- data/lib/sequel/extensions/schema_dumper.rb +282 -76
- data/lib/sequel/extensions/select_remove.rb +39 -0
- data/lib/sequel/extensions/server_block.rb +140 -0
- data/lib/sequel/extensions/split_array_nil.rb +65 -0
- data/lib/sequel/extensions/sql_expr.rb +8 -110
- data/lib/sequel/extensions/string_date_time.rb +4 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +10 -4
- data/lib/sequel/extensions/to_dot.rb +99 -83
- data/lib/sequel/model/associations.rb +1263 -409
- data/lib/sequel/model/base.rb +624 -171
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +24 -2
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/model.rb +30 -11
- data/lib/sequel/no_core_ext.rb +2 -0
- data/lib/sequel/plugins/active_model.rb +13 -1
- data/lib/sequel/plugins/association_pks.rb +137 -16
- data/lib/sequel/plugins/caching.rb +25 -18
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/composition.rb +44 -12
- data/lib/sequel/plugins/constraint_validations.rb +198 -0
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +72 -0
- data/lib/sequel/plugins/dirty.rb +214 -0
- data/lib/sequel/plugins/eager_each.rb +59 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/plugins/identity_map.rb +134 -15
- data/lib/sequel/plugins/instance_filters.rb +10 -0
- data/lib/sequel/plugins/instance_hooks.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +77 -6
- data/lib/sequel/plugins/list.rb +13 -2
- data/lib/sequel/plugins/many_through_many.rb +103 -51
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
- data/lib/sequel/plugins/nested_attributes.rb +150 -66
- data/lib/sequel/plugins/optimistic_locking.rb +8 -0
- data/lib/sequel/plugins/pg_row.rb +121 -0
- data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
- data/lib/sequel/plugins/prepared_statements.rb +168 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
- data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
- data/lib/sequel/plugins/rcte_tree.rb +31 -17
- data/lib/sequel/plugins/schema.rb +8 -3
- data/lib/sequel/plugins/serialization.rb +98 -49
- data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
- data/lib/sequel/plugins/sharding.rb +21 -54
- data/lib/sequel/plugins/single_table_inheritance.rb +57 -12
- data/lib/sequel/plugins/static_cache.rb +99 -0
- data/lib/sequel/plugins/subclasses.rb +29 -3
- data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
- data/lib/sequel/plugins/timestamps.rb +1 -1
- data/lib/sequel/plugins/touch.rb +18 -6
- data/lib/sequel/plugins/tree.rb +3 -3
- data/lib/sequel/plugins/typecast_on_load.rb +9 -12
- data/lib/sequel/plugins/update_primary_key.rb +2 -2
- data/lib/sequel/plugins/validation_class_methods.rb +2 -1
- data/lib/sequel/plugins/validation_helpers.rb +57 -4
- data/lib/sequel/plugins/xml_serializer.rb +15 -4
- data/lib/sequel/sql.rb +721 -141
- data/lib/sequel/timezones.rb +67 -40
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +146 -0
- data/spec/adapters/firebird_spec.rb +53 -39
- data/spec/adapters/mssql_spec.rb +261 -66
- data/spec/adapters/mysql_spec.rb +597 -352
- data/spec/adapters/oracle_spec.rb +92 -117
- data/spec/adapters/postgres_spec.rb +2103 -341
- data/spec/adapters/spec_helper.rb +16 -6
- data/spec/adapters/sqlite_spec.rb +237 -76
- data/spec/core/connection_pool_spec.rb +270 -141
- data/spec/core/database_spec.rb +980 -524
- data/spec/core/dataset_spec.rb +1658 -1243
- data/spec/core/expression_filters_spec.rb +741 -334
- data/spec/core/mock_adapter_spec.rb +453 -0
- data/spec/core/object_graph_spec.rb +88 -129
- data/spec/core/schema_generator_spec.rb +4 -4
- data/spec/core/schema_spec.rb +556 -53
- data/spec/core/spec_helper.rb +7 -48
- data/spec/core_extensions_spec.rb +626 -0
- data/spec/extensions/active_model_spec.rb +13 -0
- data/spec/extensions/arbitrary_servers_spec.rb +110 -0
- data/spec/extensions/association_autoreloading_spec.rb +18 -10
- data/spec/extensions/association_dependencies_spec.rb +15 -25
- data/spec/extensions/association_pks_spec.rb +227 -33
- data/spec/extensions/association_proxies_spec.rb +4 -4
- data/spec/extensions/boolean_readers_spec.rb +25 -25
- data/spec/extensions/caching_spec.rb +47 -51
- data/spec/extensions/class_table_inheritance_spec.rb +31 -83
- data/spec/extensions/columns_introspection_spec.rb +91 -0
- data/spec/extensions/composition_spec.rb +18 -13
- data/spec/extensions/connection_validator_spec.rb +118 -0
- data/spec/extensions/constraint_validations_plugin_spec.rb +196 -0
- data/spec/extensions/constraint_validations_spec.rb +316 -0
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +88 -0
- data/spec/extensions/dirty_spec.rb +155 -0
- data/spec/extensions/eager_each_spec.rb +34 -0
- data/spec/extensions/eval_inspect_spec.rb +67 -0
- data/spec/extensions/force_encoding_spec.rb +4 -2
- data/spec/extensions/hook_class_methods_spec.rb +97 -128
- data/spec/extensions/identity_map_spec.rb +142 -24
- data/spec/extensions/inflector_spec.rb +0 -4
- data/spec/extensions/instance_filters_spec.rb +11 -21
- data/spec/extensions/instance_hooks_spec.rb +72 -0
- data/spec/extensions/json_serializer_spec.rb +49 -12
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +49 -40
- data/spec/extensions/looser_typecasting_spec.rb +7 -7
- data/spec/extensions/many_through_many_spec.rb +368 -254
- data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
- data/spec/extensions/migration_spec.rb +140 -35
- data/spec/extensions/named_timezones_spec.rb +29 -11
- data/spec/extensions/nested_attributes_spec.rb +268 -89
- data/spec/extensions/null_dataset_spec.rb +85 -0
- data/spec/extensions/optimistic_locking_spec.rb +24 -21
- data/spec/extensions/pg_array_ops_spec.rb +112 -0
- data/spec/extensions/pg_array_spec.rb +324 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
- data/spec/extensions/pg_hstore_ops_spec.rb +140 -0
- data/spec/extensions/pg_hstore_spec.rb +200 -0
- data/spec/extensions/pg_inet_spec.rb +47 -0
- data/spec/extensions/pg_interval_spec.rb +72 -0
- data/spec/extensions/pg_json_spec.rb +99 -0
- data/spec/extensions/pg_range_ops_spec.rb +56 -0
- data/spec/extensions/pg_range_spec.rb +395 -0
- data/spec/extensions/pg_row_ops_spec.rb +58 -0
- data/spec/extensions/pg_row_plugin_spec.rb +49 -0
- data/spec/extensions/pg_row_spec.rb +340 -0
- data/spec/extensions/pg_statement_cache_spec.rb +208 -0
- data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
- data/spec/extensions/prepared_statements_spec.rb +87 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
- data/spec/extensions/pretty_table_spec.rb +7 -6
- data/spec/extensions/query_literals_spec.rb +167 -0
- data/spec/extensions/query_spec.rb +9 -3
- data/spec/extensions/rcte_tree_spec.rb +50 -43
- data/spec/extensions/schema_caching_spec.rb +41 -0
- data/spec/extensions/schema_dumper_spec.rb +434 -49
- data/spec/extensions/schema_spec.rb +30 -49
- data/spec/extensions/select_remove_spec.rb +38 -0
- data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
- data/spec/extensions/serialization_spec.rb +86 -48
- data/spec/extensions/server_block_spec.rb +90 -0
- data/spec/extensions/sharding_spec.rb +69 -143
- data/spec/extensions/single_table_inheritance_spec.rb +65 -29
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +34 -67
- data/spec/extensions/split_array_nil_spec.rb +24 -0
- data/spec/extensions/sql_expr_spec.rb +29 -60
- data/spec/extensions/static_cache_spec.rb +145 -0
- data/spec/extensions/subclasses_spec.rb +14 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/timestamps_spec.rb +6 -6
- data/spec/extensions/to_dot_spec.rb +8 -11
- data/spec/extensions/touch_spec.rb +53 -14
- data/spec/extensions/tree_spec.rb +11 -26
- data/spec/extensions/typecast_on_load_spec.rb +9 -6
- data/spec/extensions/update_primary_key_spec.rb +30 -24
- data/spec/extensions/validation_class_methods_spec.rb +77 -68
- data/spec/extensions/validation_helpers_spec.rb +48 -37
- data/spec/extensions/xml_serializer_spec.rb +29 -4
- data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
- data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
- data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
- data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
- data/spec/integration/associations_test.rb +659 -21
- data/spec/integration/database_test.rb +25 -5
- data/spec/integration/dataset_test.rb +729 -141
- data/spec/integration/eager_loader_test.rb +38 -54
- data/spec/integration/migrator_test.rb +2 -3
- data/spec/integration/model_test.rb +81 -2
- data/spec/integration/plugin_test.rb +871 -160
- data/spec/integration/prepared_statement_test.rb +272 -128
- data/spec/integration/schema_test.rb +377 -57
- data/spec/integration/spec_helper.rb +49 -32
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +183 -8
- data/spec/integration/type_test.rb +40 -8
- data/spec/model/association_reflection_spec.rb +207 -8
- data/spec/model/associations_spec.rb +1206 -693
- data/spec/model/base_spec.rb +334 -100
- data/spec/model/dataset_methods_spec.rb +45 -27
- data/spec/model/eager_loading_spec.rb +828 -692
- data/spec/model/hooks_spec.rb +355 -67
- data/spec/model/model_spec.rb +251 -179
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +506 -232
- data/spec/model/spec_helper.rb +16 -77
- data/spec/model/validations_spec.rb +38 -2
- data/spec/rcov.opts +2 -0
- metadata +223 -81
- data/spec/core/core_sql_spec.rb +0 -451
data/lib/sequel/sql.rb
CHANGED
|
@@ -38,6 +38,16 @@ module Sequel
|
|
|
38
38
|
class LiteralString < ::String
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
+
# Time subclass that gets literalized with only the time value, so it operates
|
|
42
|
+
# like a standard SQL time type.
|
|
43
|
+
class SQLTime < ::Time
|
|
44
|
+
# Create a new SQLTime instance given an hour, minute, and second.
|
|
45
|
+
def self.create(hour, minute, second, usec = 0)
|
|
46
|
+
t = now
|
|
47
|
+
local(t.year, t.month, t.day, hour, minute, second, usec)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
41
51
|
# The SQL module holds classes whose instances represent SQL fragments.
|
|
42
52
|
# It also holds modules that are included in core ruby classes that
|
|
43
53
|
# make Sequel a friendly DSL.
|
|
@@ -50,28 +60,38 @@ module Sequel
|
|
|
50
60
|
|
|
51
61
|
# Base class for all SQL expression objects.
|
|
52
62
|
class Expression
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
@comparison_attrs = []
|
|
64
|
+
|
|
65
|
+
class << self
|
|
66
|
+
# All attributes used for equality and hash methods.
|
|
67
|
+
attr_reader :comparison_attrs
|
|
68
|
+
|
|
69
|
+
# Expression objects are assumed to be value objects, where their
|
|
70
|
+
# attribute values can't change after assignment. In order to make
|
|
71
|
+
# it easy to define equality and hash methods, subclass
|
|
72
|
+
# instances assume that the only values that affect the results of
|
|
73
|
+
# such methods are the values of the object's attributes.
|
|
74
|
+
def attr_reader(*args)
|
|
75
|
+
super
|
|
76
|
+
comparison_attrs.concat(args)
|
|
77
|
+
end
|
|
62
78
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
79
|
+
# Copy the comparison_attrs into the subclass.
|
|
80
|
+
def inherited(subclass)
|
|
81
|
+
super
|
|
82
|
+
subclass.instance_variable_set(:@comparison_attrs, comparison_attrs.dup)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private
|
|
67
86
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
87
|
+
# Create a to_s instance method that takes a dataset, and calls
|
|
88
|
+
# the method provided on the dataset with args as the argument (self by default).
|
|
89
|
+
# Used to DRY up some code.
|
|
90
|
+
def to_s_method(meth, args=:self) # :nodoc:
|
|
91
|
+
class_eval("def to_s(ds) ds.#{meth}(#{args}) end", __FILE__, __LINE__)
|
|
92
|
+
class_eval("def to_s_append(ds, sql) ds.#{meth}_append(sql, #{args}) end", __FILE__, __LINE__)
|
|
93
|
+
end
|
|
73
94
|
end
|
|
74
|
-
private_class_method :to_s_method
|
|
75
95
|
|
|
76
96
|
# Alias of <tt>eql?</tt>
|
|
77
97
|
def ==(other)
|
|
@@ -127,7 +147,10 @@ module Sequel
|
|
|
127
147
|
MATHEMATICAL_OPERATORS = [:+, :-, :/, :*]
|
|
128
148
|
|
|
129
149
|
# Bitwise mathematical operators used in +NumericMethods+
|
|
130
|
-
BITWISE_OPERATORS = [:&, :|, :^, :<<,
|
|
150
|
+
BITWISE_OPERATORS = [:&, :|, :^, :<<, :>>, :%]
|
|
151
|
+
|
|
152
|
+
# Operators that check for equality
|
|
153
|
+
EQUALITY_OPERATORS = [:'=', :'!=']
|
|
131
154
|
|
|
132
155
|
# Inequality operators used in +InequalityMethods+
|
|
133
156
|
INEQUALITY_OPERATORS = [:<, :>, :<=, :>=]
|
|
@@ -141,23 +164,30 @@ module Sequel
|
|
|
141
164
|
# Operators that use IS, used for special casing to override literal true/false values
|
|
142
165
|
IS_OPERATORS = [:IS, :'IS NOT']
|
|
143
166
|
|
|
167
|
+
# Operators that do pattern matching via regular expressions
|
|
168
|
+
REGEXP_OPERATORS = [:~, :'!~', :'~*', :'!~*']
|
|
169
|
+
|
|
170
|
+
# Operators that do pattern matching via LIKE
|
|
171
|
+
LIKE_OPERATORS = [:LIKE, :'NOT LIKE', :ILIKE, :'NOT ILIKE']
|
|
172
|
+
|
|
144
173
|
# Operator symbols that take exactly two arguments
|
|
145
|
-
TWO_ARITY_OPERATORS =
|
|
146
|
-
:~, :'!~', :'~*', :'!~*', :ILIKE, :'NOT ILIKE'] + \
|
|
147
|
-
INEQUALITY_OPERATORS + BITWISE_OPERATORS + IS_OPERATORS + IN_OPERATORS
|
|
174
|
+
TWO_ARITY_OPERATORS = EQUALITY_OPERATORS + INEQUALITY_OPERATORS + IS_OPERATORS + IN_OPERATORS + REGEXP_OPERATORS + LIKE_OPERATORS
|
|
148
175
|
|
|
149
176
|
# Operator symbols that take one or more arguments
|
|
150
|
-
N_ARITY_OPERATORS = [:AND, :OR, :'||'] + MATHEMATICAL_OPERATORS
|
|
177
|
+
N_ARITY_OPERATORS = [:AND, :OR, :'||'] + MATHEMATICAL_OPERATORS + BITWISE_OPERATORS
|
|
151
178
|
|
|
152
179
|
# Operator symbols that take only a single argument
|
|
153
180
|
ONE_ARITY_OPERATORS = [:NOT, :NOOP, :'B~']
|
|
154
181
|
|
|
155
|
-
#
|
|
156
|
-
|
|
182
|
+
# Custom expressions that may have different syntax on different databases
|
|
183
|
+
CUSTOM_EXPRESSIONS = [:extract]
|
|
157
184
|
|
|
158
185
|
# The operator symbol for this object
|
|
159
186
|
attr_reader :op
|
|
160
187
|
|
|
188
|
+
# An array of args for this object
|
|
189
|
+
attr_reader :args
|
|
190
|
+
|
|
161
191
|
# Set the operator symbol and arguments for this object to the ones given.
|
|
162
192
|
# Convert all args that are hashes or arrays of two element arrays to +BooleanExpressions+,
|
|
163
193
|
# other than the second arg for an IN/NOT IN operator.
|
|
@@ -180,6 +210,8 @@ module Sequel
|
|
|
180
210
|
args[1] = orig_args[1] if IN_OPERATORS.include?(op)
|
|
181
211
|
when *ONE_ARITY_OPERATORS
|
|
182
212
|
raise(Error, "The #{op} operator requires a single argument") unless args.length == 1
|
|
213
|
+
when *CUSTOM_EXPRESSIONS
|
|
214
|
+
# nothing
|
|
183
215
|
else
|
|
184
216
|
raise(Error, "Invalid operator #{op}")
|
|
185
217
|
end
|
|
@@ -201,7 +233,7 @@ module Sequel
|
|
|
201
233
|
module AliasMethods
|
|
202
234
|
# Create an SQL alias (+AliasedExpression+) of the receiving column or expression to the given alias.
|
|
203
235
|
#
|
|
204
|
-
# :
|
|
236
|
+
# Sequel.function(:func).as(:alias) # func() AS "alias"
|
|
205
237
|
def as(aliaz)
|
|
206
238
|
AliasedExpression.new(self, aliaz)
|
|
207
239
|
end
|
|
@@ -219,14 +251,7 @@ module Sequel
|
|
|
219
251
|
# ~:a.sql_number # ~"a"
|
|
220
252
|
module BitwiseMethods
|
|
221
253
|
ComplexExpression::BITWISE_OPERATORS.each do |o|
|
|
222
|
-
|
|
223
|
-
case ce
|
|
224
|
-
when BooleanExpression, StringExpression
|
|
225
|
-
raise(Sequel::Error, "cannot apply #{o} to a non-numeric expression")
|
|
226
|
-
else
|
|
227
|
-
NumericExpression.new(o, self, ce)
|
|
228
|
-
end
|
|
229
|
-
end
|
|
254
|
+
module_eval("def #{o}(o) NumericExpression.new(#{o.inspect}, self, o) end", __FILE__, __LINE__)
|
|
230
255
|
end
|
|
231
256
|
|
|
232
257
|
# Do the bitwise compliment of the self
|
|
@@ -244,16 +269,24 @@ module Sequel
|
|
|
244
269
|
# :a & :b # "a" AND "b"
|
|
245
270
|
# :a | :b # "a" OR "b"
|
|
246
271
|
# ~:a # NOT "a"
|
|
272
|
+
#
|
|
273
|
+
# One exception to this is when a NumericExpression or Integer is the argument
|
|
274
|
+
# to & or |, in which case a bitwise method will be used:
|
|
275
|
+
#
|
|
276
|
+
# :a & 1 # "a" & 1
|
|
277
|
+
# :a | (:b + 1) # "a" | ("b" + 1)
|
|
247
278
|
module BooleanMethods
|
|
248
279
|
ComplexExpression::BOOLEAN_OPERATOR_METHODS.each do |m, o|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
280
|
+
module_eval(<<-END, __FILE__, __LINE__+1)
|
|
281
|
+
def #{m}(o)
|
|
282
|
+
case o
|
|
283
|
+
when NumericExpression, Integer
|
|
284
|
+
NumericExpression.new(#{m.inspect}, self, o)
|
|
285
|
+
else
|
|
286
|
+
BooleanExpression.new(#{o.inspect}, self, o)
|
|
287
|
+
end
|
|
255
288
|
end
|
|
256
|
-
|
|
289
|
+
END
|
|
257
290
|
end
|
|
258
291
|
|
|
259
292
|
# Create a new BooleanExpression with NOT, representing the inversion of whatever self represents.
|
|
@@ -264,13 +297,353 @@ module Sequel
|
|
|
264
297
|
end
|
|
265
298
|
end
|
|
266
299
|
|
|
300
|
+
# These methods are designed as replacements for the core extensions, so that
|
|
301
|
+
# Sequel is still easy to use if the core extensions are not enabled.
|
|
302
|
+
module Builders
|
|
303
|
+
# Create an SQL::AliasedExpression for the given expression and alias.
|
|
304
|
+
#
|
|
305
|
+
# Sequel.as(:column, :alias) # "column" AS "alias"
|
|
306
|
+
def as(exp, aliaz)
|
|
307
|
+
SQL::AliasedExpression.new(exp, aliaz)
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# Order the given argument ascending.
|
|
311
|
+
# Options:
|
|
312
|
+
#
|
|
313
|
+
# :nulls :: Set to :first to use NULLS FIRST (so NULL values are ordered
|
|
314
|
+
# before other values), or :last to use NULLS LAST (so NULL values
|
|
315
|
+
# are ordered after other values).
|
|
316
|
+
#
|
|
317
|
+
# Sequel.asc(:a) # a ASC
|
|
318
|
+
# Sequel.asc(:b, :nulls=>:last) # b ASC NULLS LAST
|
|
319
|
+
def asc(arg, opts={})
|
|
320
|
+
SQL::OrderedExpression.new(arg, false, opts)
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
# Return an <tt>SQL::Blob</tt> that holds the same data as this string.
|
|
324
|
+
# Blobs provide proper escaping of binary data. If given a blob, returns it
|
|
325
|
+
# directly.
|
|
326
|
+
def blob(s)
|
|
327
|
+
if s.is_a?(SQL::Blob)
|
|
328
|
+
s
|
|
329
|
+
else
|
|
330
|
+
SQL::Blob.new(s)
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
# Return an <tt>SQL::CaseExpression</tt> created with the given arguments.
|
|
335
|
+
#
|
|
336
|
+
# Sequel.case([[{:a=>[2,3]}, 1]], 0) # SQL: CASE WHEN a IN (2, 3) THEN 1 ELSE 0 END
|
|
337
|
+
# Sequel.case({:a=>1}, 0, :b) # SQL: CASE b WHEN a THEN 1 ELSE 0 END
|
|
338
|
+
def case(*args) # core_sql ignore
|
|
339
|
+
SQL::CaseExpression.new(*args)
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
# Cast the reciever to the given SQL type. You can specify a ruby class as a type,
|
|
343
|
+
# and it is handled similarly to using a database independent type in the schema methods.
|
|
344
|
+
#
|
|
345
|
+
# Sequel.cast(:a, :integer) # CAST(a AS integer)
|
|
346
|
+
# Sequel.cast(:a, String) # CAST(a AS varchar(255))
|
|
347
|
+
def cast(arg, sql_type)
|
|
348
|
+
SQL::Cast.new(arg, sql_type)
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
# Cast the reciever to the given SQL type (or the database's default Integer type if none given),
|
|
352
|
+
# and return the result as a +NumericExpression+, so you can use the bitwise operators
|
|
353
|
+
# on the result.
|
|
354
|
+
#
|
|
355
|
+
# Sequel.cast_numeric(:a) # CAST(a AS integer)
|
|
356
|
+
# Sequel.cast_numeric(:a, Float) # CAST(a AS double precision)
|
|
357
|
+
def cast_numeric(arg, sql_type = nil)
|
|
358
|
+
cast(arg, sql_type || Integer).sql_number
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
# Cast the reciever to the given SQL type (or the database's default String type if none given),
|
|
362
|
+
# and return the result as a +StringExpression+, so you can use +
|
|
363
|
+
# directly on the result for SQL string concatenation.
|
|
364
|
+
#
|
|
365
|
+
# Sequel.cast_string(:a) # CAST(a AS varchar(255))
|
|
366
|
+
# Sequel.cast_string(:a, :text) # CAST(a AS text)
|
|
367
|
+
def cast_string(arg, sql_type = nil)
|
|
368
|
+
cast(arg, sql_type || String).sql_string
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
# Return an emulated function call for getting the number of characters
|
|
372
|
+
# in the argument:
|
|
373
|
+
#
|
|
374
|
+
# Sequel.char_length(:a) # char_length(a) -- Most databases
|
|
375
|
+
# Sequel.char_length(:a) # length(a) -- SQLite
|
|
376
|
+
def char_length(arg)
|
|
377
|
+
SQL::EmulatedFunction.new(:char_length, arg)
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
# Return a delayed evaluation that uses the passed block. This is used
|
|
381
|
+
# to delay evaluations of the code to runtime. For example, with
|
|
382
|
+
# the following code:
|
|
383
|
+
#
|
|
384
|
+
# ds = DB[:table].where{column > Time.now}
|
|
385
|
+
#
|
|
386
|
+
# The filter is fixed to the time that where was called. Unless you are
|
|
387
|
+
# only using the dataset once immediately after creating it, that's
|
|
388
|
+
# probably not desired. If you just want to set it to the time when the
|
|
389
|
+
# query is sent to the database, you can wrap it in Sequel.delay:
|
|
390
|
+
#
|
|
391
|
+
# ds = DB[:table].where{column > Sequel.delay{Time.now}}
|
|
392
|
+
#
|
|
393
|
+
# Note that for dates and timestamps, you are probably better off using
|
|
394
|
+
# Sequel::CURRENT_DATE and Sequel::CURRENT_TIMESTAMP instead of this
|
|
395
|
+
# generic delayed evaluation facility.
|
|
396
|
+
def delay(&block)
|
|
397
|
+
raise(Error, "Sequel.delay requires a block") unless block
|
|
398
|
+
SQL::DelayedEvaluation.new(block)
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
# Order the given argument descending.
|
|
402
|
+
# Options:
|
|
403
|
+
#
|
|
404
|
+
# :nulls :: Set to :first to use NULLS FIRST (so NULL values are ordered
|
|
405
|
+
# before other values), or :last to use NULLS LAST (so NULL values
|
|
406
|
+
# are ordered after other values).
|
|
407
|
+
#
|
|
408
|
+
# Sequel.desc(:a) # b DESC
|
|
409
|
+
# Sequel.desc(:b, :nulls=>:first) # b DESC NULLS FIRST
|
|
410
|
+
def desc(arg, opts={})
|
|
411
|
+
SQL::OrderedExpression.new(arg, true, opts)
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
# Wraps the given object in an appropriate Sequel wrapper.
|
|
415
|
+
# If the given object is already a Sequel object, return it directly.
|
|
416
|
+
# For condition specifiers (hashes and arrays of two pairs), true, and false,
|
|
417
|
+
# return a boolean expressions. For numeric objects, return a numeric
|
|
418
|
+
# expression. For strings, return a string expression. For procs or when
|
|
419
|
+
# the method is passed a block, evaluate it as a virtual row and wrap it
|
|
420
|
+
# appropriately. In all other cases, use a generic wrapper.
|
|
421
|
+
#
|
|
422
|
+
# This method allows you to construct SQL expressions that are difficult
|
|
423
|
+
# to construct via other methods. For example:
|
|
424
|
+
#
|
|
425
|
+
# Sequel.expr(1) - :a # SQL: (1 - a)
|
|
426
|
+
def expr(arg=(no_arg=true), &block)
|
|
427
|
+
if block_given?
|
|
428
|
+
if no_arg
|
|
429
|
+
return expr(block)
|
|
430
|
+
else
|
|
431
|
+
raise Error, 'cannot provide both an argument and a block to Sequel.expr'
|
|
432
|
+
end
|
|
433
|
+
elsif no_arg
|
|
434
|
+
raise Error, 'must provide either an argument or a block to Sequel.expr'
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
case arg
|
|
438
|
+
when Symbol
|
|
439
|
+
t, c, a = Sequel.split_symbol(arg)
|
|
440
|
+
|
|
441
|
+
arg = if t
|
|
442
|
+
SQL::QualifiedIdentifier.new(t, c)
|
|
443
|
+
else
|
|
444
|
+
SQL::Identifier.new(c)
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
if a
|
|
448
|
+
arg = SQL::AliasedExpression.new(arg, a)
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
arg
|
|
452
|
+
when SQL::Expression, LiteralString, SQL::Blob
|
|
453
|
+
arg
|
|
454
|
+
when Hash
|
|
455
|
+
SQL::BooleanExpression.from_value_pairs(arg, :AND)
|
|
456
|
+
when Array
|
|
457
|
+
if condition_specifier?(arg)
|
|
458
|
+
SQL::BooleanExpression.from_value_pairs(arg, :AND)
|
|
459
|
+
else
|
|
460
|
+
SQL::Wrapper.new(arg)
|
|
461
|
+
end
|
|
462
|
+
when Numeric
|
|
463
|
+
SQL::NumericExpression.new(:NOOP, arg)
|
|
464
|
+
when String
|
|
465
|
+
SQL::StringExpression.new(:NOOP, arg)
|
|
466
|
+
when TrueClass, FalseClass
|
|
467
|
+
SQL::BooleanExpression.new(:NOOP, arg)
|
|
468
|
+
when Proc
|
|
469
|
+
expr(virtual_row(&arg))
|
|
470
|
+
else
|
|
471
|
+
SQL::Wrapper.new(arg)
|
|
472
|
+
end
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
# Extract a datetime_part (e.g. year, month) from the given
|
|
476
|
+
# expression:
|
|
477
|
+
#
|
|
478
|
+
# Sequel.extract(:year, :date) # extract(year FROM "date")
|
|
479
|
+
def extract(datetime_part, exp)
|
|
480
|
+
SQL::NumericExpression.new(:extract, datetime_part, exp)
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
# Returns a <tt>Sequel::SQL::Function</tt> with the function name
|
|
484
|
+
# and the given arguments.
|
|
485
|
+
#
|
|
486
|
+
# Sequel.function(:now) # SQL: now()
|
|
487
|
+
# Sequel.function(:substr, :a, 1) # SQL: substr(a, 1)
|
|
488
|
+
def function(name, *args)
|
|
489
|
+
SQL::Function.new(name, *args)
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
# Return the argument wrapped as an <tt>SQL::Identifier</tt>.
|
|
493
|
+
#
|
|
494
|
+
# Sequel.identifier(:a__b) # "a__b"
|
|
495
|
+
def identifier(name)
|
|
496
|
+
SQL::Identifier.new(name)
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
# Return a <tt>Sequel::SQL::StringExpression</tt> representing an SQL string made up of the
|
|
500
|
+
# concatenation of the given array's elements. If an argument is passed,
|
|
501
|
+
# it is used in between each element of the array in the SQL
|
|
502
|
+
# concatenation.
|
|
503
|
+
#
|
|
504
|
+
# Sequel.join([:a]) # SQL: a
|
|
505
|
+
# Sequel.join([:a, :b]) # SQL: a || b
|
|
506
|
+
# Sequel.join([:a, 'b']) # SQL: a || 'b'
|
|
507
|
+
# Sequel.join(['a', :b], ' ') # SQL: 'a' || ' ' || b
|
|
508
|
+
def join(args, joiner=nil)
|
|
509
|
+
raise Error, 'argument to Sequel.join must be an array' unless args.is_a?(Array)
|
|
510
|
+
if joiner
|
|
511
|
+
args = args.zip([joiner]*args.length).flatten
|
|
512
|
+
args.pop
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
return SQL::StringExpression.new(:NOOP, '') if args.empty?
|
|
516
|
+
|
|
517
|
+
args = args.map do |a|
|
|
518
|
+
case a
|
|
519
|
+
when Symbol, ::Sequel::SQL::Expression, ::Sequel::LiteralString, TrueClass, FalseClass, NilClass
|
|
520
|
+
a
|
|
521
|
+
else
|
|
522
|
+
a.to_s
|
|
523
|
+
end
|
|
524
|
+
end
|
|
525
|
+
SQL::StringExpression.new(:'||', *args)
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
# Create a <tt>BooleanExpression</tt> case insensitive (if the database supports it) pattern match of the receiver with
|
|
529
|
+
# the given patterns. See <tt>SQL::StringExpression.like</tt>.
|
|
530
|
+
#
|
|
531
|
+
# Sequel.ilike(:a, 'A%') # "a" ILIKE 'A%'
|
|
532
|
+
def ilike(*args)
|
|
533
|
+
SQL::StringExpression.like(*(args << {:case_insensitive=>true}))
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
# Create a <tt>SQL::BooleanExpression</tt> case sensitive (if the database supports it) pattern match of the receiver with
|
|
537
|
+
# the given patterns. See <tt>SQL::StringExpression.like</tt>.
|
|
538
|
+
#
|
|
539
|
+
# Sequel.like(:a, 'A%') # "a" LIKE 'A%'
|
|
540
|
+
def like(*args)
|
|
541
|
+
SQL::StringExpression.like(*args)
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
# Converts a string into a <tt>Sequel::LiteralString</tt>, in order to override string
|
|
545
|
+
# literalization, e.g.:
|
|
546
|
+
#
|
|
547
|
+
# DB[:items].filter(:abc => 'def').sql #=>
|
|
548
|
+
# "SELECT * FROM items WHERE (abc = 'def')"
|
|
549
|
+
#
|
|
550
|
+
# DB[:items].filter(:abc => Sequel.lit('def')).sql #=>
|
|
551
|
+
# "SELECT * FROM items WHERE (abc = def)"
|
|
552
|
+
#
|
|
553
|
+
# You can also provide arguments, to create a <tt>Sequel::SQL::PlaceholderLiteralString</tt>:
|
|
554
|
+
#
|
|
555
|
+
# DB[:items].select{|o| o.count(Sequel.lit('DISTINCT ?', :a))}.sql #=>
|
|
556
|
+
# "SELECT count(DISTINCT a) FROM items"
|
|
557
|
+
def lit(s, *args) # core_sql ignore
|
|
558
|
+
if args.empty?
|
|
559
|
+
if s.is_a?(LiteralString)
|
|
560
|
+
s
|
|
561
|
+
else
|
|
562
|
+
LiteralString.new(s)
|
|
563
|
+
end
|
|
564
|
+
else
|
|
565
|
+
SQL::PlaceholderLiteralString.new(s, args)
|
|
566
|
+
end
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
# Return a <tt>Sequel::SQL::BooleanExpression</tt> created from the condition
|
|
570
|
+
# specifier, matching none of the conditions.
|
|
571
|
+
#
|
|
572
|
+
# Sequel.negate(:a=>true) # SQL: a IS NOT TRUE
|
|
573
|
+
# Sequel.negate([[:a, true]]) # SQL: a IS NOT TRUE
|
|
574
|
+
# Sequel.negate([[:a, 1], [:b, 2]]) # SQL: ((a != 1) AND (b != 2))
|
|
575
|
+
def negate(arg)
|
|
576
|
+
if condition_specifier?(arg)
|
|
577
|
+
SQL::BooleanExpression.from_value_pairs(arg, :AND, true)
|
|
578
|
+
else
|
|
579
|
+
raise Error, 'must pass a conditions specifier to Sequel.negate'
|
|
580
|
+
end
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
# Return a <tt>Sequel::SQL::BooleanExpression</tt> created from the condition
|
|
584
|
+
# specifier, matching any of the conditions.
|
|
585
|
+
#
|
|
586
|
+
# Sequel.or(:a=>true) # SQL: a IS TRUE
|
|
587
|
+
# Sequel.or([[:a, true]]) # SQL: a IS TRUE
|
|
588
|
+
# Sequel.or([[:a, 1], [:b, 2]]) # SQL: ((a = 1) OR (b = 2))
|
|
589
|
+
def or(arg)
|
|
590
|
+
if condition_specifier?(arg)
|
|
591
|
+
SQL::BooleanExpression.from_value_pairs(arg, :OR, false)
|
|
592
|
+
else
|
|
593
|
+
raise Error, 'must pass a conditions specifier to Sequel.or'
|
|
594
|
+
end
|
|
595
|
+
end
|
|
596
|
+
|
|
597
|
+
# Create a qualified identifier with the given qualifier and identifier
|
|
598
|
+
#
|
|
599
|
+
# Sequel.qualify(:table, :column) # "table"."column"
|
|
600
|
+
# Sequel.qualify(:schema, :table) # "schema"."table"
|
|
601
|
+
# Sequel.qualify(:table, :column).qualify(:schema) # "schema"."table"."column"
|
|
602
|
+
def qualify(qualifier, identifier)
|
|
603
|
+
SQL::QualifiedIdentifier.new(qualifier, identifier)
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
# Return an <tt>SQL::Subscript</tt> with the given arguments, representing an
|
|
607
|
+
# SQL array access.
|
|
608
|
+
#
|
|
609
|
+
# Sequel.subscript(:array, 1) # array[1]
|
|
610
|
+
# Sequel.subscript(:array, 1, 2) # array[1, 2]
|
|
611
|
+
# Sequel.subscript(:array, [1, 2]) # array[1, 2]
|
|
612
|
+
def subscript(exp, *subs)
|
|
613
|
+
SQL::Subscript.new(exp, subs.flatten)
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
# Return an emulated function call for trimming a string of spaces from
|
|
617
|
+
# both sides (similar to ruby's String#strip).
|
|
618
|
+
#
|
|
619
|
+
# Sequel.trim(:a) # trim(a) -- Most databases
|
|
620
|
+
# Sequel.trim(:a) # ltrim(rtrim(a)) -- Microsoft SQL Server
|
|
621
|
+
def trim(arg)
|
|
622
|
+
SQL::EmulatedFunction.new(:trim, arg)
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
# Return a <tt>SQL::ValueList</tt> created from the given array. Used if the array contains
|
|
626
|
+
# all two element arrays and you want it treated as an SQL value list (IN predicate)
|
|
627
|
+
# instead of as a conditions specifier (similar to a hash). This is not necessary if you are using
|
|
628
|
+
# this array as a value in a filter, but may be necessary if you are using it as a
|
|
629
|
+
# value with placeholder SQL:
|
|
630
|
+
#
|
|
631
|
+
# DB[:a].filter([:a, :b]=>[[1, 2], [3, 4]]) # SQL: (a, b) IN ((1, 2), (3, 4))
|
|
632
|
+
# DB[:a].filter('(a, b) IN ?', [[1, 2], [3, 4]]) # SQL: (a, b) IN ((1 = 2) AND (3 = 4))
|
|
633
|
+
# DB[:a].filter('(a, b) IN ?', Sequel.value_list([[1, 2], [3, 4]])) # SQL: (a, b) IN ((1, 2), (3, 4))
|
|
634
|
+
def value_list(arg)
|
|
635
|
+
raise Error, 'argument to Sequel.value_list must be an array' unless arg.is_a?(Array)
|
|
636
|
+
SQL::ValueList.new(arg)
|
|
637
|
+
end
|
|
638
|
+
end
|
|
639
|
+
|
|
267
640
|
# Holds methods that are used to cast objects to different SQL types.
|
|
268
641
|
module CastMethods
|
|
269
642
|
# Cast the reciever to the given SQL type. You can specify a ruby class as a type,
|
|
270
643
|
# and it is handled similarly to using a database independent type in the schema methods.
|
|
271
644
|
#
|
|
272
|
-
# :
|
|
273
|
-
# :
|
|
645
|
+
# Sequel.function(:func).cast(:integer) # CAST(func() AS integer)
|
|
646
|
+
# Sequel.function(:func).cast(String) # CAST(func() AS varchar(255))
|
|
274
647
|
def cast(sql_type)
|
|
275
648
|
Cast.new(self, sql_type)
|
|
276
649
|
end
|
|
@@ -279,8 +652,8 @@ module Sequel
|
|
|
279
652
|
# and return the result as a +NumericExpression+, so you can use the bitwise operators
|
|
280
653
|
# on the result.
|
|
281
654
|
#
|
|
282
|
-
# :
|
|
283
|
-
# :
|
|
655
|
+
# Sequel.function(:func).cast_numeric # CAST(func() AS integer)
|
|
656
|
+
# Sequel.function(:func).cast_numeric(Float) # CAST(func() AS double precision)
|
|
284
657
|
def cast_numeric(sql_type = nil)
|
|
285
658
|
cast(sql_type || Integer).sql_number
|
|
286
659
|
end
|
|
@@ -289,13 +662,13 @@ module Sequel
|
|
|
289
662
|
# and return the result as a +StringExpression+, so you can use +
|
|
290
663
|
# directly on the result for SQL string concatenation.
|
|
291
664
|
#
|
|
292
|
-
# :
|
|
293
|
-
# :
|
|
665
|
+
# Sequel.function(:func).cast_string # CAST(func() AS varchar(255))
|
|
666
|
+
# Sequel.function(:func).cast_string(:text) # CAST(func() AS text)
|
|
294
667
|
def cast_string(sql_type = nil)
|
|
295
668
|
cast(sql_type || String).sql_string
|
|
296
669
|
end
|
|
297
670
|
end
|
|
298
|
-
|
|
671
|
+
|
|
299
672
|
# Adds methods that allow you to treat an object as an instance of a specific
|
|
300
673
|
# +ComplexExpression+ subclass. This is useful if another library
|
|
301
674
|
# overrides the methods defined by Sequel.
|
|
@@ -310,18 +683,14 @@ module Sequel
|
|
|
310
683
|
#
|
|
311
684
|
# :price.sql_number/10 > 100
|
|
312
685
|
module ComplexExpressionMethods
|
|
313
|
-
# Extract a
|
|
686
|
+
# Extract a datetime part (e.g. year, month) from self:
|
|
314
687
|
#
|
|
315
688
|
# :date.extract(:year) # extract(year FROM "date")
|
|
316
689
|
#
|
|
317
690
|
# Also has the benefit of returning the result as a
|
|
318
691
|
# NumericExpression instead of a generic ComplexExpression.
|
|
319
|
-
#
|
|
320
|
-
# The extract function is in the SQL standard, but it doesn't
|
|
321
|
-
# doesn't use the standard function calling convention, and it
|
|
322
|
-
# doesn't work on all databases.
|
|
323
692
|
def extract(datetime_part)
|
|
324
|
-
|
|
693
|
+
NumericExpression.new(:extract, datetime_part, self)
|
|
325
694
|
end
|
|
326
695
|
|
|
327
696
|
# Return a BooleanExpression representation of +self+.
|
|
@@ -346,55 +715,21 @@ module Sequel
|
|
|
346
715
|
end
|
|
347
716
|
end
|
|
348
717
|
|
|
349
|
-
# Includes an +identifier+ method that returns <tt>Identifier</tt>s.
|
|
350
|
-
module IdentifierMethods
|
|
351
|
-
# Return self wrapped as an <tt>SQL::Identifier</tt>.
|
|
352
|
-
#
|
|
353
|
-
# :a__b # "a"."b"
|
|
354
|
-
# :a__b.identifier # "a__b"
|
|
355
|
-
def identifier
|
|
356
|
-
Identifier.new(self)
|
|
357
|
-
end
|
|
358
|
-
end
|
|
359
|
-
|
|
360
718
|
# This module includes the inequality methods (>, <, >=, <=) that are defined on objects that can be
|
|
361
|
-
# used in a numeric or string context in SQL
|
|
362
|
-
# <tt>SQL::GenericExpression</tt>).
|
|
719
|
+
# used in a numeric or string context in SQL.
|
|
363
720
|
#
|
|
364
|
-
# 'a'
|
|
365
|
-
# 'a'
|
|
366
|
-
# 'a'
|
|
367
|
-
# 'a'
|
|
721
|
+
# Sequel.lit('a') > :b # a > "b"
|
|
722
|
+
# Sequel.lit('a') < :b # a > "b"
|
|
723
|
+
# Sequel.lit('a') >= :b # a >= "b"
|
|
724
|
+
# Sequel.lit('a') <= :b # a <= "b"
|
|
368
725
|
module InequalityMethods
|
|
369
726
|
ComplexExpression::INEQUALITY_OPERATORS.each do |o|
|
|
370
|
-
|
|
371
|
-
case ce
|
|
372
|
-
when BooleanExpression, TrueClass, FalseClass, NilClass, Hash, ::Array
|
|
373
|
-
raise(Error, "cannot apply #{o} to a boolean expression")
|
|
374
|
-
else
|
|
375
|
-
BooleanExpression.new(o, self, ce)
|
|
376
|
-
end
|
|
377
|
-
end
|
|
727
|
+
module_eval("def #{o}(o) BooleanExpression.new(#{o.inspect}, self, o) end", __FILE__, __LINE__)
|
|
378
728
|
end
|
|
379
729
|
end
|
|
380
730
|
|
|
381
|
-
#
|
|
382
|
-
# +ComplexExpression+ subclass it is included in, so that
|
|
383
|
-
# attempting to use boolean input when initializing a +NumericExpression+
|
|
384
|
-
# or +StringExpression+ results in an error. It is not expected to be
|
|
385
|
-
# used directly.
|
|
731
|
+
# Only exists for backwards compatibility, ignore it.
|
|
386
732
|
module NoBooleanInputMethods
|
|
387
|
-
# Raise an +Error+ if one of the args would be boolean in an SQL
|
|
388
|
-
# context, otherwise call super.
|
|
389
|
-
def initialize(op, *args)
|
|
390
|
-
args.each do |a|
|
|
391
|
-
case a
|
|
392
|
-
when BooleanExpression, TrueClass, FalseClass, NilClass, Hash, ::Array
|
|
393
|
-
raise(Error, "cannot apply #{op} to a boolean expression")
|
|
394
|
-
end
|
|
395
|
-
end
|
|
396
|
-
super
|
|
397
|
-
end
|
|
398
733
|
end
|
|
399
734
|
|
|
400
735
|
# This module includes the standard mathematical methods (+, -, *, and /)
|
|
@@ -405,15 +740,66 @@ module Sequel
|
|
|
405
740
|
# :a - :b # "a" - "b"
|
|
406
741
|
# :a * :b # "a" * "b"
|
|
407
742
|
# :a / :b # "a" / "b"
|
|
743
|
+
#
|
|
744
|
+
# One exception to this is if + is called with a +String+ or +StringExpression+,
|
|
745
|
+
# in which case the || operator is used instead of the + operator:
|
|
746
|
+
#
|
|
747
|
+
# :a + 'b' # "a" || 'b'
|
|
408
748
|
module NumericMethods
|
|
409
749
|
ComplexExpression::MATHEMATICAL_OPERATORS.each do |o|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
750
|
+
module_eval("def #{o}(o) NumericExpression.new(#{o.inspect}, self, o) end", __FILE__, __LINE__) unless o == :+
|
|
751
|
+
end
|
|
752
|
+
|
|
753
|
+
# Use || as the operator when called with StringExpression and String instances,
|
|
754
|
+
# and the + operator for LiteralStrings and all other types.
|
|
755
|
+
def +(ce)
|
|
756
|
+
case ce
|
|
757
|
+
when LiteralString
|
|
758
|
+
NumericExpression.new(:+, self, ce)
|
|
759
|
+
when StringExpression, String
|
|
760
|
+
StringExpression.new(:'||', self, ce)
|
|
761
|
+
else
|
|
762
|
+
NumericExpression.new(:+, self, ce)
|
|
763
|
+
end
|
|
764
|
+
end
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
# These methods are designed as replacements for the core extension operator
|
|
768
|
+
# methods, so that Sequel is still easy to use if the core extensions are not
|
|
769
|
+
# enabled.
|
|
770
|
+
#
|
|
771
|
+
# The following methods are defined via metaprogramming: +, -, *, /, &, |.
|
|
772
|
+
# The +, -, *, and / operators return numeric expressions combining all the
|
|
773
|
+
# arguments with the appropriate operator, and the & and | operators return
|
|
774
|
+
# boolean expressions combining all of the arguments with either AND or OR.
|
|
775
|
+
module OperatorBuilders
|
|
776
|
+
%w'+ - * /'.each do |op|
|
|
777
|
+
class_eval(<<-END, __FILE__, __LINE__ + 1)
|
|
778
|
+
def #{op}(*args)
|
|
779
|
+
SQL::NumericExpression.new(:#{op}, *args)
|
|
780
|
+
end
|
|
781
|
+
END
|
|
782
|
+
end
|
|
783
|
+
|
|
784
|
+
{'&'=>'AND', '|'=>'OR'}.each do |m, op|
|
|
785
|
+
class_eval(<<-END, __FILE__, __LINE__ + 1)
|
|
786
|
+
def #{m}(*args)
|
|
787
|
+
SQL::BooleanExpression.new(:#{op}, *args)
|
|
416
788
|
end
|
|
789
|
+
END
|
|
790
|
+
end
|
|
791
|
+
|
|
792
|
+
# Invert the given expression. Returns a <tt>Sequel::SQL::BooleanExpression</tt>
|
|
793
|
+
# created from this argument, not matching all of the conditions.
|
|
794
|
+
#
|
|
795
|
+
# Sequel.~(nil) # SQL: NOT NULL
|
|
796
|
+
# Sequel.~([[:a, true]]) # SQL: a IS NOT TRUE
|
|
797
|
+
# Sequel.~([[:a, 1], [:b, [2, 3]]]) # SQL: a != 1 OR b NOT IN (2, 3)
|
|
798
|
+
def ~(arg)
|
|
799
|
+
if condition_specifier?(arg)
|
|
800
|
+
SQL::BooleanExpression.from_value_pairs(arg, :OR, true)
|
|
801
|
+
else
|
|
802
|
+
SQL::BooleanExpression.invert(arg)
|
|
417
803
|
end
|
|
418
804
|
end
|
|
419
805
|
end
|
|
@@ -443,13 +829,25 @@ module Sequel
|
|
|
443
829
|
end
|
|
444
830
|
|
|
445
831
|
# Includes a +qualify+ method that created <tt>QualifiedIdentifier</tt>s, used for qualifying column
|
|
446
|
-
# names with a table or table names with a schema
|
|
832
|
+
# names with a table or table names with a schema, and the * method for returning all columns in
|
|
833
|
+
# the identifier if no arguments are given.
|
|
447
834
|
module QualifyingMethods
|
|
835
|
+
# If no arguments are given, return an SQL::ColumnAll:
|
|
836
|
+
#
|
|
837
|
+
# Sequel.expr(:a__b).* # a.b.*
|
|
838
|
+
def *(ce=(arg=false;nil))
|
|
839
|
+
if arg == false
|
|
840
|
+
Sequel::SQL::ColumnAll.new(self)
|
|
841
|
+
else
|
|
842
|
+
super(ce)
|
|
843
|
+
end
|
|
844
|
+
end
|
|
845
|
+
|
|
448
846
|
# Qualify the receiver with the given +qualifier+ (table for column/schema for table).
|
|
449
847
|
#
|
|
450
|
-
# :column.qualify(:table) # "table"."column"
|
|
451
|
-
# :table.qualify(:schema) # "schema"."table"
|
|
452
|
-
#
|
|
848
|
+
# Sequel.expr(:column).qualify(:table) # "table"."column"
|
|
849
|
+
# Sequel.expr(:table).qualify(:schema) # "schema"."table"
|
|
850
|
+
# Sequel.qualify(:table, :column).qualify(:schema) # "schema"."table"."column"
|
|
453
851
|
def qualify(qualifier)
|
|
454
852
|
QualifiedIdentifier.new(qualifier, self)
|
|
455
853
|
end
|
|
@@ -523,8 +921,16 @@ module Sequel
|
|
|
523
921
|
# stored as a blob type in the database. Sequel represents binary data as a Blob object because
|
|
524
922
|
# most database engines require binary data to be escaped differently than regular strings.
|
|
525
923
|
class Blob < ::String
|
|
526
|
-
|
|
527
|
-
|
|
924
|
+
include SQL::AliasMethods
|
|
925
|
+
include SQL::CastMethods
|
|
926
|
+
|
|
927
|
+
# Return a LiteralString with the same content if no args are given, otherwise
|
|
928
|
+
# return a SQL::PlaceholderLiteralString with the current string and the given args.
|
|
929
|
+
def lit(*args)
|
|
930
|
+
args.empty? ? LiteralString.new(self) : SQL::PlaceholderLiteralString.new(self, args)
|
|
931
|
+
end
|
|
932
|
+
|
|
933
|
+
# Returns +self+, since it is already a blob.
|
|
528
934
|
def to_sequel_blob
|
|
529
935
|
self
|
|
530
936
|
end
|
|
@@ -556,27 +962,33 @@ module Sequel
|
|
|
556
962
|
# ~from_value_pairs(hash)
|
|
557
963
|
# from_value_pairs(hash, :OR, true)
|
|
558
964
|
def self.from_value_pairs(pairs, op=:AND, negate=false)
|
|
559
|
-
pairs = pairs.
|
|
560
|
-
|
|
561
|
-
when Range
|
|
562
|
-
new(:AND, new(:>=, l, r.begin), new(r.exclude_end? ? :< : :<=, l, r.end))
|
|
563
|
-
when ::Array, ::Sequel::Dataset
|
|
564
|
-
new(:IN, l, r)
|
|
565
|
-
when NegativeBooleanConstant
|
|
566
|
-
new(:"IS NOT", l, r.constant)
|
|
567
|
-
when BooleanConstant
|
|
568
|
-
new(:IS, l, r.constant)
|
|
569
|
-
when NilClass, TrueClass, FalseClass
|
|
570
|
-
new(:IS, l, r)
|
|
571
|
-
when Regexp
|
|
572
|
-
StringExpression.like(l, r)
|
|
573
|
-
else
|
|
574
|
-
new(:'=', l, r)
|
|
575
|
-
end
|
|
576
|
-
negate ? invert(ce) : ce
|
|
577
|
-
end
|
|
965
|
+
pairs = pairs.map{|l,r| from_value_pair(l, r)}
|
|
966
|
+
pairs.map!{|ce| invert(ce)} if negate
|
|
578
967
|
pairs.length == 1 ? pairs.at(0) : new(op, *pairs)
|
|
579
968
|
end
|
|
969
|
+
|
|
970
|
+
# Return a BooleanExpression based on the right side of the pair.
|
|
971
|
+
def self.from_value_pair(l, r)
|
|
972
|
+
case r
|
|
973
|
+
when Range
|
|
974
|
+
new(:AND, new(:>=, l, r.begin), new(r.exclude_end? ? :< : :<=, l, r.end))
|
|
975
|
+
when ::Array, ::Sequel::Dataset
|
|
976
|
+
new(:IN, l, r)
|
|
977
|
+
when NegativeBooleanConstant
|
|
978
|
+
new(:"IS NOT", l, r.constant)
|
|
979
|
+
when BooleanConstant
|
|
980
|
+
new(:IS, l, r.constant)
|
|
981
|
+
when NilClass, TrueClass, FalseClass
|
|
982
|
+
new(:IS, l, r)
|
|
983
|
+
when Regexp
|
|
984
|
+
StringExpression.like(l, r)
|
|
985
|
+
when DelayedEvaluation
|
|
986
|
+
Sequel.delay{from_value_pair(l, r.callable.call)}
|
|
987
|
+
else
|
|
988
|
+
new(:'=', l, r)
|
|
989
|
+
end
|
|
990
|
+
end
|
|
991
|
+
private_class_method :from_value_pair
|
|
580
992
|
|
|
581
993
|
# Invert the expression, if possible. If the expression cannot
|
|
582
994
|
# be inverted, raise an error. An inverted expression should match everything that the
|
|
@@ -595,10 +1007,27 @@ module Sequel
|
|
|
595
1007
|
end
|
|
596
1008
|
when StringExpression, NumericExpression
|
|
597
1009
|
raise(Sequel::Error, "cannot invert #{ce.inspect}")
|
|
1010
|
+
when Constant
|
|
1011
|
+
CONSTANT_INVERSIONS[ce] || raise(Sequel::Error, "cannot invert #{ce.inspect}")
|
|
598
1012
|
else
|
|
599
1013
|
BooleanExpression.new(:NOT, ce)
|
|
600
1014
|
end
|
|
601
1015
|
end
|
|
1016
|
+
|
|
1017
|
+
# Always use an AND operator for & on BooleanExpressions
|
|
1018
|
+
def &(ce)
|
|
1019
|
+
BooleanExpression.new(:AND, self, ce)
|
|
1020
|
+
end
|
|
1021
|
+
|
|
1022
|
+
# Always use an OR operator for | on BooleanExpressions
|
|
1023
|
+
def |(ce)
|
|
1024
|
+
BooleanExpression.new(:OR, self, ce)
|
|
1025
|
+
end
|
|
1026
|
+
|
|
1027
|
+
# Return self instead of creating a new object to save on memory.
|
|
1028
|
+
def sql_boolean
|
|
1029
|
+
self
|
|
1030
|
+
end
|
|
602
1031
|
end
|
|
603
1032
|
|
|
604
1033
|
# Represents an SQL CASE expression, used for conditional branching in SQL.
|
|
@@ -628,6 +1057,17 @@ module Sequel
|
|
|
628
1057
|
!@no_expression
|
|
629
1058
|
end
|
|
630
1059
|
|
|
1060
|
+
# Merge the CASE expression into the conditions, useful for databases that
|
|
1061
|
+
# don't support CASE expressions.
|
|
1062
|
+
def with_merged_expression
|
|
1063
|
+
if expression?
|
|
1064
|
+
e = expression
|
|
1065
|
+
CaseExpression.new(conditions.map{|c, r| [::Sequel::SQL::BooleanExpression.new(:'=', e, c), r]}, default)
|
|
1066
|
+
else
|
|
1067
|
+
self
|
|
1068
|
+
end
|
|
1069
|
+
end
|
|
1070
|
+
|
|
631
1071
|
to_s_method :case_expression_sql
|
|
632
1072
|
end
|
|
633
1073
|
|
|
@@ -666,6 +1106,21 @@ module Sequel
|
|
|
666
1106
|
include CastMethods
|
|
667
1107
|
include OrderMethods
|
|
668
1108
|
include SubscriptMethods
|
|
1109
|
+
|
|
1110
|
+
# Return a BooleanExpression with the same op and args.
|
|
1111
|
+
def sql_boolean
|
|
1112
|
+
BooleanExpression.new(self.op, *self.args)
|
|
1113
|
+
end
|
|
1114
|
+
|
|
1115
|
+
# Return a NumericExpression with the same op and args.
|
|
1116
|
+
def sql_number
|
|
1117
|
+
NumericExpression.new(self.op, *self.args)
|
|
1118
|
+
end
|
|
1119
|
+
|
|
1120
|
+
# Return a StringExpression with the same op and args.
|
|
1121
|
+
def sql_string
|
|
1122
|
+
StringExpression.new(self.op, *self.args)
|
|
1123
|
+
end
|
|
669
1124
|
end
|
|
670
1125
|
|
|
671
1126
|
# Represents constants or psuedo-constants (e.g. +CURRENT_DATE+) in SQL.
|
|
@@ -688,7 +1143,7 @@ module Sequel
|
|
|
688
1143
|
|
|
689
1144
|
# Represents inverse boolean constants (currently only +NOTNULL+). A
|
|
690
1145
|
# special class to allow for special behavior.
|
|
691
|
-
class NegativeBooleanConstant <
|
|
1146
|
+
class NegativeBooleanConstant < Constant
|
|
692
1147
|
to_s_method :negative_boolean_constant_sql, '@constant'
|
|
693
1148
|
end
|
|
694
1149
|
|
|
@@ -706,14 +1161,35 @@ module Sequel
|
|
|
706
1161
|
NOTNULL = NegativeBooleanConstant.new(nil)
|
|
707
1162
|
end
|
|
708
1163
|
|
|
1164
|
+
class ComplexExpression
|
|
1165
|
+
# A hash of the opposite for each constant, used for inverting constants.
|
|
1166
|
+
CONSTANT_INVERSIONS = {Constants::TRUE=>Constants::FALSE, Constants::FALSE=>Constants::TRUE,
|
|
1167
|
+
Constants::NULL=>Constants::NOTNULL, Constants::NOTNULL=>Constants::NULL}
|
|
1168
|
+
end
|
|
1169
|
+
|
|
1170
|
+
# Represents a delayed evaluation, encapsulating a callable
|
|
1171
|
+
# object which returns the value to use when called.
|
|
1172
|
+
class DelayedEvaluation < GenericExpression
|
|
1173
|
+
# A callable object that returns the value of the evaluation
|
|
1174
|
+
# when called.
|
|
1175
|
+
attr_reader :callable
|
|
1176
|
+
|
|
1177
|
+
# Set the callable object
|
|
1178
|
+
def initialize(callable)
|
|
1179
|
+
@callable = callable
|
|
1180
|
+
end
|
|
1181
|
+
|
|
1182
|
+
to_s_method :delayed_evaluation_sql, '@callable'
|
|
1183
|
+
end
|
|
1184
|
+
|
|
709
1185
|
# Represents an SQL function call.
|
|
710
1186
|
class Function < GenericExpression
|
|
711
|
-
# The array of arguments to pass to the function (may be blank)
|
|
712
|
-
attr_reader :args
|
|
713
|
-
|
|
714
1187
|
# The SQL function to call
|
|
715
1188
|
attr_reader :f
|
|
716
1189
|
|
|
1190
|
+
# The array of arguments to pass to the function (may be blank)
|
|
1191
|
+
attr_reader :args
|
|
1192
|
+
|
|
717
1193
|
# Set the functions and args to the given arguments
|
|
718
1194
|
def initialize(f, *args)
|
|
719
1195
|
@f, @args = f, args
|
|
@@ -721,6 +1197,12 @@ module Sequel
|
|
|
721
1197
|
|
|
722
1198
|
to_s_method :function_sql
|
|
723
1199
|
end
|
|
1200
|
+
|
|
1201
|
+
# Represents an SQL function call that is translated/emulated
|
|
1202
|
+
# on databases that lack support for such a function.
|
|
1203
|
+
class EmulatedFunction < Function
|
|
1204
|
+
to_s_method :emulated_function_sql
|
|
1205
|
+
end
|
|
724
1206
|
|
|
725
1207
|
class GenericExpression
|
|
726
1208
|
include AliasMethods
|
|
@@ -806,15 +1288,16 @@ module Sequel
|
|
|
806
1288
|
# required for the prepared statement support and for database-specific
|
|
807
1289
|
# literalization.
|
|
808
1290
|
class PlaceholderLiteralString < GenericExpression
|
|
1291
|
+
# The literal string containing placeholders. This can also be an array
|
|
1292
|
+
# of strings, where each arg in args goes between the string elements.
|
|
1293
|
+
attr_reader :str
|
|
1294
|
+
|
|
809
1295
|
# The arguments that will be subsituted into the placeholders.
|
|
810
1296
|
# Either an array of unnamed placeholders (which will be substituted in
|
|
811
1297
|
# order for ? characters), or a hash of named placeholders (which will be
|
|
812
1298
|
# substituted for :key phrases).
|
|
813
1299
|
attr_reader :args
|
|
814
1300
|
|
|
815
|
-
# The literal string containing placeholders
|
|
816
|
-
attr_reader :str
|
|
817
|
-
|
|
818
1301
|
# Whether to surround the expression with parantheses
|
|
819
1302
|
attr_reader :parens
|
|
820
1303
|
|
|
@@ -834,7 +1317,16 @@ module Sequel
|
|
|
834
1317
|
include BitwiseMethods
|
|
835
1318
|
include NumericMethods
|
|
836
1319
|
include InequalityMethods
|
|
837
|
-
|
|
1320
|
+
|
|
1321
|
+
# Always use + for + operator for NumericExpressions.
|
|
1322
|
+
def +(ce)
|
|
1323
|
+
NumericExpression.new(:+, self, ce)
|
|
1324
|
+
end
|
|
1325
|
+
|
|
1326
|
+
# Return self instead of creating a new object to save on memory.
|
|
1327
|
+
def sql_number
|
|
1328
|
+
self
|
|
1329
|
+
end
|
|
838
1330
|
end
|
|
839
1331
|
|
|
840
1332
|
# Represents a column/expression to order the result set by.
|
|
@@ -880,18 +1372,18 @@ module Sequel
|
|
|
880
1372
|
class QualifiedIdentifier < GenericExpression
|
|
881
1373
|
include QualifyingMethods
|
|
882
1374
|
|
|
883
|
-
# The column/table referenced
|
|
884
|
-
attr_reader :column
|
|
885
|
-
|
|
886
1375
|
# The table/schema qualifying the reference
|
|
887
1376
|
attr_reader :table
|
|
888
1377
|
|
|
1378
|
+
# The column/table referenced
|
|
1379
|
+
attr_reader :column
|
|
1380
|
+
|
|
889
1381
|
# Set the table and column to the given arguments
|
|
890
1382
|
def initialize(table, column)
|
|
891
1383
|
@table, @column = table, column
|
|
892
1384
|
end
|
|
893
1385
|
|
|
894
|
-
to_s_method :qualified_identifier_sql
|
|
1386
|
+
to_s_method :qualified_identifier_sql, "@table, @column"
|
|
895
1387
|
end
|
|
896
1388
|
|
|
897
1389
|
# Subclass of +ComplexExpression+ where the expression results
|
|
@@ -900,7 +1392,6 @@ module Sequel
|
|
|
900
1392
|
include StringMethods
|
|
901
1393
|
include StringConcatenationMethods
|
|
902
1394
|
include InequalityMethods
|
|
903
|
-
include NoBooleanInputMethods
|
|
904
1395
|
|
|
905
1396
|
# Map of [regexp, case_insenstive] to +ComplexExpression+ operator symbol
|
|
906
1397
|
LIKE_MAP = {[true, true]=>:'~*', [true, false]=>:~, [false, true]=>:ILIKE, [false, false]=>:LIKE}
|
|
@@ -949,6 +1440,11 @@ module Sequel
|
|
|
949
1440
|
end
|
|
950
1441
|
end
|
|
951
1442
|
private_class_method :like_element
|
|
1443
|
+
|
|
1444
|
+
# Return self instead of creating a new object to save on memory.
|
|
1445
|
+
def sql_string
|
|
1446
|
+
self
|
|
1447
|
+
end
|
|
952
1448
|
end
|
|
953
1449
|
|
|
954
1450
|
# Represents an SQL array access, with multiple possible arguments.
|
|
@@ -966,9 +1462,21 @@ module Sequel
|
|
|
966
1462
|
|
|
967
1463
|
# Create a new +Subscript+ appending the given subscript(s)
|
|
968
1464
|
# the the current array of subscripts.
|
|
1465
|
+
#
|
|
1466
|
+
# :a.sql_subscript(2) # a[2]
|
|
1467
|
+
# :a.sql_subscript(2) | 1 # a[2, 1]
|
|
969
1468
|
def |(sub)
|
|
970
1469
|
Subscript.new(@f, @sub + Array(sub))
|
|
971
1470
|
end
|
|
1471
|
+
|
|
1472
|
+
# Create a new +Subscript+ by accessing a subarray of a multidimensional
|
|
1473
|
+
# array.
|
|
1474
|
+
#
|
|
1475
|
+
# :a.sql_subscript(2) # a[2]
|
|
1476
|
+
# :a.sql_subscript(2)[1] # a[2][1]
|
|
1477
|
+
def [](sub)
|
|
1478
|
+
Subscript.new(self, Array(sub))
|
|
1479
|
+
end
|
|
972
1480
|
|
|
973
1481
|
to_s_method :subscript_sql
|
|
974
1482
|
end
|
|
@@ -1019,28 +1527,71 @@ module Sequel
|
|
|
1019
1527
|
# Examples:
|
|
1020
1528
|
#
|
|
1021
1529
|
# ds = DB[:t]
|
|
1530
|
+
#
|
|
1022
1531
|
# # Argument yielded to block
|
|
1023
1532
|
# ds.filter{|r| r.name < 2} # SELECT * FROM t WHERE (name < 2)
|
|
1533
|
+
#
|
|
1024
1534
|
# # Block without argument (instance_eval)
|
|
1025
1535
|
# ds.filter{name < 2} # SELECT * FROM t WHERE (name < 2)
|
|
1536
|
+
#
|
|
1026
1537
|
# # Qualified identifiers
|
|
1027
1538
|
# ds.filter{table__column + 1 < 2} # SELECT * FROM t WHERE ((table.column + 1) < 2)
|
|
1539
|
+
#
|
|
1028
1540
|
# # Functions
|
|
1029
1541
|
# ds.filter{is_active(1, 'arg2')} # SELECT * FROM t WHERE is_active(1, 'arg2')
|
|
1030
1542
|
# ds.select{version{}} # SELECT version() FROM t
|
|
1031
1543
|
# ds.select{count(:*){}} # SELECT count(*) FROM t
|
|
1032
1544
|
# ds.select{count(:distinct, col1){}} # SELECT count(DISTINCT col1) FROM t
|
|
1545
|
+
#
|
|
1033
1546
|
# # Window Functions
|
|
1034
1547
|
# ds.select{rank(:over){}} # SELECT rank() OVER () FROM t
|
|
1035
1548
|
# ds.select{count(:over, :*=>true){}} # SELECT count(*) OVER () FROM t
|
|
1036
1549
|
# ds.select{sum(:over, :args=>col1, :partition=>col2, :order=>col3){}} # SELECT sum(col1) OVER (PARTITION BY col2 ORDER BY col3) FROM t
|
|
1037
1550
|
#
|
|
1551
|
+
# # Math Operators
|
|
1552
|
+
# ds.select{|o| o.+(1, :a).as(:b)} # SELECT (1 + a) AS b FROM t
|
|
1553
|
+
# ds.select{|o| o.-(2, :a).as(:b)} # SELECT (2 - a) AS b FROM t
|
|
1554
|
+
# ds.select{|o| o.*(3, :a).as(:b)} # SELECT (3 * a) AS b FROM t
|
|
1555
|
+
# ds.select{|o| o./(4, :a).as(:b)} # SELECT (4 / a) AS b FROM t
|
|
1556
|
+
#
|
|
1557
|
+
# # Boolean Operators
|
|
1558
|
+
# ds.filter{|o| o.&({:a=>1}, :b)} # SELECT * FROM t WHERE ((a = 1) AND b)
|
|
1559
|
+
# ds.filter{|o| o.|({:a=>1}, :b)} # SELECT * FROM t WHERE ((a = 1) OR b)
|
|
1560
|
+
# ds.filter{|o| o.~({:a=>1})} # SELECT * FROM t WHERE (a != 1)
|
|
1561
|
+
# ds.filter{|o| o.~({:a=>1, :b=>2})} # SELECT * FROM t WHERE ((a != 1) OR (b != 2))
|
|
1562
|
+
#
|
|
1563
|
+
# # Inequality Operators
|
|
1564
|
+
# ds.filter{|o| o.>(1, :a)} # SELECT * FROM t WHERE (1 > a)
|
|
1565
|
+
# ds.filter{|o| o.<(2, :a)} # SELECT * FROM t WHERE (2 < a)
|
|
1566
|
+
# ds.filter{|o| o.>=(3, :a)} # SELECT * FROM t WHERE (3 >= a)
|
|
1567
|
+
# ds.filter{|o| o.<=(4, :a)} # SELECT * FROM t WHERE (4 <= a)
|
|
1568
|
+
#
|
|
1569
|
+
# # Literal Strings
|
|
1570
|
+
# ds.filter{{a=>`some SQL`}} # SELECT * FROM t WHERE (a = some SQL)
|
|
1571
|
+
#
|
|
1038
1572
|
# For a more detailed explanation, see the {Virtual Rows guide}[link:files/doc/virtual_rows_rdoc.html].
|
|
1039
1573
|
class VirtualRow < BasicObject
|
|
1040
1574
|
WILDCARD = LiteralString.new('*').freeze
|
|
1041
1575
|
QUESTION_MARK = LiteralString.new('?').freeze
|
|
1042
1576
|
COMMA_SEPARATOR = LiteralString.new(', ').freeze
|
|
1043
1577
|
DOUBLE_UNDERSCORE = '__'.freeze
|
|
1578
|
+
DISTINCT = ["DISTINCT ".freeze].freeze
|
|
1579
|
+
COMMA_ARRAY = [COMMA_SEPARATOR].freeze
|
|
1580
|
+
|
|
1581
|
+
include OperatorBuilders
|
|
1582
|
+
|
|
1583
|
+
%w'> < >= <='.each do |op|
|
|
1584
|
+
class_eval(<<-END, __FILE__, __LINE__ + 1)
|
|
1585
|
+
def #{op}(*args)
|
|
1586
|
+
SQL::BooleanExpression.new(:#{op}, *args)
|
|
1587
|
+
end
|
|
1588
|
+
END
|
|
1589
|
+
end
|
|
1590
|
+
|
|
1591
|
+
# Return a literal string created with the given string.
|
|
1592
|
+
def `(s)
|
|
1593
|
+
Sequel::LiteralString.new(s)
|
|
1594
|
+
end
|
|
1044
1595
|
|
|
1045
1596
|
# Return an +Identifier+, +QualifiedIdentifier+, +Function+, or +WindowFunction+, depending
|
|
1046
1597
|
# on arguments and whether a block is provided. Does not currently call the block.
|
|
@@ -1054,7 +1605,7 @@ module Sequel
|
|
|
1054
1605
|
when :*
|
|
1055
1606
|
Function.new(m, WILDCARD)
|
|
1056
1607
|
when :distinct
|
|
1057
|
-
Function.new(m, PlaceholderLiteralString.new(
|
|
1608
|
+
Function.new(m, PlaceholderLiteralString.new(DISTINCT + COMMA_ARRAY * (args.length-1), args))
|
|
1058
1609
|
when :over
|
|
1059
1610
|
opts = args.shift || {}
|
|
1060
1611
|
fun_args = ::Kernel.Array(opts[:*] ? WILDCARD : opts[:args])
|
|
@@ -1108,6 +1659,20 @@ module Sequel
|
|
|
1108
1659
|
|
|
1109
1660
|
to_s_method :window_function_sql, '@function, @window'
|
|
1110
1661
|
end
|
|
1662
|
+
|
|
1663
|
+
# A +Wrapper+ is a simple way to wrap an existing object so that it supports
|
|
1664
|
+
# the Sequel DSL.
|
|
1665
|
+
class Wrapper < GenericExpression
|
|
1666
|
+
# The underlying value wrapped by this object.
|
|
1667
|
+
attr_reader :value
|
|
1668
|
+
|
|
1669
|
+
# Set the value wrapped by the object.
|
|
1670
|
+
def initialize(value)
|
|
1671
|
+
@value = value
|
|
1672
|
+
end
|
|
1673
|
+
|
|
1674
|
+
to_s_method :literal, '@value'
|
|
1675
|
+
end
|
|
1111
1676
|
end
|
|
1112
1677
|
|
|
1113
1678
|
# +LiteralString+ is used to represent literal SQL expressions. A
|
|
@@ -1120,7 +1685,22 @@ module Sequel
|
|
|
1120
1685
|
include SQL::NumericMethods
|
|
1121
1686
|
include SQL::StringMethods
|
|
1122
1687
|
include SQL::InequalityMethods
|
|
1688
|
+
include SQL::AliasMethods
|
|
1689
|
+
include SQL::CastMethods
|
|
1690
|
+
|
|
1691
|
+
# Return self if no args are given, otherwise return a SQL::PlaceholderLiteralString
|
|
1692
|
+
# with the current string and the given args.
|
|
1693
|
+
def lit(*args)
|
|
1694
|
+
args.empty? ? self : SQL::PlaceholderLiteralString.new(self, args)
|
|
1695
|
+
end
|
|
1696
|
+
|
|
1697
|
+
# Convert a literal string to a SQL::Blob.
|
|
1698
|
+
def to_sequel_blob
|
|
1699
|
+
SQL::Blob.new(self)
|
|
1700
|
+
end
|
|
1123
1701
|
end
|
|
1124
1702
|
|
|
1125
1703
|
include SQL::Constants
|
|
1704
|
+
extend SQL::Builders
|
|
1705
|
+
extend SQL::OperatorBuilders
|
|
1126
1706
|
end
|