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
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# The pg_row_ops extension adds support to Sequel's DSL to make
|
|
2
|
+
# it easier to deal with PostgreSQL row-valued/composite types.
|
|
3
|
+
#
|
|
4
|
+
# To load the extension:
|
|
5
|
+
#
|
|
6
|
+
# Sequel.extension :pg_row_ops
|
|
7
|
+
#
|
|
8
|
+
# The most common usage is passing an expression to Sequel.pg_row_op:
|
|
9
|
+
#
|
|
10
|
+
# r = Sequel.pg_row_op(:row_column)
|
|
11
|
+
#
|
|
12
|
+
# If you have also loaded the pg_row extension, you can use
|
|
13
|
+
# Sequel.pg_row as well:
|
|
14
|
+
#
|
|
15
|
+
# r = Sequel.pg_row(:row_column)
|
|
16
|
+
#
|
|
17
|
+
# Also, on most Sequel expression objects, you can call the pg_row
|
|
18
|
+
# method:
|
|
19
|
+
#
|
|
20
|
+
# r = Sequel.expr(:row_column).pg_row
|
|
21
|
+
#
|
|
22
|
+
# If you have loaded the {core_extensions extension}[link:files/doc/core_extensions_rdoc.html]),
|
|
23
|
+
# you can also call Symbol#pg_row:
|
|
24
|
+
#
|
|
25
|
+
# r = :row_column.pg_row
|
|
26
|
+
#
|
|
27
|
+
# There's only fairly basic support currently. You can use the [] method to access
|
|
28
|
+
# a member of the composite type:
|
|
29
|
+
#
|
|
30
|
+
# r[:a] # (row_column).a
|
|
31
|
+
#
|
|
32
|
+
# This can be chained:
|
|
33
|
+
#
|
|
34
|
+
# r[:a][:b] # ((row_column).a).b
|
|
35
|
+
#
|
|
36
|
+
# If you've loaded the pg_array_ops extension, you there is also support for composite
|
|
37
|
+
# types that include arrays, or arrays of composite types:
|
|
38
|
+
#
|
|
39
|
+
# r[1][:a] # (row_column[1]).a
|
|
40
|
+
# r[:a][1] # (row_column).a[1]
|
|
41
|
+
#
|
|
42
|
+
# The only other support is the splat method:
|
|
43
|
+
#
|
|
44
|
+
# r.splat # (row_column.*)
|
|
45
|
+
#
|
|
46
|
+
# The splat method is necessary if you are trying to reference a table's type when the
|
|
47
|
+
# table has the same name as one of it's columns. For example:
|
|
48
|
+
#
|
|
49
|
+
# DB.create_table(:a){Integer :a; Integer :b}
|
|
50
|
+
#
|
|
51
|
+
# Let's say you want to reference the composite type for the table:
|
|
52
|
+
#
|
|
53
|
+
# a = Sequel.pg_row_op(:a)
|
|
54
|
+
# DB[:a].select(a[:b]) # SELECT (a).b FROM a
|
|
55
|
+
#
|
|
56
|
+
# Unfortunately, that doesn't work, as it references the integer column, not the table.
|
|
57
|
+
# The splat method works around this:
|
|
58
|
+
#
|
|
59
|
+
# DB[:a].select(a.splat[:b]) # SELECT (a.*).b FROM a
|
|
60
|
+
#
|
|
61
|
+
# Splat also takes an argument which is used for casting. This is necessary if you
|
|
62
|
+
# want to return the composite type itself, instead of the columns in the composite
|
|
63
|
+
# type. For example:
|
|
64
|
+
#
|
|
65
|
+
# DB[:a].select(a.splat).first # SELECT (a.*) FROM a
|
|
66
|
+
# # => {:a=>1, :b=>2}
|
|
67
|
+
#
|
|
68
|
+
# By casting the expression, you can get a composite type returned:
|
|
69
|
+
#
|
|
70
|
+
# DB[:a].select(a.splat).first # SELECT (a.*)::a FROM a
|
|
71
|
+
# # => {:a=>"(1,2)"} # or {:a=>{:a=>1, :b=>2}} if the "a" type has been registered
|
|
72
|
+
# # with the the pg_row extension
|
|
73
|
+
#
|
|
74
|
+
# This feature is mostly useful for a different way to graph tables:
|
|
75
|
+
#
|
|
76
|
+
# DB[:a].join(:b, :id=>:b_id).select(Sequel.pg_row_op(:a).splat(:a),
|
|
77
|
+
# Sequel.pg_row_op(:b).splat(:b))
|
|
78
|
+
# # SELECT (a.*)::a, (b.*)::b FROM a INNER JOIN b ON (b.id = a.b_id)
|
|
79
|
+
# # => {:a=>{:id=>1, :b_id=>2}, :b=>{:id=>2}}
|
|
80
|
+
|
|
81
|
+
module Sequel
|
|
82
|
+
module Postgres
|
|
83
|
+
# This class represents a composite type expression reference.
|
|
84
|
+
class PGRowOp < SQL::PlaceholderLiteralString
|
|
85
|
+
OPEN = '('.freeze
|
|
86
|
+
CLOSE_DOT = ').'.freeze
|
|
87
|
+
CLOSE_STAR = '.*)'.freeze
|
|
88
|
+
CLOSE_STAR_CAST = '.*)::'.freeze
|
|
89
|
+
EMPTY = "".freeze
|
|
90
|
+
ROW = [OPEN, CLOSE_STAR].freeze
|
|
91
|
+
ROW_CAST = [OPEN, CLOSE_STAR_CAST].freeze
|
|
92
|
+
QUALIFY = [OPEN, CLOSE_DOT].freeze
|
|
93
|
+
WRAP = [EMPTY].freeze
|
|
94
|
+
|
|
95
|
+
# Wrap the expression in a PGRowOp, without changing the
|
|
96
|
+
# SQL it would use.
|
|
97
|
+
def self.wrap(expr)
|
|
98
|
+
PGRowOp.new(WRAP, [expr])
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Access a member of the composite type if given a
|
|
102
|
+
# symbol or an SQL::Identifier. For all other access,
|
|
103
|
+
# assuming the pg_array_ops extension is loaded and
|
|
104
|
+
# that it represents an array access. In either
|
|
105
|
+
# case, return a PgRowOp so that access can be cascaded.
|
|
106
|
+
def [](member)
|
|
107
|
+
case member
|
|
108
|
+
when Symbol, SQL::Identifier
|
|
109
|
+
PGRowOp.new(QUALIFY, [self, member])
|
|
110
|
+
else
|
|
111
|
+
PGRowOp.wrap(Sequel.pg_array_op(self)[member])
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Use the (identifier).* syntax to reference the members
|
|
116
|
+
# of the composite type as separate columns. Generally
|
|
117
|
+
# used when you want to expand the columns of a composite
|
|
118
|
+
# type to be separate columns in the result set.
|
|
119
|
+
#
|
|
120
|
+
# Sequel.pg_row_op(:a).* # (a).*
|
|
121
|
+
# Sequel.pg_row_op(:a)[:b].* # ((a).b).*
|
|
122
|
+
def *(ce=(arg=false;nil))
|
|
123
|
+
if arg == false
|
|
124
|
+
Sequel::SQL::ColumnAll.new([self])
|
|
125
|
+
else
|
|
126
|
+
super(ce)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Use the (identifier.*) syntax to indicate that this
|
|
131
|
+
# expression represents the composite type of one
|
|
132
|
+
# of the tables being referenced, if it has the same
|
|
133
|
+
# name as one of the columns. If the cast_to argument
|
|
134
|
+
# is given, also cast the expression to that type
|
|
135
|
+
# (which should be a symbol representing the composite type).
|
|
136
|
+
# This is used if you want to return whole table row as a
|
|
137
|
+
# composite type.
|
|
138
|
+
#
|
|
139
|
+
# Sequel.pg_row_op(:a).splat[:b] # (a.*).b
|
|
140
|
+
# Sequel.pg_row_op(:a).splat(:a) # (a.*)::a
|
|
141
|
+
def splat(cast_to=nil)
|
|
142
|
+
if args.length > 1
|
|
143
|
+
raise Error, 'cannot splat a PGRowOp with multiple arguments'
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
if cast_to
|
|
147
|
+
PGRowOp.new(ROW_CAST, args + [cast_to])
|
|
148
|
+
else
|
|
149
|
+
PGRowOp.new(ROW, args)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
module ExpressionMethods
|
|
154
|
+
# Return a PGRowOp wrapping the receiver.
|
|
155
|
+
def pg_row
|
|
156
|
+
Sequel.pg_row_op(self)
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
module SQL::Builders
|
|
163
|
+
# Return a PGRowOp wrapping the given expression.
|
|
164
|
+
def pg_row_op(expr)
|
|
165
|
+
Postgres::PGRowOp.wrap(expr)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
class SQL::GenericExpression
|
|
170
|
+
include Sequel::Postgres::PGRowOp::ExpressionMethods
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
class LiteralString
|
|
174
|
+
include Sequel::Postgres::PGRowOp::ExpressionMethods
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
if Sequel.core_extensions?
|
|
179
|
+
class Symbol
|
|
180
|
+
include Sequel::Postgres::PGRowOp::ExpressionMethods
|
|
181
|
+
end
|
|
182
|
+
end
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
# This extension adds a statement cache to Sequel's postgres adapter,
|
|
2
|
+
# with the ability to automatically prepare statements that are
|
|
3
|
+
# executed repeatedly. When combined with the pg_auto_parameterize
|
|
4
|
+
# extension, it can take Sequel code such as:
|
|
5
|
+
#
|
|
6
|
+
# DB.extension :pg_auto_parameterize, :pg_statement_cache
|
|
7
|
+
# DB[:table].filter(:a=>1)
|
|
8
|
+
# DB[:table].filter(:a=>2)
|
|
9
|
+
# DB[:table].filter(:a=>3)
|
|
10
|
+
#
|
|
11
|
+
# And use the same prepared statement to execute the queries.
|
|
12
|
+
#
|
|
13
|
+
# The backbone of this extension is a modified LRU cache. It considers
|
|
14
|
+
# both the last executed time and the number of executions when
|
|
15
|
+
# determining which queries to keep in the cache. It only cleans the
|
|
16
|
+
# cache when a high water mark has been passed, and removes queries
|
|
17
|
+
# until it reaches the low water mark, in order to avoid thrashing when
|
|
18
|
+
# you are using more than the maximum number of queries. To avoid
|
|
19
|
+
# preparing queries when it isn't necessary, it does not prepare them
|
|
20
|
+
# on the server side unless they are being executed more than once.
|
|
21
|
+
# The cache is very tunable, allowing you to set the high and low
|
|
22
|
+
# water marks, the number of executions before preparing the query,
|
|
23
|
+
# and even use a custom callback for determine which queries to keep
|
|
24
|
+
# in the cache.
|
|
25
|
+
#
|
|
26
|
+
# Note that automatically preparing statements does have some issues.
|
|
27
|
+
# Most notably, if you change the result type that the query returns,
|
|
28
|
+
# PostgreSQL will raise an error. This can happen if you have
|
|
29
|
+
# prepared a statement that selects all columns from a table, and then
|
|
30
|
+
# you add or remove a column from that table. This extension does
|
|
31
|
+
# attempt to check that case and clear the statement caches if you use
|
|
32
|
+
# alter_table from within Sequel, but it cannot fix the case when such
|
|
33
|
+
# a change is made externally.
|
|
34
|
+
#
|
|
35
|
+
# This extension only works when the pg driver is used as the backend
|
|
36
|
+
# for the postgres adapter.
|
|
37
|
+
|
|
38
|
+
module Sequel
|
|
39
|
+
module Postgres
|
|
40
|
+
module StatementCache
|
|
41
|
+
# A simple structure used for the values in the StatementCache's hash.
|
|
42
|
+
# It does not hold the related SQL, since that is used as the key for
|
|
43
|
+
# the StatementCache's hash.
|
|
44
|
+
class Statement
|
|
45
|
+
# The last time this statement was seen by the cache, persumably the
|
|
46
|
+
# last time it was executed.
|
|
47
|
+
attr_accessor :last_seen
|
|
48
|
+
|
|
49
|
+
# The total number of executions since the statement entered the cache.
|
|
50
|
+
attr_accessor :num_executes
|
|
51
|
+
|
|
52
|
+
# The id related to the statement, used as part of the prepared statement
|
|
53
|
+
# name.
|
|
54
|
+
attr_reader :cache_id
|
|
55
|
+
|
|
56
|
+
# Used when adding entries to the cache, just sets their id. Uses
|
|
57
|
+
# 0 for num_executes since that is incremented elsewhere. Does not
|
|
58
|
+
# set last_seen since that is set elsewhere to reduce branching.
|
|
59
|
+
def initialize(cache_id)
|
|
60
|
+
@num_executes = 0
|
|
61
|
+
@cache_id = cache_id
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# The name to use for the server side prepared statement. Note that this
|
|
65
|
+
# statement might not actually be prepared.
|
|
66
|
+
def name
|
|
67
|
+
"sequel_pgap_#{cache_id}"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# The backbone of the block, a modified LRU (least recently used) cache
|
|
72
|
+
# mapping SQL query strings to Statement objects.
|
|
73
|
+
class StatementCache
|
|
74
|
+
include Enumerable
|
|
75
|
+
|
|
76
|
+
# Set the options for the statement cache. These are generally set at
|
|
77
|
+
# the database level using the :statement_cache_opts Database option.
|
|
78
|
+
#
|
|
79
|
+
# :max_size :: The maximum size (high water mark) for the cache. If
|
|
80
|
+
# an entry is added when the current size of the cache is
|
|
81
|
+
# equal to the maximum size, the cache is cleaned up to
|
|
82
|
+
# reduce the number of entries to the :min_size. Defaults
|
|
83
|
+
# to 1000.
|
|
84
|
+
# :min_size :: The minimum size (low water mark) for the cache. On
|
|
85
|
+
# cleanup, the size of the cache is reduced to this
|
|
86
|
+
# number. Note that there could be fewer than this
|
|
87
|
+
# number of entries in the cache. Defaults to :max_size/2.
|
|
88
|
+
# :prepare_after :: The number of executions to wait for before preparing
|
|
89
|
+
# the query server-side. If set to 1, prepares all executed
|
|
90
|
+
# queries server-side. If set to 5, does not attempt to
|
|
91
|
+
# prepare the query until the 5th execution. Defaults to 2.
|
|
92
|
+
# :sorter :: A callable object that takes two arguments, the current time
|
|
93
|
+
# and the related Statement instance, and should return some
|
|
94
|
+
# Comparable (usually a numeric) such that the lowest values
|
|
95
|
+
# returned are the first to be removed when it comes time to
|
|
96
|
+
# clean the pool. The default is basically:
|
|
97
|
+
#
|
|
98
|
+
# lambda{|t, stmt| (stmt.last_seen - t)/stmt.num_executes}
|
|
99
|
+
#
|
|
100
|
+
# so that it doesn't remove statements that have been executed
|
|
101
|
+
# many times just because many less-frequently executed statements
|
|
102
|
+
# have been executed recently.
|
|
103
|
+
#
|
|
104
|
+
# The block passed is called with the Statement object's name, only for
|
|
105
|
+
# statements that have been prepared, and should be used to deallocate the
|
|
106
|
+
# statements.
|
|
107
|
+
def initialize(opts={}, &block)
|
|
108
|
+
@cleanup_proc = block
|
|
109
|
+
@prepare_after = opts.fetch(:prepare_after, 2)
|
|
110
|
+
@max_size = opts.fetch(:max_size, 1000)
|
|
111
|
+
@min_size = opts.fetch(:min_size, @max_size/2)
|
|
112
|
+
@sorter = opts.fetch(:sorter){method(:default_sorter)}
|
|
113
|
+
@ids = (1..@max_size).to_a.reverse
|
|
114
|
+
@hash = {}
|
|
115
|
+
#
|
|
116
|
+
# We add one so that when we clean the cache, the entry
|
|
117
|
+
# about to be added brings us to the min_size.
|
|
118
|
+
@size_diff = @max_size - @min_size + 1
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Completely clear the statement cache, deallocating on
|
|
122
|
+
# the server side all statements that have been prepared.
|
|
123
|
+
def clear
|
|
124
|
+
@hash.keys.each{|k| remove(k)}
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Yield each SQL string and Statement instance in the cache
|
|
128
|
+
# to the block.
|
|
129
|
+
def each(&block)
|
|
130
|
+
@hash.each(&block)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Get the related statement name from the cache. If the
|
|
134
|
+
# entry is already in the cache, just bump it's last seen
|
|
135
|
+
# time and the number of executions. Otherwise, add it
|
|
136
|
+
# to the cache. If the cache is already full, clean it up
|
|
137
|
+
# before adding it.
|
|
138
|
+
#
|
|
139
|
+
# If the num of executions has passed the threshhold, yield
|
|
140
|
+
# the statement name to the block, which should be used to
|
|
141
|
+
# prepare the statement on the server side.
|
|
142
|
+
#
|
|
143
|
+
# This method should return the prepared statment name if
|
|
144
|
+
# the statement has been prepared, and nil if the query
|
|
145
|
+
# has not been prepared and the statement should be executed
|
|
146
|
+
# normally.
|
|
147
|
+
def fetch(sql)
|
|
148
|
+
unless stmt = @hash[sql]
|
|
149
|
+
# Get the next id from the id pool.
|
|
150
|
+
unless id = @ids.pop
|
|
151
|
+
# No id left, cache must be full, so cleanup and then
|
|
152
|
+
# get the next id from the id pool.
|
|
153
|
+
cleanup
|
|
154
|
+
id = @ids.pop
|
|
155
|
+
end
|
|
156
|
+
@hash[sql] = stmt = Statement.new(id)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
stmt.last_seen = Time.now
|
|
160
|
+
stmt.num_executes += 1
|
|
161
|
+
|
|
162
|
+
if stmt.num_executes >= @prepare_after
|
|
163
|
+
if stmt.num_executes == @prepare_after
|
|
164
|
+
begin
|
|
165
|
+
yield(stmt.name)
|
|
166
|
+
rescue PGError
|
|
167
|
+
# An error occurred while preparing the statement,
|
|
168
|
+
# execute it normally (which will probably raise
|
|
169
|
+
# the error again elsewhere), but decrement the
|
|
170
|
+
# number of executions so we don't think we've
|
|
171
|
+
# prepared the statement when we haven't.
|
|
172
|
+
stmt.num_executes -= 1
|
|
173
|
+
return nil
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
stmt.name
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# The current size of the statement cache.
|
|
181
|
+
def size
|
|
182
|
+
@hash.length
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
private
|
|
186
|
+
|
|
187
|
+
# Sort by time since last execution and number of executions.
|
|
188
|
+
# We don't want to throw stuff out of the
|
|
189
|
+
# cache if it has been executed a lot,
|
|
190
|
+
# but a bunch of queries that were
|
|
191
|
+
# executed only once came in more recently.
|
|
192
|
+
def default_sorter(t, stmt)
|
|
193
|
+
(stmt.last_seen - t)/stmt.num_executes
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# After sorting the cache appropriately (so that the least important
|
|
197
|
+
# items are first), reduce the number of entries in the cache to
|
|
198
|
+
# the low water mark by removing the related query. Should only be
|
|
199
|
+
# called when the cache is full.
|
|
200
|
+
def cleanup
|
|
201
|
+
t = Time.now
|
|
202
|
+
@hash.sort_by{|k,v| @sorter.call(t, v)}.first(@size_diff).each{|sql, stmt| remove(sql)}
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Remove the query from the cache. If it has been prepared,
|
|
206
|
+
# call the cleanup_proc to deallocate the statement.
|
|
207
|
+
def remove(sql)
|
|
208
|
+
stmt = @hash.delete(sql)
|
|
209
|
+
if stmt.num_executes >= @prepare_after
|
|
210
|
+
@cleanup_proc.call(stmt.name)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Return id to the pool of ids
|
|
214
|
+
@ids.push(stmt.cache_id)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
module AdapterMethods
|
|
219
|
+
# A regular expression for the types of queries to cache. Any queries not
|
|
220
|
+
# matching this regular expression are not cached.
|
|
221
|
+
DML_RE = /\A(WITH|SELECT|INSERT|UPDATE|DELETE) /
|
|
222
|
+
|
|
223
|
+
# The StatementCache instance for this connection. Note that
|
|
224
|
+
# each connection has a separate StatementCache, because prepared
|
|
225
|
+
# statements are connection-specific.
|
|
226
|
+
attr_reader :statement_cache
|
|
227
|
+
|
|
228
|
+
# Set the statement_cache for the connection, using the database's
|
|
229
|
+
# :statement_cache_opts option.
|
|
230
|
+
def self.extended(c)
|
|
231
|
+
c.instance_variable_set(:@statement_cache, StatementCache.new(c.sequel_db.opts[:statement_cache_opts] || {}){|name| c.deallocate(name)})
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# pg seems to already use the db method (but not the @db instance variable),
|
|
235
|
+
# so use the sequel_db method to access the related Sequel::Database object.
|
|
236
|
+
def sequel_db
|
|
237
|
+
@db
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Deallocate on the server the prepared statement with the given name.
|
|
241
|
+
def deallocate(name)
|
|
242
|
+
begin
|
|
243
|
+
execute("DEALLOCATE #{name}")
|
|
244
|
+
rescue PGError
|
|
245
|
+
# table probably got removed, just ignore it
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
private
|
|
250
|
+
|
|
251
|
+
# If the sql query string is one we should cache, cache it. If the query already
|
|
252
|
+
# has a related prepared statement with it, execute the prepared statement instead
|
|
253
|
+
# of executing the query normally.
|
|
254
|
+
def execute_query(sql, args=nil)
|
|
255
|
+
if sql =~ DML_RE
|
|
256
|
+
if name = statement_cache.fetch(sql){|stmt_name| sequel_db.log_yield("PREPARE #{stmt_name} AS #{sql}"){prepare(stmt_name, sql)}}
|
|
257
|
+
if args
|
|
258
|
+
sequel_db.log_yield("EXECUTE #{name} (#{sql})", args){exec_prepared(name, args)}
|
|
259
|
+
else
|
|
260
|
+
sequel_db.log_yield("EXECUTE #{name} (#{sql})"){exec_prepared(name)}
|
|
261
|
+
end
|
|
262
|
+
else
|
|
263
|
+
super
|
|
264
|
+
end
|
|
265
|
+
else
|
|
266
|
+
super
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
module DatabaseMethods
|
|
272
|
+
# Setup the after_connect proc for the connection pool to make
|
|
273
|
+
# sure the connection object is extended with the appropriate
|
|
274
|
+
# module. This disconnects any existing connections to ensure
|
|
275
|
+
# that all connections in the pool have been extended appropriately.
|
|
276
|
+
def self.extended(db)
|
|
277
|
+
# Respect existing after_connect proc if one is present
|
|
278
|
+
pr = db.opts[:after_connect]
|
|
279
|
+
|
|
280
|
+
# Set the after_connect proc to extend the adapter with
|
|
281
|
+
# the statement cache support.
|
|
282
|
+
db.pool.after_connect = db.opts[:after_connect] = proc do |c|
|
|
283
|
+
pr.call(c) if pr
|
|
284
|
+
c.extend(AdapterMethods)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# Disconnect to make sure all connections get set up with
|
|
288
|
+
# statement cache.
|
|
289
|
+
db.disconnect
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
# Clear statement caches for all connections when altering tables.
|
|
293
|
+
def alter_table(*)
|
|
294
|
+
clear_statement_caches
|
|
295
|
+
super
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
# Clear statement caches for all connections when dropping tables.
|
|
299
|
+
def drop_table(*)
|
|
300
|
+
clear_statement_caches
|
|
301
|
+
super
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
private
|
|
305
|
+
|
|
306
|
+
# Clear the statement cache for all connections. Note that for
|
|
307
|
+
# the threaded pools, this will not affect connections currently
|
|
308
|
+
# allocated to other threads.
|
|
309
|
+
def clear_statement_caches
|
|
310
|
+
pool.all_connections{|c| c.statement_cache.clear}
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
Database.register_extension(:pg_statement_cache, Postgres::StatementCache::DatabaseMethods)
|
|
317
|
+
end
|
|
@@ -1,82 +1,27 @@
|
|
|
1
1
|
# The pretty_table extension adds Sequel::Dataset#print and the
|
|
2
2
|
# Sequel::PrettyTable class for creating nice-looking plain-text
|
|
3
|
-
# tables.
|
|
3
|
+
# tables. Example:
|
|
4
|
+
#
|
|
5
|
+
# +--+-------+
|
|
6
|
+
# |id|name |
|
|
7
|
+
# |--+-------|
|
|
8
|
+
# |1 |fasdfas|
|
|
9
|
+
# |2 |test |
|
|
10
|
+
# +--+-------+
|
|
11
|
+
#
|
|
12
|
+
# To load the extension:
|
|
13
|
+
#
|
|
14
|
+
# Sequel.extension :pretty_table
|
|
4
15
|
|
|
5
16
|
module Sequel
|
|
17
|
+
extension :_pretty_table
|
|
18
|
+
|
|
6
19
|
class Dataset
|
|
7
20
|
# Pretty prints the records in the dataset as plain-text table.
|
|
8
21
|
def print(*cols)
|
|
9
|
-
|
|
22
|
+
ds = naked
|
|
23
|
+
rows = ds.all
|
|
24
|
+
Sequel::PrettyTable.print(rows, cols.empty? ? ds.columns : cols)
|
|
10
25
|
end
|
|
11
26
|
end
|
|
12
|
-
|
|
13
|
-
module PrettyTable
|
|
14
|
-
# Prints nice-looking plain-text tables via puts
|
|
15
|
-
#
|
|
16
|
-
# +--+-------+
|
|
17
|
-
# |id|name |
|
|
18
|
-
# |--+-------|
|
|
19
|
-
# |1 |fasdfas|
|
|
20
|
-
# |2 |test |
|
|
21
|
-
# +--+-------+
|
|
22
|
-
def self.print(records, columns = nil) # records is an array of hashes
|
|
23
|
-
columns ||= records.first.keys.sort_by{|x|x.to_s}
|
|
24
|
-
sizes = column_sizes(records, columns)
|
|
25
|
-
sep_line = separator_line(columns, sizes)
|
|
26
|
-
|
|
27
|
-
puts sep_line
|
|
28
|
-
puts header_line(columns, sizes)
|
|
29
|
-
puts sep_line
|
|
30
|
-
records.each {|r| puts data_line(columns, sizes, r)}
|
|
31
|
-
puts sep_line
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
### Private Module Methods ###
|
|
35
|
-
|
|
36
|
-
# Hash of the maximum size of the value for each column
|
|
37
|
-
def self.column_sizes(records, columns) # :nodoc:
|
|
38
|
-
sizes = Hash.new {0}
|
|
39
|
-
columns.each do |c|
|
|
40
|
-
s = c.to_s.size
|
|
41
|
-
sizes[c.to_sym] = s if s > sizes[c.to_sym]
|
|
42
|
-
end
|
|
43
|
-
records.each do |r|
|
|
44
|
-
columns.each do |c|
|
|
45
|
-
s = r[c].to_s.size
|
|
46
|
-
sizes[c.to_sym] = s if s > sizes[c.to_sym]
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
sizes
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
# String for each data line
|
|
53
|
-
def self.data_line(columns, sizes, record) # :nodoc:
|
|
54
|
-
'|' << columns.map {|c| format_cell(sizes[c], record[c])}.join('|') << '|'
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# Format the value so it takes up exactly size characters
|
|
58
|
-
def self.format_cell(size, v) # :nodoc:
|
|
59
|
-
case v
|
|
60
|
-
when Bignum, Fixnum
|
|
61
|
-
"%#{size}d" % v
|
|
62
|
-
when Float
|
|
63
|
-
"%#{size}g" % v
|
|
64
|
-
else
|
|
65
|
-
"%-#{size}s" % v.to_s
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
# String for header line
|
|
70
|
-
def self.header_line(columns, sizes) # :nodoc:
|
|
71
|
-
'|' << columns.map {|c| "%-#{sizes[c]}s" % c.to_s}.join('|') << '|'
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
# String for separtor line
|
|
75
|
-
def self.separator_line(columns, sizes) # :nodoc:
|
|
76
|
-
'+' << columns.map {|c| '-' * sizes[c]}.join('+') << '+'
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
private_class_method :column_sizes, :data_line, :format_cell, :header_line, :separator_line
|
|
80
|
-
end
|
|
81
27
|
end
|
|
82
|
-
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# The query extension adds Sequel::Dataset#query which allows
|
|
2
2
|
# a different way to construct queries instead of the usual
|
|
3
3
|
# method chaining.
|
|
4
|
+
#
|
|
5
|
+
# To load the extension, do:
|
|
6
|
+
#
|
|
7
|
+
# Sequel.extension :query
|
|
4
8
|
|
|
5
9
|
module Sequel
|
|
6
10
|
class Database
|
|
@@ -16,13 +20,13 @@ module Sequel
|
|
|
16
20
|
#
|
|
17
21
|
# dataset = DB[:items].query do
|
|
18
22
|
# select :x, :y, :z
|
|
19
|
-
# filter{
|
|
20
|
-
#
|
|
23
|
+
# filter{(x > 1) & (y > 2)}
|
|
24
|
+
# reverse :z
|
|
21
25
|
# end
|
|
22
26
|
#
|
|
23
27
|
# Which is the same as:
|
|
24
28
|
#
|
|
25
|
-
# dataset = DB[:items].select(:x, :y, :z).filter{
|
|
29
|
+
# dataset = DB[:items].select(:x, :y, :z).filter{(x > 1) & (y > 2)}.reverse(:z)
|
|
26
30
|
#
|
|
27
31
|
# Note that inside a call to query, you cannot call each, insert, update,
|
|
28
32
|
# or delete (or any method that calls those), or Sequel will raise an
|
|
@@ -43,7 +47,7 @@ module Sequel
|
|
|
43
47
|
|
|
44
48
|
# Merge the given options into the receiver's options and return the receiver
|
|
45
49
|
# instead of cloning the receiver.
|
|
46
|
-
def clone(opts =
|
|
50
|
+
def clone(opts = {})
|
|
47
51
|
@opts.merge!(opts)
|
|
48
52
|
self
|
|
49
53
|
end
|