sequel 3.21.0 → 3.39.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 +1061 -3
- data/MIT-LICENSE +1 -1
- data/README.rdoc +103 -63
- data/Rakefile +59 -27
- data/bin/sequel +50 -26
- data/doc/active_record.rdoc +67 -51
- data/doc/advanced_associations.rdoc +189 -75
- data/doc/association_basics.rdoc +327 -79
- 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 +547 -0
- data/doc/opening_databases.rdoc +114 -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/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/mssql.rb +18 -6
- data/lib/sequel/adapters/ado.rb +40 -18
- data/lib/sequel/adapters/amalgalite.rb +17 -9
- data/lib/sequel/adapters/db2.rb +175 -86
- data/lib/sequel/adapters/dbi.rb +15 -15
- 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 +18 -36
- data/lib/sequel/adapters/firebird.rb +27 -208
- data/lib/sequel/adapters/ibmdb.rb +453 -0
- data/lib/sequel/adapters/informix.rb +6 -23
- data/lib/sequel/adapters/jdbc/as400.rb +16 -34
- data/lib/sequel/adapters/jdbc/db2.rb +56 -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 +73 -31
- data/lib/sequel/adapters/jdbc/hsqldb.rb +184 -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 +7 -24
- 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 +66 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +279 -97
- data/lib/sequel/adapters/mock.rb +372 -0
- data/lib/sequel/adapters/mysql.rb +125 -222
- data/lib/sequel/adapters/mysql2.rb +65 -56
- data/lib/sequel/adapters/odbc/mssql.rb +17 -9
- data/lib/sequel/adapters/odbc.rb +28 -9
- data/lib/sequel/adapters/openbase.rb +3 -5
- data/lib/sequel/adapters/oracle.rb +349 -53
- data/lib/sequel/adapters/postgres.rb +368 -138
- data/lib/sequel/adapters/shared/access.rb +32 -9
- data/lib/sequel/adapters/shared/db2.rb +343 -0
- data/lib/sequel/adapters/shared/firebird.rb +221 -0
- data/lib/sequel/adapters/shared/informix.rb +53 -0
- data/lib/sequel/adapters/shared/mssql.rb +401 -116
- data/lib/sequel/adapters/shared/mysql.rb +424 -89
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
- data/lib/sequel/adapters/shared/oracle.rb +257 -45
- data/lib/sequel/adapters/shared/postgres.rb +675 -279
- data/lib/sequel/adapters/shared/progress.rb +5 -8
- data/lib/sequel/adapters/shared/sqlite.rb +285 -96
- data/lib/sequel/adapters/sqlite.rb +101 -39
- 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 +28 -19
- data/lib/sequel/adapters/tinytds.rb +174 -22
- 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/stored_procedures.rb +1 -11
- data/lib/sequel/ast_transformer.rb +194 -0
- data/lib/sequel/connection_pool/sharded_single.rb +11 -1
- data/lib/sequel/connection_pool/sharded_threaded.rb +33 -2
- data/lib/sequel/connection_pool/single.rb +5 -0
- data/lib/sequel/connection_pool/threaded.rb +43 -14
- data/lib/sequel/connection_pool.rb +10 -2
- data/lib/sequel/core.rb +143 -11
- data/lib/sequel/database/connecting.rb +38 -28
- 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 +190 -46
- data/lib/sequel/database/query.rb +272 -110
- data/lib/sequel/database/schema_generator.rb +103 -36
- data/lib/sequel/database/schema_methods.rb +300 -67
- 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 +305 -54
- data/lib/sequel/dataset/sql.rb +720 -292
- 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/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 +537 -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 +313 -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 +208 -0
- data/lib/sequel/extensions/pg_range.rb +512 -0
- data/lib/sequel/extensions/pg_range_ops.rb +150 -0
- data/lib/sequel/extensions/pg_row.rb +572 -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 +22 -4
- 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 +58 -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 +167 -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 +5 -3
- 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/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 +1 -1
- data/lib/sequel/plugins/validation_helpers.rb +55 -4
- data/lib/sequel/plugins/xml_serializer.rb +15 -4
- data/lib/sequel/sql.rb +649 -122
- 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 +1 -1
- data/spec/adapters/mssql_spec.rb +194 -66
- data/spec/adapters/mysql_spec.rb +475 -306
- data/spec/adapters/oracle_spec.rb +92 -117
- data/spec/adapters/postgres_spec.rb +1982 -325
- data/spec/adapters/spec_helper.rb +9 -6
- data/spec/adapters/sqlite_spec.rb +203 -75
- data/spec/core/connection_pool_spec.rb +218 -93
- data/spec/core/database_spec.rb +956 -522
- data/spec/core/dataset_spec.rb +1631 -1242
- data/spec/core/expression_filters_spec.rb +690 -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 +66 -32
- 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/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 +320 -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 +194 -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 +323 -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 +23 -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 +13 -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 +58 -67
- data/spec/extensions/validation_helpers_spec.rb +31 -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 +11 -5
- data/spec/integration/dataset_test.rb +717 -129
- 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 +604 -147
- data/spec/integration/prepared_statement_test.rb +272 -128
- data/spec/integration/schema_test.rb +367 -57
- data/spec/integration/spec_helper.rb +42 -32
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +183 -8
- data/spec/integration/type_test.rb +31 -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 +209 -80
- 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
|
|
67
84
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
85
|
+
private
|
|
86
|
+
|
|
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,332 @@ 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
|
+
# Order the given argument descending.
|
|
381
|
+
# Options:
|
|
382
|
+
#
|
|
383
|
+
# :nulls :: Set to :first to use NULLS FIRST (so NULL values are ordered
|
|
384
|
+
# before other values), or :last to use NULLS LAST (so NULL values
|
|
385
|
+
# are ordered after other values).
|
|
386
|
+
#
|
|
387
|
+
# Sequel.desc(:a) # b DESC
|
|
388
|
+
# Sequel.desc(:b, :nulls=>:first) # b DESC NULLS FIRST
|
|
389
|
+
def desc(arg, opts={})
|
|
390
|
+
SQL::OrderedExpression.new(arg, true, opts)
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
# Wraps the given object in an appropriate Sequel wrapper.
|
|
394
|
+
# If the given object is already a Sequel object, return it directly.
|
|
395
|
+
# For condition specifiers (hashes and arrays of two pairs), true, and false,
|
|
396
|
+
# return a boolean expressions. For numeric objects, return a numeric
|
|
397
|
+
# expression. For strings, return a string expression. For procs or when
|
|
398
|
+
# the method is passed a block, evaluate it as a virtual row and wrap it
|
|
399
|
+
# appropriately. In all other cases, use a generic wrapper.
|
|
400
|
+
#
|
|
401
|
+
# This method allows you to construct SQL expressions that are difficult
|
|
402
|
+
# to construct via other methods. For example:
|
|
403
|
+
#
|
|
404
|
+
# Sequel.expr(1) - :a # SQL: (1 - a)
|
|
405
|
+
def expr(arg=(no_arg=true), &block)
|
|
406
|
+
if block_given?
|
|
407
|
+
if no_arg
|
|
408
|
+
return expr(block)
|
|
409
|
+
else
|
|
410
|
+
raise Error, 'cannot provide both an argument and a block to Sequel.expr'
|
|
411
|
+
end
|
|
412
|
+
elsif no_arg
|
|
413
|
+
raise Error, 'must provide either an argument or a block to Sequel.expr'
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
case arg
|
|
417
|
+
when Symbol
|
|
418
|
+
t, c, a = Sequel.split_symbol(arg)
|
|
419
|
+
|
|
420
|
+
arg = if t
|
|
421
|
+
SQL::QualifiedIdentifier.new(t, c)
|
|
422
|
+
else
|
|
423
|
+
SQL::Identifier.new(c)
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
if a
|
|
427
|
+
arg = SQL::AliasedExpression.new(arg, a)
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
arg
|
|
431
|
+
when SQL::Expression, LiteralString, SQL::Blob
|
|
432
|
+
arg
|
|
433
|
+
when Hash
|
|
434
|
+
SQL::BooleanExpression.from_value_pairs(arg, :AND)
|
|
435
|
+
when Array
|
|
436
|
+
if condition_specifier?(arg)
|
|
437
|
+
SQL::BooleanExpression.from_value_pairs(arg, :AND)
|
|
438
|
+
else
|
|
439
|
+
SQL::Wrapper.new(arg)
|
|
440
|
+
end
|
|
441
|
+
when Numeric
|
|
442
|
+
SQL::NumericExpression.new(:NOOP, arg)
|
|
443
|
+
when String
|
|
444
|
+
SQL::StringExpression.new(:NOOP, arg)
|
|
445
|
+
when TrueClass, FalseClass
|
|
446
|
+
SQL::BooleanExpression.new(:NOOP, arg)
|
|
447
|
+
when Proc
|
|
448
|
+
expr(virtual_row(&arg))
|
|
449
|
+
else
|
|
450
|
+
SQL::Wrapper.new(arg)
|
|
451
|
+
end
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
# Extract a datetime_part (e.g. year, month) from the given
|
|
455
|
+
# expression:
|
|
456
|
+
#
|
|
457
|
+
# Sequel.extract(:year, :date) # extract(year FROM "date")
|
|
458
|
+
def extract(datetime_part, exp)
|
|
459
|
+
SQL::NumericExpression.new(:extract, datetime_part, exp)
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
# Returns a <tt>Sequel::SQL::Function</tt> with the function name
|
|
463
|
+
# and the given arguments.
|
|
464
|
+
#
|
|
465
|
+
# Sequel.function(:now) # SQL: now()
|
|
466
|
+
# Sequel.function(:substr, :a, 1) # SQL: substr(a, 1)
|
|
467
|
+
def function(name, *args)
|
|
468
|
+
SQL::Function.new(name, *args)
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
# Return the argument wrapped as an <tt>SQL::Identifier</tt>.
|
|
472
|
+
#
|
|
473
|
+
# Sequel.identifier(:a__b) # "a__b"
|
|
474
|
+
def identifier(name)
|
|
475
|
+
SQL::Identifier.new(name)
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
# Return a <tt>Sequel::SQL::StringExpression</tt> representing an SQL string made up of the
|
|
479
|
+
# concatenation of the given array's elements. If an argument is passed,
|
|
480
|
+
# it is used in between each element of the array in the SQL
|
|
481
|
+
# concatenation.
|
|
482
|
+
#
|
|
483
|
+
# Sequel.join([:a]) # SQL: a
|
|
484
|
+
# Sequel.join([:a, :b]) # SQL: a || b
|
|
485
|
+
# Sequel.join([:a, 'b']) # SQL: a || 'b'
|
|
486
|
+
# Sequel.join(['a', :b], ' ') # SQL: 'a' || ' ' || b
|
|
487
|
+
def join(args, joiner=nil)
|
|
488
|
+
raise Error, 'argument to Sequel.join must be an array' unless args.is_a?(Array)
|
|
489
|
+
if joiner
|
|
490
|
+
args = args.zip([joiner]*args.length).flatten
|
|
491
|
+
args.pop
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
return SQL::StringExpression.new(:NOOP, '') if args.empty?
|
|
495
|
+
|
|
496
|
+
args = args.map do |a|
|
|
497
|
+
case a
|
|
498
|
+
when Symbol, ::Sequel::SQL::Expression, ::Sequel::LiteralString, TrueClass, FalseClass, NilClass
|
|
499
|
+
a
|
|
500
|
+
else
|
|
501
|
+
a.to_s
|
|
502
|
+
end
|
|
503
|
+
end
|
|
504
|
+
SQL::StringExpression.new(:'||', *args)
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
# Create a <tt>BooleanExpression</tt> case insensitive (if the database supports it) pattern match of the receiver with
|
|
508
|
+
# the given patterns. See <tt>SQL::StringExpression.like</tt>.
|
|
509
|
+
#
|
|
510
|
+
# Sequel.ilike(:a, 'A%') # "a" ILIKE 'A%'
|
|
511
|
+
def ilike(*args)
|
|
512
|
+
SQL::StringExpression.like(*(args << {:case_insensitive=>true}))
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
# Create a <tt>SQL::BooleanExpression</tt> case sensitive (if the database supports it) pattern match of the receiver with
|
|
516
|
+
# the given patterns. See <tt>SQL::StringExpression.like</tt>.
|
|
517
|
+
#
|
|
518
|
+
# Sequel.like(:a, 'A%') # "a" LIKE 'A%'
|
|
519
|
+
def like(*args)
|
|
520
|
+
SQL::StringExpression.like(*args)
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
# Converts a string into a <tt>Sequel::LiteralString</tt>, in order to override string
|
|
524
|
+
# literalization, e.g.:
|
|
525
|
+
#
|
|
526
|
+
# DB[:items].filter(:abc => 'def').sql #=>
|
|
527
|
+
# "SELECT * FROM items WHERE (abc = 'def')"
|
|
528
|
+
#
|
|
529
|
+
# DB[:items].filter(:abc => Sequel.lit('def')).sql #=>
|
|
530
|
+
# "SELECT * FROM items WHERE (abc = def)"
|
|
531
|
+
#
|
|
532
|
+
# You can also provide arguments, to create a <tt>Sequel::SQL::PlaceholderLiteralString</tt>:
|
|
533
|
+
#
|
|
534
|
+
# DB[:items].select{|o| o.count(Sequel.lit('DISTINCT ?', :a))}.sql #=>
|
|
535
|
+
# "SELECT count(DISTINCT a) FROM items"
|
|
536
|
+
def lit(s, *args) # core_sql ignore
|
|
537
|
+
if args.empty?
|
|
538
|
+
if s.is_a?(LiteralString)
|
|
539
|
+
s
|
|
540
|
+
else
|
|
541
|
+
LiteralString.new(s)
|
|
542
|
+
end
|
|
543
|
+
else
|
|
544
|
+
SQL::PlaceholderLiteralString.new(s, args)
|
|
545
|
+
end
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
# Return a <tt>Sequel::SQL::BooleanExpression</tt> created from the condition
|
|
549
|
+
# specifier, matching none of the conditions.
|
|
550
|
+
#
|
|
551
|
+
# Sequel.negate(:a=>true) # SQL: a IS NOT TRUE
|
|
552
|
+
# Sequel.negate([[:a, true]]) # SQL: a IS NOT TRUE
|
|
553
|
+
# Sequel.negate([[:a, 1], [:b, 2]]) # SQL: ((a != 1) AND (b != 2))
|
|
554
|
+
def negate(arg)
|
|
555
|
+
if condition_specifier?(arg)
|
|
556
|
+
SQL::BooleanExpression.from_value_pairs(arg, :AND, true)
|
|
557
|
+
else
|
|
558
|
+
raise Error, 'must pass a conditions specifier to Sequel.negate'
|
|
559
|
+
end
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
# Return a <tt>Sequel::SQL::BooleanExpression</tt> created from the condition
|
|
563
|
+
# specifier, matching any of the conditions.
|
|
564
|
+
#
|
|
565
|
+
# Sequel.or(:a=>true) # SQL: a IS TRUE
|
|
566
|
+
# Sequel.or([[:a, true]]) # SQL: a IS TRUE
|
|
567
|
+
# Sequel.or([[:a, 1], [:b, 2]]) # SQL: ((a = 1) OR (b = 2))
|
|
568
|
+
def or(arg)
|
|
569
|
+
if condition_specifier?(arg)
|
|
570
|
+
SQL::BooleanExpression.from_value_pairs(arg, :OR, false)
|
|
571
|
+
else
|
|
572
|
+
raise Error, 'must pass a conditions specifier to Sequel.or'
|
|
573
|
+
end
|
|
574
|
+
end
|
|
575
|
+
|
|
576
|
+
# Create a qualified identifier with the given qualifier and identifier
|
|
577
|
+
#
|
|
578
|
+
# Sequel.qualify(:table, :column) # "table"."column"
|
|
579
|
+
# Sequel.qualify(:schema, :table) # "schema"."table"
|
|
580
|
+
# Sequel.qualify(:table, :column).qualify(:schema) # "schema"."table"."column"
|
|
581
|
+
def qualify(qualifier, identifier)
|
|
582
|
+
SQL::QualifiedIdentifier.new(qualifier, identifier)
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
# Return an <tt>SQL::Subscript</tt> with the given arguments, representing an
|
|
586
|
+
# SQL array access.
|
|
587
|
+
#
|
|
588
|
+
# Sequel.subscript(:array, 1) # array[1]
|
|
589
|
+
# Sequel.subscript(:array, 1, 2) # array[1, 2]
|
|
590
|
+
# Sequel.subscript(:array, [1, 2]) # array[1, 2]
|
|
591
|
+
def subscript(exp, *subs)
|
|
592
|
+
SQL::Subscript.new(exp, subs.flatten)
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
# Return an emulated function call for trimming a string of spaces from
|
|
596
|
+
# both sides (similar to ruby's String#strip).
|
|
597
|
+
#
|
|
598
|
+
# Sequel.trim(:a) # trim(a) -- Most databases
|
|
599
|
+
# Sequel.trim(:a) # ltrim(rtrim(a)) -- Microsoft SQL Server
|
|
600
|
+
def trim(arg)
|
|
601
|
+
SQL::EmulatedFunction.new(:trim, arg)
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
# Return a <tt>SQL::ValueList</tt> created from the given array. Used if the array contains
|
|
605
|
+
# all two element arrays and you want it treated as an SQL value list (IN predicate)
|
|
606
|
+
# instead of as a conditions specifier (similar to a hash). This is not necessary if you are using
|
|
607
|
+
# this array as a value in a filter, but may be necessary if you are using it as a
|
|
608
|
+
# value with placeholder SQL:
|
|
609
|
+
#
|
|
610
|
+
# DB[:a].filter([:a, :b]=>[[1, 2], [3, 4]]) # SQL: (a, b) IN ((1, 2), (3, 4))
|
|
611
|
+
# DB[:a].filter('(a, b) IN ?', [[1, 2], [3, 4]]) # SQL: (a, b) IN ((1 = 2) AND (3 = 4))
|
|
612
|
+
# DB[:a].filter('(a, b) IN ?', Sequel.value_list([[1, 2], [3, 4]])) # SQL: (a, b) IN ((1, 2), (3, 4))
|
|
613
|
+
def value_list(arg)
|
|
614
|
+
raise Error, 'argument to Sequel.value_list must be an array' unless arg.is_a?(Array)
|
|
615
|
+
SQL::ValueList.new(arg)
|
|
616
|
+
end
|
|
617
|
+
end
|
|
618
|
+
|
|
267
619
|
# Holds methods that are used to cast objects to different SQL types.
|
|
268
620
|
module CastMethods
|
|
269
621
|
# Cast the reciever to the given SQL type. You can specify a ruby class as a type,
|
|
270
622
|
# and it is handled similarly to using a database independent type in the schema methods.
|
|
271
623
|
#
|
|
272
|
-
# :
|
|
273
|
-
# :
|
|
624
|
+
# Sequel.function(:func).cast(:integer) # CAST(func() AS integer)
|
|
625
|
+
# Sequel.function(:func).cast(String) # CAST(func() AS varchar(255))
|
|
274
626
|
def cast(sql_type)
|
|
275
627
|
Cast.new(self, sql_type)
|
|
276
628
|
end
|
|
@@ -279,8 +631,8 @@ module Sequel
|
|
|
279
631
|
# and return the result as a +NumericExpression+, so you can use the bitwise operators
|
|
280
632
|
# on the result.
|
|
281
633
|
#
|
|
282
|
-
# :
|
|
283
|
-
# :
|
|
634
|
+
# Sequel.function(:func).cast_numeric # CAST(func() AS integer)
|
|
635
|
+
# Sequel.function(:func).cast_numeric(Float) # CAST(func() AS double precision)
|
|
284
636
|
def cast_numeric(sql_type = nil)
|
|
285
637
|
cast(sql_type || Integer).sql_number
|
|
286
638
|
end
|
|
@@ -289,13 +641,13 @@ module Sequel
|
|
|
289
641
|
# and return the result as a +StringExpression+, so you can use +
|
|
290
642
|
# directly on the result for SQL string concatenation.
|
|
291
643
|
#
|
|
292
|
-
# :
|
|
293
|
-
# :
|
|
644
|
+
# Sequel.function(:func).cast_string # CAST(func() AS varchar(255))
|
|
645
|
+
# Sequel.function(:func).cast_string(:text) # CAST(func() AS text)
|
|
294
646
|
def cast_string(sql_type = nil)
|
|
295
647
|
cast(sql_type || String).sql_string
|
|
296
648
|
end
|
|
297
649
|
end
|
|
298
|
-
|
|
650
|
+
|
|
299
651
|
# Adds methods that allow you to treat an object as an instance of a specific
|
|
300
652
|
# +ComplexExpression+ subclass. This is useful if another library
|
|
301
653
|
# overrides the methods defined by Sequel.
|
|
@@ -310,18 +662,14 @@ module Sequel
|
|
|
310
662
|
#
|
|
311
663
|
# :price.sql_number/10 > 100
|
|
312
664
|
module ComplexExpressionMethods
|
|
313
|
-
# Extract a
|
|
665
|
+
# Extract a datetime part (e.g. year, month) from self:
|
|
314
666
|
#
|
|
315
667
|
# :date.extract(:year) # extract(year FROM "date")
|
|
316
668
|
#
|
|
317
669
|
# Also has the benefit of returning the result as a
|
|
318
670
|
# 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
671
|
def extract(datetime_part)
|
|
324
|
-
|
|
672
|
+
NumericExpression.new(:extract, datetime_part, self)
|
|
325
673
|
end
|
|
326
674
|
|
|
327
675
|
# Return a BooleanExpression representation of +self+.
|
|
@@ -346,55 +694,21 @@ module Sequel
|
|
|
346
694
|
end
|
|
347
695
|
end
|
|
348
696
|
|
|
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
697
|
# 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>).
|
|
698
|
+
# used in a numeric or string context in SQL.
|
|
363
699
|
#
|
|
364
|
-
# 'a'
|
|
365
|
-
# 'a'
|
|
366
|
-
# 'a'
|
|
367
|
-
# 'a'
|
|
700
|
+
# Sequel.lit('a') > :b # a > "b"
|
|
701
|
+
# Sequel.lit('a') < :b # a > "b"
|
|
702
|
+
# Sequel.lit('a') >= :b # a >= "b"
|
|
703
|
+
# Sequel.lit('a') <= :b # a <= "b"
|
|
368
704
|
module InequalityMethods
|
|
369
705
|
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
|
|
706
|
+
module_eval("def #{o}(o) BooleanExpression.new(#{o.inspect}, self, o) end", __FILE__, __LINE__)
|
|
378
707
|
end
|
|
379
708
|
end
|
|
380
709
|
|
|
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.
|
|
710
|
+
# Only exists for backwards compatibility, ignore it.
|
|
386
711
|
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
712
|
end
|
|
399
713
|
|
|
400
714
|
# This module includes the standard mathematical methods (+, -, *, and /)
|
|
@@ -405,15 +719,66 @@ module Sequel
|
|
|
405
719
|
# :a - :b # "a" - "b"
|
|
406
720
|
# :a * :b # "a" * "b"
|
|
407
721
|
# :a / :b # "a" / "b"
|
|
722
|
+
#
|
|
723
|
+
# One exception to this is if + is called with a +String+ or +StringExpression+,
|
|
724
|
+
# in which case the || operator is used instead of the + operator:
|
|
725
|
+
#
|
|
726
|
+
# :a + 'b' # "a" || 'b'
|
|
408
727
|
module NumericMethods
|
|
409
728
|
ComplexExpression::MATHEMATICAL_OPERATORS.each do |o|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
729
|
+
module_eval("def #{o}(o) NumericExpression.new(#{o.inspect}, self, o) end", __FILE__, __LINE__) unless o == :+
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
# Use || as the operator when called with StringExpression and String instances,
|
|
733
|
+
# and the + operator for LiteralStrings and all other types.
|
|
734
|
+
def +(ce)
|
|
735
|
+
case ce
|
|
736
|
+
when LiteralString
|
|
737
|
+
NumericExpression.new(:+, self, ce)
|
|
738
|
+
when StringExpression, String
|
|
739
|
+
StringExpression.new(:'||', self, ce)
|
|
740
|
+
else
|
|
741
|
+
NumericExpression.new(:+, self, ce)
|
|
742
|
+
end
|
|
743
|
+
end
|
|
744
|
+
end
|
|
745
|
+
|
|
746
|
+
# These methods are designed as replacements for the core extension operator
|
|
747
|
+
# methods, so that Sequel is still easy to use if the core extensions are not
|
|
748
|
+
# enabled.
|
|
749
|
+
#
|
|
750
|
+
# The following methods are defined via metaprogramming: +, -, *, /, &, |.
|
|
751
|
+
# The +, -, *, and / operators return numeric expressions combining all the
|
|
752
|
+
# arguments with the appropriate operator, and the & and | operators return
|
|
753
|
+
# boolean expressions combining all of the arguments with either AND or OR.
|
|
754
|
+
module OperatorBuilders
|
|
755
|
+
%w'+ - * /'.each do |op|
|
|
756
|
+
class_eval(<<-END, __FILE__, __LINE__ + 1)
|
|
757
|
+
def #{op}(*args)
|
|
758
|
+
SQL::NumericExpression.new(:#{op}, *args)
|
|
416
759
|
end
|
|
760
|
+
END
|
|
761
|
+
end
|
|
762
|
+
|
|
763
|
+
{'&'=>'AND', '|'=>'OR'}.each do |m, op|
|
|
764
|
+
class_eval(<<-END, __FILE__, __LINE__ + 1)
|
|
765
|
+
def #{m}(*args)
|
|
766
|
+
SQL::BooleanExpression.new(:#{op}, *args)
|
|
767
|
+
end
|
|
768
|
+
END
|
|
769
|
+
end
|
|
770
|
+
|
|
771
|
+
# Invert the given expression. Returns a <tt>Sequel::SQL::BooleanExpression</tt>
|
|
772
|
+
# created from this argument, not matching all of the conditions.
|
|
773
|
+
#
|
|
774
|
+
# Sequel.~(nil) # SQL: NOT NULL
|
|
775
|
+
# Sequel.~([[:a, true]]) # SQL: a IS NOT TRUE
|
|
776
|
+
# Sequel.~([[:a, 1], [:b, [2, 3]]]) # SQL: a != 1 OR b NOT IN (2, 3)
|
|
777
|
+
def ~(arg)
|
|
778
|
+
if condition_specifier?(arg)
|
|
779
|
+
SQL::BooleanExpression.from_value_pairs(arg, :OR, true)
|
|
780
|
+
else
|
|
781
|
+
SQL::BooleanExpression.invert(arg)
|
|
417
782
|
end
|
|
418
783
|
end
|
|
419
784
|
end
|
|
@@ -443,13 +808,25 @@ module Sequel
|
|
|
443
808
|
end
|
|
444
809
|
|
|
445
810
|
# 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
|
|
811
|
+
# names with a table or table names with a schema, and the * method for returning all columns in
|
|
812
|
+
# the identifier if no arguments are given.
|
|
447
813
|
module QualifyingMethods
|
|
814
|
+
# If no arguments are given, return an SQL::ColumnAll:
|
|
815
|
+
#
|
|
816
|
+
# Sequel.expr(:a__b).* # a.b.*
|
|
817
|
+
def *(ce=(arg=false;nil))
|
|
818
|
+
if arg == false
|
|
819
|
+
Sequel::SQL::ColumnAll.new(self)
|
|
820
|
+
else
|
|
821
|
+
super(ce)
|
|
822
|
+
end
|
|
823
|
+
end
|
|
824
|
+
|
|
448
825
|
# Qualify the receiver with the given +qualifier+ (table for column/schema for table).
|
|
449
826
|
#
|
|
450
|
-
# :column.qualify(:table) # "table"."column"
|
|
451
|
-
# :table.qualify(:schema) # "schema"."table"
|
|
452
|
-
#
|
|
827
|
+
# Sequel.expr(:column).qualify(:table) # "table"."column"
|
|
828
|
+
# Sequel.expr(:table).qualify(:schema) # "schema"."table"
|
|
829
|
+
# Sequel.qualify(:table, :column).qualify(:schema) # "schema"."table"."column"
|
|
453
830
|
def qualify(qualifier)
|
|
454
831
|
QualifiedIdentifier.new(qualifier, self)
|
|
455
832
|
end
|
|
@@ -523,8 +900,16 @@ module Sequel
|
|
|
523
900
|
# stored as a blob type in the database. Sequel represents binary data as a Blob object because
|
|
524
901
|
# most database engines require binary data to be escaped differently than regular strings.
|
|
525
902
|
class Blob < ::String
|
|
526
|
-
|
|
527
|
-
|
|
903
|
+
include SQL::AliasMethods
|
|
904
|
+
include SQL::CastMethods
|
|
905
|
+
|
|
906
|
+
# Return a LiteralString with the same content if no args are given, otherwise
|
|
907
|
+
# return a SQL::PlaceholderLiteralString with the current string and the given args.
|
|
908
|
+
def lit(*args)
|
|
909
|
+
args.empty? ? LiteralString.new(self) : SQL::PlaceholderLiteralString.new(self, args)
|
|
910
|
+
end
|
|
911
|
+
|
|
912
|
+
# Returns +self+, since it is already a blob.
|
|
528
913
|
def to_sequel_blob
|
|
529
914
|
self
|
|
530
915
|
end
|
|
@@ -595,10 +980,27 @@ module Sequel
|
|
|
595
980
|
end
|
|
596
981
|
when StringExpression, NumericExpression
|
|
597
982
|
raise(Sequel::Error, "cannot invert #{ce.inspect}")
|
|
983
|
+
when Constant
|
|
984
|
+
CONSTANT_INVERSIONS[ce] || raise(Sequel::Error, "cannot invert #{ce.inspect}")
|
|
598
985
|
else
|
|
599
986
|
BooleanExpression.new(:NOT, ce)
|
|
600
987
|
end
|
|
601
988
|
end
|
|
989
|
+
|
|
990
|
+
# Always use an AND operator for & on BooleanExpressions
|
|
991
|
+
def &(ce)
|
|
992
|
+
BooleanExpression.new(:AND, self, ce)
|
|
993
|
+
end
|
|
994
|
+
|
|
995
|
+
# Always use an OR operator for | on BooleanExpressions
|
|
996
|
+
def |(ce)
|
|
997
|
+
BooleanExpression.new(:OR, self, ce)
|
|
998
|
+
end
|
|
999
|
+
|
|
1000
|
+
# Return self instead of creating a new object to save on memory.
|
|
1001
|
+
def sql_boolean
|
|
1002
|
+
self
|
|
1003
|
+
end
|
|
602
1004
|
end
|
|
603
1005
|
|
|
604
1006
|
# Represents an SQL CASE expression, used for conditional branching in SQL.
|
|
@@ -666,6 +1068,21 @@ module Sequel
|
|
|
666
1068
|
include CastMethods
|
|
667
1069
|
include OrderMethods
|
|
668
1070
|
include SubscriptMethods
|
|
1071
|
+
|
|
1072
|
+
# Return a BooleanExpression with the same op and args.
|
|
1073
|
+
def sql_boolean
|
|
1074
|
+
BooleanExpression.new(self.op, *self.args)
|
|
1075
|
+
end
|
|
1076
|
+
|
|
1077
|
+
# Return a NumericExpression with the same op and args.
|
|
1078
|
+
def sql_number
|
|
1079
|
+
NumericExpression.new(self.op, *self.args)
|
|
1080
|
+
end
|
|
1081
|
+
|
|
1082
|
+
# Return a StringExpression with the same op and args.
|
|
1083
|
+
def sql_string
|
|
1084
|
+
StringExpression.new(self.op, *self.args)
|
|
1085
|
+
end
|
|
669
1086
|
end
|
|
670
1087
|
|
|
671
1088
|
# Represents constants or psuedo-constants (e.g. +CURRENT_DATE+) in SQL.
|
|
@@ -688,7 +1105,7 @@ module Sequel
|
|
|
688
1105
|
|
|
689
1106
|
# Represents inverse boolean constants (currently only +NOTNULL+). A
|
|
690
1107
|
# special class to allow for special behavior.
|
|
691
|
-
class NegativeBooleanConstant <
|
|
1108
|
+
class NegativeBooleanConstant < Constant
|
|
692
1109
|
to_s_method :negative_boolean_constant_sql, '@constant'
|
|
693
1110
|
end
|
|
694
1111
|
|
|
@@ -706,14 +1123,20 @@ module Sequel
|
|
|
706
1123
|
NOTNULL = NegativeBooleanConstant.new(nil)
|
|
707
1124
|
end
|
|
708
1125
|
|
|
1126
|
+
class ComplexExpression
|
|
1127
|
+
# A hash of the opposite for each constant, used for inverting constants.
|
|
1128
|
+
CONSTANT_INVERSIONS = {Constants::TRUE=>Constants::FALSE, Constants::FALSE=>Constants::TRUE,
|
|
1129
|
+
Constants::NULL=>Constants::NOTNULL, Constants::NOTNULL=>Constants::NULL}
|
|
1130
|
+
end
|
|
1131
|
+
|
|
709
1132
|
# Represents an SQL function call.
|
|
710
1133
|
class Function < GenericExpression
|
|
711
|
-
# The array of arguments to pass to the function (may be blank)
|
|
712
|
-
attr_reader :args
|
|
713
|
-
|
|
714
1134
|
# The SQL function to call
|
|
715
1135
|
attr_reader :f
|
|
716
1136
|
|
|
1137
|
+
# The array of arguments to pass to the function (may be blank)
|
|
1138
|
+
attr_reader :args
|
|
1139
|
+
|
|
717
1140
|
# Set the functions and args to the given arguments
|
|
718
1141
|
def initialize(f, *args)
|
|
719
1142
|
@f, @args = f, args
|
|
@@ -721,6 +1144,12 @@ module Sequel
|
|
|
721
1144
|
|
|
722
1145
|
to_s_method :function_sql
|
|
723
1146
|
end
|
|
1147
|
+
|
|
1148
|
+
# Represents an SQL function call that is translated/emulated
|
|
1149
|
+
# on databases that lack support for such a function.
|
|
1150
|
+
class EmulatedFunction < Function
|
|
1151
|
+
to_s_method :emulated_function_sql
|
|
1152
|
+
end
|
|
724
1153
|
|
|
725
1154
|
class GenericExpression
|
|
726
1155
|
include AliasMethods
|
|
@@ -806,15 +1235,16 @@ module Sequel
|
|
|
806
1235
|
# required for the prepared statement support and for database-specific
|
|
807
1236
|
# literalization.
|
|
808
1237
|
class PlaceholderLiteralString < GenericExpression
|
|
1238
|
+
# The literal string containing placeholders. This can also be an array
|
|
1239
|
+
# of strings, where each arg in args goes between the string elements.
|
|
1240
|
+
attr_reader :str
|
|
1241
|
+
|
|
809
1242
|
# The arguments that will be subsituted into the placeholders.
|
|
810
1243
|
# Either an array of unnamed placeholders (which will be substituted in
|
|
811
1244
|
# order for ? characters), or a hash of named placeholders (which will be
|
|
812
1245
|
# substituted for :key phrases).
|
|
813
1246
|
attr_reader :args
|
|
814
1247
|
|
|
815
|
-
# The literal string containing placeholders
|
|
816
|
-
attr_reader :str
|
|
817
|
-
|
|
818
1248
|
# Whether to surround the expression with parantheses
|
|
819
1249
|
attr_reader :parens
|
|
820
1250
|
|
|
@@ -834,7 +1264,16 @@ module Sequel
|
|
|
834
1264
|
include BitwiseMethods
|
|
835
1265
|
include NumericMethods
|
|
836
1266
|
include InequalityMethods
|
|
837
|
-
|
|
1267
|
+
|
|
1268
|
+
# Always use + for + operator for NumericExpressions.
|
|
1269
|
+
def +(ce)
|
|
1270
|
+
NumericExpression.new(:+, self, ce)
|
|
1271
|
+
end
|
|
1272
|
+
|
|
1273
|
+
# Return self instead of creating a new object to save on memory.
|
|
1274
|
+
def sql_number
|
|
1275
|
+
self
|
|
1276
|
+
end
|
|
838
1277
|
end
|
|
839
1278
|
|
|
840
1279
|
# Represents a column/expression to order the result set by.
|
|
@@ -880,18 +1319,18 @@ module Sequel
|
|
|
880
1319
|
class QualifiedIdentifier < GenericExpression
|
|
881
1320
|
include QualifyingMethods
|
|
882
1321
|
|
|
883
|
-
# The column/table referenced
|
|
884
|
-
attr_reader :column
|
|
885
|
-
|
|
886
1322
|
# The table/schema qualifying the reference
|
|
887
1323
|
attr_reader :table
|
|
888
1324
|
|
|
1325
|
+
# The column/table referenced
|
|
1326
|
+
attr_reader :column
|
|
1327
|
+
|
|
889
1328
|
# Set the table and column to the given arguments
|
|
890
1329
|
def initialize(table, column)
|
|
891
1330
|
@table, @column = table, column
|
|
892
1331
|
end
|
|
893
1332
|
|
|
894
|
-
to_s_method :qualified_identifier_sql
|
|
1333
|
+
to_s_method :qualified_identifier_sql, "@table, @column"
|
|
895
1334
|
end
|
|
896
1335
|
|
|
897
1336
|
# Subclass of +ComplexExpression+ where the expression results
|
|
@@ -900,7 +1339,6 @@ module Sequel
|
|
|
900
1339
|
include StringMethods
|
|
901
1340
|
include StringConcatenationMethods
|
|
902
1341
|
include InequalityMethods
|
|
903
|
-
include NoBooleanInputMethods
|
|
904
1342
|
|
|
905
1343
|
# Map of [regexp, case_insenstive] to +ComplexExpression+ operator symbol
|
|
906
1344
|
LIKE_MAP = {[true, true]=>:'~*', [true, false]=>:~, [false, true]=>:ILIKE, [false, false]=>:LIKE}
|
|
@@ -949,6 +1387,11 @@ module Sequel
|
|
|
949
1387
|
end
|
|
950
1388
|
end
|
|
951
1389
|
private_class_method :like_element
|
|
1390
|
+
|
|
1391
|
+
# Return self instead of creating a new object to save on memory.
|
|
1392
|
+
def sql_string
|
|
1393
|
+
self
|
|
1394
|
+
end
|
|
952
1395
|
end
|
|
953
1396
|
|
|
954
1397
|
# Represents an SQL array access, with multiple possible arguments.
|
|
@@ -966,9 +1409,21 @@ module Sequel
|
|
|
966
1409
|
|
|
967
1410
|
# Create a new +Subscript+ appending the given subscript(s)
|
|
968
1411
|
# the the current array of subscripts.
|
|
1412
|
+
#
|
|
1413
|
+
# :a.sql_subscript(2) # a[2]
|
|
1414
|
+
# :a.sql_subscript(2) | 1 # a[2, 1]
|
|
969
1415
|
def |(sub)
|
|
970
1416
|
Subscript.new(@f, @sub + Array(sub))
|
|
971
1417
|
end
|
|
1418
|
+
|
|
1419
|
+
# Create a new +Subscript+ by accessing a subarray of a multidimensional
|
|
1420
|
+
# array.
|
|
1421
|
+
#
|
|
1422
|
+
# :a.sql_subscript(2) # a[2]
|
|
1423
|
+
# :a.sql_subscript(2)[1] # a[2][1]
|
|
1424
|
+
def [](sub)
|
|
1425
|
+
Subscript.new(self, Array(sub))
|
|
1426
|
+
end
|
|
972
1427
|
|
|
973
1428
|
to_s_method :subscript_sql
|
|
974
1429
|
end
|
|
@@ -1019,28 +1474,71 @@ module Sequel
|
|
|
1019
1474
|
# Examples:
|
|
1020
1475
|
#
|
|
1021
1476
|
# ds = DB[:t]
|
|
1477
|
+
#
|
|
1022
1478
|
# # Argument yielded to block
|
|
1023
1479
|
# ds.filter{|r| r.name < 2} # SELECT * FROM t WHERE (name < 2)
|
|
1480
|
+
#
|
|
1024
1481
|
# # Block without argument (instance_eval)
|
|
1025
1482
|
# ds.filter{name < 2} # SELECT * FROM t WHERE (name < 2)
|
|
1483
|
+
#
|
|
1026
1484
|
# # Qualified identifiers
|
|
1027
1485
|
# ds.filter{table__column + 1 < 2} # SELECT * FROM t WHERE ((table.column + 1) < 2)
|
|
1486
|
+
#
|
|
1028
1487
|
# # Functions
|
|
1029
1488
|
# ds.filter{is_active(1, 'arg2')} # SELECT * FROM t WHERE is_active(1, 'arg2')
|
|
1030
1489
|
# ds.select{version{}} # SELECT version() FROM t
|
|
1031
1490
|
# ds.select{count(:*){}} # SELECT count(*) FROM t
|
|
1032
1491
|
# ds.select{count(:distinct, col1){}} # SELECT count(DISTINCT col1) FROM t
|
|
1492
|
+
#
|
|
1033
1493
|
# # Window Functions
|
|
1034
1494
|
# ds.select{rank(:over){}} # SELECT rank() OVER () FROM t
|
|
1035
1495
|
# ds.select{count(:over, :*=>true){}} # SELECT count(*) OVER () FROM t
|
|
1036
1496
|
# ds.select{sum(:over, :args=>col1, :partition=>col2, :order=>col3){}} # SELECT sum(col1) OVER (PARTITION BY col2 ORDER BY col3) FROM t
|
|
1037
1497
|
#
|
|
1498
|
+
# # Math Operators
|
|
1499
|
+
# ds.select{|o| o.+(1, :a).as(:b)} # SELECT (1 + a) AS b FROM t
|
|
1500
|
+
# ds.select{|o| o.-(2, :a).as(:b)} # SELECT (2 - a) AS b FROM t
|
|
1501
|
+
# ds.select{|o| o.*(3, :a).as(:b)} # SELECT (3 * a) AS b FROM t
|
|
1502
|
+
# ds.select{|o| o./(4, :a).as(:b)} # SELECT (4 / a) AS b FROM t
|
|
1503
|
+
#
|
|
1504
|
+
# # Boolean Operators
|
|
1505
|
+
# ds.filter{|o| o.&({:a=>1}, :b)} # SELECT * FROM t WHERE ((a = 1) AND b)
|
|
1506
|
+
# ds.filter{|o| o.|({:a=>1}, :b)} # SELECT * FROM t WHERE ((a = 1) OR b)
|
|
1507
|
+
# ds.filter{|o| o.~({:a=>1})} # SELECT * FROM t WHERE (a != 1)
|
|
1508
|
+
# ds.filter{|o| o.~({:a=>1, :b=>2})} # SELECT * FROM t WHERE ((a != 1) OR (b != 2))
|
|
1509
|
+
#
|
|
1510
|
+
# # Inequality Operators
|
|
1511
|
+
# ds.filter{|o| o.>(1, :a)} # SELECT * FROM t WHERE (1 > a)
|
|
1512
|
+
# ds.filter{|o| o.<(2, :a)} # SELECT * FROM t WHERE (2 < a)
|
|
1513
|
+
# ds.filter{|o| o.>=(3, :a)} # SELECT * FROM t WHERE (3 >= a)
|
|
1514
|
+
# ds.filter{|o| o.<=(4, :a)} # SELECT * FROM t WHERE (4 <= a)
|
|
1515
|
+
#
|
|
1516
|
+
# # Literal Strings
|
|
1517
|
+
# ds.filter{{a=>`some SQL`}} # SELECT * FROM t WHERE (a = some SQL)
|
|
1518
|
+
#
|
|
1038
1519
|
# For a more detailed explanation, see the {Virtual Rows guide}[link:files/doc/virtual_rows_rdoc.html].
|
|
1039
1520
|
class VirtualRow < BasicObject
|
|
1040
1521
|
WILDCARD = LiteralString.new('*').freeze
|
|
1041
1522
|
QUESTION_MARK = LiteralString.new('?').freeze
|
|
1042
1523
|
COMMA_SEPARATOR = LiteralString.new(', ').freeze
|
|
1043
1524
|
DOUBLE_UNDERSCORE = '__'.freeze
|
|
1525
|
+
DISTINCT = ["DISTINCT ".freeze].freeze
|
|
1526
|
+
COMMA_ARRAY = [COMMA_SEPARATOR].freeze
|
|
1527
|
+
|
|
1528
|
+
include OperatorBuilders
|
|
1529
|
+
|
|
1530
|
+
%w'> < >= <='.each do |op|
|
|
1531
|
+
class_eval(<<-END, __FILE__, __LINE__ + 1)
|
|
1532
|
+
def #{op}(*args)
|
|
1533
|
+
SQL::BooleanExpression.new(:#{op}, *args)
|
|
1534
|
+
end
|
|
1535
|
+
END
|
|
1536
|
+
end
|
|
1537
|
+
|
|
1538
|
+
# Return a literal string created with the given string.
|
|
1539
|
+
def `(s)
|
|
1540
|
+
Sequel::LiteralString.new(s)
|
|
1541
|
+
end
|
|
1044
1542
|
|
|
1045
1543
|
# Return an +Identifier+, +QualifiedIdentifier+, +Function+, or +WindowFunction+, depending
|
|
1046
1544
|
# on arguments and whether a block is provided. Does not currently call the block.
|
|
@@ -1054,7 +1552,7 @@ module Sequel
|
|
|
1054
1552
|
when :*
|
|
1055
1553
|
Function.new(m, WILDCARD)
|
|
1056
1554
|
when :distinct
|
|
1057
|
-
Function.new(m, PlaceholderLiteralString.new(
|
|
1555
|
+
Function.new(m, PlaceholderLiteralString.new(DISTINCT + COMMA_ARRAY * (args.length-1), args))
|
|
1058
1556
|
when :over
|
|
1059
1557
|
opts = args.shift || {}
|
|
1060
1558
|
fun_args = ::Kernel.Array(opts[:*] ? WILDCARD : opts[:args])
|
|
@@ -1108,6 +1606,20 @@ module Sequel
|
|
|
1108
1606
|
|
|
1109
1607
|
to_s_method :window_function_sql, '@function, @window'
|
|
1110
1608
|
end
|
|
1609
|
+
|
|
1610
|
+
# A +Wrapper+ is a simple way to wrap an existing object so that it supports
|
|
1611
|
+
# the Sequel DSL.
|
|
1612
|
+
class Wrapper < GenericExpression
|
|
1613
|
+
# The underlying value wrapped by this object.
|
|
1614
|
+
attr_reader :value
|
|
1615
|
+
|
|
1616
|
+
# Set the value wrapped by the object.
|
|
1617
|
+
def initialize(value)
|
|
1618
|
+
@value = value
|
|
1619
|
+
end
|
|
1620
|
+
|
|
1621
|
+
to_s_method :literal, '@value'
|
|
1622
|
+
end
|
|
1111
1623
|
end
|
|
1112
1624
|
|
|
1113
1625
|
# +LiteralString+ is used to represent literal SQL expressions. A
|
|
@@ -1120,7 +1632,22 @@ module Sequel
|
|
|
1120
1632
|
include SQL::NumericMethods
|
|
1121
1633
|
include SQL::StringMethods
|
|
1122
1634
|
include SQL::InequalityMethods
|
|
1635
|
+
include SQL::AliasMethods
|
|
1636
|
+
include SQL::CastMethods
|
|
1637
|
+
|
|
1638
|
+
# Return self if no args are given, otherwise return a SQL::PlaceholderLiteralString
|
|
1639
|
+
# with the current string and the given args.
|
|
1640
|
+
def lit(*args)
|
|
1641
|
+
args.empty? ? self : SQL::PlaceholderLiteralString.new(self, args)
|
|
1642
|
+
end
|
|
1643
|
+
|
|
1644
|
+
# Convert a literal string to a SQL::Blob.
|
|
1645
|
+
def to_sequel_blob
|
|
1646
|
+
SQL::Blob.new(self)
|
|
1647
|
+
end
|
|
1123
1648
|
end
|
|
1124
1649
|
|
|
1125
1650
|
include SQL::Constants
|
|
1651
|
+
extend SQL::Builders
|
|
1652
|
+
extend SQL::OperatorBuilders
|
|
1126
1653
|
end
|