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

Scopes and building smart where objects closes #386 #748

Merged
merged 10 commits into from Aug 23, 2013

Conversation

6 participants
@durango
Member

durango commented Jul 5, 2013

Several things in this commit:

  1. New scope() functionality, works very similar to ActiveRecord's scope.
  2. Big internal changes (but as of right now only related to scope()) made for the {where} object when using finders (se Utils.smartWhere). Could be useful for some, it basically breaks down several where objects into one concise object.
  3. New where finders.. 'eq', 'like', 'nlike', 'notlike', and 'not' (not in).
  4. New finder shortcuts, '..' for between and '..' for not between

Usage

sequelize.define('table', {
  username: DataTypes.STRING,
  email: DataTypes.STRING,
  status: DataTypes.STRING,
  accessLevel: DataTypes.INTEGER
}, {
  defaultScope: {
    where: {
      status: 'active'
    }
  },
  scopes: {
    orderScope: {
      order: 'accessLevel DESC'
    },
    limitScope: {
      limit: 2
    },
    sequelizeTeam: {
      where: ['email LIKE \'%@sequelizejs.com\'']
    },
    lowAccess: {
      where: {
        accessLevel: 5
      }
    },
    specificAccess: function(value) {
      return {
        where: {
          accessLevel: value
        }
      }
    },
    isActive: {
      where: {
        status: 'active'
      }
    },
    isSuspended: function(value) {
      return {
        where: {
          status: 'suspended'
        }
      }
    },
  }
})

// Any select methods will now prepend the where object with the defaultScope
table.findAll().success(function(users){
  console.log(users) // will only return users with status='active'
})

// You can also amend to scopes in any of the select/finder calls...
table.findAll({
  where: {
    email: {
      like: '%@sequelizejs.com' // This is new too!
    }
  }
}).success(function(users){
  console.log(users) // will only return users with status='active' and emails like '%@sequelizejs.com'
})

// NOTE: When calling a predefined scope, the defaultScope is no longer taken into consideration and complete scraped
// To call a predefined scope
table.scope('sequelizeTeam').findAll().success(function(users){
  // notice the where clause is NOT "WHERE status='active'" but simply "WHERE email LIKE '%@sequelizejs.com' 
  console.log(users) // will return users with email LIKE '%@sequelizejs.com'
})

// You can combine scopes...
table.scope('orderScope', 'limitScope', 'sequelizeTeam').findAll().success(function(users){
  console.log(users) // will return users with email LIKE '%@sequelizejs.com', order by accessLevel, and limited to 2...
})

// alternatively you can do.. ['orderScope', 'limitScope', 'sequelizeTeam'] within scope()

// You can also call function'd scopes... it's just a simple .apply() method
table.scope({method: ['specificAccess', 10]}).findAll().success(function(users){
  console.log(users) // will return users with an accessLevel of 10
})

// If your function had more than one argument just simply keep adding to the array
// e.g. {method: ['someScope', 'hello', 'world', 'third_argument', 'fourth!']}

// Sometimes your scopes will clash together like so...
table.scope('isActive', 'isSuspended').success(function(users){
 // WHERE status='active' AND status='suspended'
})

// You can apply a "merge" attribute to your scope in order to let sequelize know which value to overwrite/merge.
table.scope('isActive', {merge: 'isSuspended'}).success(function(users){
  // WHERE status='suspended'
})

// ...yes you can merge method scopes
table.scope('lowAccess', {merge: true, method: ['specificAccess', 10]}).success(function(users) {
  console.log(users) // WHERE accessLevel=10 and NOT accessLevel=5 AND accessLevel=10
})

// you can even separate out scopes, no pollution required!
var sequelizeTeam = table.scope('sequelizeTeam')
   , isActive = table.scope('isActive')

sequelizeTeam.all().success(function(team) {
  isActive.all().success(function(active) {
    console.log(team) // sequelize team
    console.log(active) // active users
  })
})

// if you don't want to use a scope, simply call scope with no arguments
table.scope().findAll()

// you can alternatively just throw a falsy value into the first argument
table.scope(false).findAll()

