Skip to content

Commit

Permalink
Working implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
mathieujobin committed Feb 21, 2017
1 parent 3173e8f commit 3a660ff
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 30 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ ActiveRecord::Schema.define(version: 20161122225732) do
end
```

Define it in your model

```
class Worker < ActiveRecord::Base
attribute :job_uuid, :uuid
end
```

Then use as regular string column, except that it will be stored in a 16 bytes binary column.

## Development
Expand Down
4 changes: 2 additions & 2 deletions activerecord-mysql-uuid-column.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "rspec", "~> 3.0"
spec.add_development_dependency "byebug", '~> 0'
spec.add_development_dependency "looksee", '~> 0'
spec.add_dependency "activerecord", ">= 4.2.5", "< 6"
spec.add_dependency "mysql2", "~> 0.4.0"
spec.add_dependency "activerecord", ">= 5", "< 6"
spec.add_dependency "mysql2", "~> 0.4.4"
end
32 changes: 6 additions & 26 deletions lib/active_record-mysql-uuid_column.rb
Original file line number Diff line number Diff line change
@@ -1,28 +1,8 @@
require "active_record-mysql-uuid_column/version"
require 'active_record'
require 'active_record/connection_adapters/mysql2_adapter'
require 'active_record-mysql-uuid_column/version'
require 'active_record-mysql-uuid_column/migration_column.rb'
require 'active_record-mysql-uuid_column/type_class.rb'
require 'active_record-mysql-uuid_column/mysql2_adapter_monkey_patch.rb'

module ActiveModel
module Type
class Uuid
def method_missing(name)
debugger
puts "whatever"
end
end
end
end
module ActiveRecord
module ConnectionAdapters
module MySQL
module ColumnMethods
def uuid(*args, **options)
# http://dba.stackexchange.com/questions/904/mysql-data-type-for-128-bit-integers
# http://dev.mysql.com/doc/refman/5.7/en/binary-varbinary.html
args.each { |name| column(name, :binary, options.merge(limit: 16)) }
end
end
end

end
end

ActiveRecord::Type.register(:uuid, ActiveRecord::Type::Uuid, adapter: :mysql2)
13 changes: 13 additions & 0 deletions lib/active_record-mysql-uuid_column/migration_column.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module ActiveRecord
module ConnectionAdapters
module MySQL
module ColumnMethods
def uuid(*args, **options)
# http://dba.stackexchange.com/questions/904/mysql-data-type-for-128-bit-integers
# http://dev.mysql.com/doc/refman/5.7/en/binary-varbinary.html
args.each { |name| column(name, :binary, options.merge(limit: 16)) }
end
end
end
end
end
15 changes: 15 additions & 0 deletions lib/active_record-mysql-uuid_column/mysql2_adapter_monkey_patch.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module ActiveRecord
module ConnectionAdapters
class Mysql2Adapter
private

def _quote(value)
if value.is_a?(Type::Uuid::Data) or value.is_a?(Type::Binary::Data)
"x'#{value.hex}'"
else
super
end
end
end
end
end
78 changes: 78 additions & 0 deletions lib/active_record-mysql-uuid_column/type_class.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
module ActiveRecord
module Type
class Uuid < ActiveRecord::Type::Binary
def type
:uuid
end

# from database binary(16) to string
def deserialize(value)
return nil if value.nil?
Data.from_database(value)
end

# from user input (string) to database
def cast(value)
if value.is_a?(Data)
value
elsif value.is_a?(ActiveSupport::ToJsonWithActiveSupportEncoder) or value.is_a?(String)
Data.from_uuid_string(super)
else
raise ArgumentError,
"Unsupported input data of class type #{value.class}"
end
end

def serialize(value)
value
end

def assert_valid_value(value)
case value.class
when String, ActiveSupport::ToJsonWithActiveSupportEncoder
if value.downcase.gsub(/[^a-f0-9]/, '').size == 32
value
else
raise SerializationTypeMismatch,
"Invalid String uuid #{value}."
end
else
raise SerializationTypeMismatch,
"Unsupported value object of type #{value.class}."
end
end

class Data
def initialize(display_format, storage_format)
@display_format, @storage_format = display_format, storage_format
end

def self.from_uuid_string(uuid)
new(uuid, uuid.downcase.gsub(/[^a-f0-9]/, ''))
end

def self.from_database(value)
storage_format = value.unpack('H*').first.rjust(32, '0')
new(
storage_format.gsub(/^(.{8})(.{4})(.{4})(.{4})(.{12})$/, '\1-\2-\3-\4-\5'),
storage_format
)
end

def to_s
@display_format
end
alias_method :to_str, :to_s

def hex
@storage_format
end

def ==(other)
other == to_s || super
end
end

end
end
end
3 changes: 1 addition & 2 deletions spec/mysql_uuid_column_spec.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
require "spec_helper"
require 'byebug'
require 'looksee'

class TestUuid < ActiveRecord::Base
attribute :uuid, :uuid
end

describe ActiveRecord::Mysql::UuidColumn do
Expand Down

0 comments on commit 3a660ff

Please sign in to comment.