Skip to content

Commit

Permalink
Merge pull request #1924 from Shopify/Alex/typed_store-arrays
Browse files Browse the repository at this point in the history
Support array types in `typed_store` compiler
  • Loading branch information
amomchilov authored Jun 17, 2024
2 parents aaf1d32 + 30c373e commit 0c6796d
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 5 deletions.
23 changes: 18 additions & 5 deletions lib/tapioca/dsl/compilers/active_record_typed_store.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,7 @@ def decorate
stores.values.each do |store_data|
store_data.accessors.each do |accessor, name|
field = store_data.fields.fetch(accessor)
type = type_for(field.type_sym)
type = as_nilable_type(type) if field.null
type = type_for(field)
name ||= field.name # support < 1.5.0

generate_methods(store_accessors_module, name.to_s, type)
Expand Down Expand Up @@ -136,9 +135,23 @@ def gather_constants
T::Hash[Symbol, String],
)

sig { params(attr_type: Symbol).returns(String) }
def type_for(attr_type)
TYPES.fetch(attr_type, "T.untyped")
sig { params(field: ActiveRecord::TypedStore::Field).returns(String) }
def type_for(field)
type = TYPES.fetch(field.type_sym, "T.untyped")

type = if field.array
# `null: false` applies to the array itself, not the elements, which are always nilable.
# https://github.com/byroot/activerecord-typedstore/blob/2f3fb98/spec/support/models.rb#L46C34-L46C45
# https://github.com/byroot/activerecord-typedstore/blob/2f3fb98/spec/active_record/typed_store_spec.rb#L854-L857
nilable_element_type = as_nilable_type(type)
"T::Array[#{nilable_element_type}]"
else
type
end

type = as_nilable_type(type) if field.null

type
end

sig do
Expand Down
54 changes: 54 additions & 0 deletions spec/tapioca/dsl/compilers/active_record_typed_store_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,60 @@ def rate=(rate); end
assert_includes(rbi_for(:Post), expected)
end

it "generates methods with nilable Array type of nilable elements for attributes marked as array: true" do
add_ruby_file("post.rb", <<~RUBY)
class Post < ActiveRecord::Base
typed_store :metadata do |s|
s.string(:comments, array: true, null: true)
end
end
RUBY

expected = <<~RBI
# typed: strong
class Post
include StoreAccessors
module StoreAccessors
sig { returns(T.nilable(T::Array[T.nilable(String)])) }
def comments; end
sig { params(comments: T.nilable(T::Array[T.nilable(String)])).returns(T.nilable(T::Array[T.nilable(String)])) }
def comments=(comments); end
RBI

rbi = rbi_for(:Post)
assert_includes(rbi, expected)
end

it "generates methods with non-nilable Array type for attributes marked as array: true and null: false" do
add_ruby_file("post.rb", <<~RUBY)
class Post < ActiveRecord::Base
typed_store :metadata do |s|
s.string(:comments, array: true, null: false)
end
end
RUBY

expected = <<~RBI
# typed: strong
class Post
include StoreAccessors
module StoreAccessors
sig { returns(T::Array[T.nilable(String)]) }
def comments; end
sig { params(comments: T::Array[T.nilable(String)]).returns(T::Array[T.nilable(String)]) }
def comments=(comments); end
RBI

rbi = rbi_for(:Post)
assert_includes(rbi, expected)
end

it "generates methods with prefix and suffix" do
add_ruby_file("post.rb", <<~RUBY)
class Post < ActiveRecord::Base
Expand Down

0 comments on commit 0c6796d

Please sign in to comment.