Last active
February 25, 2021 05:20
-
-
Save yoshida-eth0/2d47dd43438282fad686dd2b84a5b1d1 to your computer and use it in GitHub Desktop.
Dynamoidでembeds_many/embeds_one出来るようにする
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'dynamoid' | |
module Dynamoid | |
def EmbedsMany(item_klass) | |
klass = DelegateClass(Array) | |
klass.include EmbedsManyBase | |
klass.const_set(:ITEM_CLASS, item_klass) | |
klass | |
end | |
module EmbedsManyBase | |
extend ActiveSupport::Concern | |
def dynamoid_dump | |
map(&:dynamoid_dump) | |
end | |
module ClassMethods | |
def dynamoid_load(serialized) | |
new((serialized || []).map{|item| self::ITEM_CLASS.dynamoid_load(item)}) | |
end | |
end | |
end | |
module EmbeddedDocument | |
extend ActiveSupport::Concern | |
include Document | |
def dynamoid_dump | |
embeds_many_attributes = self.attributes | |
.select {|attr, value| | |
self.class.attributes[attr] | |
}.select {|attr, value| | |
Class===self.class.attributes[attr][:type] | |
}.select {|attr, value| | |
self.class.attributes[attr][:type].include?(EmbedsManyBase) | |
} | |
normal_attributes = self.attributes | |
.reject {|attr, value| | |
embeds_many_attributes.key?(attr) | |
} | |
dumped = Dynamoid::Dumping.dump_attributes(normal_attributes, self.class.attributes) | |
embeds_many_attributes.compact.each {|attr, value| | |
dumped[attr] = value.map {|value2| | |
Dynamoid::Dumping.dump_attributes(value2.attributes, value2.class.attributes) | |
} | |
} | |
dumped | |
end | |
module ClassMethods | |
def dynamoid_load(serialized) | |
undumped = Dynamoid::Undumping.undump_attributes(serialized, self.attributes) | |
self.new(undumped) | |
end | |
end | |
end | |
module TypeCasting | |
module EmbedsManyTypeCaster | |
def process(value) | |
field_class = @options[:type] | |
if field_class.include?(EmbedsManyBase) | |
item_class = field_class::ITEM_CLASS | |
item_attributes = item_class.attributes | |
items = value.map {|item| | |
if item.respond_to?(:attributes) | |
item = item.attributes | |
end | |
casted = TypeCasting.cast_attributes(item, item_attributes) | |
item_class.new(casted) | |
} | |
field_class.new(items) | |
else | |
super(value) | |
end | |
end | |
end | |
module EmbeddedDocumentTypeCaster | |
def process(value) | |
field_class = @options[:type] | |
if field_class.include?(EmbeddedDocument) | |
if value.respond_to?(:attributes) | |
value = value.attributes | |
end | |
casted = TypeCasting.cast_attributes(value, field_class.attributes) | |
field_class.new(casted) | |
else | |
super(value) | |
end | |
end | |
end | |
class CustomTypeCaster < Base | |
prepend EmbedsManyTypeCaster | |
prepend EmbeddedDocumentTypeCaster | |
end | |
end | |
module Dumping | |
module EmbedsManyDumper | |
def process(value) | |
field_class = @options[:type] | |
if field_class.include?(EmbedsManyBase) | |
item_class = field_class::ITEM_CLASS | |
item_attributes = item_class.attributes | |
value.map {|item| | |
if item.respond_to?(:attributes) | |
item = item.attributes | |
end | |
Dumping.dump_attributes(item, item_attributes) | |
} | |
else | |
super(value) | |
end | |
end | |
end | |
class CustomTypeDumper < Base | |
prepend EmbedsManyDumper | |
end | |
end | |
module Validations | |
module ClassMethods | |
def validates_associated(*attr_names) | |
validates_with(AssociatedValidator, _merge_attributes(attr_names)) | |
end | |
class AssociatedValidator < ActiveModel::EachValidator | |
def validate_each(record, attribute, value) | |
if Array(value).reject { |r| valid_object?(r) }.any? | |
record.errors.add(attribute, :invalid, **options.merge(value: value)) | |
end | |
end | |
private | |
def valid_object?(record) | |
(record.respond_to?(:marked_for_destruction?) && record.marked_for_destruction?) || record.valid? | |
end | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def index(event:, context:) | |
users = User.all.to_a | |
{ | |
statusCode: 200, | |
body: { | |
users: users, | |
articles_class: users[0].articles.class.name, | |
article_class: users[0].articles.first.class.name, | |
comments_class: users[0].articles.first.comments.class.name, | |
comment_class: users[0].articles.first.comments.first.class.name, | |
profile_class: users[0].profile.class.name, | |
}.to_json | |
} | |
end | |
def create(event:, context:) | |
user = User.new( | |
name: "nameA", | |
articles: [ | |
{ | |
title: "titleA", | |
comments: [ | |
{ | |
name: 'commentA', | |
message: 'aaa', | |
}, | |
{ | |
name: 'commentB', | |
message: 'bbb', | |
}, | |
], | |
}, | |
], | |
profile: { | |
firstname: 'tanaka', | |
lastname: 'tarou', | |
}, | |
) | |
begin | |
user.save | |
{ | |
statusCode: 200, | |
body: { | |
user: user, | |
articles_class: user.articles.class.name, | |
article_class: user.articles.first.class.name, | |
comments_class: user.articles.first.comments.class.name, | |
comment_class: user.articles.first.comments.first.class.name, | |
profile_class: user.profile.class.name, | |
}.to_json | |
} | |
rescue Dynamoid::Errors::RecordNotUnique => e | |
{ | |
statusCode: 400, | |
body: { | |
message: e.message, | |
}.to_json | |
} | |
end | |
end | |
def update(event:, context:) | |
id = event["pathParameters"]["id"] | |
begin | |
user = User.find(id) | |
user.articles << { | |
title: "titleB", | |
comments: [ | |
{ | |
name: 'commentC', | |
message: 'ccc', | |
}, | |
], | |
} | |
user.profile.firstname = 'satou' | |
user.save | |
{ | |
statusCode: 200, | |
body: { | |
user: user, | |
articles_class: user.articles.class.name, | |
article_class: user.articles.first.class.name, | |
comments_class: user.articles.first.comments.class.name, | |
comment_class: user.articles.first.comments.first.class.name, | |
profile_class: user.profile.class.name, | |
}.to_json | |
} | |
rescue Dynamoid::Errors::RecordNotFound => e | |
{ | |
statusCode: 404, | |
body: { | |
message: e.message, | |
}.to_json | |
} | |
end | |
end | |
__END__ | |
$ curl -X POST http://localhost:3000/local/users | jq . | |
% Total % Received % Xferd Average Speed Time Time Time Current | |
Dload Upload Total Spent Left Speed | |
100 450 100 450 0 0 350 0 0:00:01 0:00:01 --:--:-- 350 | |
{ | |
"user": { | |
"name": "nameA", | |
"articles": [ | |
{ | |
"title": "titleA", | |
"comments": [ | |
{ | |
"name": "commentA", | |
"message": "aaa" | |
}, | |
{ | |
"name": "commentB", | |
"message": "bbb" | |
} | |
] | |
} | |
], | |
"profile": { | |
"firstname": "tanaka", | |
"lastname": "tarou" | |
}, | |
"created_at": "2021-02-13T17:12:22.123+09:00", | |
"updated_at": "2021-02-13T17:12:22.124+09:00", | |
"id": "517e4636-4260-4426-9050-ebe398db9a19" | |
}, | |
"articles_class": null, | |
"article_class": "Article", | |
"comments_class": null, | |
"comment_class": "Comment", | |
"profile_class": "Profile" | |
} | |
$ curl -X PUT http://localhost:3000/local/users/517e4636-4260-4426-9050-ebe398db9a19 | jq . | |
% Total % Received % Xferd Average Speed Time Time Time Current | |
Dload Upload Total Spent Left Speed | |
100 517 100 517 0 0 384 0 0:00:01 0:00:01 --:--:-- 384 | |
{ | |
"user": { | |
"created_at": "2021-02-13T08:12:22.123+00:00", | |
"updated_at": "2021-02-13T17:12:47.339+09:00", | |
"id": "517e4636-4260-4426-9050-ebe398db9a19", | |
"name": "nameA", | |
"articles": [ | |
{ | |
"title": "titleA", | |
"comments": [ | |
{ | |
"name": "commentA", | |
"message": "aaa" | |
}, | |
{ | |
"name": "commentB", | |
"message": "bbb" | |
} | |
] | |
}, | |
{ | |
"title": "titleB", | |
"comments": [ | |
{ | |
"name": "commentC", | |
"message": "ccc" | |
} | |
] | |
} | |
], | |
"profile": { | |
"firstname": "satou", | |
"lastname": "tarou" | |
} | |
}, | |
"articles_class": null, | |
"article_class": "Article", | |
"comments_class": null, | |
"comment_class": "Comment", | |
"profile_class": "Profile" | |
} | |
$ curl -X GET http://localhost:3000/local/users | jq . | |
% Total % Received % Xferd Average Speed Time Time Time Current | |
Dload Upload Total Spent Left Speed | |
100 520 100 520 0 0 411 0 0:00:01 0:00:01 --:--:-- 411 | |
{ | |
"users": [ | |
{ | |
"created_at": "2021-02-13T08:12:22.123+00:00", | |
"updated_at": "2021-02-13T08:12:47.339+00:00", | |
"id": "517e4636-4260-4426-9050-ebe398db9a19", | |
"name": "nameA", | |
"articles": [ | |
{ | |
"title": "titleA", | |
"comments": [ | |
{ | |
"name": "commentA", | |
"message": "aaa" | |
}, | |
{ | |
"name": "commentB", | |
"message": "bbb" | |
} | |
] | |
}, | |
{ | |
"title": "titleB", | |
"comments": [ | |
{ | |
"name": "commentC", | |
"message": "ccc" | |
} | |
] | |
} | |
], | |
"profile": { | |
"firstname": "satou", | |
"lastname": "tarou" | |
} | |
} | |
], | |
"articles_class": null, | |
"article_class": "Article", | |
"comments_class": null, | |
"comment_class": "Comment", | |
"profile_class": "Profile" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Article | |
include Dynamoid::EmbeddedDocument | |
field :title, :string | |
field :comments, Dynamoid::EmbedsMany(Comment) | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Comment | |
include Dynamoid::EmbeddedDocument | |
field :name, :string | |
field :message, :string | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Profile | |
include Dynamoid::EmbeddedDocument | |
field :firstname, :string | |
field :lastname, :string | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class User | |
include Dynamoid::Document | |
field :name, :string | |
field :articles, Dynamoid::EmbedsMany(Article) | |
field :profile, Profile | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment