├── .gitignore ├── .travis.yml ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── activerecord-mysql-unsigned.gemspec ├── lib ├── activerecord-mysql-unsigned.rb └── activerecord-mysql-unsigned │ ├── active_record │ ├── v3 │ │ └── connection_adapters │ │ │ ├── abstract │ │ │ ├── schema_creation.rb │ │ │ └── schema_definitions.rb │ │ │ └── abstract_mysql_adapter.rb │ └── v4 │ │ └── connection_adapters │ │ ├── abstract │ │ └── schema_definitions.rb │ │ └── abstract_mysql_adapter.rb │ ├── base.rb │ ├── railtie.rb │ └── version.rb ├── spec ├── after_option_spec.rb ├── bigint_primary_key_spec.rb ├── spec_helper.rb ├── support │ ├── database_cleaner.rb │ ├── migrations.rb │ └── models.rb └── unsigned_spec.rb └── vendor └── .keep /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | 19 | # added 20 | .DS_Store 21 | vendor/bundle 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 1.9.3 4 | - 2.0.0 5 | - 2.1 6 | env: 7 | - "AR_VERSION=3.2.21" 8 | - "AR_VERSION=4.0.12" 9 | - "AR_VERSION=4.1.8" 10 | - "AR_VERSION=4.2.0.beta4" 11 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem "activerecord", "~> #{ENV['AR_VERSION']}" if ENV['AR_VERSION'] 4 | 5 | # Specify your gem's dependencies in activerecord-mysql-unsigned.gemspec 6 | gemspec 7 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 yo_waka 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Activerecord::Mysql::Unsigned 2 | 3 | [![Build Status](https://travis-ci.org/waka/activerecord-mysql-unsigned.png?branch=master)](https://travis-ci.org/waka/activerecord-mysql-unsigned) [![Gem Version](https://badge.fury.io/rb/activerecord-mysql-unsigned.svg)](http://badge.fury.io/rb/activerecord-mysql-unsigned) 4 | 5 | Add unsigned option to integer type for ActiveRecord's MySQL2 adapter. 6 | 7 | ## Support version 8 | 9 | ``` 10 | 5.0 > ActiveRecord::VERSION >= 3.2 11 | ``` 12 | 13 | ## Installation 14 | 15 | Add this line to your application's Gemfile: 16 | 17 | gem 'activerecord-mysql-unsigned' 18 | 19 | And then execute: 20 | 21 | $ bundle 22 | 23 | Or install it yourself as: 24 | 25 | $ gem install activerecord-mysql-unsigned 26 | 27 | ## Usage 28 | 29 | In your migrations you can define integer fields such as: 30 | 31 | ``` 32 | class CreateUsersTable < ActiveRecord::Migration 33 | def self.change 34 | create_table :users, force: true do |t| 35 | t.string :name, null: false 36 | t.integer :age, null: false, unsigned: true 37 | end 38 | end 39 | end 40 | ``` 41 | 42 | You can redefine in the existing fields. 43 | 44 | ``` 45 | class ChangeColumnToUsersTable < ActiveRecord::Migration 46 | def self.change 47 | change_column :users, :age, :integer, null: false, unsigned: false 48 | end 49 | end 50 | ``` 51 | 52 | And you can also redefine in the primary key. 53 | 54 | ``` 55 | class ChangeColumnToUsersTable < ActiveRecord::Migration 56 | def self.change 57 | change_column :users, :id, :integer, null: false, auto_increment: true, unsigned: true 58 | end 59 | end 60 | ``` 61 | 62 | ## Contributing 63 | 64 | 1. Fork it 65 | 2. Create your feature branch (`git checkout -b my-new-feature`) 66 | 3. Commit your changes (`git commit -am 'Add some feature'`) 67 | 4. Push to the branch (`git push origin my-new-feature`) 68 | 5. Create new Pull Request 69 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | 3 | # Travis CI use RSpec as default task 4 | task :default => [:spec] 5 | begin 6 | require 'rspec/core/rake_task' 7 | RSpec::Core::RakeTask.new(:spec) do |spec| 8 | spec.pattern = 'spec/**/*_spec.rb' 9 | end 10 | rescue LoadError => e 11 | end 12 | -------------------------------------------------------------------------------- /activerecord-mysql-unsigned.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'activerecord-mysql-unsigned/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "activerecord-mysql-unsigned" 8 | spec.version = ActiveRecord::Mysql::Unsigned::VERSION 9 | spec.authors = ["yo_waka"] 10 | spec.email = ["y.wakahara@gmail.com"] 11 | spec.description = %q{Add unsigned option to integer type for ActiveRecord's MySQL2 adapter} 12 | spec.summary = %q{Add unsigned option to integer type for ActiveRecord's MySQL2 adapter} 13 | spec.homepage = "https://github.com/waka/activerecord-mysql-unsigned" 14 | spec.license = "MIT" 15 | 16 | spec.files = `git ls-files`.split($/) 17 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 18 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 19 | spec.require_paths = ["lib"] 20 | 21 | spec.add_development_dependency "bundler", "~> 1.3" 22 | spec.add_development_dependency "rake" 23 | spec.add_development_dependency "rspec", "~> 3.0.0" 24 | spec.add_development_dependency "database_cleaner" 25 | spec.add_runtime_dependency "activesupport", ">= 3.2", "< 5.0" 26 | spec.add_runtime_dependency "activerecord", ">= 3.2", "< 5.0" 27 | spec.add_runtime_dependency "mysql2" 28 | end 29 | -------------------------------------------------------------------------------- /lib/activerecord-mysql-unsigned.rb: -------------------------------------------------------------------------------- 1 | require 'active_support' 2 | 3 | begin 4 | require 'rails' 5 | rescue LoadError 6 | # nothing to do! yay! 7 | end 8 | 9 | if defined? Rails 10 | require 'activerecord-mysql-unsigned/railtie' 11 | else 12 | ActiveSupport.on_load :active_record do 13 | require 'activerecord-mysql-unsigned/base' 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/activerecord-mysql-unsigned/active_record/v3/connection_adapters/abstract/schema_creation.rb: -------------------------------------------------------------------------------- 1 | module ActiveRecord 2 | module ConnectionAdapters 3 | class AbstractAdapter 4 | class SchemaCreation # :nodoc: 5 | def initialize(conn) 6 | @conn = conn 7 | end 8 | 9 | private 10 | 11 | def column_options(o) 12 | column_options = {} 13 | column_options[:null] = o.null unless o.null.nil? 14 | column_options[:default] = o.default unless o.default.nil? 15 | column_options[:column] = o 16 | column_options[:first] = o.first 17 | column_options[:after] = o.after 18 | column_options 19 | end 20 | 21 | def quote_column_name(name) 22 | @conn.quote_column_name name 23 | end 24 | 25 | def add_column_options!(sql, options) 26 | sql << " DEFAULT #{quote_value(options[:default], options[:column])}" if options_include_default?(options) 27 | # must explicitly check for :null to allow change_column to work on migrations 28 | if options[:null] == false 29 | sql << " NOT NULL" 30 | end 31 | if options[:auto_increment] == true 32 | sql << " AUTO_INCREMENT" 33 | end 34 | sql 35 | end 36 | 37 | def quote_value(value, column) 38 | @conn.quote(value, column) 39 | end 40 | 41 | def options_include_default?(options) 42 | options.include?(:default) && !(options[:null] == false && options[:default].nil?) 43 | end 44 | end 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /lib/activerecord-mysql-unsigned/active_record/v3/connection_adapters/abstract/schema_definitions.rb: -------------------------------------------------------------------------------- 1 | require 'active_record/connection_adapters/abstract/schema_definitions' 2 | 3 | module ActiveRecord 4 | module ConnectionAdapters 5 | class ColumnDefinition 6 | attr_accessor :unsigned, :first, :after 7 | 8 | def sql_type 9 | base.type_to_sql(type.to_sym, limit, precision, scale, unsigned) rescue type 10 | end 11 | end 12 | 13 | class TableDefinition 14 | def primary_key(name, type = :primary_key, options = {}) 15 | column(name, type, options.merge(primary_key: true).reverse_merge(unsigned: true)) 16 | end 17 | 18 | alias_method :column_without_unsigned, :column 19 | def column(name, type, options = {}) 20 | column_without_unsigned(name, type, options) 21 | column = self[name] 22 | column.unsigned = options[:unsigned] 23 | self 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /lib/activerecord-mysql-unsigned/active_record/v3/connection_adapters/abstract_mysql_adapter.rb: -------------------------------------------------------------------------------- 1 | require 'activerecord-mysql-unsigned/active_record/v4/connection_adapters/abstract_mysql_adapter' 2 | 3 | module ActiveRecord 4 | module ConnectionAdapters 5 | class AbstractMysqlAdapter < AbstractAdapter 6 | 7 | class TableDefinition 8 | def initialize(base) 9 | @base = base 10 | end 11 | 12 | def new_column_definition(name, type, options) # :nodoc: 13 | column = create_column_definition name, type 14 | limit = options.fetch(:limit) do 15 | native[type][:limit] if native[type].is_a?(Hash) 16 | end 17 | 18 | column.limit = limit 19 | column.precision = options[:precision] 20 | column.scale = options[:scale] 21 | column.unsigned = options[:unsigned] 22 | column.default = options[:default] 23 | column.null = options[:null] 24 | column.first = options[:first] 25 | column.after = options[:after] 26 | column 27 | end 28 | 29 | private 30 | 31 | def create_column_definition(name, type) 32 | ColumnDefinition.new @base, name, type 33 | end 34 | 35 | def native 36 | @base.native_database_types 37 | end 38 | end 39 | 40 | def schema_creation 41 | SchemaCreation.new self 42 | end 43 | 44 | def create_table_definition(name, temporary, options) 45 | TableDefinition.new self 46 | end 47 | 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /lib/activerecord-mysql-unsigned/active_record/v4/connection_adapters/abstract/schema_definitions.rb: -------------------------------------------------------------------------------- 1 | require 'active_record/connection_adapters/abstract/schema_definitions' 2 | 3 | module ActiveRecord 4 | module ConnectionAdapters 5 | class ColumnDefinition 6 | attr_accessor :unsigned 7 | end 8 | 9 | class TableDefinition 10 | def primary_key(name, type = :primary_key, options = {}) 11 | column(name, type, options.merge(primary_key: true).reverse_merge(unsigned: true)) 12 | end 13 | 14 | alias_method :new_column_definition_without_unsigned, :new_column_definition 15 | def new_column_definition(name, type, options) 16 | column = new_column_definition_without_unsigned(name, type, options) 17 | column.unsigned = options[:unsigned] 18 | column 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/activerecord-mysql-unsigned/active_record/v4/connection_adapters/abstract_mysql_adapter.rb: -------------------------------------------------------------------------------- 1 | require 'active_record/connection_adapters/abstract_mysql_adapter' 2 | 3 | module ActiveRecord 4 | module ConnectionAdapters 5 | class AbstractMysqlAdapter < AbstractAdapter 6 | 7 | class ChangeColumnDefinition < Struct.new(:column, :type, :options) #:nodoc: 8 | end 9 | 10 | class SchemaCreation < AbstractAdapter::SchemaCreation 11 | def visit_AddColumn(o) 12 | sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale, o.unsigned) 13 | add_column_sql = "ADD #{quote_column_name(o.name)} #{sql_type}" 14 | add_column_options!(add_column_sql, column_options(o)) unless o.type.to_sym == :primary_key 15 | add_column_position!(add_column_sql, column_options(o)) 16 | 17 | add_column_sql 18 | end 19 | 20 | def visit_ChangeColumnDefinition(o) 21 | column = o.column 22 | options = o.options 23 | sql_type = type_to_sql(o.type, options[:limit], options[:precision], options[:scale], options[:unsigned]) 24 | change_column_sql = "CHANGE #{quote_column_name(column.name)} #{quote_column_name(options[:name])} #{sql_type}" 25 | add_column_options!(change_column_sql, options.merge(column: column)) unless o.type.to_sym == :primary_key 26 | add_column_position!(change_column_sql, options) 27 | 28 | change_column_sql 29 | end 30 | 31 | def visit_ColumnDefinition(o) 32 | sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale, o.unsigned) 33 | column_sql = "#{quote_column_name(o.name)} #{sql_type}" 34 | add_column_options!(column_sql, column_options(o)) unless o.type.to_sym == :primary_key 35 | 36 | column_sql 37 | end 38 | 39 | def column_options(o) 40 | column_options = super 41 | column_options[:first] = o.first 42 | column_options[:after] = o.after 43 | column_options 44 | end 45 | 46 | def add_column_position!(sql, options) 47 | if options[:first] 48 | sql << " FIRST" 49 | elsif options[:after] 50 | sql << " AFTER #{quote_column_name(options[:after])}" 51 | end 52 | end 53 | 54 | def type_to_sql(type, limit, precision, scale, unsigned = false) 55 | @conn.type_to_sql type.to_sym, limit, precision, scale, unsigned 56 | end 57 | end 58 | 59 | class Column < ConnectionAdapters::Column # :nodoc: 60 | def unsigned? 61 | sql_type =~ /unsigned/i 62 | end 63 | end 64 | 65 | def prepare_column_options(column, types) # :nodoc: 66 | spec = super 67 | spec[:unsigned] = 'true' if column.unsigned? 68 | spec 69 | end 70 | 71 | def migration_keys 72 | super + [:unsigned] 73 | end 74 | 75 | alias_method :type_to_sql_without_unsigned, :type_to_sql 76 | def type_to_sql(type, limit = nil, precision = nil, scale = nil, unsigned = false) 77 | case type.to_s 78 | when 'integer' 79 | case limit 80 | when nil, 4, 11; 'int' # compatibility with MySQL default 81 | else 82 | type_to_sql_without_unsigned(type, limit, precision, scale) 83 | end.tap do |sql_type| 84 | sql_type << ' unsigned' if unsigned 85 | end 86 | when 'float', 'decimal' 87 | type_to_sql_without_unsigned(type, limit, precision, scale).tap do |sql_type| 88 | sql_type << ' unsigned' if unsigned 89 | end 90 | when 'primary_key' 91 | "#{type_to_sql(:integer, limit, precision, scale, unsigned)} auto_increment PRIMARY KEY" 92 | else 93 | type_to_sql_without_unsigned(type, limit, precision, scale) 94 | end 95 | end 96 | 97 | def add_column_sql(table_name, column_name, type, options = {}) 98 | td = create_table_definition table_name, options[:temporary], options[:options] 99 | cd = td.new_column_definition(column_name, type, options) 100 | schema_creation.visit_AddColumn cd 101 | end 102 | 103 | def change_column_sql(table_name, column_name, type, options = {}) 104 | column = column_for(table_name, column_name) 105 | 106 | unless options_include_default?(options) 107 | options[:default] = column.default 108 | end 109 | 110 | unless options.has_key?(:null) 111 | options[:null] = column.null 112 | end 113 | 114 | options[:name] = column.name 115 | schema_creation.visit_ChangeColumnDefinition ChangeColumnDefinition.new column, type, options 116 | end 117 | 118 | end 119 | end 120 | end 121 | -------------------------------------------------------------------------------- /lib/activerecord-mysql-unsigned/base.rb: -------------------------------------------------------------------------------- 1 | if ActiveRecord::VERSION::MAJOR == 4 2 | require 'activerecord-mysql-unsigned/active_record/v4/connection_adapters/abstract/schema_definitions' 3 | require 'activerecord-mysql-unsigned/active_record/v4/connection_adapters/abstract_mysql_adapter' 4 | elsif ActiveRecord::VERSION::MAJOR == 3 5 | require 'activerecord-mysql-unsigned/active_record/v3/connection_adapters/abstract/schema_definitions' 6 | require 'activerecord-mysql-unsigned/active_record/v3/connection_adapters/abstract/schema_creation' 7 | require 'activerecord-mysql-unsigned/active_record/v3/connection_adapters/abstract_mysql_adapter' 8 | else 9 | raise "activerecord-mysql-unsigned supprts ActiveRecord::VERSION::MAJOR >= 3" 10 | end 11 | -------------------------------------------------------------------------------- /lib/activerecord-mysql-unsigned/railtie.rb: -------------------------------------------------------------------------------- 1 | module ActiveRecord 2 | module Mysql 3 | module Unsigned 4 | class Railtie < Rails::Railtie 5 | initializer 'activerecord-mysql-unsigned' do 6 | ActiveSupport.on_load :active_record do 7 | require 'activerecord-mysql-unsigned/base' 8 | end 9 | end 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/activerecord-mysql-unsigned/version.rb: -------------------------------------------------------------------------------- 1 | module ActiveRecord 2 | module Mysql 3 | module Unsigned 4 | VERSION = "0.3.1" 5 | end 6 | end 7 | end 8 | 9 | -------------------------------------------------------------------------------- /spec/after_option_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "after option" do 4 | before :all do 5 | AddColumnAfterToGoodsTable.change 6 | end 7 | 8 | it "insert 'added_after_name' column after 'name' column" do 9 | name_num = added_after_name_num = 0 10 | 11 | Goods.columns.each_with_index do |column, i| 12 | name_num = i if column.name == "name" 13 | added_after_name_num = i if column.name == "added_after_name" 14 | end 15 | 16 | expect(name_num + 1).to eq(added_after_name_num) 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/bigint_primary_key_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "primary_key" do 4 | it "should be bigint with limit: 8" do 5 | pkcol = Goods.columns_hash[Goods.primary_key] 6 | 7 | expect(pkcol.unsigned?).to be_truthy 8 | expect(pkcol.limit).to be 8 if ActiveRecord::VERSION::MAJOR == 4 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | require 'rubygems' 3 | require 'activerecord-mysql-unsigned' 4 | 5 | # Requires supporting files with custom matchers and macros, etc, 6 | # in ./support/ and its subdirectories. 7 | Dir["#{File.dirname(__FILE__)}/support/*.rb"].each {|file| require file} 8 | 9 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 10 | RSpec.configure do |config| 11 | config.run_all_when_everything_filtered = true 12 | config.filter_run :focus 13 | config.color = true 14 | end 15 | -------------------------------------------------------------------------------- /spec/support/database_cleaner.rb: -------------------------------------------------------------------------------- 1 | require 'database_cleaner' 2 | 3 | RSpec.configure do |config| 4 | config.before :suite do 5 | DatabaseCleaner.strategy = :transaction 6 | DatabaseCleaner.clean_with :truncation 7 | end 8 | 9 | config.before :each do 10 | DatabaseCleaner.start 11 | end 12 | 13 | config.after :each do 14 | DatabaseCleaner.clean 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/support/migrations.rb: -------------------------------------------------------------------------------- 1 | require 'active_record' 2 | 3 | config = { 4 | adapter: 'mysql2', 5 | encoding: 'utf8', 6 | database: 'activerecord_mysql_unsigned' 7 | } 8 | 9 | ActiveRecord::Base.establish_connection(config.merge(database: 'mysql')) 10 | ActiveRecord::Base.connection.drop_database(config[:database]) rescue nil 11 | ActiveRecord::Base.connection.create_database(config[:database]) 12 | ActiveRecord::Base.establish_connection(config) 13 | #ActiveRecord::Base.logger = Logger.new(STDOUT) 14 | 15 | ActiveRecord::Migration.verbose = true 16 | 17 | # create goods table 18 | class CreateGoodsTable < ActiveRecord::Migration 19 | def self.change 20 | create_table :goods, force: true, limit: 8 do |t| 21 | t.string :name, null: false 22 | t.boolean :deleted, default: false 23 | end 24 | end 25 | end 26 | CreateGoodsTable.change 27 | 28 | # create users table 29 | class CreateUsersTable < ActiveRecord::Migration 30 | def self.change 31 | create_table :users, force: true, id: false do |t| 32 | t.column :id, "int(10) NOT NULL PRIMARY KEY AUTO_INCREMENT" # AR's default primary_key 33 | t.string :name, null: false 34 | t.integer :signed_int 35 | t.integer :unsigned_int, unsigned: true 36 | t.integer :will_unsigned_int, unsigned: false 37 | t.integer :will_signed_int, unsigned: true 38 | t.integer :will_bigint 39 | t.decimal :signed_decimal, null: false, default: 0, precision: 15, scale: 2 40 | t.decimal :unsigned_decimal, null: false, default: 0, unsigned: true, precision: 15, scale: 2 41 | end 42 | end 43 | end 44 | CreateUsersTable.change 45 | 46 | class ChangePrimaryKeyToGoodsTable < ActiveRecord::Migration 47 | def self.change 48 | change_column :goods, :id, :integer, limit: 8, unsigned: true, null: false, auto_increment: true 49 | end 50 | end 51 | 52 | class ChangeColumnToUsersTable < ActiveRecord::Migration 53 | def self.change 54 | change_column :users, :id, :integer, limit: 8, unsigned: true, null: false, auto_increment: true 55 | change_column :users, :will_unsigned_int, :integer, unsigned: true 56 | change_column :users, :will_signed_int, :integer, unsigned: false 57 | change_column :users, :will_bigint, :integer, limit: 8 58 | end 59 | end 60 | 61 | class AddColumnToUsersTable < ActiveRecord::Migration 62 | def self.change 63 | add_column :users, :added_unsigned_int, :integer, unsigned: true 64 | end 65 | end 66 | 67 | class AddColumnAfterToGoodsTable < ActiveRecord::Migration 68 | def self.change 69 | add_column :goods, :added_after_name, :integer, unsigned: true, after: :name 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /spec/support/models.rb: -------------------------------------------------------------------------------- 1 | require 'active_record' 2 | 3 | class Goods < ActiveRecord::Base 4 | end 5 | 6 | class User < ActiveRecord::Base 7 | end 8 | -------------------------------------------------------------------------------- /spec/unsigned_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "INT/Decimal column" do 4 | 5 | before :all do 6 | ChangePrimaryKeyToGoodsTable.change 7 | ChangeColumnToUsersTable.change 8 | AddColumnToUsersTable.change 9 | end 10 | 11 | before(:each) do 12 | @user = User.new(name: "bob") 13 | end 14 | 15 | it "max value of signed int" do 16 | @user.signed_int = 2147483647 17 | expect(@user.save).to be_truthy 18 | end 19 | 20 | it "max value of unsigned int" do 21 | @user.unsigned_int = 4294967295 22 | expect(@user.save).to be_truthy 23 | end 24 | 25 | it "allowed minus value of signed int" do 26 | @user.signed_int = -2147483648 27 | expect(@user.save).to be_truthy 28 | end 29 | 30 | it "not allowed minus value of unsigned int" do 31 | @user.unsigned_int = -2147483648 32 | 33 | if strict_mode? 34 | begin 35 | @user.save 36 | expect(true).to be_falsey # should not be reached here 37 | rescue => e 38 | expect(e).to be_an_instance_of ActiveRecord::StatementInvalid 39 | end 40 | else 41 | @user.save 42 | @user.reload 43 | expect(@user.unsigned_int).to be 0 # saved 0 44 | end 45 | end 46 | 47 | it "unsigned column has 'unsigned' attribute" do 48 | signed_int_col = User.columns[2] 49 | expect(signed_int_col.unsigned?).to be_falsey 50 | 51 | unsigned_int_col = User.columns[3] 52 | expect(unsigned_int_col.unsigned?).to be_truthy 53 | end 54 | 55 | it "signed column has 'unsigned' attribute after changed" do 56 | will_unsigned_int_col = User.columns[4] 57 | expect(will_unsigned_int_col.unsigned?).to be_truthy 58 | end 59 | 60 | it "unsigned column has 'signed' attribute after changed" do 61 | will_signed_int_col = User.columns[5] 62 | expect(will_signed_int_col.unsigned?).to be_falsey 63 | end 64 | 65 | it "allowed minus value of signed decimal" do 66 | @user.signed_decimal = -10.0 67 | @user.save 68 | expect(@user.signed_decimal).to eq(-10.0) 69 | end 70 | 71 | it "not allowed minus value of unsigned decimal" do 72 | @user.unsigned_decimal = -10 73 | 74 | if strict_mode? 75 | begin 76 | @user.save 77 | expect(true).to be_falsey # should not be reached here 78 | rescue => e 79 | expect(e).to be_an_instance_of ActiveRecord::StatementInvalid 80 | end 81 | else 82 | @user.save 83 | @user.reload 84 | expect(@user.unsigned_decimal).to eq BigDecimal("0.00") # saved 0.00 85 | end 86 | end 87 | 88 | private 89 | 90 | def strict_mode? 91 | /STRICT_(?:TRANS|ALL)_TABLES/ =~ ActiveRecord::Base.connection.select_value("SELECT @@SESSION.sql_mode") 92 | end 93 | end 94 | -------------------------------------------------------------------------------- /vendor/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waka/activerecord-mysql-unsigned/d870663bc50f8b481009858c72fb438e7f2be828/vendor/.keep --------------------------------------------------------------------------------