-
Notifications
You must be signed in to change notification settings - Fork 639
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
Inconsistent type of 'date-time' Model properties on instances #663
Comments
Objection does no type conversions whatsoever. Neither does knex. It's the db driver that does that. With postgres you can use pg-types library to change this behaviour. You can also implement the $fromDatabaseJson to make the conversion. |
class BaseModel extends Model {
$parseDatabaseJson(json) {
json = super.$parseDatabaseJson(json);
const propSchemas = this.constructor.jsonSchema.properties;
Object.keys(propSchemas).forEach(prop => {
const schema = propSchemas[prop];
const value = json[prop];
if (schema.format === 'date-time' && value instanceof Date) {
json[prop] = value.toISOString();
}
});
return json;
}
}
class User extends BaseModel {
...
}
class Role extends BaseModel {
...
} |
Or with pg-types: const types = require('pg').types
const moment = require('moment')
const TIMESTAMPTZ_OID = 1184
const TIMESTAMP_OID = 1114
const parseFn = (val) => {
return val === null ? null : moment(val).toISOString()
}
types.setTypeParser(TIMESTAMPTZ_OID, parseFn)
types.setTypeParser(TIMESTAMP_OID, parseFn) |
Actually, this is all you need in class BaseModel extends Model {
$parseDatabaseJson(json) {
json = super.$parseDatabaseJson(json);
Object.keys(json).forEach(prop => {
const value = json[prop];
if (value instanceof Date) {
json[prop] = value.toISOString();
}
});
return json;
}
}
class User extends BaseModel {
...
}
class Role extends BaseModel {
...
} |
Thanks, @koskimas and thanks for the suggestions! Since I may go bring this up over at For example: Thanks again much for all of your hard work on Objection. It's a pleasure to work with! |
Oh, nevermind, I think I understand it a bit more and it's still something that's definitely in |
I'm pretty sure |
One doesn't need to hardcode the constants, they are already provided by pg-types: import { DateTime } from 'luxon'
import pg from 'pg'
pg.types.setTypeParser(
pg.types.builtins.TIMESTAMPTZ,
val => (val === null ? null : DateTime.fromSQL(val)),
) |
Dates can also be transformed to objects.
However this doesn't work for |
@javiertury https://vincit.github.io/objection.js/guide/hooks.html#model-data-lifecycle-hooks |
@koskimas unfortunately that suggestion doesn't work. Insert sometimes returns an incomplete object(id only) which is the only thing Also, |
So I was writing/running some tests today and I was seeing some strange, inconsistent behavior. My app is a single-page app, so it makes a sort of "initialize" API call to start things off. This call does the following:
user
gets is value by being parsed something likeconst user = User.fromJson(dataFromCache);
user
gets its value from a query that is made with a bunch ofeager
clauses for theUser
and other relations that I need.Let's say that
User
has aHasManyRelation
relation toRole
s, and eachRole
has acreated_at
property which is defined on the schema as astring
with thedate-time
format. I had some logic that was looking through theUser.roles
array for theRole
with the most recentcreated_at
time. The particulars of that logic, when I was writing/testing it originally, had found thattypeof role.created_at
was anobject
.When I today found this issue, in my investigation it turns out that
typeof role.created_at
was actuallystring
. Upon further investigation, the difference (at least in this particular case) between whentypeof role.created_at
was anobject
vs when it was astring
depended on whether or not theUser.roles
were found in cache and loaded viaUser.fromJson(...)
or whether they were loaded viaUser.query().eager('roles')...
.That was my "eureka" moment.
It turns out that Objection (or something it uses) is sometimes making
created_at
a Date object and sometimes making it a String. This is a problem! I wrote a gist here to reproduce this issue, and also highlight a bunch of other scenarios where it comes out as onetype
or another:https://gist.github.com/newhouse/c3b052a3548396274210827c6be66875
As you'll see, depending on how you are obtaining your instance, the
time
field comes out as a different type. In short:string
string
(thoughtime
fields in the parent areobject
s!!!)SomeModel.fromJson({...})
return it as astring
.object
.There are some interesting inconsistencies in the gist.
Needless to say, I'm not sure which way it "should" be, but at least if it were consistent, one could code with the assumption that it will always be a
string
(orobject
or whatever). This has caused me a lot of headaches.Is this an Objection issue?
The text was updated successfully, but these errors were encountered: