activerecord 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/CHANGELOG.md +1372 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +218 -0
- data/examples/performance.rb +184 -0
- data/examples/simple.rb +14 -0
- data/lib/active_record.rb +173 -0
- data/lib/active_record/aggregations.rb +266 -0
- data/lib/active_record/association_relation.rb +22 -0
- data/lib/active_record/associations.rb +1724 -0
- data/lib/active_record/associations/alias_tracker.rb +87 -0
- data/lib/active_record/associations/association.rb +253 -0
- data/lib/active_record/associations/association_scope.rb +194 -0
- data/lib/active_record/associations/belongs_to_association.rb +111 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +40 -0
- data/lib/active_record/associations/builder/association.rb +149 -0
- data/lib/active_record/associations/builder/belongs_to.rb +116 -0
- data/lib/active_record/associations/builder/collection_association.rb +91 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +124 -0
- data/lib/active_record/associations/builder/has_many.rb +15 -0
- data/lib/active_record/associations/builder/has_one.rb +23 -0
- data/lib/active_record/associations/builder/singular_association.rb +38 -0
- data/lib/active_record/associations/collection_association.rb +634 -0
- data/lib/active_record/associations/collection_proxy.rb +1027 -0
- data/lib/active_record/associations/has_many_association.rb +184 -0
- data/lib/active_record/associations/has_many_through_association.rb +238 -0
- data/lib/active_record/associations/has_one_association.rb +105 -0
- data/lib/active_record/associations/has_one_through_association.rb +36 -0
- data/lib/active_record/associations/join_dependency.rb +282 -0
- data/lib/active_record/associations/join_dependency/join_association.rb +122 -0
- data/lib/active_record/associations/join_dependency/join_base.rb +22 -0
- data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
- data/lib/active_record/associations/preloader.rb +203 -0
- data/lib/active_record/associations/preloader/association.rb +162 -0
- data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
- data/lib/active_record/associations/preloader/collection_association.rb +24 -0
- data/lib/active_record/associations/preloader/has_many.rb +17 -0
- data/lib/active_record/associations/preloader/has_many_through.rb +19 -0
- data/lib/active_record/associations/preloader/has_one.rb +23 -0
- data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
- data/lib/active_record/associations/preloader/singular_association.rb +21 -0
- data/lib/active_record/associations/preloader/through_association.rb +96 -0
- data/lib/active_record/associations/singular_association.rb +86 -0
- data/lib/active_record/associations/through_association.rb +96 -0
- data/lib/active_record/attribute.rb +149 -0
- data/lib/active_record/attribute_assignment.rb +212 -0
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods.rb +439 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +71 -0
- data/lib/active_record/attribute_methods/dirty.rb +181 -0
- data/lib/active_record/attribute_methods/primary_key.rb +128 -0
- data/lib/active_record/attribute_methods/query.rb +40 -0
- data/lib/active_record/attribute_methods/read.rb +103 -0
- data/lib/active_record/attribute_methods/serialization.rb +70 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -0
- data/lib/active_record/attribute_methods/write.rb +83 -0
- data/lib/active_record/attribute_set.rb +77 -0
- data/lib/active_record/attribute_set/builder.rb +86 -0
- data/lib/active_record/attributes.rb +139 -0
- data/lib/active_record/autosave_association.rb +439 -0
- data/lib/active_record/base.rb +317 -0
- data/lib/active_record/callbacks.rb +313 -0
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/coders/yaml_column.rb +38 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +659 -0
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +67 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +373 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +95 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +133 -0
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +125 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +574 -0
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +991 -0
- data/lib/active_record/connection_adapters/abstract/transaction.rb +219 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +487 -0
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +883 -0
- data/lib/active_record/connection_adapters/column.rb +82 -0
- data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +282 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +491 -0
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +93 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +232 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +99 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +108 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +588 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +754 -0
- data/lib/active_record/connection_adapters/schema_cache.rb +94 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +628 -0
- data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
- data/lib/active_record/connection_handling.rb +132 -0
- data/lib/active_record/core.rb +566 -0
- data/lib/active_record/counter_cache.rb +175 -0
- data/lib/active_record/dynamic_matchers.rb +140 -0
- data/lib/active_record/enum.rb +198 -0
- data/lib/active_record/errors.rb +252 -0
- data/lib/active_record/explain.rb +38 -0
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +29 -0
- data/lib/active_record/fixture_set/file.rb +56 -0
- data/lib/active_record/fixtures.rb +1007 -0
- data/lib/active_record/gem_version.rb +15 -0
- data/lib/active_record/inheritance.rb +247 -0
- data/lib/active_record/integration.rb +113 -0
- data/lib/active_record/locale/en.yml +47 -0
- data/lib/active_record/locking/optimistic.rb +204 -0
- data/lib/active_record/locking/pessimistic.rb +77 -0
- data/lib/active_record/log_subscriber.rb +75 -0
- data/lib/active_record/migration.rb +1051 -0
- data/lib/active_record/migration/command_recorder.rb +197 -0
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/model_schema.rb +340 -0
- data/lib/active_record/nested_attributes.rb +548 -0
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +81 -0
- data/lib/active_record/persistence.rb +532 -0
- data/lib/active_record/query_cache.rb +56 -0
- data/lib/active_record/querying.rb +68 -0
- data/lib/active_record/railtie.rb +162 -0
- data/lib/active_record/railties/console_sandbox.rb +5 -0
- data/lib/active_record/railties/controller_runtime.rb +50 -0
- data/lib/active_record/railties/databases.rake +391 -0
- data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
- data/lib/active_record/readonly_attributes.rb +23 -0
- data/lib/active_record/reflection.rb +881 -0
- data/lib/active_record/relation.rb +681 -0
- data/lib/active_record/relation/batches.rb +138 -0
- data/lib/active_record/relation/calculations.rb +403 -0
- data/lib/active_record/relation/delegation.rb +140 -0
- data/lib/active_record/relation/finder_methods.rb +528 -0
- data/lib/active_record/relation/merger.rb +170 -0
- data/lib/active_record/relation/predicate_builder.rb +126 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +47 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
- data/lib/active_record/relation/query_methods.rb +1176 -0
- data/lib/active_record/relation/spawn_methods.rb +75 -0
- data/lib/active_record/result.rb +131 -0
- data/lib/active_record/runtime_registry.rb +22 -0
- data/lib/active_record/sanitization.rb +191 -0
- data/lib/active_record/schema.rb +64 -0
- data/lib/active_record/schema_dumper.rb +251 -0
- data/lib/active_record/schema_migration.rb +56 -0
- data/lib/active_record/scoping.rb +87 -0
- data/lib/active_record/scoping/default.rb +134 -0
- data/lib/active_record/scoping/named.rb +164 -0
- data/lib/active_record/serialization.rb +22 -0
- data/lib/active_record/serializers/xml_serializer.rb +193 -0
- data/lib/active_record/statement_cache.rb +111 -0
- data/lib/active_record/store.rb +205 -0
- data/lib/active_record/tasks/database_tasks.rb +296 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +145 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +55 -0
- data/lib/active_record/timestamp.rb +121 -0
- data/lib/active_record/transactions.rb +417 -0
- data/lib/active_record/translation.rb +22 -0
- data/lib/active_record/type.rb +23 -0
- data/lib/active_record/type/big_integer.rb +13 -0
- data/lib/active_record/type/binary.rb +50 -0
- data/lib/active_record/type/boolean.rb +30 -0
- data/lib/active_record/type/date.rb +46 -0
- data/lib/active_record/type/date_time.rb +43 -0
- data/lib/active_record/type/decimal.rb +40 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/decorator.rb +14 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +17 -0
- data/lib/active_record/type/integer.rb +55 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +56 -0
- data/lib/active_record/type/string.rb +36 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +64 -0
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type/value.rb +101 -0
- data/lib/active_record/validations.rb +90 -0
- data/lib/active_record/validations/associated.rb +51 -0
- data/lib/active_record/validations/presence.rb +67 -0
- data/lib/active_record/validations/uniqueness.rb +229 -0
- data/lib/active_record/version.rb +8 -0
- data/lib/rails/generators/active_record.rb +17 -0
- data/lib/rails/generators/active_record/migration.rb +18 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +70 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +22 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +45 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +52 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +10 -0
- data/lib/rails/generators/active_record/model/templates/module.rb +7 -0
- metadata +309 -0
@@ -0,0 +1,251 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'active_support/core_ext/big_decimal'
|
3
|
+
|
4
|
+
module ActiveRecord
|
5
|
+
# = Active Record Schema Dumper
|
6
|
+
#
|
7
|
+
# This class is used to dump the database schema for some connection to some
|
8
|
+
# output format (i.e., ActiveRecord::Schema).
|
9
|
+
class SchemaDumper #:nodoc:
|
10
|
+
private_class_method :new
|
11
|
+
|
12
|
+
##
|
13
|
+
# :singleton-method:
|
14
|
+
# A list of tables which should not be dumped to the schema.
|
15
|
+
# Acceptable values are strings as well as regexp.
|
16
|
+
# This setting is only used if ActiveRecord::Base.schema_format == :ruby
|
17
|
+
cattr_accessor :ignore_tables
|
18
|
+
@@ignore_tables = []
|
19
|
+
|
20
|
+
class << self
|
21
|
+
def dump(connection=ActiveRecord::Base.connection, stream=STDOUT, config = ActiveRecord::Base)
|
22
|
+
new(connection, generate_options(config)).dump(stream)
|
23
|
+
stream
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def generate_options(config)
|
28
|
+
{
|
29
|
+
table_name_prefix: config.table_name_prefix,
|
30
|
+
table_name_suffix: config.table_name_suffix
|
31
|
+
}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def dump(stream)
|
36
|
+
header(stream)
|
37
|
+
extensions(stream)
|
38
|
+
tables(stream)
|
39
|
+
trailer(stream)
|
40
|
+
stream
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def initialize(connection, options = {})
|
46
|
+
@connection = connection
|
47
|
+
@types = @connection.native_database_types
|
48
|
+
@version = Migrator::current_version rescue nil
|
49
|
+
@options = options
|
50
|
+
end
|
51
|
+
|
52
|
+
def header(stream)
|
53
|
+
define_params = @version ? "version: #{@version}" : ""
|
54
|
+
|
55
|
+
if stream.respond_to?(:external_encoding) && stream.external_encoding
|
56
|
+
stream.puts "# encoding: #{stream.external_encoding.name}"
|
57
|
+
end
|
58
|
+
|
59
|
+
stream.puts <<HEADER
|
60
|
+
# This file is auto-generated from the current state of the database. Instead
|
61
|
+
# of editing this file, please use the migrations feature of Active Record to
|
62
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
63
|
+
#
|
64
|
+
# Note that this schema.rb definition is the authoritative source for your
|
65
|
+
# database schema. If you need to create the application database on another
|
66
|
+
# system, you should be using db:schema:load, not running all the migrations
|
67
|
+
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
68
|
+
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
69
|
+
#
|
70
|
+
# It's strongly recommended that you check this file into your version control system.
|
71
|
+
|
72
|
+
ActiveRecord::Schema.define(#{define_params}) do
|
73
|
+
|
74
|
+
HEADER
|
75
|
+
end
|
76
|
+
|
77
|
+
def trailer(stream)
|
78
|
+
stream.puts "end"
|
79
|
+
end
|
80
|
+
|
81
|
+
def extensions(stream)
|
82
|
+
return unless @connection.supports_extensions?
|
83
|
+
extensions = @connection.extensions
|
84
|
+
if extensions.any?
|
85
|
+
stream.puts " # These are extensions that must be enabled in order to support this database"
|
86
|
+
extensions.each do |extension|
|
87
|
+
stream.puts " enable_extension #{extension.inspect}"
|
88
|
+
end
|
89
|
+
stream.puts
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def tables(stream)
|
94
|
+
sorted_tables = @connection.tables.sort
|
95
|
+
|
96
|
+
sorted_tables.each do |table_name|
|
97
|
+
table(table_name, stream) unless ignored?(table_name)
|
98
|
+
end
|
99
|
+
|
100
|
+
# dump foreign keys at the end to make sure all dependent tables exist.
|
101
|
+
if @connection.supports_foreign_keys?
|
102
|
+
sorted_tables.each do |tbl|
|
103
|
+
foreign_keys(tbl, stream) unless ignored?(tbl)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def table(table, stream)
|
109
|
+
columns = @connection.columns(table)
|
110
|
+
begin
|
111
|
+
tbl = StringIO.new
|
112
|
+
|
113
|
+
# first dump primary key column
|
114
|
+
pk = @connection.primary_key(table)
|
115
|
+
|
116
|
+
tbl.print " create_table #{remove_prefix_and_suffix(table).inspect}"
|
117
|
+
pkcol = columns.detect { |c| c.name == pk }
|
118
|
+
if pkcol
|
119
|
+
if pk != 'id'
|
120
|
+
tbl.print %Q(, primary_key: "#{pk}")
|
121
|
+
elsif pkcol.sql_type == 'bigint'
|
122
|
+
tbl.print ", id: :bigserial"
|
123
|
+
elsif pkcol.sql_type == 'uuid'
|
124
|
+
tbl.print ", id: :uuid"
|
125
|
+
tbl.print %Q(, default: "#{pkcol.default_function}") if pkcol.default_function
|
126
|
+
end
|
127
|
+
else
|
128
|
+
tbl.print ", id: false"
|
129
|
+
end
|
130
|
+
tbl.print ", force: :cascade"
|
131
|
+
tbl.puts " do |t|"
|
132
|
+
|
133
|
+
# then dump all non-primary key columns
|
134
|
+
column_specs = columns.map do |column|
|
135
|
+
raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
|
136
|
+
next if column.name == pk
|
137
|
+
@connection.column_spec(column, @types)
|
138
|
+
end.compact
|
139
|
+
|
140
|
+
# find all migration keys used in this table
|
141
|
+
keys = @connection.migration_keys
|
142
|
+
|
143
|
+
# figure out the lengths for each column based on above keys
|
144
|
+
lengths = keys.map { |key|
|
145
|
+
column_specs.map { |spec|
|
146
|
+
spec[key] ? spec[key].length + 2 : 0
|
147
|
+
}.max
|
148
|
+
}
|
149
|
+
|
150
|
+
# the string we're going to sprintf our values against, with standardized column widths
|
151
|
+
format_string = lengths.map{ |len| "%-#{len}s" }
|
152
|
+
|
153
|
+
# find the max length for the 'type' column, which is special
|
154
|
+
type_length = column_specs.map{ |column| column[:type].length }.max
|
155
|
+
|
156
|
+
# add column type definition to our format string
|
157
|
+
format_string.unshift " t.%-#{type_length}s "
|
158
|
+
|
159
|
+
format_string *= ''
|
160
|
+
|
161
|
+
column_specs.each do |colspec|
|
162
|
+
values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len }
|
163
|
+
values.unshift colspec[:type]
|
164
|
+
tbl.print((format_string % values).gsub(/,\s*$/, ''))
|
165
|
+
tbl.puts
|
166
|
+
end
|
167
|
+
|
168
|
+
tbl.puts " end"
|
169
|
+
tbl.puts
|
170
|
+
|
171
|
+
indexes(table, tbl)
|
172
|
+
|
173
|
+
tbl.rewind
|
174
|
+
stream.print tbl.read
|
175
|
+
rescue => e
|
176
|
+
stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
|
177
|
+
stream.puts "# #{e.message}"
|
178
|
+
stream.puts
|
179
|
+
end
|
180
|
+
|
181
|
+
stream
|
182
|
+
end
|
183
|
+
|
184
|
+
def indexes(table, stream)
|
185
|
+
if (indexes = @connection.indexes(table)).any?
|
186
|
+
add_index_statements = indexes.map do |index|
|
187
|
+
statement_parts = [
|
188
|
+
"add_index #{remove_prefix_and_suffix(index.table).inspect}",
|
189
|
+
index.columns.inspect,
|
190
|
+
"name: #{index.name.inspect}",
|
191
|
+
]
|
192
|
+
statement_parts << 'unique: true' if index.unique
|
193
|
+
|
194
|
+
index_lengths = (index.lengths || []).compact
|
195
|
+
statement_parts << "length: #{Hash[index.columns.zip(index.lengths)].inspect}" if index_lengths.any?
|
196
|
+
|
197
|
+
index_orders = index.orders || {}
|
198
|
+
statement_parts << "order: #{index.orders.inspect}" if index_orders.any?
|
199
|
+
statement_parts << "where: #{index.where.inspect}" if index.where
|
200
|
+
statement_parts << "using: #{index.using.inspect}" if index.using
|
201
|
+
statement_parts << "type: #{index.type.inspect}" if index.type
|
202
|
+
|
203
|
+
" #{statement_parts.join(', ')}"
|
204
|
+
end
|
205
|
+
|
206
|
+
stream.puts add_index_statements.sort.join("\n")
|
207
|
+
stream.puts
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def foreign_keys(table, stream)
|
212
|
+
if (foreign_keys = @connection.foreign_keys(table)).any?
|
213
|
+
add_foreign_key_statements = foreign_keys.map do |foreign_key|
|
214
|
+
parts = [
|
215
|
+
"add_foreign_key #{remove_prefix_and_suffix(foreign_key.from_table).inspect}",
|
216
|
+
remove_prefix_and_suffix(foreign_key.to_table).inspect,
|
217
|
+
]
|
218
|
+
|
219
|
+
if foreign_key.column != @connection.foreign_key_column_for(foreign_key.to_table)
|
220
|
+
parts << "column: #{foreign_key.column.inspect}"
|
221
|
+
end
|
222
|
+
|
223
|
+
if foreign_key.custom_primary_key?
|
224
|
+
parts << "primary_key: #{foreign_key.primary_key.inspect}"
|
225
|
+
end
|
226
|
+
|
227
|
+
if foreign_key.name !~ /^fk_rails_[0-9a-f]{10}$/
|
228
|
+
parts << "name: #{foreign_key.name.inspect}"
|
229
|
+
end
|
230
|
+
|
231
|
+
parts << "on_update: #{foreign_key.on_update.inspect}" if foreign_key.on_update
|
232
|
+
parts << "on_delete: #{foreign_key.on_delete.inspect}" if foreign_key.on_delete
|
233
|
+
|
234
|
+
" #{parts.join(', ')}"
|
235
|
+
end
|
236
|
+
|
237
|
+
stream.puts add_foreign_key_statements.sort.join("\n")
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def remove_prefix_and_suffix(table)
|
242
|
+
table.gsub(/^(#{@options[:table_name_prefix]})(.+)(#{@options[:table_name_suffix]})$/, "\\2")
|
243
|
+
end
|
244
|
+
|
245
|
+
def ignored?(table_name)
|
246
|
+
['schema_migrations', ignore_tables].flatten.any? do |ignored|
|
247
|
+
ignored === remove_prefix_and_suffix(table_name)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'active_record/scoping/default'
|
2
|
+
require 'active_record/scoping/named'
|
3
|
+
require 'active_record/base'
|
4
|
+
|
5
|
+
module ActiveRecord
|
6
|
+
class SchemaMigration < ActiveRecord::Base
|
7
|
+
class << self
|
8
|
+
def primary_key
|
9
|
+
nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def table_name
|
13
|
+
"#{table_name_prefix}#{ActiveRecord::Base.schema_migrations_table_name}#{table_name_suffix}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def index_name
|
17
|
+
"#{table_name_prefix}unique_#{ActiveRecord::Base.schema_migrations_table_name}#{table_name_suffix}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def table_exists?
|
21
|
+
connection.table_exists?(table_name)
|
22
|
+
end
|
23
|
+
|
24
|
+
def create_table(limit=nil)
|
25
|
+
unless table_exists?
|
26
|
+
version_options = {null: false}
|
27
|
+
version_options[:limit] = limit if limit
|
28
|
+
|
29
|
+
connection.create_table(table_name, id: false) do |t|
|
30
|
+
t.column :version, :string, version_options
|
31
|
+
end
|
32
|
+
connection.add_index table_name, :version, unique: true, name: index_name
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def drop_table
|
37
|
+
if table_exists?
|
38
|
+
connection.remove_index table_name, name: index_name
|
39
|
+
connection.drop_table(table_name)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def normalize_migration_number(number)
|
44
|
+
"%.3d" % number.to_i
|
45
|
+
end
|
46
|
+
|
47
|
+
def normalized_versions
|
48
|
+
pluck(:version).map { |v| normalize_migration_number v }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def version
|
53
|
+
super.to_i
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'active_support/per_thread_registry'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Scoping
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
include Default
|
9
|
+
include Named
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def current_scope #:nodoc:
|
14
|
+
ScopeRegistry.value_for(:current_scope, base_class.to_s)
|
15
|
+
end
|
16
|
+
|
17
|
+
def current_scope=(scope) #:nodoc:
|
18
|
+
ScopeRegistry.set_value_for(:current_scope, base_class.to_s, scope)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def populate_with_current_scope_attributes
|
23
|
+
return unless self.class.scope_attributes?
|
24
|
+
|
25
|
+
self.class.scope_attributes.each do |att,value|
|
26
|
+
send("#{att}=", value) if respond_to?("#{att}=")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize_internals_callback
|
31
|
+
super
|
32
|
+
populate_with_current_scope_attributes
|
33
|
+
end
|
34
|
+
|
35
|
+
# This class stores the +:current_scope+ and +:ignore_default_scope+ values
|
36
|
+
# for different classes. The registry is stored as a thread local, which is
|
37
|
+
# accessed through +ScopeRegistry.current+.
|
38
|
+
#
|
39
|
+
# This class allows you to store and get the scope values on different
|
40
|
+
# classes and different types of scopes. For example, if you are attempting
|
41
|
+
# to get the current_scope for the +Board+ model, then you would use the
|
42
|
+
# following code:
|
43
|
+
#
|
44
|
+
# registry = ActiveRecord::Scoping::ScopeRegistry
|
45
|
+
# registry.set_value_for(:current_scope, "Board", some_new_scope)
|
46
|
+
#
|
47
|
+
# Now when you run:
|
48
|
+
#
|
49
|
+
# registry.value_for(:current_scope, "Board")
|
50
|
+
#
|
51
|
+
# You will obtain whatever was defined in +some_new_scope+. The +value_for+
|
52
|
+
# and +set_value_for+ methods are delegated to the current +ScopeRegistry+
|
53
|
+
# object, so the above example code can also be called as:
|
54
|
+
#
|
55
|
+
# ActiveRecord::Scoping::ScopeRegistry.set_value_for(:current_scope,
|
56
|
+
# "Board", some_new_scope)
|
57
|
+
class ScopeRegistry # :nodoc:
|
58
|
+
extend ActiveSupport::PerThreadRegistry
|
59
|
+
|
60
|
+
VALID_SCOPE_TYPES = [:current_scope, :ignore_default_scope]
|
61
|
+
|
62
|
+
def initialize
|
63
|
+
@registry = Hash.new { |hash, key| hash[key] = {} }
|
64
|
+
end
|
65
|
+
|
66
|
+
# Obtains the value for a given +scope_name+ and +variable_name+.
|
67
|
+
def value_for(scope_type, variable_name)
|
68
|
+
raise_invalid_scope_type!(scope_type)
|
69
|
+
@registry[scope_type][variable_name]
|
70
|
+
end
|
71
|
+
|
72
|
+
# Sets the +value+ for a given +scope_type+ and +variable_name+.
|
73
|
+
def set_value_for(scope_type, variable_name, value)
|
74
|
+
raise_invalid_scope_type!(scope_type)
|
75
|
+
@registry[scope_type][variable_name] = value
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def raise_invalid_scope_type!(scope_type)
|
81
|
+
if !VALID_SCOPE_TYPES.include?(scope_type)
|
82
|
+
raise ArgumentError, "Invalid scope type '#{scope_type}' sent to the registry. Scope types must be included in VALID_SCOPE_TYPES"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Scoping
|
3
|
+
module Default
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
# Stores the default scope for the class.
|
8
|
+
class_attribute :default_scopes, instance_writer: false, instance_predicate: false
|
9
|
+
|
10
|
+
self.default_scopes = []
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
# Returns a scope for the model without the previously set scopes.
|
15
|
+
#
|
16
|
+
# class Post < ActiveRecord::Base
|
17
|
+
# def self.default_scope
|
18
|
+
# where published: true
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# Post.all # Fires "SELECT * FROM posts WHERE published = true"
|
23
|
+
# Post.unscoped.all # Fires "SELECT * FROM posts"
|
24
|
+
# Post.where(published: false).unscoped.all # Fires "SELECT * FROM posts"
|
25
|
+
#
|
26
|
+
# This method also accepts a block. All queries inside the block will
|
27
|
+
# not use the previously set scopes.
|
28
|
+
#
|
29
|
+
# Post.unscoped {
|
30
|
+
# Post.limit(10) # Fires "SELECT * FROM posts LIMIT 10"
|
31
|
+
# }
|
32
|
+
def unscoped
|
33
|
+
block_given? ? relation.scoping { yield } : relation
|
34
|
+
end
|
35
|
+
|
36
|
+
def before_remove_const #:nodoc:
|
37
|
+
self.current_scope = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
# Use this macro in your model to set a default scope for all operations on
|
43
|
+
# the model.
|
44
|
+
#
|
45
|
+
# class Article < ActiveRecord::Base
|
46
|
+
# default_scope { where(published: true) }
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# Article.all # => SELECT * FROM articles WHERE published = true
|
50
|
+
#
|
51
|
+
# The +default_scope+ is also applied while creating/building a record.
|
52
|
+
# It is not applied while updating a record.
|
53
|
+
#
|
54
|
+
# Article.new.published # => true
|
55
|
+
# Article.create.published # => true
|
56
|
+
#
|
57
|
+
# (You can also pass any object which responds to +call+ to the
|
58
|
+
# +default_scope+ macro, and it will be called when building the
|
59
|
+
# default scope.)
|
60
|
+
#
|
61
|
+
# If you use multiple +default_scope+ declarations in your model then
|
62
|
+
# they will be merged together:
|
63
|
+
#
|
64
|
+
# class Article < ActiveRecord::Base
|
65
|
+
# default_scope { where(published: true) }
|
66
|
+
# default_scope { where(rating: 'G') }
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
# Article.all # => SELECT * FROM articles WHERE published = true AND rating = 'G'
|
70
|
+
#
|
71
|
+
# This is also the case with inheritance and module includes where the
|
72
|
+
# parent or module defines a +default_scope+ and the child or including
|
73
|
+
# class defines a second one.
|
74
|
+
#
|
75
|
+
# If you need to do more complex things with a default scope, you can
|
76
|
+
# alternatively define it as a class method:
|
77
|
+
#
|
78
|
+
# class Article < ActiveRecord::Base
|
79
|
+
# def self.default_scope
|
80
|
+
# # Should return a scope, you can call 'super' here etc.
|
81
|
+
# end
|
82
|
+
# end
|
83
|
+
def default_scope(scope = nil)
|
84
|
+
scope = Proc.new if block_given?
|
85
|
+
|
86
|
+
if scope.is_a?(Relation) || !scope.respond_to?(:call)
|
87
|
+
raise ArgumentError,
|
88
|
+
"Support for calling #default_scope without a block is removed. For example instead " \
|
89
|
+
"of `default_scope where(color: 'red')`, please use " \
|
90
|
+
"`default_scope { where(color: 'red') }`. (Alternatively you can just redefine " \
|
91
|
+
"self.default_scope.)"
|
92
|
+
end
|
93
|
+
|
94
|
+
self.default_scopes += [scope]
|
95
|
+
end
|
96
|
+
|
97
|
+
def build_default_scope(base_rel = relation) # :nodoc:
|
98
|
+
if !Base.is_a?(method(:default_scope).owner)
|
99
|
+
# The user has defined their own default scope method, so call that
|
100
|
+
evaluate_default_scope { default_scope }
|
101
|
+
elsif default_scopes.any?
|
102
|
+
evaluate_default_scope do
|
103
|
+
default_scopes.inject(base_rel) do |default_scope, scope|
|
104
|
+
default_scope.merge(base_rel.scoping { scope.call })
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def ignore_default_scope? # :nodoc:
|
111
|
+
ScopeRegistry.value_for(:ignore_default_scope, self)
|
112
|
+
end
|
113
|
+
|
114
|
+
def ignore_default_scope=(ignore) # :nodoc:
|
115
|
+
ScopeRegistry.set_value_for(:ignore_default_scope, self, ignore)
|
116
|
+
end
|
117
|
+
|
118
|
+
# The ignore_default_scope flag is used to prevent an infinite recursion
|
119
|
+
# situation where a default scope references a scope which has a default
|
120
|
+
# scope which references a scope...
|
121
|
+
def evaluate_default_scope # :nodoc:
|
122
|
+
return if ignore_default_scope?
|
123
|
+
|
124
|
+
begin
|
125
|
+
self.ignore_default_scope = true
|
126
|
+
yield
|
127
|
+
ensure
|
128
|
+
self.ignore_default_scope = false
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|