Skip to content

Feature/key transform #45

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Fast JSON API serialized 250 records in 3.01 ms
* [Serializer Definition](#serializer-definition)
* [Object Serialization](#object-serialization)
* [Compound Document](#compound-document)
* [Key Transforms](#key-transforms)
* [Collection Serialization](#collection-serialization)
* [Caching](#caching)
* [Contributing](#contributing)
Expand Down Expand Up @@ -134,6 +135,26 @@ json_string = MovieSerializer.new(movie).serialized_json
}

```

### Key Transforms
By default fast_jsonapi underscores the key names. It supports the same key transforms that are supported by AMS. Here is the syntax of specifying a key transform

```ruby
class MovieSerializer
include FastJsonapi::ObjectSerializer
# Available options :camel, :camel_lower, :dash, :underscore(default)
set_key_transform :camel
end
```
Here are examples of how these options transform the keys

```ruby
set_key_transform :camel # "some_key" => "SomeKey"
set_key_transform :camel_lower # "some_key" => "someKey"
set_key_transform :dash # "some_key" => "some-key"
set_key_transform :underscore # "some_key" => "some_key"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw, the fastest key transform in AMS is :unaltered :)

```

### Compound Document

Support for top-level included member through ` options[:include] `.
Expand Down
72 changes: 33 additions & 39 deletions lib/fast_jsonapi/object_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,19 +104,6 @@ def is_collection?(resource)
end

class_methods do
def use_hyphen
@hyphenated = true
end

def set_type(type)
return unless type

type = type.to_s.underscore
type = type.dasherize if @hyphenated

self.record_type = type.to_sym
end

def reflected_record_type
return @reflected_record_type if defined?(@reflected_record_type)

Expand All @@ -127,6 +114,28 @@ def reflected_record_type
end
end

def set_key_transform(transform_name)
mapping = {
camel: :camelize,
camel_lower: [:camelize, :lower],
dash: :dasherize,
underscore: :underscore
}
@transform_method = mapping[transform_name.to_sym]
end

def run_key_transform(input)
if @transform_method.present?
input.to_s.send(*@transform_method).to_sym
else
input.to_sym
end
end

def set_type(type_name)
self.record_type = run_key_transform(type_name)
end

def cache_options(cache_options)
self.cached = cache_options[:enabled] || false
self.cache_length = cache_options[:cache_length] || 5.minutes
Expand All @@ -137,10 +146,7 @@ def attributes(*attributes_list)
self.attributes_to_serialize = {} if self.attributes_to_serialize.nil?
attributes_list.each do |attr_name|
method_name = attr_name
key = method_name
if @hyphenated
key = attr_name.to_s.dasherize.to_sym
end
key = run_key_transform(method_name)
attributes_to_serialize[key] = method_name
end
end
Expand All @@ -159,15 +165,11 @@ def add_relationship(name, relationship)
end

def has_many(relationship_name, options = {})
singular_name = relationship_name.to_s.singularize
record_type = options[:record_type] || singular_name.to_sym
name = relationship_name.to_sym
key = options[:key] || name
if @hyphenated
key = options[:key] || relationship_name.to_s.dasherize.to_sym
record_type = options[:record_type] || singular_name.to_s.dasherize.to_sym
end
serializer_key = options[:serializer] || record_type
singular_name = relationship_name.to_s.singularize
serializer_key = options[:serializer] || singular_name.to_sym
key = options[:key] || run_key_transform(relationship_name)
record_type = options[:record_type] || run_key_transform(singular_name)
relationship = {
key: key,
name: name,
Expand All @@ -183,13 +185,9 @@ def has_many(relationship_name, options = {})

def belongs_to(relationship_name, options = {})
name = relationship_name.to_sym
key = options[:key] || name
record_type = options[:record_type] || name
serializer_key = options[:serializer] || record_type
if @hyphenated
key = options[:key] || relationship_name.to_s.dasherize.to_sym
record_type = options[:record_type] || relationship_name.to_s.dasherize.to_sym
end
serializer_key = options[:serializer] || relationship_name.to_sym
key = options[:key] || run_key_transform(relationship_name)
record_type = options[:record_type] || run_key_transform(relationship_name)
add_relationship(name, {
key: key,
name: name,
Expand All @@ -204,13 +202,9 @@ def belongs_to(relationship_name, options = {})

def has_one(relationship_name, options = {})
name = relationship_name.to_sym
key = options[:key] || name
record_type = options[:record_type] || name
serializer_key = options[:serializer] || record_type
if @hyphenated
key = options[:key] || relationship_name.to_s.dasherize.to_sym
record_type = options[:record_type] || relationship_name.to_s.dasherize.to_sym
end
serializer_key = options[:serializer] || name
key = options[:key] || run_key_transform(relationship_name)
record_type = options[:record_type] || run_key_transform(relationship_name)
add_relationship(name, {
key: key,
name: name,
Expand Down
40 changes: 0 additions & 40 deletions spec/lib/object_serializer_hyphen_spec.rb

This file was deleted.

80 changes: 80 additions & 0 deletions spec/lib/object_serializer_key_transform_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
require 'spec_helper'

describe FastJsonapi::ObjectSerializer do
include_context 'movie class'
include_context 'ams movie class'

before(:context) do
[:dash, :camel, :camel_lower, :underscore].each do |transform_type|
movie_serializer_name = "#{transform_type}_movie_serializer".classify
movie_type_serializer_name = "#{transform_type}_movie_type_serializer".classify
# https://stackoverflow.com/questions/4113479/dynamic-class-definition-with-a-class-name
movie_serializer_class = Object.const_set(
movie_serializer_name,
Class.new {
}
)
# https://rubymonk.com/learning/books/5-metaprogramming-ruby-ascent/chapters/24-eval/lessons/67-instance-eval
movie_serializer_class.instance_eval do
include FastJsonapi::ObjectSerializer
set_type :movie
set_key_transform transform_type
attributes :name, :release_year
has_many :actors
belongs_to :owner, record_type: :user
belongs_to :movie_type
end
movie_type_serializer_class = Object.const_set(
movie_type_serializer_name,
Class.new {
}
)
movie_type_serializer_class.instance_eval do
include FastJsonapi::ObjectSerializer
set_key_transform transform_type
set_type :movie_type
attributes :name
end
end
end

context 'when using dashes for word separation in the JSON API members' do
it 'returns correct hash when serializable_hash is called' do
serializable_hash = DashMovieSerializer.new([movie, movie]).serializable_hash
expect(serializable_hash[:data].length).to eq 2
expect(serializable_hash[:data][0][:relationships].length).to eq 3
expect(serializable_hash[:data][0][:relationships]).to have_key('movie-type'.to_sym)
expect(serializable_hash[:data][0][:attributes].length).to eq 2
expect(serializable_hash[:data][0][:attributes]).to have_key("release-year".to_sym)

serializable_hash = DashMovieSerializer.new(movie_struct).serializable_hash
expect(serializable_hash[:data][:relationships].length).to eq 3
expect(serializable_hash[:data][:relationships]).to have_key('movie-type'.to_sym)
expect(serializable_hash[:data][:attributes].length).to eq 2
expect(serializable_hash[:data][:attributes]).to have_key('release-year'.to_sym)
expect(serializable_hash[:data][:id]).to eq movie_struct.id.to_s
end

it 'returns type hypenated when trying to serializing a class with multiple words' do
movie_type = MovieType.new
movie_type.id = 3
movie_type.name = "x"
serializable_hash = DashMovieTypeSerializer.new(movie_type).serializable_hash
expect(serializable_hash[:data][:type].to_sym).to eq 'movie-type'.to_sym
end
end

context 'when using other key transforms' do
[:camel, :camel_lower, :underscore, :dash].each do |transform_type|
it "returns same thing as ams when using #{transform_type}" do
ams_movie = build_ams_movies(1).first
movie = build_movies(1).first
movie_serializer_class = "#{transform_type}_movie_serializer".classify.constantize
our_json = movie_serializer_class.new([movie]).serialized_json
ams_json = ActiveModelSerializers::SerializableResource.new([ams_movie], key_transform: transform_type).to_json
expect(our_json.length).to eq (ams_json.length)
end
end
end

end
22 changes: 0 additions & 22 deletions spec/shared/contexts/movie_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,28 +95,6 @@ class MovieSerializer
end
end


# Hyphenated keys for the serializer
before(:context) do
class HyphenMovieSerializer
include FastJsonapi::ObjectSerializer
use_hyphen
set_type :movie
attributes :name, :release_year
has_many :actors
belongs_to :owner, record_type: :user
belongs_to :movie_type
end

class HyphenMovieTypeSerializer
include FastJsonapi::ObjectSerializer
use_hyphen
set_type :movie_type
attributes :name
end
end


# Movie and Actor struct
before(:context) do
MovieStruct = Struct.new(
Expand Down