Exclude column from Query

See original GitHub issue

Hi. First of all, congratulations for this awesome tool. English is not my first language, so I apologize for eventual mistakes.

It’s relatively common for ORMs to read the tables before execution to know exactly all the columns and its specifications. For example: in Mysql/MariaDb: DESCRIBE products; could return something like this:

Field	    Type               Null     Key     Default    Extra
id          int(11) unsigned   NO       PRI     NULL       auto_increment
uuid        char(36)           NO               NULL
name        varchar(255)       NO               NULL
created_at  datetime           NO               NULL
updated_at  datetime           YES              NULL

By doing this, the QueryBuilder could start all SELECT queries with all fields by default, instead of *. And this is great for several reasons.

I’d like to know if there is a way to enable this? At this moment all my queries are using “select table.* […]”

My second question is: how to exclude columns from my query? I already saw how to omit columns after fetched, but i think this is a really poor solution, since my query:

static findByUUID( uuid ) {
        return this.query().where( 'uuid', uuid ).first().omit( [ 'id' ] );
    }

… Is being written like this anyway: select `products`.* from `products` where `uuid` = ?

Summing up: I’m just trying to do this:

select
    `products`.`uuid`,
    `products`.`name`,
    `products`.`created_at`,
    `products`.`updated_at`
from `products` where `uuid` = ?

I really appreciate any contributions, since I’m really new to Knex and/or Objection.js.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:14

github_iconTop GitHub Comments

2reactions
koskimascommented, Sep 16, 2018

After more consideration, this is too much of a hack for objection.

1reaction
koskimascommented, Jan 22, 2018

Here’s an example plugin that implements the feature using only public interface:

const Metadata = (Model) => {
  class MetadataQueryBuilder extends Model.QueryBuilder {
    constructor(...args) {
      super(...args);

      // Whenever a query builder is created, register a function to be called
      // during it's build phase.
      this.onBuild(builder => {
        // Select all columns except excluded ones, but only if there are no
        // explicit selects.
        if (!builder.hasSelects()) {
          const modelClass = builder.modelClass();
          // The correct table reference. Can be other than the table name
          // for example if an alias is used.
          const table = builder.tableRefFor(modelClass);

          builder.select(modelClass.$$columns
            .filter(col => !builder.$$unselect || !builder.$$unselect.includes(col))
            .map(col => `${table}.${col}`));
        }
      });
    }

    // We need to override `clone` too so that our custom property
    // is cloned too.
    clone(...args) {
      const copy = super.clone(...args);

      if (this.$$unselect) {
        Object.defineProperty(copy, '$$unselect', {
          enumerable: false,
          value: this.$$unselect
        });
      }

      return copy;
    }

    // This is a new query builder method that can be used to exclude columns.
    unselect(columns) {
      // We use `Object.defineProperty` to hide our custom property. 
      // This is not necessary. You could just use `this.$$unselect = something`
      // or even `this.unselected = something`. `$` prefix is just a convention for
      // "internal" properties.
      Object.defineProperty(this, '$$unselect', {
        enumerable: false,
        value: columns
      });

      return this;
    }
  }

  return class extends Model {
    // Register our custom query builder to be used instead of the default one.
    static get QueryBuilder() {
      return MetadataQueryBuilder;
    }

    // An initialization function that fetches the column metadata. This only
    // needs to be called once. `knex` argument is optional and only needed
    // if you haven't given the knex connection using `Model.knex(knex)` or
    // any other supported way.
    static initialize(Models, knex) {
      return Promise.all(Models.map(async (Model) => {
        const columnInfo = await  Model.query(knex).columnInfo();

        // We use `Object.defineProperty` to hide our custom property. 
        // This is not necessary. You could just use `Model.$$columns = something`
        // or even `Model.columns = something`. `$` prefix is just a convention for
        // "internal" properties.
        Object.defineProperty(Model, '$$columns', {
          enumerable: false,
          // Run the properties through `propertyNameToColumnName` to make sure
          // any possible column name conversion (for example snake_case -> camelCase)
          // is done.
          value: Object.keys(columnInfo).map(prop => Model.propertyNameToColumnName(prop))
        });
      }));
    }
  };
}

You would use it like this:

const { Model } = require('objection');

class BaseModel extends Metadata(Model) {

}

...

class Product extends BaseModel {
  ...
}

...

// In some initialization code
await BaseModel.initialize([Product, Foo, Bar, Baz, Spam, All, Your, Models]);

...

// Use it
static findByUUID( uuid ) {
    return this.query().findOne({ uuid }).unselect( [ 'id' ] );
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Exclude a Column using SELECT * - Data School
List out all columns in your query, omit the undesired fields by: ... SELECT column1, --column2, column4 FROM table_name;. Here we deleted column3...
Read more >
sql - Exclude a column using SELECT * [except columnA ...
In your select statement, just highlight the referenced columns folder above and drag and drop it into the query window. It will paste...
Read more >
Exclude Columns in SELECT * - LinkedIn
From Databricks Runtime 9.0, it is possible to exclude one or more specified columns from the SELECT * command.
Read more >
how to exclude columns from select sql? - Oracle Communities
Hii all,. I have already googled it and all i found that there is no way to exclude a column name in a...
Read more >
How to SELECT all columns except one in MySQL
To exclude columns, you use the REPLACE() and GROUP_CONCAT() functions to generate the column names you wish to include in your SELECT statement ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found