barkibu-kb 0.16.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/.env.example +3 -0
  3. data/.gitignore +20 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +45 -0
  6. data/.ruby-version +2 -0
  7. data/.travis.yml +7 -0
  8. data/CHANGELOG.md +185 -0
  9. data/CODE_OF_CONDUCT.md +74 -0
  10. data/Gemfile +7 -0
  11. data/Gemfile.lock +182 -0
  12. data/LICENSE.txt +21 -0
  13. data/README.md +243 -0
  14. data/Rakefile +28 -0
  15. data/barkibu-kb-fake.gemspec +41 -0
  16. data/barkibu-kb.gemspec +54 -0
  17. data/bin/console +14 -0
  18. data/bin/setup +8 -0
  19. data/docker-compose.yaml +15 -0
  20. data/lib/barkibu-kb-fake.rb +1 -0
  21. data/lib/barkibu-kb.rb +33 -0
  22. data/lib/kb/cache.rb +23 -0
  23. data/lib/kb/client.rb +85 -0
  24. data/lib/kb/client_resolver.rb +62 -0
  25. data/lib/kb/concerns/as_kb_wrapper.rb +67 -0
  26. data/lib/kb/concerns.rb +1 -0
  27. data/lib/kb/errors/client_error.rb +9 -0
  28. data/lib/kb/errors/conflict_error.rb +3 -0
  29. data/lib/kb/errors/error.rb +26 -0
  30. data/lib/kb/errors/resource_not_found.rb +3 -0
  31. data/lib/kb/errors/unprocessable_entity_error.rb +3 -0
  32. data/lib/kb/errors.rb +6 -0
  33. data/lib/kb/fake/api.rb +72 -0
  34. data/lib/kb/fake/bounded_context/pet_family/breeds.rb +15 -0
  35. data/lib/kb/fake/bounded_context/pet_family/hubspot_relationship.rb +17 -0
  36. data/lib/kb/fake/bounded_context/pet_family/pet_contracts.rb +24 -0
  37. data/lib/kb/fake/bounded_context/pet_family/pet_parents.rb +98 -0
  38. data/lib/kb/fake/bounded_context/pet_family/pets.rb +84 -0
  39. data/lib/kb/fake/bounded_context/pet_family/products.rb +28 -0
  40. data/lib/kb/fake/bounded_context/rest_resource.rb +134 -0
  41. data/lib/kb/fake.rb +6 -0
  42. data/lib/kb/inflections.rb +3 -0
  43. data/lib/kb/models/assessment.rb +58 -0
  44. data/lib/kb/models/base_model.rb +40 -0
  45. data/lib/kb/models/breed.rb +39 -0
  46. data/lib/kb/models/concerns/creatable.rb +18 -0
  47. data/lib/kb/models/concerns/destroyable.rb +17 -0
  48. data/lib/kb/models/concerns/find_or_creatable.rb +19 -0
  49. data/lib/kb/models/concerns/findable.rb +19 -0
  50. data/lib/kb/models/concerns/inspectionable.rb +13 -0
  51. data/lib/kb/models/concerns/listable.rb +21 -0
  52. data/lib/kb/models/concerns/queryable.rb +34 -0
  53. data/lib/kb/models/concerns/updatable.rb +18 -0
  54. data/lib/kb/models/concerns/upsertable.rb +17 -0
  55. data/lib/kb/models/concerns.rb +10 -0
  56. data/lib/kb/models/condition.rb +32 -0
  57. data/lib/kb/models/hubspot_relationship.rb +34 -0
  58. data/lib/kb/models/pet.rb +68 -0
  59. data/lib/kb/models/pet_contract.rb +77 -0
  60. data/lib/kb/models/pet_parent.rb +111 -0
  61. data/lib/kb/models/plan.rb +44 -0
  62. data/lib/kb/models/product.rb +34 -0
  63. data/lib/kb/models/symptom.rb +25 -0
  64. data/lib/kb/models.rb +15 -0
  65. data/lib/kb/type/array_of_conditions_type.rb +13 -0
  66. data/lib/kb/type/array_of_strings_type.rb +9 -0
  67. data/lib/kb/type/array_of_symptoms_type.rb +13 -0
  68. data/lib/kb/types.rb +7 -0
  69. data/lib/kb/validators/uniqueness_validator.rb +26 -0
  70. data/lib/kb/validators.rb +1 -0
  71. data/lib/kb/version.rb +3 -0
  72. metadata +325 -0
