Skip to content

Instantly share code, notes, and snippets.

@joegaudet
Created April 30, 2020 17:55
Show Gist options
  • Save joegaudet/965f1569cec4a107562d81a2a1364774 to your computer and use it in GitHub Desktop.
Save joegaudet/965f1569cec4a107562d81a2a1364774 to your computer and use it in GitHub Desktop.
class JrClientGenerator < Rails::Generators::Base
source_root File.expand_path('../templates', __FILE__)
def self.process_resource(resource_klass)
attributes = resource_klass._attributes.clone
model_klass = resource_klass._model_name.safe_constantize
# We only want the type value from each column, and we also need
# to convert the key to a symbol, if you're using non AR records to back
# your JR model, its not going to have an attribute hash, so lets just
# rescue to an empty hash
model_attribute_types = model_klass.columns_hash.map {|k, v| [k.to_sym, v.type]}.to_h rescue {}
# for each of the resource attributes, if no type information
# is provided, lets us the backing model annotation
attributes.each do |k, v|
attributes[k][:type] ||= model_attribute_types[k] || :any
end
relationships = resource_klass._relationships.map do |k, v|
{
name: k,
type: v.class_name,
one: v.is_a?(JSONAPI::Relationship::ToOne)
}
end
filters = resource_klass.filters.map do |k, v|
{
name: k,
type: v[:type] || model_attribute_types[k] || :any
}
end
{
name: resource_klass.name.demodulize.gsub('Resource', ''),
attributes: attributes,
relationships: relationships,
filters: filters
}
end
def self.process_resources(base_resource_klass)
base_resource_klass.descendants.reject {|r_k| r_k._abstract}.map {|r_k| process_resource(r_k)}
end
def self.process
# We're using our base resource because JR nuked the descendants expected behavior
# so we can't enumerate the Resources
process_resources(API::V3::BaseResource)
end
def self.map_to_js(resources)
resources.map do |resource|
resource_name = resource[:name]
resource_type = resource[:name].to_s.underscore.pluralize.dasherize
relationships = resource[:relationships].map do |relationship|
rel_name = camelize(relationship[:name].to_s)
rel_type = relationship[:type]
jr_name = rel_name.underscore.dasherize
{
name: rel_name,
jr_name: jr_name,
js_name: rel_name,
klass: rel_type,
path: relationship[:one] ? jr_name : jr_name.pluralize,
one: relationship[:one]
}
end
ones = relationships.select {|r| r[:one]}
manies = relationships.reject {|r| r[:one]}
attributes = resource[:attributes].map do |attribute, details|
js_name = camelize(attribute.to_s)
attr_name = attribute.to_s
jr_name = attribute.to_s.underscore.dasherize
attr_type = map_types(details[:type])
if attr_name == 'default'
js_name = 'isDefault'
end
unless attr_name == 'id'
{
jr_name: jr_name,
js_name: js_name,
name: attr_name,
type: attr_type
}
end
end
filters = resource[:filters].map do |filter|
filter[:js_name] = camelize(filter[:name])
filter
end
{
filters: filters,
klass: resource_name,
js_name: camelize(resource_name),
type: resource_type,
path: resource_type,
attrs: attributes.compact,
relationships: relationships,
ones: ones,
manies: manies
}
end.sort {|x, y| y[:klass] <=> x[:klass]}.reverse
end
def self.map_types(type)
ret = case type
when :text
:string
when :time
when :datetime
:Date
when :decimal
when :integer
:number
else
type
end
ret || '*'
end
def self.camelize(term)
ActiveSupport::Inflector.camelize(term, false)
end
argument :path
# Do the stuff
def generate_jr_client
$resources = self.class.map_to_js(self.class.process + MICRO_SERVICE_RESOURCES)
template 'audit.csv.erb', "#{path}src/audit.csv"
template 'resources.js.erb', "#{path}src/resources/resources.js"
template 'daos.js.erb', "#{path}src/data-access/daos.js"
template 'index.js.erb', "#{path}/src/index.js"
template 'README.md.erb', "#{path}/README.md"
end
end
@eccegordo
Copy link

I can't seem to get base_resource_klass.descendants to return anything

My resources hierarchy looks like this

resources/
--api_resource.rb
----api/
------part_resource.rb
------part/
--------thing_resource.rb

and the resource files like this

class ApiResource < JSONAPI::Resource
  abstract
end


class Api::PartResource < JSONAPI::Resource
  abstract
end


class Api::Part::ThingResource < JSONAPI::Resource
  immutable  
  model_name "Part::Thing"
  attribute :name
  attribute :notes
  end
end

so I have routes like this http://localhost:3000/api/part/thing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment