created not being set on 'save'
I think the 'created' field is not being set on a Save, which obviously it shouldn't in general, but the first save feels like it should save the 'created' field.
I believe the following would test for this:
// Create basic order and save
order := demo.Order{}
n, err := db.Save(&order)
looking := demo.Order{}
_, err = db.Save(&looking, order.ID)
if order.created != looking.created {
t.Error("The created field is not being set by the first 'Save' only a subsequent lookup.")
}
Note, I believe this fails because lookup has the correct created field but order does not, even though of course order does have its ID field set.
Basically this currently means that whenever you save for the first time you have to do:
db.Save(&entity)
entity.GetCreated()
Looking at it, GetCreated could just be called on every 'Save'. Alternatively just don't have the 'created' field at all and force the user to use 'GetCreated' to inspect the time associated with the ID (though this would mean it would not be included in any JSON).
As a secondary point, I think GetCreated is confusing, from that name it is not at all clear that the 'created' field will be set to 'now':
For reference the default implementation of GetCreated gets the time from the ID.
func (m *Model) GetCreated() time.Time {
createdAt := m.ID.Time()
m.Created = createdAt
return createdAt
}
'Created' is a calculated field which is not stored in the DB. That is because the ID's have the creation time baked into them. The GetCreated() is used in the get trigger to fill the field in so that it can be disaplyed in JSON api rest endpoints.
Right, but 'Created' is a field that is defined by Tormenta. So it is reasonable for the consumer to assume that it will be filled in on first save in the same way that the ID field is. This confused me enough to first of all have written some wrong code, and then spend some twenty minutes figuring it out. To put it another way, because you can write code like this:
entity := MyEntity{}
_, err := db.Save(&entity)
return entity.ID
It seems like you would be able to write code like:
entity := MyEntity{}
_, err := db.Save(&entity)
return entity // Believe that entity.Created will have been set.
Or
entity := MyEntity{}
_, err := db.Save(&entity)
renderJson (entity) // Ah great my JSON entity has the correct ID, I can continue (later, when I use it I realise that my JSON entity as a 0 'created' field.
One solution is to provide, in addition to 'Save', an 'Insert' method which just does
func (db DB) Insert(entities ...Tormentable) (int, error) { num, err := db.Save(entities) if err != nil { return 0, err } for _, entity := range entities{ entity.GetCreated() } }
Or alternatively, in 'Save' check if 'created' is 0 and if so set it.
I guess the problem is, that you want it to be a computable field, but also one that is output in the JSON, and so you end up having it on the struct *only* so that you can write `json:"created"`. But think of this, would you *ever* want that created field to be 0? By making it computable, you're not saving space because Go will initialise it with the zero value. I think having it as "possibly zero unless you have either directly called 'GetCreated' or it was a result of some query" is just asking for bugs.
Perhaps we should have a built in trigger on Get that fills the field in - better than on save?