Skip to content

Commit 9af3191

Browse files
authored
TECH-13204/support prefix indexes (#168)
* TECH-13204: update README * TECH-13204: update CHANGELOG * TECH-13204: add length: support to SchemaChange::IndexAdd * TECH-13204: deprecate belongs_to index: 'name' and unique: true|false * TECH-13204: add index support for length; add options; refactor to_key and settings * TECH-13204: add spec for with_name and drop unused index_name * TECH-13204: fix bug where indexes on the same set of fields would not be allowed (now they must be equivalent) * TECH-13204: [] -> Set so that idempotence is built in * TECH-13204: include .to_a to convert Sets to Arrays * TECH-13204: raise ArgumentError if index: false contradicts other options * TECH-13204: update comment to drop mention of prefix (partial) indexes not being supported * TECH-13204: make #hash public * TECH-13204: test that parent class is lazy required * TECH-13204: unabbreviate fkey and refl * TECH-13204: treat belongs_to index: :name same as "name" * TECH-13204: parse lengths in for_model * TECH-13204: fix code to be confident that parent_table_name will be present * TECH-13204: add utf8mb3 -> utf8mb3_general_ci inference * TECH-13204: use reflection.class_name so class can be lazy-evaluated * TECH-13204: plumb connection from model into HabtmModelShim * TECH-13204: add IndexDefinition.normalize_index_length; use it to normalize user and database config before comparing * TECH-13204: drop connection: from HabtmModelShim.from_reflection; use klass instead of our own constantize * TECH-13204: add contract checks for ColumnAdd table_name and column_name * TECH-13204: exclude Array _declared_primary_key from consideration as a column * TECH-13204: use ActiveSupport::Deprecation for all warnings; include name.inspect * TECH-13204: add warnings about unnecessary null: and optional: combinations; qualify with [declare_schema] prefix * TECH-13204: document belongs_to args and options and which pass through * TECH-13204: release v1.4.0
1 parent 956aebd commit 9af3191

File tree

15 files changed

+658
-258
lines changed

15 files changed

+658
-258
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ Inspired by [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
44

55
Note: this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [1.4.0] - 2024-01-24
8+
### Added
9+
- Added support for partial indexes with `length:` option.
10+
### Changed
11+
- Deprecate index: 'name' and unique: true|false in favor of index: { name: 'name', unique: true|false }.
12+
713
## [1.3.6] - 2024-01-22
814
### Fixed
915
- Add missing commits around connection: and Array check for composite declared primary key.

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
declare_schema (1.3.6)
4+
declare_schema (1.4.0)
55
rails (>= 5.0)
66

77
GEM

README.md

Lines changed: 82 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Make a model and declare your schema within a `declare_schema do ... end` block:
99
class Company < ActiveRecord::Base
1010
declare_schema do
1111
string :company_name, limit: 100
12-
string :ticker_symbol, limit: 4, null: true, index: true, unique: true
12+
string :ticker_symbol, limit: 4, null: true, index: { unique: true }
1313
integer :employee_count
1414
text :comments
1515

@@ -60,6 +60,61 @@ declare_schema id: :bigint do
6060
end
6161
```
6262

63+
## declare_schema DSL field (column) declaration
64+
The `declare_schema` DSL is yielded to the block as shown with block variable `t` (for table).
65+
Each field (column) is declared with the syntax `t.<type> :<column_name>, <options>` as shown here for the `string` column `company_name`:
66+
```ruby
67+
create_table :companies, id: :bigint do |t|
68+
t.string :company_name, null: false, limit: 100
69+
...
70+
end
71+
```
72+
### Field (Column) Types
73+
All of the ActiveRecord field types are supported, as returned by the database driver in use at the time.
74+
These typically include:
75+
- `binary` (blob)
76+
- `text`
77+
- `integer`
78+
- `bigint`
79+
- `float`
80+
- `decimal`
81+
- `date`
82+
- `time`
83+
- `datetime`
84+
- `timestamp`
85+
- `string` (varchar)
86+
- `boolean` (tinyint 0 or 1)
87+
- `json`
88+
- `array`
89+
- `enum` (if using the `activerecord-mysql-enum` gem) (MySQL enum)
90+
91+
### Field (Column) Options
92+
The following field options are:
93+
- `limit` (integer) - The maximum length of the field. For `text` and `binary` fields, this is the maximum number of bytes.
94+
For `string` fields, this is the maximum number of characters, and defaults to `DeclareSchema.default_string_limit`; for `text`, defaults to `DeclareSchema.default_text_limit`.
95+
For `enum`
96+
- `null` (boolean) - Whether the field is nullable. Defaults to `DeclareSchema.default_null`.
97+
- `default` (any) - The default value for the field.
98+
- `ruby_default` (Proc) - A callable Ruby Proc that returns the default value for the field. This is useful for default values that require Ruby computation.
99+
(Provided by the `attr_default` gem.)
100+
- `index` (boolean [deprecated] or hash) - Whether to create an index for the field. If `true`, defaults to `{ unique: false }` [deprecated]. See below for supported `index` options.
101+
- `unique` [deprecated] (boolean) - Whether to create a unique index for the field. Defaults to `false`. Deprecated in favor of `index: { unique: <boolean> }`.
102+
- `charset` (string) - The character set for the field. Defaults to `default_charset` (see below).
103+
- `collation` (string) - The collation for the field. Defaults to `default_collation` (see below).
104+
- `precision` (integer) - The precision for the numeric field.
105+
- `scale` (integer) - The scale for the numeric field.
106+
107+
### Index Options
108+
The following `index` options are supported:
109+
- `name` (string) - The name of the index. Defaults the longest format that will fit within `DeclareSchema.max_index_and_constraint_name_length`. They are tried in this order:
110+
1. `index_<table>_on_<col1>[_and_<col2>...]>`.
111+
2. `__<col1>[_<col2>...]>`
112+
3. `<table_prefix><sha256_of_columns_prefix>`
113+
- `unique` (boolean) - Whether the index is unique. Defaults to `false`.
114+
- `order` (synbol or hash) - The index order. If `:asc` or `:desc` is provided, it is used as the order for all columns. If hash is provided, it is used to specify the order of individual columns, where the column names are given as `Symbol` hash keys with values of `:asc` or `:desc` indicating the sort order of that column.
115+
- `length` (integer or hash) - The partial index length(s). If an integer is provided, it is used as the length for all columns. If a hash is provided, it is used to specify the length for individual columns, where the column names are given as `Symbol` hash keys.
116+
- `where` (string) - The subset index predicate.
117+
63118
## Usage without Rails
64119

65120
When using `DeclareSchema` without Rails, you can use the `declare_schema/rake` task to generate the migration file.
@@ -115,13 +170,13 @@ end
115170
```
116171

117172
### clear_default_schema
118-
This method clears out any previously declared `default_schema`.
173+
This method clears out any previously declared `default_schema`. This can be useful for tests.
119174
```ruby
120175
DeclareSchema.clear_default_schema
121176
```
122177

123178
### Global Configuration
124-
Configurations can be set at the global level to customize default declaration for the following values:
179+
Configurations can be set globally to customize default declaration for the following values:
125180

126181
#### Text Limit
127182
The default text limit can be set using the `DeclareSchema.default_text_limit=` method.
@@ -134,8 +189,6 @@ set the default `text limit` value to `0xffff`:
134189

135190
**declare_schema.rb**
136191
```ruby
137-
# frozen_string_literal: true
138-
139192
DeclareSchema.default_text_limit = 0xffff
140193
```
141194

@@ -150,8 +203,6 @@ set the default `string limit` value to `255`:
150203

151204
**declare_schema.rb**
152205
```ruby
153-
# frozen_string_literal: true
154-
155206
DeclareSchema.default_string_limit = 255
156207
```
157208

@@ -166,40 +217,34 @@ set the default `null` value to `true`:
166217

167218
**declare_schema.rb**
168219
```ruby
169-
# frozen_string_literal: true
170-
171220
DeclareSchema.default_null = true
172221
```
173222

174223
#### Generate Foreign Keys
175-
The default value for generate foreign keys can be set using the `DeclareSchema.default_generate_foreign_keys=` method.
176-
This value defaults to `true` and can only be set at the global level.
224+
You can choose whether to generate foreign keys by using the `DeclareSchema.default_generate_foreign_keys=` method.
225+
This defaults to `true` and can only be set globally.
177226

178-
For example, adding the following to your `config/initializers` directory will set
179-
the default `generate foreign keys` value to `false`:
227+
For example, adding the following to your `config/initializers` directory will cause
228+
foreign keys not to be generated:
180229

181230
**declare_schema.rb**
182231
```ruby
183-
# frozen_string_literal: true
184-
185232
DeclareSchema.default_generate_foreign_keys = false
186233
```
187234

188235
#### Generate Indexing
189-
The default value for generate indexing can be set using the `DeclareSchema.default_generate_indexing=` method.
190-
This value defaults to `true` and can only be set at the global level.
236+
You can choose whether to generate indexes automatically by using the `DeclareSchema.default_generate_indexing=` method.
237+
This defaults to `true` and can only be set globally.
191238

192-
For example, adding the following to your `config/initializers` directory will
193-
set the default `generate indexing` value to `false`:
239+
For example, adding the following to your `config/initializers` directory will cause
240+
indexes not to be generated by `declare_schema`:
194241

195242
**declare_schema.rb**
196243
```ruby
197-
# frozen_string_literal: true
198-
199244
DeclareSchema.default_generate_indexing = false
200245
```
201246
#### Character Set and Collation
202-
The character set and collation for all tables and fields can be set at the global level
247+
The character set and collation for all tables and fields can be set at globally
203248
using the `Generators::DeclareSchema::Migrator.default_charset=` and
204249
`Generators::DeclareSchema::Migrator.default_collation=` configuration methods.
205250

@@ -208,8 +253,6 @@ turn all tables into `utf8mb4` supporting tables:
208253

209254
**declare_schema.rb**
210255
```ruby
211-
# frozen_string_literal: true
212-
213256
DeclareSchema.default_charset = "utf8mb4"
214257
DeclareSchema.default_collation = "utf8mb4_bin"
215258
```
@@ -224,7 +267,7 @@ bundle exec rails db:migrate
224267
```
225268
If your repo has a different command to run for migrations, you can configure it like this:
226269
```ruby
227-
`DeclareSchema.db_migrate_command = "bundle exec rails db:migrate_immediate"`
270+
DeclareSchema.db_migrate_command = "bundle exec rails db:migrate_immediate"
228271
```
229272

230273
## The `belongs_to` Association
@@ -233,24 +276,16 @@ association is outside of the `declare_schema do` block, so `declare_schema` int
233276
infer the foreign key column.
234277

235278
By default, `declare_schema` creates an index for `belongs_to` relations. If this default index is not desired,
236-
you can use `index: false` in the `belongs_to` expression. This may be the case if for example a different index
237-
already accounts for it.
279+
you can use `index: false` in the `belongs_to` expression. This may be the case if, for example, a different index
280+
already covers those columns at the front.
238281

239282
## The `has_and_belongs_to_many` Association
240283
Like the `belongs_to` association, `has_and_belongs_to_many` is outside of the `declare_schema ` block. `declare_schema` similarly
241284
infers foreign keys (and the intersection table).
242285

243286
## Ignored Tables
244-
If a table's schema or metadata are managed elsewhere, `declare_schema` probably should not alter it. Accordingly,
245-
`declare_schema` can be configured to ignore tables.
246-
247-
`declare_schema` by default ignores these tables:
248-
- The ActiveRecord `schema_info` table
249-
- The ActiveRecord schema migrations table (generally named `schema_migrations`)
250-
- The ActiveRecord internal metadata table (generally named `ar_internal_metadata`)
251-
- If defined/configured, the CGI ActiveRecordStore session table
252-
253-
Additional tables can be ignored by configuring `Generators::DeclareSchema::Migration::Migrator.ignore_tables`.
287+
If a table's schema or metadata are managed elsewhere, `declare_schema` can be instructed to ignore it
288+
by adding those table names to the array assigned to `Generators::DeclareSchema::Migration::Migrator.ignore_tables`.
254289
For example:
255290

256291
```ruby
@@ -261,6 +296,12 @@ For example:
261296
]
262297
```
263298

299+
Note: `declare_schema` always ignores these tables:
300+
- The ActiveRecord `schema_info` table
301+
- The ActiveRecord schema migrations table (generally named `schema_migrations`)
302+
- The ActiveRecord internal metadata table (generally named `ar_internal_metadata`)
303+
- If defined/configured, the CGI ActiveRecordStore session table
304+
264305
## Maximum Length of Index and Constraint Names
265306

266307
MySQL limits the length of index and constraint names to 64 characters.
@@ -282,7 +323,10 @@ But later, Unicode was extended beyond U+FFFF to make room for emojis, and with
282323
UTF-8 require 1-4 bytes (`mb4` or "multi-byte 4"). With this addition, there has
283324
come a need to dynamically define the character set and collation for individual
284325
tables and columns in the database. With `declare_schema` this can be configured
285-
at three separate levels
326+
at three separate levels.
327+
328+
### Global Configuration
329+
The global configuration option is explained above in the [Character Set and Collation](#Character-Set-and-Collation) section.
286330

287331
### Table Configuration
288332
In order to configure a table's default character set and collation, the `charset` and

0 commit comments

Comments
 (0)