Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DB::Serializable #115

Merged
merged 5 commits into from
Oct 31, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion shard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ version: 0.7.0
authors:
- Brian J. Cardiff <bcardiff@manas.tech>

crystal: 0.24.0
crystal: 0.25.0

license: MIT
220 changes: 220 additions & 0 deletions spec/serializable_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
require "./spec_helper"
require "base64"
require "json"

class SimpleModel
include DB::Serializable

property c0 : Int32
property c1 : String
end

class NonStrictModel
include DB::Serializable
include DB::Serializable::NonStrict

property c1 : Int32
property c2 : String
end

class ModelWithDefaults
include DB::Serializable

property c0 : Int32 = 10
property c1 : String = "c"
end

class ModelWithNilables
include DB::Serializable

property c0 : Int32? = 10
property c1 : String?
end

class ModelWithNilUnionTypes
include DB::Serializable

property c0 : Int32 | Nil = 10
property c1 : String | Nil
end

class ModelWithKeys
include DB::Serializable

@[DB::Field(key: "c0")]
property foo : Int32
@[DB::Field(key: "c1")]
property bar : String
end

class ModelWithConverter
module Base64Converter
def self.from_rs(rs)
Base64.decode(rs.read(String))
end
end

include DB::Serializable

@[DB::Field(converter: ModelWithConverter::Base64Converter)]
property c0 : Slice(UInt8)
property c1 : String
end

class ModelWithInitialize
include DB::Serializable

property c0 : Int32
property c1 : String

def_equals c0, c1

def initialize(@c0, @c1)
end
end

class ModelWithJSON
include JSON::Serializable
include DB::Serializable

property c0 : Int32
property c1 : String
end

macro from_dummy(query, type)
with_dummy do |db|
rs = db.query({{ query }})
rs.move_next
%obj = {{ type }}.new(rs)
rs.close
%obj
end
end

macro expect_model(query, t, values)
%obj = from_dummy({{ query }}, {{ t }})
%obj.should be_a({{ t }})
{% for key, value in values %}
%obj.{{key.id}}.should eq({{value}})
{% end %}
end

describe "DB::Serializable" do
it "should initialize a simple model" do
expect_model("1,a", SimpleModel, {c0: 1, c1: "a"})
end

it "should fail to initialize a simple model if types do not match" do
expect_raises ArgumentError do
from_dummy("b,a", SimpleModel)
end
end

it "should fail to initialize a simple model if there is a missing column" do
expect_raises DB::MappingException do
from_dummy("1", SimpleModel)
end
end

it "should fail to initialize a simple model if there is an unexpected column" do
expect_raises DB::MappingException do
from_dummy("1,a,b", SimpleModel)
end
end

it "should initialize a non-strict model if there is an unexpected column" do
expect_model("1,2,a,b", NonStrictModel, {c1: 2, c2: "a"})
end

it "should initialize a model with default values" do
expect_model("1,a", ModelWithDefaults, {c0: 1, c1: "a"})
end

it "should initialize a model using default values if columns are missing" do
expect_model("1", ModelWithDefaults, {c0: 1, c1: "c"})
end

it "should initialize a model using default values if values are nil and types are non nilable" do
expect_model("1,NULL", ModelWithDefaults, {c0: 1, c1: "c"})
end

it "should initialize a model with nilables if columns are missing" do
expect_model("1", ModelWithNilables, {c0: 1, c1: nil})
end

it "should initialize a model with nilables ignoring default value if NULL" do
expect_model("NULL,a", ModelWithNilables, {c0: nil, c1: "a"})
end

it "should initialize a model with nil union types if columns are missing" do
expect_model("1", ModelWithNilUnionTypes, {c0: 1, c1: nil})
end

it "should initialize a model with nil union types ignoring default value if NULL" do
expect_model("NULL,a", ModelWithNilUnionTypes, {c0: nil, c1: "a"})
end

it "should initialize a model with different keys" do
expect_model("1,a", ModelWithKeys, {foo: 1, bar: "a"})
end

it "should initialize a model with a value converter" do
expect_model("Zm9v,a", ModelWithConverter, {c0: "foo".to_slice, c1: "a"})
end

it "should initialize a model with an initialize" do
obj1 = from_dummy("1,a", ModelWithInitialize)
obj2 = ModelWithInitialize.new(1, "a")
obj1.should eq obj2
end

it "should initialize a model with JSON serialization also defined" do
expect_model("1,a", ModelWithJSON, {c0: 1, c1: "a"})
end

it "should initialize multiple instances from a single resultset" do
with_dummy do |db|
db.query("1,a 2,b") do |rs|
objs = SimpleModel.from_rs(rs)
objs.size.should eq(2)
objs[0].c0.should eq(1)
objs[0].c1.should eq("a")
objs[1].c0.should eq(2)
objs[1].c1.should eq("b")
end
end
end

it "Class.from_rs should close resultset" do
with_dummy do |db|
rs = db.query("1,a 2,b")
objs = SimpleModel.from_rs(rs)
rs.closed?.should be_true

objs.size.should eq(2)
objs[0].c0.should eq(1)
objs[0].c1.should eq("a")
objs[1].c0.should eq(2)
objs[1].c1.should eq("b")
end
end

it "should initialize from a query_one" do
with_dummy do |db|
obj = db.query_one "1,a", as: SimpleModel
obj.c0.should eq(1)
obj.c1.should eq("a")
end
end

it "should initialize from a query_all" do
with_dummy do |db|
objs = db.query_all "1,a 2,b", as: SimpleModel
objs.size.should eq(2)
objs[0].c0.should eq(1)
objs[0].c1.should eq("a")
objs[1].c0.should eq(2)
objs[1].c1.should eq("b")
end
end
end
1 change: 1 addition & 0 deletions src/db.cr
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,4 @@ require "./db/pool_unprepared_statement"
require "./db/result_set"
require "./db/error"
require "./db/mapping"
require "./db/serializable"
Loading