Skip to content

Commit

Permalink
Support default values (#312)
Browse files Browse the repository at this point in the history
* Support default values

Optimize #quote

* Fix specs

* Fix for real this time.
  • Loading branch information
Blacksmoke16 authored and drujensen committed Jan 7, 2019
1 parent 3d73a5d commit c441e5f
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 35 deletions.
17 changes: 15 additions & 2 deletions docs/getting_started.md
Expand Up @@ -133,6 +133,21 @@ book.isbn # => nil
book.save
book.isbn # => RFC4122 V4 UUID string
```
### Default values

A default value can be assigned to a field that will be used if another value is not specified/supplies.

```Crystal
class Book < Granite::Base
adapter mysql
field name : String, default: "DefaultBook"
end
book = Book.new
book.name # => "DefaultBook"
```


### Generating Documentation

Expand All @@ -142,8 +157,6 @@ The `field` and `primary` macros have a comment option that will specify the doc

`field age : Int32, comment: "# Number of seconds since the post was posted"`

See the [Docs folder](./) for additional information.

### Third-Party Annotations

Annotations can be a powerful method of adding property specific features with minimal amounts of code. Since Granite utilizes the `property` keyword for its fields, annotations are able to be applied easily. This is accomplished by using the `annotations` option on a field, similar to the `comment` option above. It is used in the form of `annotations: ["annotation1", "annotation2"]`, for example:
Expand Down
32 changes: 30 additions & 2 deletions spec/granite_spec.cr
@@ -1,6 +1,13 @@
require "./spec_helper"

describe "Granite::Base" do
describe Granite::Base do
it "can instaniate a model with default values" do
model = DefaultValues.new
model.name.should eq "Jim"
model.age.should eq 0.0
model.is_alive.should be_true
end

describe "JSON" do
describe ".from_json" do
it "can create an object from json" do
Expand Down Expand Up @@ -40,6 +47,15 @@ describe "Granite::Base" do
model.name.should eq "after_initialize"
model.priority.should eq 1000
end

describe "with default values" do
it "correctly applies values" do
model = DefaultValues.from_json(%({"name": "Bob"}))
model.name.should eq "Bob"
model.age.should eq 0.0
model.is_alive.should be_true
end
end
end

describe "#to_json" do
Expand Down Expand Up @@ -136,6 +152,15 @@ describe "Granite::Base" do
model.name.should eq "after_initialize"
model.priority.should eq 1000
end

describe "with default values" do
it "correctly applies values" do
model = DefaultValues.from_yaml(%(---\nname: Bob))
model.name.should eq "Bob"
model.age.should eq 0.0
model.is_alive.should be_true
end
end
end

describe "#to_yaml" do
Expand Down Expand Up @@ -249,6 +274,8 @@ describe "Granite::Base" do
model = ArrayModel.new
model.id = 2
model.str_array = [] of String
model.f64_array.should be_a(Array(Float64))
model.f64_array.should eq [] of Float64
model.save.should be_true
end

Expand All @@ -260,7 +287,8 @@ describe "Granite::Base" do
model.i32_array.should be_nil
model.i64_array.should be_nil
model.f32_array.should be_nil
model.f64_array.should be_nil
model.f64_array.should be_a(Array(Float64))
model.f64_array.should eq [] of Float64
model.bool_array.should be_nil
end
end
Expand Down
67 changes: 40 additions & 27 deletions spec/spec_models.cr
Expand Up @@ -342,7 +342,7 @@ require "uuid"
field i32_array : Array(Int32)
field i64_array : Array(Int64)
field f32_array : Array(Float32)
field f64_array : Array(Float64)
field f64_array : Array(Float64), default: [] of Float64
field bool_array : Array(Bool)
end
ArrayModel.migrator.drop_and_create
Expand Down Expand Up @@ -375,6 +375,15 @@ require "uuid"
field created_at : Time, yaml_options: {key: "posted"}
end

class DefaultValues < Granite::Base
adapter {{ adapter_literal }}
table_name defaults

field name : String, default: "Jim"
field is_alive : Bool, default: true
field age : Float64, default: 0.0
end

class TimeTest < Granite::Base
adapter {{ adapter_literal }}
table_name times
Expand Down Expand Up @@ -502,48 +511,52 @@ require "uuid"
validate_exclusion :name, ["test_name"]
end

NilTest.migrator.drop_and_create
BlankTest.migrator.drop_and_create
ChoiceTest.migrator.drop_and_create
LessThanTest.migrator.drop_and_create
ExclusionTest.migrator.drop_and_create
GreaterThanTest.migrator.drop_and_create
LengthTest.migrator.drop_and_create
LessThanTest.migrator.drop_and_create
NilTest.migrator.drop_and_create
PersonUniqueness.migrator.drop_and_create
ExclusionTest.migrator.drop_and_create
end

Parent.migrator.drop_and_create
Teacher.migrator.drop_and_create
Student.migrator.drop_and_create
Klass.migrator.drop_and_create
Enrollment.migrator.drop_and_create
School.migrator.drop_and_create
User.migrator.drop_and_create
Profile.migrator.drop_and_create
Nation::County.migrator.drop_and_create
Review.migrator.drop_and_create
Empty.migrator.drop_and_create
ReservedWord.migrator.drop_and_create
AfterInit.migrator.drop_and_create
Article.migrator.drop_and_create
Book.migrator.drop_and_create
BookReview.migrator.drop_and_create
Callback.migrator.drop_and_create
CallbackWithAbort.migrator.drop_and_create
Kvs.migrator.drop_and_create
Person.migrator.drop_and_create
Character.migrator.drop_and_create
Comment.migrator.drop_and_create
Company.migrator.drop_and_create
Book.migrator.drop_and_create
BookReview.migrator.drop_and_create
Courier.migrator.drop_and_create
CourierService.migrator.drop_and_create
CustomSongThread.migrator.drop_and_create
DefaultValues.migrator.drop_and_create
Empty.migrator.drop_and_create
Enrollment.migrator.drop_and_create
Item.migrator.drop_and_create
NonAutoDefaultPK.migrator.drop_and_create
Klass.migrator.drop_and_create
Kvs.migrator.drop_and_create
Nation::County.migrator.drop_and_create
NonAutoCustomPK.migrator.drop_and_create
Article.migrator.drop_and_create
Comment.migrator.drop_and_create
NonAutoDefaultPK.migrator.drop_and_create
Parent.migrator.drop_and_create
Person.migrator.drop_and_create
Profile.migrator.drop_and_create
ReservedWord.migrator.drop_and_create
Review.migrator.drop_and_create
School.migrator.drop_and_create
SongThread.migrator.drop_and_create
Student.migrator.drop_and_create
Teacher.migrator.drop_and_create
Todo.migrator.drop_and_create
TodoEmitNull.migrator.drop_and_create
AfterInit.migrator.drop_and_create
SongThread.migrator.drop_and_create
CustomSongThread.migrator.drop_and_create
UUIDModel.migrator.drop_and_create
TodoJsonOptions.migrator.drop_and_create
TodoYamlOptions.migrator.drop_and_create
User.migrator.drop_and_create
UUIDModel.migrator.drop_and_create
Character.migrator.drop_and_create
Courier.migrator.drop_and_create
CourierService.migrator.drop_and_create
Expand Down
9 changes: 6 additions & 3 deletions src/adapter/base.cr
Expand Up @@ -92,12 +92,15 @@ abstract class Granite::Adapter::Base
macro inherited
# quotes table and column names
def quote(name : String) : String
char = QUOTING_CHAR
char + name.gsub(char, "#{char}#{char}") + char
String.build do |str|
str << QUOTING_CHAR
str << name
str << QUOTING_CHAR
end
end

# converts the crystal class to database type of this adapter
def self.schema_type?(key : String)
def self.schema_type?(key : String) : String?
Schema::TYPES[key]? || Granite::Adapter::Base::Schema::TYPES[key]?
end
end
Expand Down
2 changes: 1 addition & 1 deletion src/granite/fields.cr
Expand Up @@ -66,7 +66,7 @@ module Granite::Fields
{% if options[:comment] %}
{{options[:comment].id}}
{% end %}
property{{suffixes[0].id}} {{name.id}} : Union({{type.id}} | Nil)
property{{suffixes[0].id}} {{name.id}} : Union({{type.id}} | Nil){% if options[:default] %} = {{options[:default]}} {% end %}
disable_granite_docs? def {{name.id}}{{suffixes[1].id}}
raise {{@type.name.stringify}} + "#" + {{name.stringify}} + " cannot be nil" if @{{name.id}}.nil?
@{{name.id}}.not_nil!
Expand Down

0 comments on commit c441e5f

Please sign in to comment.