rubocop-mismatched-foreign-key-type 0.1.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 +7 -0
- data/config/default.yml +7 -0
- data/lib/rubocop/cop/rails/mismatched_foreign_key_type.rb +121 -0
- data/lib/rubocop/mismatched_foreign_key_type/version.rb +7 -0
- data/lib/rubocop-mismatched-foreign-key-type.rb +3 -0
- data/spec/rubocop/cop/rails/mismatched_foreign_key_type_spec.rb +184 -0
- data/spec/spec_helper.rb +12 -0
- metadata +78 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: d7806c9473411325f857346dec50a0bfbd26446c245a01cca4afe9e0f365232f
|
|
4
|
+
data.tar.gz: 01cd58f6564b755edfac4b256dfe5efd8e1535345f660e9a2dba98a4cfb56990
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: d29bf6f4ccec1216fec2f3d7525b689746ee18ce040c761d9a2e3157dc1de65b037e4deee698c86f87cdb5f38584b07a38ac4deedd8bd2f54ccb8e0dcaadd8a6
|
|
7
|
+
data.tar.gz: 3a601d99511f6071975f6548ceafc48f002af2403f139d1816fb4a09781212b962a91b405e512ba29d81ff934d3443cd0f5c58419f2363223d196136f9fb5b93
|
data/config/default.yml
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/inflector'
|
|
4
|
+
|
|
5
|
+
module RuboCop
|
|
6
|
+
module Cop
|
|
7
|
+
module Rails
|
|
8
|
+
# This cop checks for foreign key type mismatches in db/schema.rb.
|
|
9
|
+
# It detects when a table uses `t.integer :xxx_id` but the referenced
|
|
10
|
+
# table's primary key is `bigint` (Rails 5.1+ default).
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
# # bad
|
|
14
|
+
# create_table "users", force: :cascade do |t|
|
|
15
|
+
# ...
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# create_table "posts", force: :cascade do |t|
|
|
19
|
+
# t.integer "user_id"
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# # good
|
|
23
|
+
# create_table "users", force: :cascade do |t|
|
|
24
|
+
# ...
|
|
25
|
+
# end
|
|
26
|
+
#
|
|
27
|
+
# create_table "posts", force: :cascade do |t|
|
|
28
|
+
# t.bigint "user_id"
|
|
29
|
+
# end
|
|
30
|
+
class MismatchedForeignKeyType < RuboCop::Cop::Base
|
|
31
|
+
MSG = 'Use bigint for foreign keys that reference bigint primary keys.'
|
|
32
|
+
|
|
33
|
+
def initialize(*args)
|
|
34
|
+
super
|
|
35
|
+
@table_pk_types = {}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Called before all on_xxx callbacks are executed.
|
|
39
|
+
def on_new_investigation
|
|
40
|
+
super
|
|
41
|
+
|
|
42
|
+
processed_source.ast.each_node(:send) do |node|
|
|
43
|
+
next unless node.method?(:create_table)
|
|
44
|
+
|
|
45
|
+
table_name = extract_table_name(node)
|
|
46
|
+
next unless table_name
|
|
47
|
+
|
|
48
|
+
@table_pk_types[table_name] = extract_pk_type(node)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def on_send(node)
|
|
53
|
+
return unless node.method?(:create_table)
|
|
54
|
+
|
|
55
|
+
block = node.block_node
|
|
56
|
+
check_integer_foreign_keys(block) if block
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def extract_table_name(node)
|
|
62
|
+
table_name_node = node.arguments.first
|
|
63
|
+
return unless table_name_node&.str_type?
|
|
64
|
+
|
|
65
|
+
table_name_node.value
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def extract_pk_type(node)
|
|
69
|
+
node.arguments.each do |arg|
|
|
70
|
+
next unless arg.hash_type?
|
|
71
|
+
|
|
72
|
+
pk_type = extract_pk_type_from_hash(arg)
|
|
73
|
+
return pk_type if pk_type
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Default to bigint (Rails 5.1+)
|
|
77
|
+
:bigint
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def extract_pk_type_from_hash(hash_node)
|
|
81
|
+
hash_node.each_pair do |key, value|
|
|
82
|
+
next unless key.sym_type? && key.value == :id
|
|
83
|
+
next unless value.sym_type?
|
|
84
|
+
|
|
85
|
+
case value.value
|
|
86
|
+
when :integer then return :integer
|
|
87
|
+
when :bigint then return :bigint
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
nil
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def check_integer_foreign_keys(block_node)
|
|
94
|
+
return unless block_node.body
|
|
95
|
+
|
|
96
|
+
block_node.body.each_node(:send) do |send_node|
|
|
97
|
+
next unless send_node.method_name == :integer
|
|
98
|
+
|
|
99
|
+
check_integer_foreign_key(send_node)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def check_integer_foreign_key(send_node)
|
|
104
|
+
fk_name = send_node.arguments.first&.value
|
|
105
|
+
return unless fk_name&.end_with?('_id')
|
|
106
|
+
|
|
107
|
+
referenced_table = extract_referenced_table(fk_name)
|
|
108
|
+
referenced_pk_type = @table_pk_types[referenced_table]
|
|
109
|
+
return unless referenced_pk_type == :bigint
|
|
110
|
+
|
|
111
|
+
add_offense(send_node, message: MSG)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def extract_referenced_table(fk_name)
|
|
115
|
+
base = fk_name.delete_suffix('_id')
|
|
116
|
+
base.pluralize
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
RSpec.describe RuboCop::Cop::Rails::MismatchedForeignKeyType, :config do
|
|
6
|
+
let(:config) do
|
|
7
|
+
RuboCop::Config.new(
|
|
8
|
+
'Rails/MismatchedForeignKeyType' => {
|
|
9
|
+
'Enabled' => true
|
|
10
|
+
}
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe 'MismatchedForeignKeyType' do
|
|
15
|
+
context 'when an incorrect foreign key type is used' do
|
|
16
|
+
it 'registers an offense for implicit bigint primary key' do
|
|
17
|
+
expect_offense(<<~RUBY)
|
|
18
|
+
create_table "users", force: :cascade do |t|
|
|
19
|
+
t.string "name"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
create_table "posts", force: :cascade do |t|
|
|
23
|
+
t.integer "user_id"
|
|
24
|
+
^^^^^^^^^^^^^^^^^^^ Use bigint for foreign keys that reference bigint primary keys.
|
|
25
|
+
end
|
|
26
|
+
RUBY
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'registers an offense for explicit bigint primary key' do
|
|
30
|
+
expect_offense(<<~RUBY)
|
|
31
|
+
create_table "users", id: :bigint, force: :cascade do |t|
|
|
32
|
+
t.string "name"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
create_table "posts", force: :cascade do |t|
|
|
36
|
+
t.integer "user_id"
|
|
37
|
+
^^^^^^^^^^^^^^^^^^^ Use bigint for foreign keys that reference bigint primary keys.
|
|
38
|
+
end
|
|
39
|
+
RUBY
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'registers offenses for multiple bigint primary keys' do
|
|
43
|
+
expect_offense(<<~RUBY)
|
|
44
|
+
create_table "users", force: :cascade do |t|
|
|
45
|
+
t.string "name"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
create_table "categories", force: :cascade do |t|
|
|
49
|
+
t.string "name"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
create_table "posts", force: :cascade do |t|
|
|
53
|
+
t.integer "user_id"
|
|
54
|
+
^^^^^^^^^^^^^^^^^^^ Use bigint for foreign keys that reference bigint primary keys.
|
|
55
|
+
t.integer "category_id"
|
|
56
|
+
^^^^^^^^^^^^^^^^^^^^^^^ Use bigint for foreign keys that reference bigint primary keys.
|
|
57
|
+
end
|
|
58
|
+
RUBY
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it 'registers an offense for foreign keys referencing tables with underscores' do
|
|
62
|
+
expect_offense(<<~RUBY)
|
|
63
|
+
create_table "user_profiles", force: :cascade do |t|
|
|
64
|
+
t.string "name"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
create_table "posts", force: :cascade do |t|
|
|
68
|
+
t.integer "user_profile_id"
|
|
69
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use bigint for foreign keys that reference bigint primary keys.
|
|
70
|
+
end
|
|
71
|
+
RUBY
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it 'registers offenses for various pluralization patterns' , :aggregate_failures do
|
|
75
|
+
expect_offense(<<~RUBY)
|
|
76
|
+
create_table "categories", force: :cascade do |t|
|
|
77
|
+
t.string "name"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
create_table "posts", force: :cascade do |t|
|
|
81
|
+
t.integer "category_id"
|
|
82
|
+
^^^^^^^^^^^^^^^^^^^^^^^ Use bigint for foreign keys that reference bigint primary keys.
|
|
83
|
+
end
|
|
84
|
+
RUBY
|
|
85
|
+
|
|
86
|
+
expect_offense(<<~RUBY)
|
|
87
|
+
create_table "addresses", force: :cascade do |t|
|
|
88
|
+
t.string "street"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
create_table "users", force: :cascade do |t|
|
|
92
|
+
t.integer "address_id"
|
|
93
|
+
^^^^^^^^^^^^^^^^^^^^^^ Use bigint for foreign keys that reference bigint primary keys.
|
|
94
|
+
end
|
|
95
|
+
RUBY
|
|
96
|
+
|
|
97
|
+
expect_offense(<<~RUBY)
|
|
98
|
+
create_table "people", force: :cascade do |t|
|
|
99
|
+
t.string "name"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
create_table "posts", force: :cascade do |t|
|
|
103
|
+
t.integer "person_id"
|
|
104
|
+
^^^^^^^^^^^^^^^^^^^^^ Use bigint for foreign keys that reference bigint primary keys.
|
|
105
|
+
end
|
|
106
|
+
RUBY
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it 'registers offense even if referenced table is defined laster' do
|
|
110
|
+
expect_offense(<<~RUBY)
|
|
111
|
+
create_table "posts", force: :cascade do |t|
|
|
112
|
+
t.integer "user_id"
|
|
113
|
+
^^^^^^^^^^^^^^^^^^^ Use bigint for foreign keys that reference bigint primary keys.
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
create_table "users", force: :cascade do |t|
|
|
117
|
+
t.string "name"
|
|
118
|
+
end
|
|
119
|
+
RUBY
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
context 'when the correct foreign key type is used' do
|
|
124
|
+
it 'does not register an offense for bigint foreign key referencing bigint primary key' do
|
|
125
|
+
expect_no_offenses(<<~RUBY)
|
|
126
|
+
create_table "users", force: :cascade do |t|
|
|
127
|
+
t.string "name"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
create_table "posts", force: :cascade do |t|
|
|
131
|
+
t.bigint "user_id"
|
|
132
|
+
end
|
|
133
|
+
RUBY
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it 'does not register an offense for integer foreign key referencing integer primary key' do
|
|
137
|
+
expect_no_offenses(<<~RUBY)
|
|
138
|
+
create_table "users", id: :integer, force: :cascade do |t|
|
|
139
|
+
t.string "name"
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
create_table "posts", force: :cascade do |t|
|
|
143
|
+
t.integer "user_id"
|
|
144
|
+
end
|
|
145
|
+
RUBY
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
context 'when not recognized as a foreign key' do
|
|
150
|
+
it 'does not register an offense if there is no foreign key column' do
|
|
151
|
+
expect_no_offenses(<<~RUBY)
|
|
152
|
+
create_table "users", force: :cascade do |t|
|
|
153
|
+
t.string "name"
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
create_table "posts", force: :cascade do |t|
|
|
157
|
+
t.string "title"
|
|
158
|
+
t.text "content"
|
|
159
|
+
end
|
|
160
|
+
RUBY
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
it 'does not register an offense if the referenced table does not exist' do
|
|
164
|
+
expect_no_offenses(<<~RUBY)
|
|
165
|
+
create_table "posts", force: :cascade do |t|
|
|
166
|
+
t.integer "user_id"
|
|
167
|
+
end
|
|
168
|
+
RUBY
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it 'does not register an offense for columns not ending with _id' do
|
|
172
|
+
expect_no_offenses(<<~RUBY)
|
|
173
|
+
create_table "users", force: :cascade do |t|
|
|
174
|
+
t.string "name"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
create_table "posts", force: :cascade do |t|
|
|
178
|
+
t.integer "user_reference"
|
|
179
|
+
end
|
|
180
|
+
RUBY
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rubocop'
|
|
4
|
+
require 'rubocop/rspec/support'
|
|
5
|
+
require "rubocop-mismatched-foreign-key-type"
|
|
6
|
+
|
|
7
|
+
RSpec.configure do |config|
|
|
8
|
+
config.disable_monkey_patching!
|
|
9
|
+
config.expect_with :rspec do |c|
|
|
10
|
+
c.syntax = :expect
|
|
11
|
+
end
|
|
12
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rubocop-mismatched-foreign-key-type
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- yohei.hokari
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 2025-12-25 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rubocop
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '1.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '1.0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: activesupport
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '6.0'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '6.0'
|
|
40
|
+
description: This cop identifies integer foreign keys that should be biginteger, based
|
|
41
|
+
on the primary key of the referenced table.
|
|
42
|
+
email:
|
|
43
|
+
- yohei.hokari@optim.co.jp
|
|
44
|
+
executables: []
|
|
45
|
+
extensions: []
|
|
46
|
+
extra_rdoc_files: []
|
|
47
|
+
files:
|
|
48
|
+
- config/default.yml
|
|
49
|
+
- lib/rubocop-mismatched-foreign-key-type.rb
|
|
50
|
+
- lib/rubocop/cop/rails/mismatched_foreign_key_type.rb
|
|
51
|
+
- lib/rubocop/mismatched_foreign_key_type/version.rb
|
|
52
|
+
- spec/rubocop/cop/rails/mismatched_foreign_key_type_spec.rb
|
|
53
|
+
- spec/spec_helper.rb
|
|
54
|
+
homepage: https://gitlab.tokyo.optim.co.jp/yohei.hokari/rubocop-mismatched-foreign-key-type
|
|
55
|
+
licenses:
|
|
56
|
+
- MIT
|
|
57
|
+
metadata:
|
|
58
|
+
homepage_uri: https://gitlab.tokyo.optim.co.jp/yohei.hokari/rubocop-mismatched-foreign-key-type
|
|
59
|
+
source_code_uri: https://gitlab.tokyo.optim.co.jp/yohei.hokari/rubocop-mismatched-foreign-key-type
|
|
60
|
+
changelog_uri: https://gitlab.tokyo.optim.co.jp/yohei.hokari/rubocop-mismatched-foreign-key-type/blob/main/CHANGELOG.md
|
|
61
|
+
rdoc_options: []
|
|
62
|
+
require_paths:
|
|
63
|
+
- lib
|
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: 3.0.0
|
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
70
|
+
requirements:
|
|
71
|
+
- - ">="
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
version: '0'
|
|
74
|
+
requirements: []
|
|
75
|
+
rubygems_version: 3.6.2
|
|
76
|
+
specification_version: 4
|
|
77
|
+
summary: A RuboCop extension to check for mismatched foreign key types in schema.rb.
|
|
78
|
+
test_files: []
|