lib/wcc/contentful/model_builder.rb in wcc-contentful-0.2.2 vs lib/wcc/contentful/model_builder.rb in wcc-contentful-0.3.0.pre.rc
- old
+ new
@@ -1,7 +1,9 @@
# frozen_string_literal: true
+require_relative './sys'
+
module WCC::Contentful
class ModelBuilder
include Helpers
def initialize(types)
@@ -20,84 +22,74 @@
const = typedef.name
return WCC::Contentful::Model.const_get(const) if WCC::Contentful::Model.const_defined?(const)
# TODO: https://github.com/dkubb/ice_nine ?
typedef = typedef.deep_dup.freeze
- fields = typedef.fields.keys
WCC::Contentful::Model.const_set(const,
Class.new(WCC::Contentful::Model) do
+ extend ModelSingletonMethods
+ include ModelMethods
include Helpers
+ const_set('ATTRIBUTES', typedef.fields.keys.map(&:to_sym).freeze)
+ const_set('FIELDS', typedef.fields.keys.freeze)
+
+ # Magic type in their system which has a separate endpoint
+ # but we represent in the same model space
+ if const == 'Asset'
+ define_singleton_method(:type) { 'Asset' }
+ else
+ define_singleton_method(:type) { 'Entry' }
+ end
+
define_singleton_method(:content_type) do
typedef.content_type
end
define_singleton_method(:content_type_definition) do
typedef
end
- define_singleton_method(:find) do |id, context = nil|
- raw = WCC::Contentful::Model.store.find(id)
- new(raw, context) if raw.present?
- end
-
- define_singleton_method(:find_all) do |filter = nil, context = nil|
- if filter
- filter.transform_keys! { |k| k.to_s.camelize(:lower) }
- bad_fields = filter.keys.reject { |k| fields.include?(k) }
- raise ArgumentError, "These fields do not exist: #{bad_fields}" unless bad_fields.empty?
- end
-
- query = WCC::Contentful::Model.store.find_all(content_type: content_type)
- query = query.apply(filter) if filter
- query.map { |r| new(r, context) }
- end
-
- define_singleton_method(:find_by) do |filter, context = nil|
- filter.transform_keys! { |k| k.to_s.camelize(:lower) }
- bad_fields = filter.keys.reject { |k| fields.include?(k) }
- raise ArgumentError, "These fields do not exist: #{bad_fields}" unless bad_fields.empty?
-
- result =
- if defined?(context[:preview]) && context[:preview] == true
- WCC::Contentful::Model.preview_store.find_by(content_type: content_type, filter: filter)
- else
- WCC::Contentful::Model.store.find_by(content_type: content_type, filter: filter)
- end
-
- new(result, context) if result
- end
-
- define_singleton_method(:inherited) do |subclass|
- # only register if it's not already registered
- return if WCC::Contentful::Model.registered?(typedef.content_type)
- WCC::Contentful::Model.register_for_content_type(typedef.content_type, klass: subclass)
- end
-
define_method(:initialize) do |raw, context = nil|
ct = content_type_from_raw(raw)
if ct != typedef.content_type
raise ArgumentError, 'Wrong Content Type - ' \
"'#{raw.dig('sys', 'id')}' is a #{ct}, expected #{typedef.content_type}"
end
+ @raw = raw.freeze
- @locale = context[:locale] if context.present?
- @locale ||= 'en-US'
- @id = raw.dig('sys', 'id')
- @space = raw.dig('sys', 'space', 'sys', 'id')
- @created_at = raw.dig('sys', 'createdAt')
- @created_at = Time.parse(@created_at) if @created_at.present?
- @updated_at = raw.dig('sys', 'updatedAt')
- @updated_at = Time.parse(@updated_at) if @updated_at.present?
- @revision = raw.dig('sys', 'revision')
+ created_at = raw.dig('sys', 'createdAt')
+ created_at = Time.parse(created_at) if created_at.present?
+ updated_at = raw.dig('sys', 'updatedAt')
+ updated_at = Time.parse(updated_at) if updated_at.present?
+ @sys = WCC::Contentful::Sys.new(
+ raw.dig('sys', 'id'),
+ raw.dig('sys', 'type'),
+ raw.dig('sys', 'locale') || context.try(:[], :locale) || 'en-US',
+ raw.dig('sys', 'space', 'sys', 'id'),
+ created_at,
+ updated_at,
+ raw.dig('sys', 'revision'),
+ OpenStruct.new(context).freeze
+ )
typedef.fields.each_value do |f|
- raw_value = raw.dig('fields', f.name, @locale)
+ raw_value = raw.dig('fields', f.name, @sys.locale)
if raw_value.present?
case f.type
- when :DateTime
- raw_value = Time.parse(raw_value).localtime
+ # DateTime is intentionally not parsed!
+ # a DateTime can be '2018-09-28', '2018-09-28T17:00:00', or '2018-09-28T17:00:00Z'
+ # depending entirely on the editor interface in Contentful. Trying to parse this
+ # requires an assumption of the correct time zone to place them in. At this point
+ # in the code we don't have that knowledge, so we're punting to app-defined models.
+ #
+ # As an example, a user enters '2018-09-28' into Contentful. That date is parsed as
+ # '2018-09-28T00:00:00Z' when system time is UTC (ex. on Heroku), but translating that
+ # date to US Central results in '2018-09-27' which is not what the user intentded.
+ #
+ # when :DateTime
+ # raw_value = Time.parse(raw_value).localtime
when :Int
raw_value = Integer(raw_value)
when :Float
raw_value = Float(raw_value)
end
@@ -107,15 +99,17 @@
end
instance_variable_set('@' + f.name, raw_value)
end
end
- attr_reader :id
- attr_reader :space
- attr_reader :created_at
- attr_reader :updated_at
- attr_reader :revision
+ attr_reader :sys
+ attr_reader :raw
+ delegate :id, to: :sys
+ delegate :created_at, to: :sys
+ delegate :updated_at, to: :sys
+ delegate :revision, to: :sys
+ delegate :space, to: :sys
# Make a field for each column:
typedef.fields.each_value do |f|
name = f.name
var_name = '@' + name
@@ -123,22 +117,25 @@
when :Asset, :Link
define_method(name) do
val = instance_variable_get(var_name + '_resolved')
return val if val.present?
- return unless val = instance_variable_get(var_name)
+ _resolve_field(name)
+ end
- val =
- if val.is_a? Array
- val.map { |v| WCC::Contentful::Model.find(v.dig('sys', 'id')) }
- else
- WCC::Contentful::Model.find(val.dig('sys', 'id'))
- end
-
- instance_variable_set(var_name + '_resolved', val)
- val
+ id_method_name = "#{name}_id"
+ if f.array
+ id_method_name = "#{name}_ids"
+ define_method(id_method_name) do
+ instance_variable_get(var_name)&.map { |link| link.dig('sys', 'id') }
+ end
+ else
+ define_method(id_method_name) do
+ instance_variable_get(var_name)&.dig('sys', 'id')
+ end
end
+ alias_method id_method_name.underscore, id_method_name
when :Coordinates
define_method(name) do
val = instance_variable_get(var_name)
OpenStruct.new(val.slice('lat', 'lon')) if val
end
@@ -160,9 +157,10 @@
else
define_method(name) do
instance_variable_get(var_name)
end
end
+
alias_method name.underscore, name
end
end)
end
end