belongs_to association for content entries [WIP]
did
committed Mar 01, 2015
commit d9582c9f299d93ce6bc024c4c7c4d47ba02fc0b2
Showing 25
changed files with
537 additions
and 432 deletions
locomotive/steam/adapters/filesystem.rb b/lib/locomotive/steam/adapters/filesystem.rb
+11
-1
| @@ | @@ -35,7 +35,8 @@ module Locomotive::Steam |
| end | |
| def find(mapper, scope, id) | |
| - | _query(mapper, scope) { where(_id: id) }.first |
| + | name = identifier_name(mapper) |
| + | _query(mapper, scope) { where(name => id) }.first |
| end | |
| def theme_assets_base_url(scope) | |
| @@ | @@ -44,6 +45,15 @@ module Locomotive::Steam |
| private | |
| + | def identifier_name(mapper) |
| + | case mapper.name |
| + | when :content_types then :slug |
| + | when :content_entries then :_slug |
| + | else |
| + | :_id |
| + | end |
| + | end |
| + | |
| def _query(mapper, scope, &block) | |
| Locomotive::Steam::Adapters::Memory::Query.new(all(mapper, scope), scope.locale, &block) | |
| end | |
locomotive/steam/adapters/filesystem/sanitizers/content_entry.rb b/lib/locomotive/steam/adapters/filesystem/sanitizers/content_entry.rb
+1
-76
| @@ | @@ -33,12 +33,11 @@ module Locomotive::Steam |
| def set_slug(entry, dataset) | |
| if entry._label.respond_to?(:translations) # localized? | |
| - | entry[:_slug] ||= {} |
| entry._label.each do |locale, label| | |
| entry[:_slug][locale] ||= slugify(label, dataset, locale) | |
| end | |
| else | |
| - | entry[:_slug] ||= slugify(entry._label, dataset) |
| + | entry[:_slug][locale] = slugify(entry._label, dataset) |
| end | |
| end | |
| @@ | @@ -55,9 +54,6 @@ module Locomotive::Steam |
| def is_slug_unique?(slug, dataset, locale) | |
| dataset.query(locale) { where(_slug: slug) }.first.nil? | |
| - | # Filesystem::MemoryAdapter::Query.new(collection, locale) do |
| - | # where(_slug: slug) |
| - | # end.first.nil? |
| end | |
| end | |
| @@ | @@ -66,74 +62,3 @@ module Locomotive::Steam |
| end | |
| end | |
| end | |
| - | |
| - | |
| - | |
| - | |
| - | |
| - | # module Locomotive |
| - | # module Steam |
| - | # module Repositories |
| - | # module Filesystem |
| - | # module Sanitizers |
| - | |
| - | # class ContentEntry < Struct.new(:default_locale, :locales) |
| - | |
| - | # def apply_to(collection) |
| - | # collection.each do |entry| |
| - | # set_content_type(entry) |
| - | # add_label(entry) |
| - | # set_slug(entry, collection) |
| - | # end |
| - | # end |
| - | |
| - | # def set_slug(entry, collection) |
| - | # if entry._label.is_a?(Hash) |
| - | # entry[:_slug] ||= {} |
| - | # entry._label.each do |locale, label| |
| - | # entry[:_slug][locale] ||= slugify(label, collection, locale) |
| - | # end |
| - | # else |
| - | # entry[:_slug] ||= slugify(entry._label, collection) |
| - | # end |
| - | # end |
| - | |
| - | # def slugify(label, collection, locale = nil) |
| - | # base, index = label.permalink(false), nil |
| - | # _slugify = -> (i) { [base, i].compact.join('-') } |
| - | |
| - | # while !is_slug_unique?(_slugify.call(index), collection, locale) |
| - | # index = index ? index + 1 : 1 |
| - | # end |
| - | |
| - | # _slugify.call(index) |
| - | # end |
| - | |
| - | # def is_slug_unique?(slug, collection, locale) |
| - | # Filesystem::MemoryAdapter::Query.new(collection, locale) do |
| - | # where(_slug: slug) |
| - | # end.first.nil? |
| - | # end |
| - | |
| - | # def set_content_type(entry) |
| - | # entry.content_type = entry.attributes.delete(:content_type) |
| - | # end |
| - | |
| - | # def add_label(entry) |
| - | # value = entry.attributes.delete(:_label) |
| - | # name = entry.content_type.label_field_name |
| - | |
| - | # if entry.attributes[name].is_a?(Hash) # localized? |
| - | # entry.attributes[name][default_locale] = value |
| - | # else |
| - | # entry.attributes[name] ||= value |
| - | # end |
| - | # end |
| - | |
| - | # end |
| - | |
| - | # end |
| - | # end |
| - | # end |
| - | # end |
| - | # end |
locomotive/steam/adapters/filesystem/yaml_loaders/content_entry.rb b/lib/locomotive/steam/adapters/filesystem/yaml_loaders/content_entry.rb
+20
-3
| @@ | @@ -18,12 +18,25 @@ module Locomotive |
| def load_list | |
| [].tap do |list| | |
| each(content_type_slug) do |label, attributes, position| | |
| - | default = { _position: position, _label: label.to_s } |
| - | list << default.merge(attributes) |
| + | _attributes = { _position: position, _label: label.to_s }.merge(attributes) |
| + | |
| + | setup_belongs_to_associations(_attributes) |
| + | |
| + | list << _attributes |
| end | |
| end | |
| end | |
| + | def setup_belongs_to_associations(attributes) |
| + | content_type.belongs_to_fields.each do |field| |
| + | # <name>_id |
| + | attributes[:"#{field.name}_id"] = attributes.delete(field.name.to_sym) |
| + | |
| + | # _position_in_<name> |
| + | attributes[:"_position_in_#{field.name}"] = attributes[:_position] |
| + | end |
| + | end |
| + | |
| def each(slug, &block) | |
| position = 0 | |
| _load(File.join(path, "#{slug}.yml")).each do |element| | |
| @@ | @@ -37,8 +50,12 @@ module Locomotive |
| File.join(site_path, 'data') | |
| end | |
| + | def content_type |
| + | @scope.context[:content_type] |
| + | end |
| + | |
| def content_type_slug | |
| - | @scope.context[:content_type].slug |
| + | content_type.slug |
| end | |
| end | |
locomotive/steam/entities/content_entry.rb b/lib/locomotive/steam/entities/content_entry.rb
+10
-14
| @@ | @@ -4,7 +4,7 @@ module Locomotive::Steam |
| class ContentEntry | |
| - | ASSOCIATION_NAMES = [:belongs_to, :has_many, :many_to_many].freeze |
| + | # ASSOCIATION_NAMES = [:belongs_to, :has_many, :many_to_many].freeze |
| include Locomotive::Steam::Models::Entity | |
| @@ | @@ -55,10 +55,6 @@ module Locomotive::Steam |
| self[content_type.label_field_name] | |
| end | |
| - | # def localized_attributes |
| - | # self.class.localized_attributes + content_type.localized_fields_names |
| - | # end |
| - | |
| def to_liquid | |
| Locomotive::Steam::Liquid::Drops::ContentEntry.new(self) | |
| end | |
| @@ | @@ -81,9 +77,9 @@ module Locomotive::Steam |
| end | |
| def _cast_value(field) | |
| - | if ASSOCIATION_NAMES.include?(field.type) |
| - | AssociationMetadata.new(field.type, self, field, [*attributes[field.name]]) |
| - | elsif private_methods.include?(:"_cast_#{field.type}") |
| + | # if ASSOCIATION_NAMES.include?(field.type) |
| + | # AssociationMetadata.new(field.type, self, field, [*attributes[field.name]]) |
| + | if private_methods.include?(:"_cast_#{field.type}") |
| send(:"_cast_#{field.type}", field.name) | |
| else | |
| attributes[field.name] | |
| @@ | @@ -127,12 +123,12 @@ module Locomotive::Steam |
| end | |
| end | |
| - | class AssociationMetadata < Struct.new(:type, :source, :field, :target_slugs) |
| - | def association; true; end |
| - | def inverse_of; field.inverse_of; end |
| - | def target_class_slug; field.class_name; end |
| - | def order_by; field[:order_by]; end |
| - | end |
| + | # class AssociationMetadata < Struct.new(:type, :source, :field, :target_slugs) |
| + | # def association; true; end |
| + | # def inverse_of; field.inverse_of; end |
| + | # def target_class_slug; field.class_name; end |
| + | # def order_by; field[:order_by]; end |
| + | # end |
| end | |
locomotive/steam/entities/content_type.rb b/lib/locomotive/steam/entities/content_type.rb
+10
-3
| @@ | @@ -3,6 +3,9 @@ module Locomotive::Steam |
| class ContentType | |
| include Locomotive::Steam::Models::Entity | |
| + | extend Forwardable |
| + | |
| + | def_delegators :fields, :localized_fields_names, :belongs_to_fields |
| def initialize(attributes = {}) | |
| super({ | |
| @@ | @@ -23,9 +26,13 @@ module Locomotive::Steam |
| end) | |
| end | |
| - | def localized_fields_names |
| - | self.fields.localized_fields_names |
| - | end |
| + | # def belongs_to_fields |
| + | # self.fields.belongs_to |
| + | # end |
| + | |
| + | # def localized_fields_names |
| + | # self.fields.localized_fields_names |
| + | # end |
| def label_field_name | |
| (self[:label_field_name] || fields.first.name).to_sym | |
locomotive/steam/entities/content_type_field.rb b/lib/locomotive/steam/entities/content_type_field.rb
+10
-0
| @@ | @@ -15,13 +15,23 @@ module Locomotive::Steam |
| }.merge(attributes)) | |
| end | |
| + | def type |
| + | self[:type].try(:to_sym) |
| + | end |
| + | |
| def class_name | |
| self[:class_name] || self[:target] | |
| end | |
| + | alias :target :class_name |
| + | |
| def required?; self[:required]; end | |
| def localized?; self[:localized]; end | |
| + | def association_options |
| + | @attributes.slice(:inverse_of, :order_by).merge(class_name: class_name) |
| + | end |
| + | |
| class SelectOption | |
| include Locomotive::Steam::Models::Entity | |
locomotive/steam/liquid/drops/content_types.rb b/lib/locomotive/steam/liquid/drops/content_types.rb
+1
-0
| @@ | @@ -58,6 +58,7 @@ module Locomotive |
| end | |
| def collection | |
| + | # TODO: repository.for(@content_type).all(....) |
| @collection ||= repository.all(@content_type, @context['with_scope']) | |
| end | |
locomotive/steam/models.rb b/lib/locomotive/steam/models.rb
+2
-1
| @@ | @@ -1,6 +1,7 @@ |
| require_relative 'models/concerns/validation' | |
| require_relative 'models/i18n_field' | |
| - | require_relative 'models/association' |
| + | require_relative 'models/associations/embedded' |
| + | require_relative 'models/associations/belongs_to' |
| require_relative 'models/entity' | |
| require_relative 'models/mapper' | |
| require_relative 'models/scope' | |
locomotive/steam/models/association.rb b/lib/locomotive/steam/models/association.rb
+0
-40
| @@ | @@ -1,40 +0,0 @@ |
| - | require 'locomotive/steam/adapters/memory' |
| - | require 'morphine' |
| - | |
| - | module Locomotive::Steam |
| - | module Models |
| - | |
| - | # Note: represents an embedded collection |
| - | class Association |
| - | |
| - | include Morphine |
| - | |
| - | register :adapter do |
| - | Locomotive::Steam::MemoryAdapter.new(nil) |
| - | end |
| - | |
| - | # use the scope from the parent repository |
| - | # one of the benefits is that if we change the current_locale |
| - | # of the parent repository, that will change the local repository |
| - | # as well. |
| - | def initialize(repository_klass, collection, scope) |
| - | adapter.collection = collection |
| - | |
| - | @repository = repository_klass.new(adapter) |
| - | @repository.scope = scope |
| - | end |
| - | |
| - | # In order to keep track of the entity which owns |
| - | # the association. |
| - | def attach(name, entity) |
| - | @repository.send(:"#{name}=", entity) |
| - | end |
| - | |
| - | def method_missing(name, *args, &block) |
| - | @repository.send(name, *args, &block) |
| - | end |
| - | |
| - | end |
| - | |
| - | end |
| - | end |
locomotive/steam/models/associations/belongs_to.rb b/lib/locomotive/steam/models/associations/belongs_to.rb
+41
-0
| @@ | @@ -0,0 +1,41 @@ |
| + | require 'locomotive/steam/adapters/memory' |
| + | require 'morphine' |
| + | |
| + | module Locomotive::Steam |
| + | module Models |
| + | |
| + | # Note: represents an embedded collection |
| + | class BelongsToAssociation |
| + | |
| + | attr_reader :repository |
| + | |
| + | def initialize(repository_klass, scope, adapter) |
| + | # build a new instance of the target repository |
| + | @repository = repository_klass.new(adapter) |
| + | |
| + | # Note: if we change the locale of the parent repository, that won't |
| + | # reflect in that repository |
| + | @repository.scope = scope.dup |
| + | end |
| + | |
| + | def attach(name, entity) |
| + | @name, @entity = name, entity |
| + | end |
| + | |
| + | def target_id |
| + | @entity[:"#{@name}_id"] |
| + | end |
| + | |
| + | def method_missing(name, *args, &block) |
| + | target = @repository.find(target_id) |
| + | |
| + | # replace the proxy class by the real target entity |
| + | @entity[@name] = target |
| + | |
| + | target.try(:send, name, *args, &block) |
| + | end |
| + | |
| + | end |
| + | |
| + | end |
| + | end |
locomotive/steam/models/associations/embedded.rb b/lib/locomotive/steam/models/associations/embedded.rb
+40
-0
| @@ | @@ -0,0 +1,40 @@ |
| + | require 'locomotive/steam/adapters/memory' |
| + | require 'morphine' |
| + | |
| + | module Locomotive::Steam |
| + | module Models |
| + | |
| + | # Note: represents an embedded collection |
| + | class EmbeddedAssociation |
| + | |
| + | include Morphine |
| + | |
| + | register :adapter do |
| + | Locomotive::Steam::MemoryAdapter.new(nil) |
| + | end |
| + | |
| + | # use the scope from the parent repository |
| + | # one of the benefits is that if we change the current_locale |
| + | # of the parent repository, that will change the local repository |
| + | # as well. |
| + | def initialize(repository_klass, collection, scope) |
| + | adapter.collection = collection |
| + | |
| + | @repository = repository_klass.new(adapter) |
| + | @repository.scope = scope |
| + | end |
| + | |
| + | # In order to keep track of the entity which owns |
| + | # the association. |
| + | def attach(name, entity) |
| + | @repository.send(:"#{name}=", entity) |
| + | end |
| + | |
| + | def method_missing(name, *args, &block) |
| + | @repository.send(name, *args, &block) |
| + | end |
| + | |
| + | end |
| + | |
| + | end |
| + | end |
locomotive/steam/models/associations/has_many.rb b/lib/locomotive/steam/models/associations/has_many.rb
+52
-0
| @@ | @@ -0,0 +1,52 @@ |
| + | require 'locomotive/steam/adapters/memory' |
| + | require 'morphine' |
| + | |
| + | module Locomotive::Steam |
| + | module Models |
| + | |
| + | # Note: represents an embedded collection |
| + | class HasManyAssociation |
| + | |
| + | attr_reader :repository |
| + | |
| + | def initialize(repository_klass, scope, adapter) |
| + | @repository = repository_klass.new(adapter) |
| + | |
| + | # Note: if we change the locale of the parent repository, that won't |
| + | # reflect in that repository |
| + | @repository.scope = scope.dup |
| + | end |
| + | |
| + | def set_condition |
| + | @repository.association_condition = { } |
| + | end |
| + | |
| + | def method_missing(name, *args, &block) |
| + | @repository.send(name, *args, &block) |
| + | end |
| + | |
| + | # include Morphine |
| + | |
| + | # # use the scope from the parent repository |
| + | # # one of the benefits is that if we change the current_locale |
| + | # # of the parent repository, that will change the local repository |
| + | # # as well. |
| + | # def initialize(repository_klass, collection, scope) |
| + | # adapter.collection = collection |
| + | |
| + | # @repository = repository_klass.new(adapter) |
| + | # @repository.scope = scope |
| + | # end |
| + | |
| + | # # In order to keep track of the entity which owns |
| + | # # the association. |
| + | # def attach(name, entity) |
| + | # @repository.send(:"#{name}=", entity) |
| + | # end |
| + | |
| + | |
| + | |
| + | end |
| + | |
| + | end |
| + | end |
locomotive/steam/models/i18n_field.rb b/lib/locomotive/steam/models/i18n_field.rb
+4
-4
| @@ | @@ -8,11 +8,11 @@ module Locomotive::Steam |
| def initialize(name, translations) | |
| @name = name | |
| - | if translations.respond_to?(:fetch) |
| - | @translations = translations.with_indifferent_access |
| + | @translations = (if translations.respond_to?(:fetch) |
| + | translations |
| else | |
| - | @translations = Hash.new { translations } |
| - | end |
| + | Hash.new { translations } |
| + | end).with_indifferent_access |
| end | |
| def [](locale) | |
locomotive/steam/models/mapper.rb b/lib/locomotive/steam/models/mapper.rb
+35
-12
| @@ | @@ -10,7 +10,7 @@ module Locomotive::Steam |
| @localized_attributes = [] | |
| @default_attributes = [] | |
| - | @associations = [] |
| + | @associations = { embedded: [], belongs_to: [] } |
| instance_eval(&block) if block_given? | |
| end | |
| @@ | @@ -23,14 +23,18 @@ module Locomotive::Steam |
| @default_attributes += [[name.to_sym, value]] | |
| end | |
| - | # Note: only works for embedded-type associations |
| - | def association(name, repository_klass) |
| - | @associations += [[name.to_sym, repository_klass]] |
| + | def belongs_to_association(name, repository_klass, options = {}) |
| + | @associations[:belongs_to] += [[name.to_sym, repository_klass, options]] |
| + | end |
| + | |
| + | def embedded_association(name, repository_klass) |
| + | @associations[:embedded] += [[name.to_sym, repository_klass]] |
| end | |
| def to_entity(attributes) | |
| entity_klass.new(serialize(attributes)).tap do |entity| | |
| - | attach_entity_to_associations(entity) |
| + | attach_entity_to_embedded_associations(entity) |
| + | attach_entity_to_belongs_to_associations(entity) |
| set_default_attributes(entity) | |
| end | |
| end | |
| @@ | @@ -38,7 +42,8 @@ module Locomotive::Steam |
| def serialize(attributes) | |
| serialize_localized_attributes(attributes) | |
| - | serialize_associations(attributes) |
| + | serialize_embedded_associations(attributes) |
| + | serialize_belongs_to_associations(attributes) |
| attributes | |
| end | |
| @@ | @@ -47,6 +52,11 @@ module Locomotive::Steam |
| options[:entity] | |
| end | |
| + | def i18n_value_of(entity, name, locale) |
| + | value = entity.send(name.to_sym) |
| + | value.respond_to?(:translations) ? value[locale] : value |
| + | end |
| + | |
| private | |
| # create a proxy class for each localized attribute | |
| @@ | @@ -57,16 +67,29 @@ module Locomotive::Steam |
| end | |
| # build the embedded associations | |
| - | def serialize_associations(attributes) |
| - | @associations.each do |name, repository_klass| |
| - | attributes[name] = Association.new(repository_klass, attributes[name], @repository.scope) |
| + | def serialize_embedded_associations(attributes) |
| + | @associations[:embedded].each do |name, repository_klass| |
| + | attributes[name] = EmbeddedAssociation.new(repository_klass, attributes[name], @repository.scope) |
| + | end |
| + | end |
| + | |
| + | # build the belongs_to associations |
| + | def serialize_belongs_to_associations(attributes) |
| + | @associations[:belongs_to].each do |name, repository_klass, options| |
| + | attributes[name] = BelongsToAssociation.new(repository_klass, @repository.scope, @repository.adapter) |
| end | |
| end | |
| - | def attach_entity_to_associations(entity) |
| - | @associations.each do |(name, _)| |
| + | def attach_entity_to_embedded_associations(entity) |
| + | @associations[:embedded].each do |(name, _)| |
| key = self.name.to_s.singularize.to_sym | |
| - | entity[name].attach(key, entity) |
| + | entity[name].attach(key, entity) # Note: entity[name] is a proxy class |
| + | end |
| + | end |
| + | |
| + | def attach_entity_to_belongs_to_associations(entity) |
| + | @associations[:belongs_to].each do |(name, _)| |
| + | entity[name].attach(name, entity) # Note: entity[name] is a proxy class |
| end | |
| end | |
locomotive/steam/models/repository.rb b/lib/locomotive/steam/models/repository.rb
+12
-0
| @@ | @@ -17,6 +17,14 @@ module Locomotive::Steam |
| @scope = Scope.new(site, locale) | |
| end | |
| + | def build(attributes, &block) |
| + | mapper.to_entity(attributes) |
| + | end |
| + | |
| + | def create(entity) |
| + | adapter.create(entity) |
| + | end |
| + | |
| def find(id) | |
| adapter.find(mapper, scope, id) | |
| end | |
| @@ | @@ -43,6 +51,10 @@ module Locomotive::Steam |
| @mapper = Mapper.new(name, options, self, &block) | |
| end | |
| + | def i18n_value_of(entity, name) |
| + | mapper.i18n_value_of(entity, name, locale) |
| + | end |
| + | |
| # TODO: not sure about that. could it be used further in the dev | |
| # def collection_name | |
| # mapper.name | |
locomotive/steam/repositories/content_entry_repository.rb b/lib/locomotive/steam/repositories/content_entry_repository.rb
+76
-113
| @@ | @@ -5,9 +5,11 @@ module Locomotive |
| include Models::Repository | |
| - | attr_accessor :content_type |
| + | attr_reader :content_type_repository |
| + | attr_accessor :content_type, :local_conditions |
| def initialize(adapter, site = nil, locale = nil, content_type_repository = nil) | |
| + | @local_conditions = {} |
| @adapter = adapter | |
| @scope = Locomotive::Steam::Models::Scope.new(site, locale) | |
| @content_type_repository = content_type_repository | |
| @@ | @@ -18,94 +20,53 @@ module Locomotive |
| localized_attributes :_slug, :seo_title, :meta_description, :meta_keywords | |
| default_attribute :content_type, -> (repository) { repository.content_type } | |
| - | |
| - | # # embedded association |
| - | # association :entries_custom_fields, ContentTypeFieldRepository |
| end | |
| - | def all(type, conditions = {}) |
| - | conditions = { _visible: true }.merge(conditions || {}) |
| - | |
| + | # this is the starting point of all the next actions |
| + | def with(type) |
| self.content_type = type # used for creating the scope | |
| self.scope.context[:content_type] = type | |
| - | # filter the entries by the content type they belong to |
| - | conditions[:content_type_id] = type._id |
| + | @local_conditions[:content_type_id] = type.try(:_id) |
| + | |
| + | self # chainable |
| + | end |
| + | |
| + | def all(conditions = {}) |
| + | conditions = prepare_conditions({ _visible: true }, conditions) |
| # priority: | |
| # 1/ order_by passed in the conditions parameter | |
| # 2/ the default order (_position) defined in the content type | |
| - | order_by = conditions.delete(:order_by)|| conditions.delete('order_by') || type.order_by |
| + | order_by = conditions.delete(:order_by)|| conditions.delete('order_by') || content_type.order_by |
| query { where(conditions).order_by(order_by) }.all | |
| end | |
| - | # Engine: content_type.entries.build(attributes) |
| - | def build(type, attributes = {}) |
| - | raise 'TODO, delegate to the adapter' |
| - | |
| - | # collection_options[:model].new(attributes).tap do |entry| |
| - | # # set the reference to the content type |
| - | # entry.content_type = type |
| - | # end |
| + | def exists?(conditions = {}) |
| + | conditions = prepare_conditions(conditions) |
| + | query { where(conditions) }.all.size > 0 |
| end | |
| - | # Engine: entry.save |
| - | def persist(entry) |
| - | return nil if entry.nil? |
| - | |
| - | raise 'TODO, delegate to the adapter' |
| - | |
| - | # collection = memoized_collection(entry.content_type) |
| - | |
| - | # # slugify entry |
| - | # sanitizer.set_slug(entry, collection) |
| - | |
| - | # collection << entry # immediate result |
| - | |
| - | # # make sure we write it back to the data source |
| - | # loader.write(entry.content_type, entry.attributes) |
| - | end |
| - | |
| - | # Engine: all(conditions).count > 0 |
| - | def exists?(type, conditions = {}) |
| - | query(type) { where(conditions) }.all.size > 0 |
| - | end |
| - | |
| - | # Engine: not necessary |
| - | def by_slug(type, slug) |
| - | query(type) { where(_slug: slug) }.first |
| + | def by_slug(slug) |
| + | conditions = prepare_conditions(_slug: slug) |
| + | first { where(conditions) } |
| end | |
| - | # Engine: entry.send(:name) :-) |
| - | def value_for(name, entry, conditions = {}) |
| - | value = entry.send(name) |
| - | |
| - | if value.respond_to?(:association) |
| - | association(value, conditions || {}) |
| - | else |
| - | value |
| - | end |
| - | end |
| - | |
| - | # Engine: entry.next |
| def next(entry) | |
| next_or_previous(entry, 'gt', 'lt') | |
| end | |
| - | # Engine: entry.previous |
| def previous(entry) | |
| next_or_previous(entry, 'lt', 'gt') | |
| end | |
| - | # Engine: content_type.entries.klass.send(:group_by_select_option, name, content_type.order_by_definition) |
| - | def group_by_select_option(type, name) |
| - | return {} if type.nil? || name.nil? || type.fields_by_name[name].type != :select |
| + | def group_by_select_option(name) |
| + | return {} if name.nil? || content_type.nil? || content_type.fields_by_name[name].type != :select |
| - | raise 'TODO: implement the group_by method' |
| - | _groups = all(type).group_by(&name) |
| + | _groups = all.group_by { |entry| i18n_value_of(entry, name) } |
| - | groups = content_type_repository.select_options(type, name).map do |option| |
| + | groups = content_type_repository.select_options(content_type, name).map do |option| |
| { name: option, entries: _groups.delete(option) || [] } | |
| end | |
| @@ | @@ -119,79 +80,81 @@ module Locomotive |
| private | |
| - | def scoped_query(type, &block) |
| - | self.content_type = type |
| - | query(&block) |
| - | end |
| - | |
| - | def mapper(memoized = true) |
| - | super(false).tap do |mapper| |
| + | def mapper(memoized = false) |
| + | super(memoized).tap do |mapper| |
| unless self.content_type.localized_fields_names.blank? | |
| mapper.localized_attributes(*self.content_type.localized_fields_names) | |
| end | |
| - | end |
| - | end |
| - | def type_from(slug) |
| - | content_type_repository.by_slug(slug) |
| - | end |
| - | |
| - | def localized_slug(entry) |
| - | raise 'SHOULD NOT BE USED' |
| - | localized_attribute(entry, :_slug) |
| - | end |
| - | |
| - | def association(metadata, conditions = {}) |
| - | case metadata.type |
| - | when :belongs_to then belongs_to_association(metadata) |
| - | when :has_many then has_many_association(metadata, conditions) |
| - | when :many_to_many then many_to_many_association(metadata, conditions) |
| + | self.content_type.belongs_to_fields.each do |field| |
| + | mapper.belongs_to_association(field.name, self.class, {}) do |repository| |
| + | # TODO: load the content type (adapter.id_names[:content_types]) |
| + | repository.content_type |
| + | end # field.association_options) |
| + | end |
| end | |
| end | |
| - | def belongs_to_association(metadata) |
| - | type = type_from(metadata.target_class_slug) |
| - | by_slug(type, metadata.target_slugs.first) |
| + | def prepare_conditions(*conditions) |
| + | [*conditions].inject({}) do |memo, hash| |
| + | memo.merge!(hash) unless hash.blank? |
| + | memo |
| + | end.merge(@local_conditions) |
| end | |
| - | def has_many_association(metadata, conditions) |
| - | many_association(metadata, |
| - | { metadata.target_field => localized_slug(metadata.source) }.merge(conditions)) |
| - | end |
| + | # def type_from(slug) |
| + | # content_type_repository.by_slug(slug) |
| + | # end |
| - | def many_to_many_association(metadata, conditions) |
| - | many_association(metadata, |
| - | { '_slug.in' => metadata.target_slugs }.merge(conditions)) |
| - | end |
| + | # def localized_slug(entry) |
| + | # raise 'SHOULD NOT BE USED' |
| + | # localized_attribute(entry, :_slug) |
| + | # end |
| - | def many_association(metadata, conditions) |
| - | type = type_from(metadata.target_class_slug) |
| + | # def association(metadata, conditions = {}) |
| + | # case metadata.type |
| + | # when :belongs_to then belongs_to_association(metadata) |
| + | # when :has_many then has_many_association(metadata, conditions) |
| + | # when :many_to_many then many_to_many_association(metadata, conditions) |
| + | # end |
| + | # end |
| - | if order_by = metadata.order_by |
| - | conditions = { order_by: order_by }.merge(conditions) |
| - | end |
| + | # def belongs_to_association(metadata) |
| + | # type = type_from(metadata.target_class_slug) |
| + | # by_slug(type, metadata.target_slugs.first) |
| + | # end |
| - | all(type, conditions) |
| - | end |
| + | # def has_many_association(metadata, conditions) |
| + | # many_association(metadata, |
| + | # { metadata.target_field => localized_slug(metadata.source) }.merge(conditions)) |
| + | # end |
| + | |
| + | # def many_to_many_association(metadata, conditions) |
| + | # many_association(metadata, |
| + | # { '_slug.in' => metadata.target_slugs }.merge(conditions)) |
| + | # end |
| - | # def memoized_collection(content_type) |
| - | # slug = content_type.slug |
| - | # @collections ||= {} |
| + | # def many_association(metadata, conditions) |
| + | # type = type_from(metadata.target_class_slug) |
| - | # return @collections[slug] if @collections[slug] |
| + | # if order_by = metadata.order_by |
| + | # conditions = { order_by: order_by }.merge(conditions) |
| + | # end |
| - | # @collections[slug] = collection(content_type) |
| + | # all(type, conditions) |
| # end | |
| def next_or_previous(entry, asc_op, desc_op) | |
| return nil if entry.nil? | |
| - | type = entry.content_type |
| - | column, direction = type.order_by.split |
| - | operator = direction == 'asc' ? asc_op : desc_op |
| - | value = localized_attribute(entry, column) |
| + | with(entry.content_type) |
| + | |
| + | name, direction = self.content_type.order_by.split |
| + | op = direction == 'asc' ? asc_op : desc_op |
| + | |
| + | conditions = prepare_conditions({ k(name, op) => i18n_value_of(entry, name) }) |
| - | query(type) { where("#{column}.#{operator}" => value) }.first |
| + | first { where(conditions) } |
| end | |
| end | |
locomotive/steam/repositories/content_type_field_repository.rb b/lib/locomotive/steam/repositories/content_type_field_repository.rb
+6
-3
| @@ | @@ -11,8 +11,7 @@ module Locomotive |
| mapping :content_type_fields, entity: ContentTypeField do | |
| default_attribute :content_type, -> (repository) { repository.content_type } | |
| - | # embedded association |
| - | association :select_options, ContentTypeFieldSelectOptionRepository |
| + | embedded_association :select_options, ContentTypeFieldSelectOptionRepository |
| end | |
| def unique | |
| @@ | @@ -26,12 +25,16 @@ module Locomotive |
| query { where(required: true) }.all | |
| end | |
| + | def belongs_to |
| + | query { where(type: :belongs_to) }.all |
| + | end |
| + | |
| def localized_names | |
| query { where(localized: true) }.all.map(&:name) | |
| end | |
| def select_options(name) | |
| - | if field = first { where(name: name, type: 'select') } |
| + | if field = first { where(name: name, type: :select) } |
| field.select_options.all | |
| else | |
| nil | |
locomotive/steam/repositories/content_type_repository.rb b/lib/locomotive/steam/repositories/content_type_repository.rb
+1
-2
| @@ | @@ -7,8 +7,7 @@ module Locomotive |
| # Entity mapping | |
| mapping :content_types, entity: ContentType do | |
| - | # embedded association |
| - | association :entries_custom_fields, ContentTypeFieldRepository |
| + | embedded_association :entries_custom_fields, ContentTypeFieldRepository |
| end | |
| def by_slug(slug_or_content_type) | |
locomotive/steam/repositories/page_repository.rb b/lib/locomotive/steam/repositories/page_repository.rb
+1
-4
| @@ | @@ -9,8 +9,7 @@ module Locomotive |
| mapping :pages, entity: Page do | |
| localized_attributes :title, :slug, :permalink, :template, :template_path, :redirect_url, :fullpath, :seo_title, :meta_description, :meta_keywords | |
| - | # embedded association |
| - | association :editable_elements, EditableElementRepository |
| + | embedded_association :editable_elements, EditableElementRepository |
| end | |
| def all(conditions = {}) | |
| @@ | @@ -29,8 +28,6 @@ module Locomotive |
| end | |
| def matching_fullpath(list) | |
| - | # all(:fullpath.in => list) |
| - | # all('fullpath.in' => list) # MongoDB => fullpath.in |
| all(k(:fullpath, :in) => list) | |
| end | |
spec/unit/adapters/filesystem/yaml_loaders/content_entry_spec.rb
+14
-1
| @@ | @@ -6,7 +6,7 @@ require_relative '../../../../../lib/locomotive/steam/adapters/filesystem/yaml_l |
| describe Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::ContentEntry do | |
| let(:site_path) { default_fixture_site_path } | |
| - | let(:content_type) { instance_double('Articles', slug: 'bands') } |
| + | let(:content_type) { instance_double('Bands', slug: 'bands', belongs_to_fields: []) } |
| let(:scope) { instance_double('Scope', locale: :en, context: { content_type: content_type }) } | |
| let(:loader) { described_class.new(site_path) } | |
| @@ | @@ -20,6 +20,19 @@ describe Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::ContentEntry do |
| expect(subject.first[:content_type]).to eq nil | |
| end | |
| + | context 'a content type with a belongs_to field' do |
| + | |
| + | let(:field) { instance_double('Field', name: 'band') } |
| + | let(:content_type) { instance_double('Songs', slug: 'songs', belongs_to_fields: [field]) } |
| + | |
| + | it 'adds a new attribute for the foreign key' do |
| + | expect(subject.first[:band_id]).to eq 'pearl-jam' |
| + | expect(subject.first[:band]).to eq nil |
| + | expect(subject.first[:_position_in_band]).to eq 0 |
| + | end |
| + | |
| + | end |
| + | |
| end | |
| end | |
spec/unit/entities/content_entry_spec.rb
+27
-27
| @@ | @@ -12,7 +12,7 @@ describe Locomotive::Steam::ContentEntry do |
| describe '#valid?' do | |
| - | let(:fields) { [instance_double('Field', name: :title, type: 'string', required: true)] } |
| + | let(:fields) { [instance_double('Field', name: :title, type: :string, required: true)] } |
| before do | |
| allow(repository).to receive(:required).and_return(fields) | |
| @@ | @@ -150,32 +150,32 @@ describe Locomotive::Steam::ContentEntry do |
| end | |
| end | |
| - | context 'a belongs_to relationship' do |
| - | let(:field_type) { :belongs_to } |
| - | let(:value) { 'john-doe' } |
| - | it { expect(subject.type).to eq :belongs_to } |
| - | it { expect(subject.target_slugs).to eq ['john-doe'] } |
| - | it { expect(subject.source).to eq content_entry } |
| - | it { expect(subject.field).to eq field } |
| - | end |
| - | |
| - | context 'a has_many relationship' do |
| - | let(:field_type) { :has_many } |
| - | let(:value) { nil } |
| - | it { expect(subject.type).to eq :has_many } |
| - | it { expect(subject.target_slugs).to eq [] } |
| - | it { expect(subject.source).to eq content_entry } |
| - | it { expect(subject.field).to eq field } |
| - | end |
| - | |
| - | context 'a many_to_many relationship' do |
| - | let(:field_type) { :many_to_many } |
| - | let(:value) { ['john-doe', 'jane-doe'] } |
| - | it { expect(subject.type).to eq :many_to_many } |
| - | it { expect(subject.target_slugs).to eq ['john-doe', 'jane-doe'] } |
| - | it { expect(subject.source).to eq content_entry } |
| - | it { expect(subject.field).to eq field } |
| - | end |
| + | # context 'a belongs_to relationship' do |
| + | # let(:field_type) { :belongs_to } |
| + | # let(:value) { 'john-doe' } |
| + | # it { expect(subject.type).to eq :belongs_to } |
| + | # it { expect(subject.target_slugs).to eq ['john-doe'] } |
| + | # it { expect(subject.source).to eq content_entry } |
| + | # it { expect(subject.field).to eq field } |
| + | # end |
| + | |
| + | # context 'a has_many relationship' do |
| + | # let(:field_type) { :has_many } |
| + | # let(:value) { nil } |
| + | # it { expect(subject.type).to eq :has_many } |
| + | # it { expect(subject.target_slugs).to eq [] } |
| + | # it { expect(subject.source).to eq content_entry } |
| + | # it { expect(subject.field).to eq field } |
| + | # end |
| + | |
| + | # context 'a many_to_many relationship' do |
| + | # let(:field_type) { :many_to_many } |
| + | # let(:value) { ['john-doe', 'jane-doe'] } |
| + | # it { expect(subject.type).to eq :many_to_many } |
| + | # it { expect(subject.target_slugs).to eq ['john-doe', 'jane-doe'] } |
| + | # it { expect(subject.source).to eq content_entry } |
| + | # it { expect(subject.field).to eq field } |
| + | # end |
| end | |
spec/unit/entities/content_type_field_spec.rb
+14
-0
| @@ | @@ -0,0 +1,14 @@ |
| + | require 'spec_helper' |
| + | |
| + | describe Locomotive::Steam::ContentTypeField do |
| + | |
| + | let(:content_type) { described_class.new(name: 'title', type: 'string') } |
| + | |
| + | describe '#type' do |
| + | |
| + | subject { content_type.type } |
| + | it { is_expected.to eq :string } |
| + | |
| + | end |
| + | |
| + | end |
spec/unit/models/mapper_spec.rb
+1
-1
| @@ | @@ -36,7 +36,7 @@ describe Locomotive::Steam::Models::Mapper do |
| let(:repository) { instance_double('Repository', scope: 42) } | |
| let(:attributes) { { parents: [instance_double('Page', title: 'Hello world')] } } | |
| let(:klass) { instance_double('RepositoryKlass')} | |
| - | let(:block) { ->(_) { association(:parents, BlankRepository) } } |
| + | let(:block) { ->(_) { embedded_association(:parents, BlankRepository) } } |
| it { expect(subject.parents).not_to eq nil } | |
spec/unit/repositories/content_entry_repository_spec.rb
+147
-126
| @@ | @@ -4,7 +4,7 @@ require_relative '../../../lib/locomotive/steam/adapters/filesystem.rb' |
| describe Locomotive::Steam::ContentEntryRepository do | |
| - | let(:type) { instance_double('Articles', _id: 1, slug: 'articles', order_by: nil, label_field_name: :title, localized_fields_names: [:title], fields_by_name: { title: instance_double('Field', name: :title, type: :string) }) } |
| + | let(:type) { instance_double('Articles', _id: 1, slug: 'articles', order_by: nil, label_field_name: :title, localized_fields_names: [:title], belongs_to_fields: [], fields_by_name: { title: instance_double('Field', name: :title, type: :string) }) } |
| let(:entries) { [{ content_type_id: 1, _position: 0, _label: 'Update #1', title: { fr: 'Mise a jour #1' }, text: { en: 'added some free stuff', fr: 'phrase FR' }, date: '2009/05/12', category: 'General' }] } | |
| let(:locale) { :en } | |
| let(:site) { instance_double('Site', _id: 1, default_locale: :en, locales: %i(en fr)) } | |
| @@ | @@ -18,17 +18,37 @@ describe Locomotive::Steam::ContentEntryRepository do |
| adapter.cache = NoCacheStore.new | |
| end | |
| + | describe 'belongs_to' do |
| + | |
| + | let(:field) { instance_double('Field', name: :author, type: :belongs_to, association_options: { class_name: 'authors' }) } |
| + | let(:type) { instance_double('Articles', _id: 1, slug: 'articles', order_by: nil, label_field_name: :title, belongs_to_fields: [field], fields_by_name: { title: instance_double('Field', name: :title, type: :string), author: field }, localized_fields_names: []) } |
| + | let(:other_type) { instance_double('Authors', _id: 2, slug: 'authors', order_by: nil, label_field_name: :name, fields_by_name: { name: instance_double('Field', name: :name, type: :string) }, localized_fields_names: []) } |
| + | let(:entries) { [{ content_type_id: 1, title: 'Hello world', author_id: 'john-doe' }] } |
| + | |
| + | let(:type_repository) { instance_double('ContentTypeRepository', belongs_to: [field]) } |
| + | |
| + | before do |
| + | allow(type).to receive(:fields).and_return(type_repository) |
| + | end |
| + | |
| + | subject { repository.with(type).by_slug('hello-world') } |
| + | |
| + | it { expect(subject.author.class).to eq Locomotive::Steam::Models::BelongsToAssociation } |
| + | # it { expect(subject.author.name).to eq 'John Doe' } |
| + | |
| + | end |
| + | |
| describe '#all' do | |
| let(:conditions) { nil } | |
| - | subject { repository.all(type, conditions) } |
| + | subject { repository.with(type).all(conditions) } |
| it { expect(subject.size).to eq 1 } | |
| describe 'first element' do | |
| - | subject { repository.all(type, conditions).first } |
| + | subject { repository.with(type).all(conditions).first } |
| it { expect(subject.class).to eq Locomotive::Steam::ContentEntry } | |
| it { expect(subject._label.translations).to eq('en' => 'Update #1', 'fr' => 'Mise a jour #1') } | |
| @@ | @@ -40,66 +60,67 @@ describe Locomotive::Steam::ContentEntryRepository do |
| end | |
| - | # describe '#build' do |
| + | describe '#build' do |
| - | # let(:attributes) { { title: 'Hello world' } } |
| - | # subject { repository.build(type, attributes) } |
| + | let(:attributes) { { title: 'Hello world' } } |
| + | subject { repository.with(type).build(attributes) } |
| - | # it { expect(subject.title).to eq 'Hello world' } |
| + | it { expect(subject.title[:en]).to eq 'Hello world' } |
| + | it { expect(subject.content_type).to eq type } |
| - | # end |
| + | end |
| # describe '#persist' do | |
| - | # let(:entry) { instance_double('NewEntry', _visible: true, content_type: type, _label: 'Hello world', attributes: { title: 'Hello world' }) } |
| - | # subject { repository.persist(entry) } |
| + | # # let(:entry) { instance_double('NewEntry', _visible: true, content_type: type, _label: 'Hello world', attributes: { title: 'Hello world' }) } |
| + | # # subject { repository.persist(entry) } |
| - | # before do |
| - | # expect(entry).to receive(:[]).with(:_slug).and_return(nil) |
| - | # expect(entry).to receive(:[]=).with(:_slug, 'hello-world') |
| - | # expect(loader).to receive(:write).with(type, { title: 'Hello world' }) |
| - | # end |
| + | # # before do |
| + | # # expect(entry).to receive(:[]).with(:_slug).and_return(nil) |
| + | # # expect(entry).to receive(:[]=).with(:_slug, 'hello-world') |
| + | # # expect(loader).to receive(:write).with(type, { title: 'Hello world' }) |
| + | # # end |
| - | # it { expect { subject }.to change { repository.all(type).size }.by(1) } |
| + | # # it { expect { subject }.to change { repository.all(type).size }.by(1) } |
| # end | |
| - | # describe '#exists?' do |
| + | describe '#exists?' do |
| - | # let(:conditions) { {} } |
| - | # subject { repository.exists?(type, conditions) } |
| + | let(:conditions) { {} } |
| + | subject { repository.with(type).exists?(conditions) } |
| - | # it { expect(subject).to eq true } |
| + | it { expect(subject).to eq true } |
| - | # context 'more specific conditions' do |
| + | context 'more specific conditions' do |
| - | # let(:conditions) { { '_slug' => 'update-number-1' } } |
| - | # it { expect(subject).to eq true } |
| + | let(:conditions) { { '_slug' => 'update-number-1' } } |
| + | it { expect(subject).to eq true } |
| - | # end |
| + | end |
| - | # context 'conditions which do match any entries' do |
| + | context 'conditions which do match any entries' do |
| - | # let(:conditions) { { '_slug' => 'foo' } } |
| - | # it { expect(subject).to eq false } |
| + | let(:conditions) { { '_slug' => 'foo' } } |
| + | it { expect(subject).to eq false } |
| - | # end |
| + | end |
| - | # end |
| + | end |
| - | # describe '#by_slug' do |
| + | describe '#by_slug' do |
| - | # let(:slug) { nil } |
| - | # subject { repository.by_slug(type, slug) } |
| + | let(:slug) { nil } |
| + | subject { repository.with(type).by_slug(slug) } |
| - | # it { is_expected.to eq nil } |
| + | it { is_expected.to eq nil } |
| - | # context 'existing slug' do |
| - | # let(:slug) { 'update-number-1' } |
| - | # it { expect(subject.title).to eq({ en: 'Update #1', fr: 'Mise a jour #1' }) } |
| - | # end |
| + | context 'existing slug' do |
| + | let(:slug) { 'update-number-1' } |
| + | it { expect(subject.title.translations).to eq('en' => 'Update #1', 'fr' => 'Mise a jour #1') } |
| + | end |
| - | # end |
| + | end |
| # describe '#value_for' do | |
| @@ | @@ -132,138 +153,138 @@ describe Locomotive::Steam::ContentEntryRepository do |
| # end | |
| - | # context 'has_many association' do |
| + | # # context 'has_many association' do |
| - | # let(:association) { instance_double('Association', type: :has_many, association: true, target_class_slug: :authors, target_field: :article, order_by: 'created_at') } |
| - | # let(:name) { :authors } |
| + | # # let(:association) { instance_double('Association', type: :has_many, association: true, target_class_slug: :authors, target_field: :article, order_by: 'created_at') } |
| + | # # let(:name) { :authors } |
| - | # before do |
| - | # allow(association).to receive(:source).and_return(entry) |
| - | # expect(repository).to receive(:all).with(:author_type, { article: 'hello-world', order_by: 'created_at' }).and_return(%w(jane john)) |
| - | # end |
| + | # # before do |
| + | # # allow(association).to receive(:source).and_return(entry) |
| + | # # expect(repository).to receive(:all).with(:author_type, { article: 'hello-world', order_by: 'created_at' }).and_return(%w(jane john)) |
| + | # # end |
| - | # it { expect(subject).to eq %w(jane john) } |
| + | # # it { expect(subject).to eq %w(jane john) } |
| - | # end |
| + | # # end |
| - | # context 'many_to_many association' do |
| + | # # context 'many_to_many association' do |
| - | # let(:association) { instance_double('Association', type: :many_to_many, association: true, target_class_slug: :authors, target_slugs: %w(jane john), order_by: nil) } |
| - | # let(:name) { :authors } |
| + | # # let(:association) { instance_double('Association', type: :many_to_many, association: true, target_class_slug: :authors, target_slugs: %w(jane john), order_by: nil) } |
| + | # # let(:name) { :authors } |
| - | # before do |
| - | # expect(repository).to receive(:all).with(:author_type, { '_slug.in' => %w(jane john) }).and_return(%w(jane john)) |
| - | # end |
| + | # # before do |
| + | # # expect(repository).to receive(:all).with(:author_type, { '_slug.in' => %w(jane john) }).and_return(%w(jane john)) |
| + | # # end |
| - | # it { expect(subject).to eq %w(jane john) } |
| + | # # it { expect(subject).to eq %w(jane john) } |
| - | # end |
| + | # # end |
| # end | |
| # end | |
| - | # describe '#next' do |
| + | describe '#next' do |
| - | # let(:type) { instance_double('Articles', slug: 'articles', order_by: '_position asc', label_field_name: :title, localized_fields_names: [:title], fields_by_name: { title: instance_double('Field', name: :title, type: :string) }) } |
| - | # let(:entries) do |
| - | # [ |
| - | # { content_type: type, _position: 0, _label: 'Update #1', title: { fr: 'Mise a jour #1' }, text: { en: 'added some free stuff', fr: 'phrase FR' }, date: '2009/05/12', category: 'General' }, |
| - | # { content_type: type, _position: 1, _label: 'Update #2', title: { fr: 'Mise a jour #2' }, text: { en: 'bla bla', fr: 'blabbla' }, date: '2009/05/12', category: 'General' }, |
| - | # { content_type: type, _position: 2, _label: 'Update #3', title: { fr: 'Mise a jour #2' }, text: { en: 'bla bla', fr: 'blabbla' }, date: '2009/05/12', category: 'General' } |
| - | # ] |
| - | # end |
| + | let(:type) { instance_double('Articles', _id: 1, slug: 'articles', order_by: '_position asc', label_field_name: :title, localized_fields_names: [:title], belongs_to_fields: [], fields_by_name: { title: instance_double('Field', name: :title, type: :string) }) } |
| + | let(:entries) do |
| + | [ |
| + | { content_type_id: 1, _position: 0, _label: 'Update #1', title: { fr: 'Mise a jour #1' }, text: { en: 'added some free stuff', fr: 'phrase FR' }, date: '2009/05/12', category: 'General' }, |
| + | { content_type_id: 1, _position: 1, _label: 'Update #2', title: { fr: 'Mise a jour #2' }, text: { en: 'bla bla', fr: 'blabbla' }, date: '2009/05/12', category: 'General' }, |
| + | { content_type_id: 1, _position: 2, _label: 'Update #3', title: { fr: 'Mise a jour #2' }, text: { en: 'bla bla', fr: 'blabbla' }, date: '2009/05/12', category: 'General' } |
| + | ] |
| + | end |
| - | # let(:entry) { nil } |
| - | # subject { repository.next(entry) } |
| + | let(:entry) { nil } |
| + | subject { repository.next(entry) } |
| - | # it { is_expected.to eq nil } |
| + | it { is_expected.to eq nil } |
| - | # context 'being last' do |
| + | context 'being last' do |
| - | # let(:entry) { instance_double('Entry', content_type: type, _position: 2) } |
| - | # it { repository.send(:collection, type).inspect; is_expected.to eq nil } |
| + | let(:entry) { instance_double('Entry', content_type: type, _position: 2) } |
| + | it { is_expected.to eq nil } |
| - | # end |
| + | end |
| - | # context 'being middle' do |
| + | context 'being middle' do |
| - | # let(:entry) { instance_double('Entry', content_type: type, _position: 1) } |
| - | # it { expect(subject._position).to eq 2 } |
| + | let(:entry) { instance_double('Entry', content_type: type, _position: 1) } |
| + | it { expect(subject._position).to eq 2 } |
| - | # end |
| + | end |
| - | # end |
| + | end |
| - | # describe '#previous' do |
| + | describe '#previous' do |
| - | # let(:type) { instance_double('Articles', slug: 'articles', order_by: '_position asc', label_field_name: :title, localized_fields_names: [:title], fields_by_name: { title: instance_double('Field', name: :title, type: :string) }) } |
| - | # let(:entries) do |
| - | # [ |
| - | # { content_type: type, _position: 0, _label: 'Update #1', title: { fr: 'Mise a jour #1' }, text: { en: 'added some free stuff', fr: 'phrase FR' }, date: '2009/05/12', category: 'General' }, |
| - | # { content_type: type, _position: 1, _label: 'Update #2', title: { fr: 'Mise a jour #2' }, text: { en: 'bla bla', fr: 'blabbla' }, date: '2009/05/12', category: 'General' }, |
| - | # { content_type: type, _position: 2, _label: 'Update #3', title: { fr: 'Mise a jour #2' }, text: { en: 'bla bla', fr: 'blabbla' }, date: '2009/05/12', category: 'General' } |
| - | # ] |
| - | # end |
| + | let(:type) { instance_double('Articles', _id: 1, slug: 'articles', order_by: '_position asc', label_field_name: :title, localized_fields_names: [:title], belongs_to_fields: [], fields_by_name: { title: instance_double('Field', name: :title, type: :string) }) } |
| + | let(:entries) do |
| + | [ |
| + | { content_type_id: 1, _position: 0, _label: 'Update #1', title: { fr: 'Mise a jour #1' }, text: { en: 'added some free stuff', fr: 'phrase FR' }, date: '2009/05/12', category: 'General' }, |
| + | { content_type_id: 1, _position: 1, _label: 'Update #2', title: { fr: 'Mise a jour #2' }, text: { en: 'bla bla', fr: 'blabbla' }, date: '2009/05/12', category: 'General' }, |
| + | { content_type_id: 1, _position: 2, _label: 'Update #3', title: { fr: 'Mise a jour #2' }, text: { en: 'bla bla', fr: 'blabbla' }, date: '2009/05/12', category: 'General' } |
| + | ] |
| + | end |
| - | # let(:entry) { nil } |
| - | # subject { repository.previous(entry) } |
| + | let(:entry) { nil } |
| + | subject { repository.previous(entry) } |
| - | # it { is_expected.to eq nil } |
| + | it { is_expected.to eq nil } |
| - | # context 'being first' do |
| + | context 'being first' do |
| - | # let(:entry) { instance_double('Entry', content_type: type, _position: 0) } |
| - | # it { repository.send(:collection, type).inspect; is_expected.to eq nil } |
| + | let(:entry) { instance_double('Entry', content_type: type, _position: 0) } |
| + | it { is_expected.to eq nil } |
| - | # end |
| + | end |
| - | # context 'being middle' do |
| + | context 'being middle' do |
| - | # let(:entry) { instance_double('Entry', content_type: type, _position: 1) } |
| - | # it { expect(subject._position).to eq 0 } |
| + | let(:entry) { instance_double('Entry', content_type: type, _position: 1) } |
| + | it { expect(subject._position).to eq 0 } |
| - | # end |
| + | end |
| - | # end |
| + | end |
| - | # describe '#group_by_select_option' do |
| + | describe '#group_by_select_option' do |
| - | # let(:type) { nil } |
| - | # let(:name) { nil } |
| + | let(:type) { nil } |
| + | let(:name) { nil } |
| - | # subject { repository.group_by_select_option(type, name) } |
| + | subject { repository.with(type).group_by_select_option(name) } |
| - | # it { is_expected.to eq({}) } |
| + | it { is_expected.to eq({}) } |
| - | # context 'select field' do |
| + | context 'select field' do |
| - | # let(:fields) do |
| - | # { |
| - | # title: instance_double('TitleField', name: :title, type: :string), |
| - | # category: instance_double('SelectField', name: :category, type: :select, select_options: { en: ['cooking', 'bread'], fr: ['cuisine', 'pain'] }) |
| - | # } |
| - | # end |
| - | # let(:type) { instance_double('Articles', slug: 'articles', order_by: '_position asc', label_field_name: :title, localized_fields_names: [:title, :category], fields_by_name: fields) } |
| - | # let(:name) { :category } |
| - | |
| - | # let(:entries) do |
| - | # [ |
| - | # { content_type: type, _position: 0, _label: 'Recipe #1', category: 'cooking' }, |
| - | # { content_type: type, _position: 1, _label: 'Recipe #2', category: 'bread' }, |
| - | # { content_type: type, _position: 2, _label: 'Recipe #3', category: 'bread' }, |
| - | # { content_type: type, _position: 3, _label: 'Recipe #4', category: 'unknown' } |
| - | # ] |
| - | # end |
| + | let(:fields) do |
| + | { |
| + | title: instance_double('TitleField', name: :title, type: :string), |
| + | category: instance_double('SelectField', name: :category, type: :select, select_options: { en: ['cooking', 'bread'], fr: ['cuisine', 'pain'] }) |
| + | } |
| + | end |
| + | let(:type) { instance_double('Articles', _id: 1, slug: 'articles', order_by: '_position asc', label_field_name: :title, localized_fields_names: [:title, :category], belongs_to_fields: [], fields_by_name: fields) } |
| + | let(:name) { :category } |
| - | # before { allow(content_type_repository).to receive(:select_options).and_return(%w(cooking wine bread)) } |
| + | let(:entries) do |
| + | [ |
| + | { content_type_id: 1, _position: 0, _label: 'Recipe #1', category: 'cooking' }, |
| + | { content_type_id: 1, _position: 1, _label: 'Recipe #2', category: 'bread' }, |
| + | { content_type_id: 1, _position: 2, _label: 'Recipe #3', category: 'bread' }, |
| + | { content_type_id: 1, _position: 3, _label: 'Recipe #4', category: 'unknown' } |
| + | ] |
| + | end |
| - | # it { expect(subject.size).to eq 4 } |
| - | # it { expect(subject.map { |h| h[:name] }).to eq ['cooking', 'wine', 'bread', nil] } |
| - | # it { expect(subject.map { |h| h[:entries].size }).to eq [1, 0, 2, 1] } |
| + | before { allow(content_type_repository).to receive(:select_options).and_return(%w(cooking wine bread)) } |
| - | # end |
| + | it { expect(subject.size).to eq 4 } |
| + | it { expect(subject.map { |h| h[:name] }).to eq ['cooking', 'wine', 'bread', nil] } |
| + | it { expect(subject.map { |h| h[:entries].size }).to eq [1, 0, 2, 1] } |
| - | # end |
| + | end |
| + | |
| + | end |
| end | |
spec/unit/repositories/content_type_repository_spec.rb
+1
-1
| @@ | @@ -105,7 +105,7 @@ describe Locomotive::Steam::ContentTypeRepository do |
| let(:fields) do | |
| [ | |
| { name: 'title', hint: 'Title of the article', type: 'string' }, | |
| - | { name: 'category', type: 'select', select_options: [{ name: { en: 'cooking', fr: 'cuisine' }, position: 0 }, { name: { en: 'bread', fr: 'pain' }, position: 1 }] } |
| + | { name: 'category', type: :select, select_options: [{ name: { en: 'cooking', fr: 'cuisine' }, position: 0 }, { name: { en: 'bread', fr: 'pain' }, position: 1 }] } |
| ] | |
| end | |
| let(:name) { :category } | |