@@ -0,0 +1,18 @@
1
+ module KB
2
+ module Creatable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ include Queryable
7
+ end
8
+
9
+ module ClassMethods
10
+ def create(attributes)
11
+ api_response = kb_client.create attributes
12
+ attributes_from_response(api_response)
13
+ rescue Faraday::Error => e
14
+ raise KB::Error.from_faraday(e)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ module KB
2
+ module Destroyable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ include Queryable
7
+ end
8
+
9
+ module ClassMethods
10
+ def destroy(key)
11
+ kb_client.destroy(key)
12
+ rescue Faraday::Error => e
13
+ raise KB::Error.from_faraday(e)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ module KB
2
+ module FindOrCreatable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ include Queryable
7
+ include Listable
8
+ include Creatable
9
+ end
10
+
11
+ module ClassMethods
12
+ def find_or_create_by(attributes, additional_attributes)
13
+ all(attributes).first || new(create(additional_attributes.merge(attributes)), &:persist!)
14
+ rescue Faraday::Error => e
15
+ raise KB::Error.from_faraday(e)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module KB
2
+ module Findable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ include Queryable
7
+ end
8
+
9
+ module ClassMethods
10
+ def find(key, params = {})
11
+ from_api(kb_client.find(key, params))
12
+ rescue Faraday::ResourceNotFound => e
13
+ raise KB::ResourceNotFound.new(e.response[:status], e.response[:body], e)
14
+ rescue Faraday::Error => e
15
+ raise KB::Error.from_faraday(e)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ module Inspectionable
2
+ def inspect
3
+ attr_list = attributes.map do |key, value|
4
+ value_str = if value.is_a? ActiveModel::Model
5
+ "#<#{value.class}: #{format '%<id>#018x', id: value.object_id << 1}>"
6
+ else
7
+ value.inspect
8
+ end
9
+ "#{key}: #{value_str}"
10
+ end.join ', '
11
+ "#<#{self.class}: #{format '%<id>#018x', id: object_id << 1} #{attr_list}>"
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ module KB
2
+ module Listable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ include Queryable
7
+ end
8
+
9
+ module ClassMethods
10
+ def all(filters = {})
11
+ kb_client.all(filters).map do |pet_parent|
12
+ from_api pet_parent
13
+ end
14
+ rescue Faraday::ConnectionFailed => e
15
+ raise e
16
+ rescue Faraday::Error => e
17
+ raise KB::Error.from_faraday(e)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,34 @@
1
+ module KB
2
+ module Queryable
3
+ class KBClientNotSetException < StandardError; end
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ class_attribute :resolver_factory
8
+ end
9
+
10
+ module ClassMethods
11
+ def kb_client
12
+ if resolver_factory.blank?
13
+ raise KBClientNotSetException, "You probably forgot to call `kb_api ...` on the class #{name}"
14
+ end
15
+
16
+ @kb_client ||= ClientResolver.public_send(resolver_factory)
17
+ end
18
+
19
+ def from_api(attributes)
20
+ new(attributes_from_response(attributes), &:persist!).tap(&:clear_changes_information)
21
+ end
22
+
23
+ private
24
+
25
+ def kb_api(resolver_factory)
26
+ self.resolver_factory = resolver_factory
27
+ end
28
+
29
+ # @abstract Subclass is expected to implement #attributes_from_response
30
+ # @!method attributes_from_response
31
+ # Filter and process the response to return the relevant attributes for entity initialization
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,18 @@
1
+ module KB
2
+ module Updatable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ include Queryable
7
+ end
8
+
9
+ module ClassMethods
10
+ def update(key, attributes)
11
+ api_response = kb_client.update(key, attributes)
12
+ attributes_from_response(api_response)
13
+ rescue Faraday::Error => e
14
+ raise KB::Error.from_faraday(e)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ module KB
2
+ module Upsertable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ include Queryable
7
+ end
8
+
9
+ module ClassMethods
10
+ def upsert(attributes)
11
+ from_api kb_client.upsert(attributes)
12
+ rescue Faraday::Error => e
13
+ raise KB::Error.from_faraday(e)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,10 @@
1
+ require 'kb/models/concerns/inspectionable'
2
+
3
+ require 'kb/models/concerns/queryable'
4
+ require 'kb/models/concerns/creatable'
5
+ require 'kb/models/concerns/findable'
6
+ require 'kb/models/concerns/find_or_creatable'
7
+ require 'kb/models/concerns/upsertable'
8
+ require 'kb/models/concerns/updatable'
9
+ require 'kb/models/concerns/listable'
10
+ require 'kb/models/concerns/destroyable'
@@ -0,0 +1,32 @@
1
+ module KB
2
+ class Condition
3
+ include Inspectionable
4
+ include ActiveModel::Model
5
+ include ActiveModel::Attributes
6
+ include ActiveModel::Serializers::JSON
7
+
8
+ FIELDS = %i[key name score usualness urgent information urgency].freeze
9
+
10
+ attribute :key, :string
11
+ attribute :name, :string
12
+ attribute :score, :float
13
+ attribute :usualness, :integer
14
+ attribute :urgency, :string
15
+
16
+ attribute :article, :string, default: ''
17
+ attribute :description_short, :string
18
+ attribute :diagnosis, :string
19
+ attribute :treatment, :string
20
+ attribute :prevention, :string
21
+ attribute :first_aid, :string
22
+ attribute :predisposition_factors, :string
23
+
24
+ alias_attribute :information, :article
25
+
26
+ def urgent
27
+ return false if urgency == 'low'
28
+
29
+ true
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,34 @@
1
+ module KB
2
+ class HubspotRelationship < BaseModel
3
+ include Queryable
4
+
5
+ kb_api :hubspot
6
+
7
+ def self.attributes_from_response(response)
8
+ response.transform_keys(&:underscore).transform_keys(&:to_sym).slice(*FIELDS)
9
+ end
10
+
11
+ private_class_method :attributes_from_response
12
+
13
+ STRING_FIELDS = %i[kb_key hubspot_id].freeze
14
+ DATE_FIELDS = %i[last_updated_at].freeze
15
+ FIELDS = [*STRING_FIELDS, *DATE_FIELDS].freeze
16
+
17
+ define_attribute_methods(*FIELDS)
18
+
19
+ STRING_FIELDS.each do |field|
20
+ attribute field, :string
21
+ end
22
+
23
+ DATE_FIELDS.each do |field|
24
+ attribute field, :date
25
+ end
26
+
27
+ def self.find(model, model_key)
28
+ response = kb_client.request("#{model}/#{model_key}/relationship")
29
+ new(attributes_from_response(response))
30
+ rescue Faraday::Error => e
31
+ raise KB::Error.from_faraday(e)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,68 @@
1
+ module KB
2
+ class Pet < BaseModel
3
+ include Findable
4
+ include Updatable
5
+ include FindOrCreatable
6
+ include Destroyable
7
+ include Upsertable
8
+
9
+ kb_api :pet
10
+
11
+ def self.attributes_from_response(response)
12
+ response.transform_keys(&:underscore).transform_keys(&:to_sym).slice(*FIELDS)
13
+ end
14
+
15
+ private_class_method :attributes_from_response
16
+
17
+ STRING_FIELDS = %i[key pet_parent_key name age_category sex breed chip species].freeze
18
+ DATE_FIELDS = %i[birth_date deleted_at].freeze
19
+ BOOLEAN_FIELDS = %i[neutered mongrel].freeze
20
+ FIELDS = [*STRING_FIELDS, *DATE_FIELDS, *BOOLEAN_FIELDS].freeze
21
+
22
+ define_attribute_methods(*FIELDS)
23
+
24
+ STRING_FIELDS.each do |field|
25
+ attribute field, :string
26
+ end
27
+
28
+ BOOLEAN_FIELDS.each do |field|
29
+ attribute field, :boolean
30
+ end
31
+
32
+ DATE_FIELDS.each do |field|
33
+ attribute field, :date
34
+ end
35
+
36
+ def save!
37
+ return unless changed?
38
+
39
+ run_callbacks :save do
40
+ self.attributes = if @persisted
41
+ self.class.update key, changes.transform_values(&:last)
42
+ else
43
+ self.class.create changes.transform_values(&:last)
44
+ end
45
+
46
+ self
47
+ end
48
+ end
49
+
50
+ def destroyed?
51
+ @destroyed
52
+ end
53
+
54
+ def destroy!
55
+ return unless @persisted
56
+
57
+ self.class.destroy key
58
+ @destroyed = true
59
+ freeze
60
+ end
61
+
62
+ def contracts
63
+ self.class.kb_client.request("#{key}/contracts").map do |contract|
64
+ PetContract.from_api(contract)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,77 @@
1
+ module KB
2
+ class PetContract < BaseModel
3
+ include Findable
4
+ include Creatable
5
+ include Updatable
6
+
7
+ kb_api :pet_contract
8
+
9
+ def self.find_by_contract_number(contract_number)
10
+ find("contractnumber/#{contract_number}")
11
+ end
12
+
13
+ def self.attributes_from_response(response)
14
+ response.transform_keys(&:underscore).transform_keys(&:to_sym).slice(*FIELDS)
15
+ end
16
+
17
+ private_class_method :attributes_from_response
18
+
19
+ STRING_FIELDS = %i[key plan_key product_key pet_key contract_number contract_document status
20
+ source affiliate_online affiliate_offline
21
+ conversion_utm_adgroup conversion_utm_campaign
22
+ conversion_utm_content conversion_utm_medium
23
+ conversion_utm_source conversion_utm_term
24
+ conversion_utm_adgroup_id conversion_utm_campaign_id].freeze
25
+ DATE_FIELDS = %i[policy_start_date policy_expiration_date].freeze
26
+ INTEGER_FIELDS = %i[price_yearly price_monthly price_discount_yearly].freeze
27
+ FIELDS = [*STRING_FIELDS, *DATE_FIELDS, *INTEGER_FIELDS].freeze
28
+
29
+ IMMUTABLE_FIELDS = (FIELDS - %i[status contract_document policy_expiration_date]).freeze
30
+
31
+ define_attribute_methods(*FIELDS)
32
+
33
+ STRING_FIELDS.each do |field|
34
+ attribute field, :string
35
+ end
36
+
37
+ DATE_FIELDS.each do |field|
38
+ attribute field, :date
39
+ end
40
+
41
+ INTEGER_FIELDS.each do |field|
42
+ attribute field, :integer
43
+ end
44
+
45
+ def save!
46
+ return unless changed?
47
+
48
+ run_callbacks :save do
49
+ self.attributes = if @persisted
50
+ self.class.update key, changes.transform_values(&:last)
51
+ else
52
+ self.class.create changes.transform_values(&:last)
53
+ end
54
+
55
+ self
56
+ end
57
+ end
58
+
59
+ def plan
60
+ @plan ||= Plan.all.select { |plan| plan.key == plan_key }
61
+ end
62
+
63
+ def product
64
+ @product ||= Product.find product_key
65
+ end
66
+
67
+ def pet
68
+ @pet ||= Pet.find(pet_key)
69
+ end
70
+
71
+ def hubspot_id
72
+ @hubspot_id ||= KB::HubspotRelationship.find('policies', key).hubspot_id
73
+ rescue KB::ResourceNotFound
74
+ nil
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,111 @@
1
+ module KB
2
+ class PetParent < BaseModel
3
+ include Findable
4
+ include Updatable
5
+ include FindOrCreatable
6
+ include Upsertable
7
+ include Destroyable
8
+
9
+ kb_api :pet_parent
10
+
11
+ def self.all(filters = {})
12
+ filters[:partner_key] = ENV['KB_PARTNER_KEY']
13
+ super(filters)
14
+ end
15
+
16
+ def self.create(attributes = {})
17
+ attributes[:partner_key] = ENV['KB_PARTNER_KEY']
18
+ super(attributes)
19
+ end
20
+
21
+ def self.upsert(attributes)
22
+ attributes[:partner_key] = ENV['KB_PARTNER_KEY']
23
+ super(attributes)
24
+ end
25
+
26
+ def merge!(duplicated_pet_parent_key)
27
+ params = { preservable_pet_parent_key: key,
28
+ erasable_pet_parent_key: duplicated_pet_parent_key }.transform_keys do |key|
29
+ key.to_s.camelize(:lower)
30
+ end
31
+
32
+ response = KB::ClientResolver.admin.request("petparents?#{params.to_query}", method: :put)
33
+ PetParent.from_api response
34
+ rescue Faraday::Error => e
35
+ raise KB::Error.from_faraday(e)
36
+ end
37
+
38
+ def self.attributes_from_response(response)
39
+ response.transform_keys(&:underscore).transform_keys(&:to_sym).slice(*FIELDS)
40
+ end
41
+
42
+ private_class_method :attributes_from_response
43
+
44
+ STRING_FIELDS = %i[key partner_name first_name last_name prefix_phone_number
45
+ phone_number email country address zip_code nif affiliate_code].freeze
46
+ DATE_FIELDS = %i[birth_date deleted_at].freeze
47
+ BOOLEAN_FIELDS = %i[phone_number_verified email_verified].freeze
48
+ FIELDS = [*STRING_FIELDS, *DATE_FIELDS, *BOOLEAN_FIELDS].freeze
49
+
50
+ define_attribute_methods(*FIELDS)
51
+
52
+ alias phone_number_prefix prefix_phone_number
53
+ alias phone_number_prefix= prefix_phone_number=
54
+
55
+ STRING_FIELDS.each do |field|
56
+ attribute field, :string
57
+ end
58
+
59
+ DATE_FIELDS.each do |field|
60
+ attribute field, :date
61
+ end
62
+
63
+ BOOLEAN_FIELDS.each do |field|
64
+ attribute field, :boolean
65
+ end
66
+
67
+ attribute :first_name, :string, default: ''
68
+
69
+ def save!
70
+ return unless changed?
71
+
72
+ run_callbacks :save do
73
+ self.attributes = if @persisted
74
+ self.class.update key, changes.transform_values(&:last)
75
+ else
76
+ self.class.create changes.transform_values(&:last)
77
+ end
78
+
79
+ self
80
+ end
81
+ end
82
+
83
+ def destroyed?
84
+ @destroyed
85
+ end
86
+
87
+ def destroy!
88
+ return unless @persisted
89
+
90
+ self.class.destroy key
91
+ @destroyed = true
92
+ freeze
93
+ end
94
+
95
+ def full_phone_number
96
+ "#{phone_number_prefix}#{phone_number}"
97
+ end
98
+
99
+ def pets
100
+ self.class.kb_client.request("#{key}/pets").map do |pet|
101
+ Pet.from_api(pet)
102
+ end
103
+ end
104
+
105
+ def contracts
106
+ self.class.kb_client.request("#{key}/contracts").map do |contract|
107
+ PetContract.from_api(contract)
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,44 @@
1
+ module KB
2
+ class Plan < BaseModel
3
+ include Listable
4
+
5
+ kb_api :plan
6
+
7
+ def self.attributes_from_response(response)
8
+ response.transform_keys(&:underscore).transform_keys(&:to_sym).slice(*FIELDS)
9
+ end
10
+
11
+ private_class_method :attributes_from_response
12
+
13
+ STRING_FIELDS = %i[key description plan_name type].freeze
14
+ HASH_FIELDS = %i[benefits price].freeze
15
+ FIELDS = [*STRING_FIELDS, *HASH_FIELDS, :plan_life_in_months, :buyable].freeze
16
+
17
+ define_attribute_methods(*FIELDS)
18
+
19
+ attribute :plan_life_in_months, :integer
20
+ attribute :buyable, :boolean
21
+
22
+ STRING_FIELDS.each do |field|
23
+ attribute field, :string
24
+ end
25
+
26
+ HASH_FIELDS.each do |field|
27
+ attribute field
28
+ end
29
+
30
+ def save!
31
+ return unless changed?
32
+
33
+ run_callbacks :save do
34
+ self.attributes = if @persisted
35
+ self.class.update key, changes.transform_values(&:last)
36
+ else
37
+ self.class.create changes.transform_values(&:last)
38
+ end
39
+
40
+ self
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,34 @@
1
+ module KB
2
+ class Product < BaseModel
3
+ include Listable
4
+ include Findable
5
+
6
+ kb_api :product
7
+
8
+ def self.by_country(country)
9
+ all(country: country)
10
+ end
11
+
12
+ def self.attributes_from_response(response)
13
+ response.transform_keys(&:underscore).transform_keys(&:to_sym).slice(*FIELDS)
14
+ end
15
+
16
+ private_class_method :attributes_from_response
17
+
18
+ STRING_FIELDS = %i[key country name type].freeze
19
+ STRING_ARRAY_FIELDS = %i[exclusions inclusions features claimable_by languages].freeze
20
+ FIELDS = [*STRING_FIELDS, *STRING_ARRAY_FIELDS, :purchasable].freeze
21
+
22
+ define_attribute_methods(*FIELDS)
23
+
24
+ attribute :purchasable, :boolean
25
+
26
+ STRING_FIELDS.each do |field|
27
+ attribute field, :string
28
+ end
29
+
30
+ STRING_ARRAY_FIELDS.each do |field|
31
+ attribute field, :array_of_strings
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,25 @@
1
+ module KB
2
+ class Symptom
3
+ include Inspectionable
4
+ include ActiveModel::Model
5
+ include ActiveModel::Attributes
6
+ include ActiveModel::Serializers::JSON
7
+
8
+ attribute :key, :string
9
+ attribute :name, :string
10
+ attribute :presence, :string
11
+ attribute :duration, :string
12
+ attribute :frequency, :string
13
+
14
+ attribute :urgency, :string
15
+ attribute :article, :string, default: ''
16
+
17
+ alias_attribute :information, :article
18
+
19
+ def urgent
20
+ return false if urgency == 'low'
21
+
22
+ true
23
+ end
24
+ end
25
+ end
data/lib/kb/models.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'kb/models/concerns'
2
+ require 'kb/models/base_model'
3
+
4
+ require 'kb/models/condition'
5
+ require 'kb/models/symptom'
6
+ require 'kb/models/assessment'
7
+
8
+ require 'kb/models/pet_contract'
9
+ require 'kb/models/pet_parent'
10
+ require 'kb/models/pet'
11
+ require 'kb/models/product'
12
+ require 'kb/models/plan'
13
+ require 'kb/models/breed'
14
+
15
+ require 'kb/models/hubspot_relationship'
@@ -0,0 +1,13 @@
1
+ module Type
2
+ class ArrayOfConditionsType < ActiveModel::Type::Value
3
+ CONDITION_KEYS = KB::Condition.attribute_types.keys.map(&:to_sym)
4
+
5
+ def cast(value)
6
+ (value || []).map do |v|
7
+ next v if v.is_a? KB::Condition
8
+
9
+ KB::Condition.new v.symbolize_keys.slice(*CONDITION_KEYS)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ module Type
2
+ class ArrayOfStringsType < ActiveModel::Type::Value
3
+ def cast(values)
4
+ return [] if values.blank?
5
+
6
+ values.map(&:to_s)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module Type
2
+ class ArrayOfSymptomsType < ActiveModel::Type::Value
3
+ SYMPTOM_KEYS = KB::Symptom.attribute_types.keys.map(&:to_sym)
4
+
5
+ def cast(value)
6
+ (value || []).map do |v|
7
+ next v if v.is_a? KB::Symptom
8
+
9
+ KB::Symptom.new v.symbolize_keys.slice(*SYMPTOM_KEYS)
10
+ end
11
+ end
12
+ end
13
+ end