db-migrate-x 0.2.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a8946c58a0fbd70adc0f1c92b27dcfc001ede4438379d1c90731c061c34ad79d
4
- data.tar.gz: 804e612a9163f3692b2265b881b806800dbe13eeb2cb3ce6c1c36e0dbab36d09
3
+ metadata.gz: 0e074cbb0b589d7362ae27ff450ada897cda5fe6f061fabe73f8c67cec13b16e
4
+ data.tar.gz: 75b1eb715150b5f8c7f26ccdb8b0c692c260876f4f7e110ed28546fe3bf2ba4f
5
5
  SHA512:
6
- metadata.gz: c62649721fe87d70e29554f15f147bcba2a168b951d28834f340ba42363d7c6984d6b0b4fe0e16c5bbd879d0f3eb2ddeef63e9f91feee77611eadffe9702cc3c
7
- data.tar.gz: ba5da48eaf8bf907a8e71f3264d71f8372426b67938ab28631185a02314f72d3b64cb57fd11063c27e7d59c10d9a25e925e4d261bfd6fd66f3d861ac32d94ca0
6
+ metadata.gz: b2c772821a3da23ce85e73175e8597ff6c91f087b4ddc9f11ad9369caa05853d6df705e6d6c816c66300def442a35e157a3af92543016d8179bbc95acd5c6cb5
7
+ data.tar.gz: f65162f9b2c246dcccaec045ea47f5e5bbe75b75cbc30983eb34a47c39d8b9cb7553e03708e0cfa63d0fa5862e71a502f87c5528505183a6e0bcd354ce8b8ac9
checksums.yaml.gz.sig CHANGED
Binary file
@@ -0,0 +1,183 @@
1
+ # Alter Table
2
+
3
+ This guide explains how to modify existing database tables using `db-migrate`.
4
+
5
+ ## Basic Table Alterations
6
+
7
+ Use `alter_table` to modify an existing table:
8
+
9
+ ```ruby
10
+ DB::Migrate.migrate("update_users_table", client) do
11
+ alter_table :users do
12
+ add_column :age, "INTEGER"
13
+ add_column :active, "BOOLEAN DEFAULT TRUE"
14
+ end
15
+ end
16
+ ```
17
+
18
+ ## Adding Columns
19
+
20
+ ### Basic Column Addition
21
+
22
+ ```ruby
23
+ alter_table :users do
24
+ add_column :email, "TEXT"
25
+ add_column :phone, "TEXT"
26
+ end
27
+ ```
28
+
29
+ ### Columns with Constraints
30
+
31
+ ```ruby
32
+ alter_table :users do
33
+ add_column :email, "TEXT NOT NULL"
34
+ add_column :age, "INTEGER", default: 0
35
+ add_column :status, "TEXT", unique: true
36
+ end
37
+ ```
38
+
39
+ ## Dropping Columns
40
+
41
+ ### Basic Column Removal
42
+
43
+ ```ruby
44
+ alter_table :users do
45
+ drop_column :old_field
46
+ drop_column :deprecated_column
47
+ end
48
+ ```
49
+
50
+ ### Safe Column Removal
51
+
52
+ Use `if_exists` to avoid errors if the column doesn't exist:
53
+
54
+ ```ruby
55
+ alter_table :users do
56
+ drop_column :maybe_missing_column, if_exists: true
57
+ end
58
+ ```
59
+
60
+ ## Renaming Columns
61
+
62
+ ```ruby
63
+ alter_table :users do
64
+ rename_column :full_name, :name
65
+ rename_column :email_address, :email
66
+ end
67
+ ```
68
+
69
+ ## Changing Column Types
70
+
71
+ Use `change_column` to modify a column's data type:
72
+
73
+ ```ruby
74
+ alter_table :users do
75
+ change_column :age, "INTEGER"
76
+ change_column :balance, "DECIMAL(10,2)"
77
+ end
78
+ ```
79
+
80
+ ### Database-Specific Behavior
81
+
82
+ The gem automatically uses the appropriate syntax for your database:
83
+
84
+ **PostgreSQL:**
85
+ ```sql
86
+ ALTER TABLE users ALTER COLUMN age TYPE INTEGER USING age::INTEGER;
87
+ ```
88
+
89
+ **MariaDB/MySQL:**
90
+ ```sql
91
+ ALTER TABLE users MODIFY COLUMN age INTEGER;
92
+ ```
93
+
94
+ ## Multiple Operations
95
+
96
+ Combine multiple alterations in a single migration:
97
+
98
+ ```ruby
99
+ alter_table :users do
100
+ add_column :middle_name, "TEXT"
101
+ drop_column :old_field, if_exists: true
102
+ rename_column :full_name, :name
103
+ change_column :age, "INTEGER"
104
+ end
105
+ ```
106
+
107
+ ## Advanced Examples
108
+
109
+ ### Data Type Conversions
110
+
111
+ ```ruby
112
+ # Convert text to integer with explicit casting
113
+ alter_table :products do
114
+ change_column :price_text, "DECIMAL(10,2)"
115
+ end
116
+ ```
117
+
118
+ For PostgreSQL, this automatically includes a `USING` clause for safe conversion.
119
+
120
+ ### Adding Columns with Complex Defaults
121
+
122
+ ```ruby
123
+ alter_table :orders do
124
+ add_column :order_number, "TEXT NOT NULL",
125
+ default: "'ORD-' || EXTRACT(epoch FROM NOW())::TEXT"
126
+ end
127
+ ```
128
+
129
+ ### Conditional Schema Changes
130
+
131
+ ```ruby
132
+ alter_table :users do
133
+ # Only add column if it doesn't exist
134
+ unless information_schema.column_exists?(:users, :created_at)
135
+ add_column :created_at, "TIMESTAMP DEFAULT NOW()"
136
+ end
137
+ end
138
+ ```
139
+
140
+ ## Feature Detection
141
+
142
+ The gem uses feature detection to ensure compatibility:
143
+
144
+ - **Conditional Operations**: `IF EXISTS` clauses are only used when supported
145
+ - **Column Modification**: Uses `MODIFY COLUMN` (MariaDB) vs `ALTER COLUMN TYPE` (PostgreSQL)
146
+ - **Using Clauses**: PostgreSQL's `USING` clause for safe type conversions
147
+
148
+ ## Best Practices
149
+
150
+ ### Safe Alterations
151
+
152
+ Always use conditional operations when uncertain:
153
+
154
+ ```ruby
155
+ alter_table :users do
156
+ drop_column :deprecated_field, if_exists: true
157
+ add_column :new_field, "TEXT"
158
+ end
159
+ ```
160
+
161
+ ### Incremental Changes
162
+
163
+ Make small, focused changes rather than large alterations:
164
+
165
+ ```ruby
166
+ # Good: Focused change
167
+ alter_table :users do
168
+ add_column :email_verified, "BOOLEAN DEFAULT FALSE"
169
+ end
170
+
171
+ # Better than: Large, complex change
172
+ alter_table :users do
173
+ add_column :email_verified, "BOOLEAN DEFAULT FALSE"
174
+ add_column :phone_verified, "BOOLEAN DEFAULT FALSE"
175
+ add_column :two_factor_enabled, "BOOLEAN DEFAULT FALSE"
176
+ drop_column :old_verification_method, if_exists: true
177
+ rename_column :verification_code, :email_verification_code
178
+ end
179
+ ```
180
+
181
+ ### Performance Considerations
182
+
183
+ For large tables, consider the performance impact of schema changes, especially when adding `NOT NULL` columns without defaults.
@@ -0,0 +1,217 @@
1
+ # Create Index
2
+
3
+ This guide explains how to create database indexes using `db-migrate`.
4
+
5
+ ## Basic Index Creation
6
+
7
+ Use `create_index` to add indexes for better query performance:
8
+
9
+ ```ruby
10
+ DB::Migrate.migrate("add_user_indexes", client) do
11
+ create_index :users, :email
12
+ create_index :users, :name
13
+ end
14
+ ```
15
+
16
+ ## Composite Indexes
17
+
18
+ Create indexes on multiple columns:
19
+
20
+ ```ruby
21
+ DB::Migrate.migrate("add_composite_indexes", client) do
22
+ create_index :orders, [:user_id, :created_at]
23
+ create_index :user_preferences, [:user_id, :preference_key]
24
+ end
25
+ ```
26
+
27
+ ## Index Options
28
+
29
+ ### Unique Indexes
30
+
31
+ Enforce uniqueness at the database level:
32
+
33
+ ```ruby
34
+ create_index :users, :email, unique: true
35
+ create_index :user_preferences, [:user_id, :preference_key], unique: true
36
+ ```
37
+
38
+ ### Named Indexes
39
+
40
+ Specify custom index names:
41
+
42
+ ```ruby
43
+ create_index :users, :email, name: "idx_users_email_unique", unique: true
44
+ create_index :orders, [:user_id, :status], name: "idx_orders_user_status"
45
+ ```
46
+
47
+ ### Conditional Indexes (PostgreSQL)
48
+
49
+ Create partial indexes with conditions:
50
+
51
+ ```ruby
52
+ # PostgreSQL-specific conditional index
53
+ create_index :users, :email,
54
+ name: "idx_active_users_email",
55
+ condition: "active = true"
56
+ ```
57
+
58
+ ## Index Types
59
+
60
+ ### Standard B-tree Indexes
61
+
62
+ Default index type, good for equality and range queries:
63
+
64
+ ```ruby
65
+ create_index :users, :created_at # Range queries
66
+ create_index :users, :status # Equality queries
67
+ ```
68
+
69
+ ### Database-Specific Index Types
70
+
71
+ ```ruby
72
+ # PostgreSQL GIN index for JSONB
73
+ create_index :documents, :metadata, type: "GIN"
74
+
75
+ # PostgreSQL GiST index for geometric data
76
+ create_index :locations, :coordinates, type: "GiST"
77
+
78
+ # Text search indexes
79
+ create_index :articles, :content, type: "GIN",
80
+ expression: "to_tsvector('english', content)"
81
+ ```
82
+
83
+ ## Advanced Examples
84
+
85
+ ### Functional Indexes
86
+
87
+ Create indexes on expressions:
88
+
89
+ ```ruby
90
+ # Index on lowercase email for case-insensitive searches
91
+ create_index :users, nil,
92
+ name: "idx_users_email_lower",
93
+ expression: "LOWER(email)"
94
+
95
+ # Index on extracted JSON field
96
+ create_index :documents, nil,
97
+ name: "idx_documents_title",
98
+ expression: "metadata->>'title'"
99
+ ```
100
+
101
+ ### Concurrent Index Creation (PostgreSQL)
102
+
103
+ For large tables, create indexes without blocking writes:
104
+
105
+ ```ruby
106
+ # Note: This requires special handling and may not be supported
107
+ # in all migration contexts due to transaction requirements
108
+ create_index :large_table, :important_column,
109
+ algorithm: "CONCURRENTLY"
110
+ ```
111
+
112
+ ## Performance Considerations
113
+
114
+ ### Index Strategy
115
+
116
+ Choose indexes based on your query patterns:
117
+
118
+ ```ruby
119
+ # Good: Index frequently queried columns
120
+ create_index :orders, :user_id # For user's orders
121
+ create_index :orders, :created_at # For recent orders
122
+ create_index :orders, :status # For order filtering
123
+
124
+ # Composite index for common query combinations
125
+ create_index :orders, [:user_id, :status] # For user's pending orders
126
+ ```
127
+
128
+ ### Avoid Over-Indexing
129
+
130
+ Don't create unnecessary indexes:
131
+
132
+ ```ruby
133
+ # Avoid: Too many single-column indexes
134
+ create_index :users, :first_name
135
+ create_index :users, :last_name
136
+ create_index :users, [:first_name, :last_name] # This composite covers both
137
+
138
+ # Better: Strategic composite index
139
+ create_index :users, [:last_name, :first_name] # Covers both queries
140
+ ```
141
+
142
+ ## Creating Indexes in Table Definitions
143
+
144
+ You can also create indexes when defining tables:
145
+
146
+ ```ruby
147
+ create_table :users do
148
+ primary_key
149
+ column :email, "TEXT NOT NULL", unique: true, index: true
150
+ column :name, "TEXT", index: true
151
+ timestamps
152
+
153
+ # Composite indexes
154
+ index [:email, :created_at]
155
+ index [:name, :active], name: "idx_active_users_by_name"
156
+ end
157
+ ```
158
+
159
+ ## Dropping Indexes
160
+
161
+ Remove indexes when they're no longer needed:
162
+
163
+ ```ruby
164
+ DB::Migrate.migrate("cleanup_unused_indexes", client) do
165
+ drop_index :idx_old_user_lookup, if_exists: true
166
+ drop_index :idx_deprecated_search, if_exists: true
167
+ end
168
+ ```
169
+
170
+ ## Feature Detection
171
+
172
+ The gem automatically handles database-specific index features:
173
+
174
+ - **Conditional Indexes**: Only used when supported (PostgreSQL)
175
+ - **Index Types**: Database-specific types like GIN, GiST
176
+ - **IF EXISTS**: Safe index creation/removal when supported
177
+
178
+ ## Best Practices
179
+
180
+ ### Index Naming Convention
181
+
182
+ Use consistent naming patterns:
183
+
184
+ ```ruby
185
+ # Good: Descriptive names
186
+ create_index :users, :email, name: "idx_users_email"
187
+ create_index :orders, [:user_id, :status], name: "idx_orders_user_status"
188
+
189
+ # Pattern: idx_{table}_{columns}_{suffix}
190
+ create_index :users, :email, name: "idx_users_email_unique", unique: true
191
+ ```
192
+
193
+ ### Monitor Index Usage
194
+
195
+ Regularly review index effectiveness:
196
+
197
+ ```sql
198
+ -- PostgreSQL: Check index usage
199
+ SELECT schemaname, tablename, indexname, idx_scan
200
+ FROM pg_stat_user_indexes
201
+ WHERE idx_scan = 0;
202
+
203
+ -- MariaDB: Check index cardinality
204
+ SHOW INDEX FROM users;
205
+ ```
206
+
207
+ ### Index Maintenance
208
+
209
+ Consider index maintenance in high-traffic applications:
210
+
211
+ ```ruby
212
+ # For very large tables, create indexes during low-traffic periods
213
+ DB::Migrate.migrate("add_large_table_index", client) do
214
+ # Consider creating this during maintenance windows
215
+ create_index :large_transaction_table, :created_at
216
+ end
217
+ ```
@@ -0,0 +1,170 @@
1
+ # Create Table
2
+
3
+ This guide explains how to create database tables using `db-migrate`.
4
+
5
+ ## Basic Table Creation
6
+
7
+ Use `create_table` to define a new table:
8
+
9
+ ```ruby
10
+ DB::Migrate.migrate("create_users", client) do
11
+ create_table :users do
12
+ primary_key
13
+ column :name, "TEXT NOT NULL"
14
+ column :email, "TEXT UNIQUE"
15
+ timestamps
16
+ end
17
+ end
18
+ ```
19
+
20
+ ## Conditional Table Creation
21
+
22
+ Use `create_table?` to create a table only if it doesn't already exist:
23
+
24
+ ```ruby
25
+ DB::Migrate.migrate("safe_create_users", client) do
26
+ create_table? :users do
27
+ primary_key
28
+ column :name, "TEXT NOT NULL"
29
+ end
30
+ end
31
+ ```
32
+
33
+ ## Column Definitions
34
+
35
+ ### Basic Columns
36
+
37
+ Define columns with their SQL type:
38
+
39
+ ```ruby
40
+ create_table :products do
41
+ column :name, "TEXT NOT NULL"
42
+ column :price, "DECIMAL(10,2)"
43
+ column :description, "TEXT"
44
+ column :active, "BOOLEAN DEFAULT TRUE"
45
+ end
46
+ ```
47
+
48
+ ### Primary Keys
49
+
50
+ Add an auto-incrementing primary key:
51
+
52
+ ```ruby
53
+ create_table :users do
54
+ primary_key # Creates 'id' column
55
+ # Other columns...
56
+ end
57
+
58
+ # Custom primary key name
59
+ create_table :users do
60
+ primary_key :user_id
61
+ # Other columns...
62
+ end
63
+ ```
64
+
65
+ The primary key uses database-appropriate types:
66
+ - PostgreSQL: `BIGSERIAL PRIMARY KEY`
67
+ - MariaDB/MySQL: `BIGINT AUTO_INCREMENT PRIMARY KEY`
68
+
69
+ ### Timestamps
70
+
71
+ Add created_at and updated_at columns:
72
+
73
+ ```ruby
74
+ create_table :posts do
75
+ primary_key
76
+ column :title, "TEXT NOT NULL"
77
+ timestamps # Adds created_at and updated_at
78
+ end
79
+ ```
80
+
81
+ ## Column Options
82
+
83
+ ### Constraints
84
+
85
+ ```ruby
86
+ create_table :users do
87
+ primary_key
88
+ column :email, "TEXT NOT NULL", unique: true
89
+ column :age, "INTEGER", null: false
90
+ column :status, "TEXT", default: "'active'"
91
+ end
92
+ ```
93
+
94
+ ### Indexes
95
+
96
+ Create indexes on columns:
97
+
98
+ ```ruby
99
+ create_table :users do
100
+ primary_key
101
+ column :email, "TEXT NOT NULL", unique: true, index: true
102
+ column :name, "TEXT", index: true
103
+ end
104
+ ```
105
+
106
+ ## Advanced Examples
107
+
108
+ ### Composite Indexes
109
+
110
+ ```ruby
111
+ create_table :user_preferences do
112
+ primary_key
113
+ column :user_id, "BIGINT NOT NULL"
114
+ column :preference_key, "TEXT NOT NULL"
115
+ column :preference_value, "TEXT"
116
+
117
+ # Create composite index
118
+ index [:user_id, :preference_key], unique: true
119
+ end
120
+ ```
121
+
122
+ ### Foreign Key References
123
+
124
+ ```ruby
125
+ create_table :posts do
126
+ primary_key
127
+ column :user_id, "BIGINT NOT NULL"
128
+ column :title, "TEXT NOT NULL"
129
+ column :content, "TEXT"
130
+ timestamps
131
+
132
+ # Note: Foreign key constraints are defined separately
133
+ # This just creates the reference column
134
+ end
135
+ ```
136
+
137
+ ### Database-Specific Types
138
+
139
+ ```ruby
140
+ create_table :analytics do
141
+ primary_key
142
+ column :event_data, "JSONB" # PostgreSQL
143
+ column :tags, "JSON" # MariaDB/MySQL
144
+ column :metadata, "TEXT" # Universal fallback
145
+ end
146
+ ```
147
+
148
+ ## Options
149
+
150
+ ### Drop Existing Table
151
+
152
+ Replace an existing table:
153
+
154
+ ```ruby
155
+ create_table :users, drop_if_exists: true do
156
+ primary_key
157
+ column :name, "TEXT NOT NULL"
158
+ end
159
+ ```
160
+
161
+ ### Temporary Tables
162
+
163
+ ```ruby
164
+ create_table :temp_data, temporary: true do
165
+ column :id, "BIGINT"
166
+ column :data, "TEXT"
167
+ end
168
+ ```
169
+
170
+ Note: Temporary table support depends on your database adapter implementation.