Skip to content

Commit

Permalink
Merge branch 'feature/t5' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
oscarada87 committed Dec 24, 2020
2 parents 4cf5de5 + 3bb00c7 commit 678e5cf
Show file tree
Hide file tree
Showing 14 changed files with 231 additions and 65 deletions.
1 change: 1 addition & 0 deletions boxenn.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Gem::Specification.new do |spec|
spec.require_paths = ['lib']

spec.add_runtime_dependency 'dry-initializer', '~> 3.0'
spec.add_runtime_dependency 'dry-struct', '~> 1.3.0'
spec.add_runtime_dependency 'dry-monads', '~> 1.3'
spec.add_runtime_dependency 'wisper', '2.0.0'
end
22 changes: 22 additions & 0 deletions lib/boxenn/entity.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
require 'dry-struct'
require_relative '../initializer/dry_types'

require 'boxenn/errors'

module Boxenn
class Entity < Dry::Struct
alias assign_attributes new

def self.primary_keys
raise UndefinePrimaryKeys.new(class_name: self.class.name)
end

def primary_keys_hash
if !self.class.primary_keys.all? { |s| attributes.key? s}
raise UnassignPrimaryKeys.new(class_name: self.class.name)
else
attributes.slice(*self.class.primary_keys)
end
end
end
end
24 changes: 24 additions & 0 deletions lib/boxenn/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,28 @@ def _message(class_name:, provided:, required:)
end
end
end

class UndefinePrimaryKeys < StandardError
def initialize(**args)
super(_message(**args))
end

private

def _message(class_name:)
"Primary Key needs to be defined in #{class_name.inspect}"
end
end

class UnassignPrimaryKeys < StandardError
def initialize(**args)
super(_message(**args))
end

private

def _message(class_name:)
"Primary Key needs to be assigned in #{class_name.inspect}"
end
end
end
14 changes: 0 additions & 14 deletions lib/boxenn/query.rb

This file was deleted.

20 changes: 20 additions & 0 deletions lib/boxenn/repositories/factory.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require 'dry/initializer'

module Boxenn
module Repositories
class Factory

extend Dry::Initializer

param :entity, default: proc { nil }

def build
raise NotImplementedError
end

def primary_keys
entity.primary_keys
end
end
end
end
16 changes: 16 additions & 0 deletions lib/boxenn/repositories/query.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
require 'dry/initializer'

module Boxenn
module Repositories
class Query

extend Dry::Initializer

param :relation, default: proc { nil }

def collect
raise NotImplementedError
end
end
end
end
9 changes: 9 additions & 0 deletions lib/boxenn/repositories/record_mapper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module Boxenn
module Repositories
class RecordMapper
def build
raise NotImplementedError
end
end
end
end
20 changes: 20 additions & 0 deletions lib/boxenn/repositories/source_wrapper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require 'dry/initializer'

module Boxenn
module Repositories
class SourceWrapper

extend Dry::Initializer

param :source, default: proc { nil }

def find_by(primary_keys)
raise NotImplementedError
end

def save(primary_keys, attributes)
raise NotImplementedError
end
end
end
end
31 changes: 8 additions & 23 deletions lib/boxenn/repository.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,15 @@ class Repository

extend Dry::Initializer

option :primary_key, default: -> { self.class.__primary_key__ }, type: method(:Array)

option :source, default: -> { nil }
option :source_wrapper, default: -> { nil }

option :factory, default: -> { nil }

option :record_mapper, default: -> { nil }

def find_by_identity(**attributes)
non_primary_keys_provided = !(attributes.keys - primary_key).empty?
raise InvalidPrimaryKey.new(class_name: self.class.name, provided: attributes.keys, required: primary_key) if non_primary_keys_provided
non_primary_keys_provided = (attributes.keys - factory.primary_keys).empty? && (factory.primary_keys - attributes.keys).empty?
raise InvalidPrimaryKey.new(class_name: self.class.name, provided: attributes.keys, required: factory.primary_keys) unless non_primary_keys_provided

record = retrieve_record(attributes)
build(record)
Expand All @@ -30,21 +28,18 @@ def find_by_query(query)

def save(entity)
attributes = adapt(entity)
save_record(attributes)
save_record(entity.primary_keys_hash, attributes)
end

protected

def retrieve_record(**attributes)
primary_keys_missing = !(primary_key - attributes.keys).empty?
raise InvalidPrimaryKey.new(class_name: self.class.name, provided: attributes.keys, required: primary_key) if primary_keys_missing

pk_hash = attributes.slice(*primary_key)
record = source.find_by(pk_hash)
pk_hash = attributes.slice(*factory.primary_keys)
record = source_wrapper.find_by(pk_hash)
end

def save_record(**attributes)
source.save(attributes)
def save_record(primary_keys, attributes)
source_wrapper.save(primary_keys, attributes)
end

def build(record)
Expand All @@ -54,15 +49,5 @@ def build(record)
def adapt(entity)
record_mapper.build(entity)
end

class << self
def primary_key(*pk)
@pk = Array(pk)
end

def __primary_key__
@pk ||= [:id]
end
end
end
end
5 changes: 5 additions & 0 deletions lib/initializer/dry_types.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require 'dry-types'

module Types
include Dry.Types()
end
61 changes: 61 additions & 0 deletions spec/unit/entity_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
require 'boxenn/entity'

RSpec.describe Boxenn::Entity do

describe '#primary_keys_hash' do
context 'when method is called without defining primary key' do
class Test1 < Boxenn::Entity

end
let(:entity) { Test1.new }
subject { -> { entity.primary_keys_hash } }

it { is_expected.to raise_error(Boxenn::UndefinePrimaryKeys) }
end

context 'when method is called without assigning primary key' do
class Test2 < Boxenn::Entity
def self.primary_keys
[:id1].freeze
end
end
let(:entity) { Test2.new }
subject { -> { entity.primary_keys_hash } }

it { is_expected.to raise_error(Boxenn::UnassignPrimaryKeys) }
end

context 'when method is called with valid primary key' do
context 'accepts single primary key' do
class Test3 < Boxenn::Entity
def self.primary_keys
[:id1].freeze
end

attribute :id1, Types::Integer.default(1)
end

let(:entity) { Test3.new }
subject { entity.primary_keys_hash }

it { is_expected.to eq({ id1: 1 }) }
end

context 'accepts multiple primary key' do
class Test4 < Boxenn::Entity
def self.primary_keys
[:id1, :id2].freeze
end

attribute :id1, Types::Integer.default(1)
attribute :id2, Types::Integer.default(2)
end

let(:entity) { Test4.new }
subject { entity.primary_keys_hash }

it { is_expected.to eq({ id1: 1, id2: 2 }) }
end
end
end
end
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
require 'boxenn/query'
require 'boxenn/repositories/query'

RSpec.describe Boxenn::Query do
RSpec.describe Boxenn::Repositories::Query do

describe '#collect' do
let(:query) { Boxenn::Query.new }
let(:query) { Boxenn::Repositories::Query.new }

context 'when collect is not override' do
subject { -> { query.collect } }
Expand Down
Loading

0 comments on commit 678e5cf

Please sign in to comment.