Skip to content

$formatJson called during insertWithRelated? #326

@sweetamandas

Description

@sweetamandas

In my application I an overriding objection.Model's $formatJson() method in order to strip out certain fields from my models before they are sent based on user permissions, etc. This typically works out great.

I'm running into problems when inserting a model via insertWithRelated(). I've noticed that $formatJson() is being called on the data before it is inserted into the database so my protected fields are being striped out before being saved.

Here is a demo I put together:

const objection = require('objection');
const knex = require('knex');

const Model = objection.Model;

const db = knex({
  client: 'mysql2',
  connection: "mysql://event_planner:123456ab@localhost/event_planner",
  pool: {
    min: 2,
    max: 30
  }
});

Model.knex(db);

class Employee extends Model {

  static get tableName() {
    return 'employees';
  }

  static get relationMappings() {
    return {
      organization: {
        relation: Model.BelongsToOneRelation,
        modelClass: Organization,
        join: {
          from: 'employees.organizationId',
          to: 'organizations.id'
        }
      }
    };
  }

  $beforeInsert() {
    console.log('$beforeInsert', this.constructor.tableName);
  }

  $beforeUpdate() {
    console.log('$beforeUpdate', this.constructor.tableName);
  }

  $formatJson(json) {
    console.log('$formatJson', this.constructor.tableName);
    json = super.$formatJson(json);
    json.firstName = undefined;
    return json;
  }

  $parseJson(json, opt) {
    console.log('$parseJson', this.constructor.tableName, json, opt);
    return super.$parseJson(json, opt);
  }
}

class Organization extends Model {

  static get tableName() {
    return 'organizations';
  }

  static get relationMappings() {
    return {
      employees: {
        relation: Model.HasManyRelation,
        modelClass: Employee,
        join: {
          from: 'organizations.id',
          to: 'employees.organizationId'
        }
      }
    };
  }

  $beforeInsert() {
    console.log('$beforeInsert', this.constructor.tableName);
  }

  $beforeUpdate() {
    console.log('$beforeUpdate', this.constructor.tableName);
  }

  $formatJson(json) {
    console.log('$formatJson', this.constructor.tableName);
    return super.$formatJson(json);
  }

  $parseJson(json, opt) {
    console.log('$parseJson', this.constructor.tableName, opt);
    return super.$parseJson(json, opt);
  }
}

Organization
  .query()
  .allowInsert('[employees]')
  .insertWithRelated({
    name: "My Organization",
    employees: [{
      firstName: "John",
      lastName: "Doe",
      email: "doe@example.com"
    }]
  }).catch(err => console.error(err));

the above prints the following to the console:

$parseJson organizations { skipValidation: true }
$parseJson employees { firstName: 'John',
  lastName: 'Doe',
  email: 'doe@example.com',
  phone: '[]',
  streetAddress: '',
  notes: '',
  createdAt: 2017-03-12T01:13:18.697Z,
  updatedAt: 2017-03-12T01:13:18.697Z } { skipValidation: true }
$formatJson organizations
$parseJson organizations undefined
$beforeInsert organizations
$formatJson employees
$parseJson employees { firstName: undefined,
  lastName: 'Doe',
  email: 'doe@example.com',
  phone: '[]',
  streetAddress: '',
  notes: '',
  createdAt: 2017-03-12T01:13:18.697Z,
  updatedAt: 2017-03-12T01:13:18.697Z,
  organizationId: 156 } undefined
$beforeInsert employees

Is this behavior intended? The docs mention that $formatJson() is for converting the model from its 'internal' to 'external' format. Everything happening during an insert is 'internal' so I feel like $formatJson() shouldn't be called at all here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions