Skip to content

Commit

Permalink
Adding support for Array(Float64). Fixes #382 (#443)
Browse files Browse the repository at this point in the history
  • Loading branch information
jwoertink authored Aug 22, 2020
1 parent 5dd2676 commit 5e94a19
Show file tree
Hide file tree
Showing 8 changed files with 38 additions and 13 deletions.
13 changes: 13 additions & 0 deletions db/migrations/20200821135952_add_float_array_to_buckets.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class AddFloatArrayToBuckets::V20200821135952 < Avram::Migrator::Migration::V1
def migrate
alter table_for(Bucket) do
add floaty_numbers : Array(Float64), fill_existing_with: [0.0]
end
end

def rollback
alter table_for(Bucket) do
remove :floaty_numbers
end
end
end
6 changes: 6 additions & 0 deletions spec/array_column_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,10 @@ describe "Array Columns" do
BucketBox.new.numbers([1, 2, 3]).create
BucketQuery.new.numbers([1]).select_count.should eq 0
end

it "handles Array(Float64)" do
BucketBox.create &.floaty_numbers([1.1, 2.2, 3.3, 4.4])
bucket = BucketQuery.new.last
bucket.floaty_numbers.should eq([1.1, 2.2, 3.3, 4.4])
end
end
4 changes: 2 additions & 2 deletions spec/query_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,7 @@ describe Avram::Query do
bucket = BucketBox.new.names(["pumpkin", "zucchini"]).create

query = ArrayQuery.new.names(["pumpkin", "zucchini"])
query.to_sql.should eq ["SELECT buckets.id, buckets.created_at, buckets.updated_at, buckets.bools, buckets.small_numbers, buckets.numbers, buckets.big_numbers, buckets.names FROM buckets WHERE buckets.names = $1", "{\"pumpkin\",\"zucchini\"}"]
query.to_sql.should eq ["SELECT #{Bucket::COLUMN_SQL} FROM buckets WHERE buckets.names = $1", "{\"pumpkin\",\"zucchini\"}"]
result = query.first
result.should eq bucket
end
Expand Down Expand Up @@ -958,7 +958,7 @@ describe Avram::Query do
query.to_prepared_sql.should eq(%{SELECT posts.custom_id, posts.created_at, posts.updated_at, posts.title, posts.published_at FROM posts WHERE posts.title = 'The Short Post'})

query = Bucket::BaseQuery.new.names(["Larry", "Moe", "Curly"]).numbers([1, 2, 3])
query.to_prepared_sql.should eq(%{SELECT buckets.id, buckets.created_at, buckets.updated_at, buckets.bools, buckets.small_numbers, buckets.numbers, buckets.big_numbers, buckets.names FROM buckets WHERE buckets.names = '{"Larry","Moe","Curly"}' AND buckets.numbers = '{1,2,3}'})
query.to_prepared_sql.should eq(%{SELECT #{Bucket::COLUMN_SQL} FROM buckets WHERE buckets.names = '{"Larry","Moe","Curly"}' AND buckets.numbers = '{1,2,3}'})

query = Blob::BaseQuery.new.doc(JSON::Any.new({"properties" => JSON::Any.new("sold")}))
query.to_prepared_sql.should eq(%{SELECT blobs.id, blobs.created_at, blobs.updated_at, blobs.doc FROM blobs WHERE blobs.doc = '{"properties":"sold"}'})
Expand Down
1 change: 1 addition & 0 deletions spec/support/boxes/bucket_box.cr
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ class BucketBox < BaseBox
numbers [100, 200]
big_numbers [1000_i64, 2000_i64]
names ["Mario", "Luigi"]
floaty_numbers [0.0]
end
end
2 changes: 2 additions & 0 deletions spec/support/bucket.cr
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
class Bucket < BaseModel
COLUMN_SQL = "buckets.id, buckets.created_at, buckets.updated_at, buckets.bools, buckets.small_numbers, buckets.numbers, buckets.big_numbers, buckets.names, buckets.floaty_numbers"
table do
column bools : Array(Bool)
column small_numbers : Array(Int16)
column numbers : Array(Int32)
column big_numbers : Array(Int64)
column names : Array(String)
column floaty_numbers : Array(Float64)
end
end
5 changes: 5 additions & 0 deletions spec/type_extensions/array_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,9 @@ describe "Array" do
result = Int64::Lucky.parse(["1000"])
result.value.should eq([1000_i64])
end

it "parses Array(Float64) from Array(String)" do
result = Float64::Lucky.parse(["3.1415"])
result.value.should eq([3.1415])
end
end
4 changes: 4 additions & 0 deletions src/avram/charms/float64_extensions.cr
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ struct Float64
SuccessfulCast(Float64).new(value.to_f)
end

def parse(values : Array(PG::Numeric))
SuccessfulCast(Array(Float64)).new values.map(&.to_f)
end

def parse(value : String)
SuccessfulCast(Float64).new value.to_f64
rescue ArgumentError
Expand Down
16 changes: 5 additions & 11 deletions src/avram/model.cr
Original file line number Diff line number Diff line change
Expand Up @@ -201,18 +201,18 @@ abstract class Avram::Model
end
end

# Setup [database mapping](http://crystal-lang.github.io/crystal-db/api/0.5.0/DB.html#mapping%28properties%2Cstrict%3Dtrue%29-macro) for the model's columns.
# Setup [database mapping](http://crystal-lang.github.io/crystal-db/api/latest/DB.html) for the model's columns.
#
# NOTE: Avram::Migrator saves `Float` columns as numeric which need to be
# converted from [PG::Numeric](https://github.com/will/crystal-pg/blob/master/src/pg/numeric.cr) back to `Float64` using a `convertor`
# class.
# NOTE: Avram::Migrator saves `Float` columns as numeric which are converted
# in the avram/charms/float64_extensions.cr file
macro setup_db_mapping(columns, *args, **named_args)
DB.mapping({
{% for column in columns %}
{{column[:name]}}: {
{% if column[:type].id == Float64.id %}
type: PG::Numeric,
convertor: Float64Converter,
{% elsif column[:type].id == Array(Float64).id %}
type: Array(PG::Numeric),
{% else %}
{% if column[:type].is_a?(Generic) %}
type: {{column[:type]}},
Expand All @@ -226,12 +226,6 @@ abstract class Avram::Model
})
end

module Float64Converter
def self.from_rs(rs)
rs.read(PG::Numeric).to_f
end
end

macro setup_getters(columns, *args, **named_args)
{% for column in columns %}
{% db_type = column[:type].is_a?(Generic) ? column[:type].type_vars.first : column[:type] %}
Expand Down

0 comments on commit 5e94a19

Please sign in to comment.