// Calling an undefined scope name will simply be ignored
table.scope('sequelizeTeam', 'nonexistant').all() // just sequelizeTeam

// Alternatively, you can have sequelize throw an error (so you can wrap it in domains or whatever) by passing {silent: false} as the last argument like so...
table.scope('sequelizeTeam', 'nonexistant', {silent: false}).all() // ErrorException
@ptnplanet

This comment has been minimized.

ptnplanet commented Jul 5, 2013

This is brilliant!

@durango

This comment has been minimized.

Member

durango commented Jul 5, 2013

@ptnplanet thanks :) hopefully it'll be useful

@ALL I know we have a lot of issues still, and new features should not be added, but the company I work for actually requires this now so I decided to make it a bit early. After this I should be able to focus on the issues rather than feature sets for sequelize :) Sorry about that

side note: I forgot to remove a completely non-related array column from the tests so MySQL failed ;)

Several things in this commit: 1. New scope() functionality, works ve…
…ry similar to ActiveRecord's scope. 2. Big internal changes (but as of right now only related to scope()) made for the {where} object when using finders. Could be useful for some, it basically breaks down several where objects into one concise object. 3. New where finders.. 'eq', 'like', 'nlike', 'notlike', and 'not' (not in). 4. New finder shortcuts, '..' for between and '..' for not between
@durango

This comment has been minimized.

Member

durango commented Jul 5, 2013

Turns out postgres and mysql use substring differently :P updated tests to use LIKE instead

it("should be able to use a defaultScope if declared", function(done) {
this.ScopeMe.findAll().success(function(users) {
expect(users).toBeArray()

This comment has been minimized.

@janmeier

janmeier Jul 6, 2013

Member

Perhaps check the actual accesslevel, since that is what the scope is testing for :)

})
it("should be able to override the default scope", function(done) {
this.ScopeMe.scope('highValue').findAll().success(function(users) {

This comment has been minimized.

@janmeier

janmeier Jul 6, 2013

Member

Exactly the same assertions as the above test

@janmeier

This comment has been minimized.

Member

janmeier commented Jul 6, 2013

This is major awesome! With a couple of small fixes this is good to merge

You deserve a case of beer as well soon! ;)

@janmeier janmeier referenced this pull request Jul 6, 2013

Closed

deletedAt on find #133

durango added some commits Jul 8, 2013

Added one more test spec as well as checking for access_level in one …
…of the specs to make sure that we're getting the right information back.
@durango

This comment has been minimized.

Member

durango commented Jul 11, 2013

Added new functionality thanks for @mickhansen for pointing out the pollution/race condition problem! :)

durango added some commits Jul 11, 2013

Cleaned up the scopes code a bit, added more specs involving non exis…
…ting scopes as well as a {silent} options as the last argument.
Merge branch 'master' into scopes
Conflicts:
	lib/dao-factory.js
@durango

This comment has been minimized.

Member

durango commented Jul 13, 2013

Poor scopes, I need to temporarily close this in favor of a better smartWhere function in a future PR of mine.

@durango durango closed this Jul 13, 2013

@ghost ghost assigned durango Jul 13, 2013

durango added some commits Jul 16, 2013

Cleaned up scopes/smartwhere, added another spec to make sure SQL is …
…escaped, and fixed potential SQL injection problem with sqlite

@durango durango reopened this Jul 16, 2013

@LoicMahieu

This comment has been minimized.

Contributor

LoicMahieu commented Aug 23, 2013

This feature would be really awesome ! Is it planned to release soon ? Thanks alot for your work!

@sdepold

This comment has been minimized.

Member

sdepold commented Aug 23, 2013

oh sweet. lemme check.

@sdepold

This comment has been minimized.

Member

sdepold commented Aug 23, 2013

hmm would you mind rebasing the PR?

@sdepold

This comment has been minimized.

Member

sdepold commented Aug 23, 2013

nvm i'm on it

@sdepold sdepold merged commit 3654655 into sequelize:master Aug 23, 2013

1 check passed

default The Travis CI build passed
Details
@anoopsinghbayes

This comment has been minimized.

anoopsinghbayes commented Jul 18, 2014

can we expect the scoped behavior with create and update too????

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment