geddy / model

Datastore-agnostic ORM in JavaScript
265 stars 55 forks source link

Timestamp properties do not respect turning off auto-camel #238

Open OscarGodson opened 9 years ago

OscarGodson commented 9 years ago

In the database created_at and updated_at are stored with underscores along with everything else such as first_name. When I get data back I get {createdAt: '...', 'first_name': ...} which is inconsistent. I wouldn't care if it changed everything to camel case like firstName, but it doesn't so its kinda weird. Is there anyway I can turn that off without having to manually change that manually everywhere after getting the model data?

mde commented 9 years ago

Could you give me some more specifics? You say "when I get data back." Does that mean you're querying the DB directly, or are you saying you're getting model instances with inconsistently named properties? Are you turning off the auto-camel feature in your config?

OscarGodson commented 9 years ago

So, this:

UserModel.first(query, function (err, data) {
  console.log('DATA: ', data)
});

Gives me:

{ type: 'User',
  _saved: true,
  id: '8CC63046-CAEA-4F66-AAA6-107B5DD0574C',
  isValid: [Function],
  save: [Function],
  updateProperties: [Function],
  updateAttributes: [Function],
  toJSON: [Function],
  toData: [Function],
  toObj: [Function],
  toString: [Function],
  _getAssociation: [Function],
  _createAssociation: [Function],
  _removeAssociation: [Function],
  _commitAssociationChanges: [Function],
  clone: [Function],
  _events: {},
  createdAt: Sat Dec 06 2014 02:01:38 GMT-0800 (PST),
  updatedAt: null,
  first_name: undefined,
  last_name: undefined,
  avatar: null,
  email: 'oscar@getpiggybank.com',
  password: '$2a$10$5Up0W4QSTN4IXRM618lGyOP5PaAW47j6.B0i1eFVlBG2ST53teYCC',
  username: 'oscargodson' }

In the database its created_at:

2 mysql 2014-12-06 21-34-19

I'd like it to be created_at and updated_at in the data i'm console.logging above so that its consistent.

mde commented 9 years ago

Ah, so you have the auto-camel turned off. The issue here is that the timestamp properties are managed by the library, so they are outside the normal flow. I'll update the title of this issue to reflect that.

OscarGodson commented 9 years ago

Oh, is that an option somewhere? cmd+f'd camel and didn't see anything. I haven't actually set anything in that regard.

OscarGodson commented 9 years ago

Ok, coming back to this, I found in the source the forceCamel setting you are talking about and I successfully set it and I set it correctly. I checked the state it was at here: https://github.com/geddy/model/blob/master/lib/index.js#L740 and it was, indeed, turned off or set to whatever else I set (I tried test too).

From reading the code it appears that it will convert, like first_name above to firstName when it comes back from the DB, but I want to be able to write and read everything with underscores. In other words, I want this:

  this.defineProperties({
    userId:          { type: 'string', required: false },
    familyId:        { type: 'string', required: false },
    permission_level: { type: 'number', required: false }
  });

to look like

  this.defineProperties({
    user_id:          { type: 'string', required: false },
    family_id:        { type: 'string', required: false },
    permission_level: { type: 'number', required: false }
  });

Is that possible?

mde commented 9 years ago

This is an option you set when you bootstrap Model. If you're seeing snake_case properties on your instantiated items, you've likely got it set (to false) somewhere. The default setting of true will force properties on your params objects (what you pass to instantiate items) to camelCase before setting them:

https://github.com/geddy/model/blob/master/lib/index.js#L740

Anything outside this updateProperties call will not be affected. This means the timestamp properties managed by the system, and properties you set in lifecycle methods or in an ad hoc way.

The forceCamel was originally just a way to take form or URL params (which are often in snake_case) or JSON data from Python/Ruby services and ensure that the properties on the object set from them used the correct JS camelCase idiom. (This is actually something we don't argue about in JS Land, hooray!)

I'd be happy to merge a PR that makes this more robust and consistent, but in general it's pretty edge-casey because properties on JS objects in general should be camel. :)

OscarGodson commented 9 years ago

OK, I think that helps. So, properties aren't actually 1 to 1 with the column names in my DB. I was picturing that "define properties" meant defining props that actually match with the column names. I also agree JS objects should be camel. Maybe I'll just do everything in camelCase and then just before returning the JSON to the client go back and snake case everything or when receiving data convert all snake case to camel before giving it to model.

mde commented 9 years ago

Model uses convention very heavily. It converts back and forth pretty freely between various formats for property and constructor (datatype) names:

JS model name is PascalCase, singular -- SnowDog JS controller name is PascalCase, plural -- SnowDogs DB table name is snake_case, plural -- snow_dogs JS property name is camelCase -- fooBarBaz DB column name is snake_case -- foo_bar_baz

So the properties are 1-to-1 with the columns, with the names being translated back and forth automatically according to convention.