Skip to content
Toggle navigation
Projects
Groups
Snippets
Help
public
/
sequelize
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
不要怂,就是干,撸起袖子干!
Commit 060b766c
authored
May 03, 2018
by
Sushant
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix(isSoftDeleted): just use deletedAt as flag
1 parent
f365f72f
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
108 additions
and
137 deletions
lib/model.js
test/unit/instance/is-soft-deleted.test.js
lib/model.js
View file @
060b766
...
@@ -9,7 +9,6 @@ const sequelizeErrors = require('./errors');
...
@@ -9,7 +9,6 @@ const sequelizeErrors = require('./errors');
const
Dottie
=
require
(
'dottie'
);
const
Dottie
=
require
(
'dottie'
);
const
Promise
=
require
(
'./promise'
);
const
Promise
=
require
(
'./promise'
);
const
_
=
require
(
'lodash'
);
const
_
=
require
(
'lodash'
);
const
moment
=
require
(
'moment'
);
const
Association
=
require
(
'./associations/base'
);
const
Association
=
require
(
'./associations/base'
);
const
HasMany
=
require
(
'./associations/has-many'
);
const
HasMany
=
require
(
'./associations/has-many'
);
const
DataTypes
=
require
(
'./data-types'
);
const
DataTypes
=
require
(
'./data-types'
);
...
@@ -48,6 +47,112 @@ class Model {
...
@@ -48,6 +47,112 @@ class Model {
return
this
.
QueryInterface
.
QueryGenerator
;
return
this
.
QueryInterface
.
QueryGenerator
;
}
}
/**
* A reference to the sequelize instance
* @see {@link Sequelize}
* @property sequelize
* @return {Sequelize}
*/
get
sequelize
()
{
return
this
.
constructor
.
sequelize
;
}
/**
* Builds a new model instance.
*
* @param {Object} [values={}] an object of key value pairs
* @param {Object} [options]
* @param {Boolean} [options.raw=false] If set to true, values will ignore field and virtual setters.
* @param {Boolean} [options.isNewRecord=true]
* @param {Array} [options.include] an array of include options - Used to build prefetched/included model instances. See `set`
*/
constructor
(
values
=
{},
options
=
{})
{
options
=
_
.
extend
({
isNewRecord
:
true
,
_schema
:
this
.
constructor
.
_schema
,
_schemaDelimiter
:
this
.
constructor
.
_schemaDelimiter
},
options
||
{});
if
(
options
.
attributes
)
{
options
.
attributes
=
options
.
attributes
.
map
(
attribute
=>
Array
.
isArray
(
attribute
)
?
attribute
[
1
]
:
attribute
);
}
if
(
!
options
.
includeValidated
)
{
this
.
constructor
.
_conformOptions
(
options
,
this
.
constructor
);
if
(
options
.
include
)
{
this
.
constructor
.
_expandIncludeAll
(
options
);
this
.
constructor
.
_validateIncludedElements
(
options
);
}
}
this
.
dataValues
=
{};
this
.
_previousDataValues
=
{};
this
.
_changed
=
{};
this
.
_modelOptions
=
this
.
constructor
.
options
;
this
.
_options
=
options
||
{};
this
.
__eagerlyLoadedAssociations
=
[];
/**
* Returns true if this instance has not yet been persisted to the database
* @property isNewRecord
* @return {Boolean}
*/
this
.
isNewRecord
=
options
.
isNewRecord
;
this
.
_initValues
(
values
,
options
);
}
_initValues
(
values
,
options
)
{
let
defaults
;
let
key
;
values
=
values
&&
_
.
clone
(
values
)
||
{};
if
(
options
.
isNewRecord
)
{
defaults
=
{};
if
(
this
.
constructor
.
_hasDefaultValues
)
{
defaults
=
_
.
mapValues
(
this
.
constructor
.
_defaultValues
,
valueFn
=>
{
const
value
=
valueFn
();
return
value
&&
value
instanceof
Utils
.
SequelizeMethod
?
value
:
_
.
cloneDeep
(
value
);
});
}
// set id to null if not passed as value, a newly created dao has no id
// removing this breaks bulkCreate
// do after default values since it might have UUID as a default value
if
(
this
.
constructor
.
primaryKeyAttribute
&&
!
defaults
.
hasOwnProperty
(
this
.
constructor
.
primaryKeyAttribute
))
{
defaults
[
this
.
constructor
.
primaryKeyAttribute
]
=
null
;
}
if
(
this
.
constructor
.
_timestampAttributes
.
createdAt
&&
defaults
[
this
.
constructor
.
_timestampAttributes
.
createdAt
])
{
this
.
dataValues
[
this
.
constructor
.
_timestampAttributes
.
createdAt
]
=
Utils
.
toDefaultValue
(
defaults
[
this
.
constructor
.
_timestampAttributes
.
createdAt
],
this
.
sequelize
.
options
.
dialect
);
delete
defaults
[
this
.
constructor
.
_timestampAttributes
.
createdAt
];
}
if
(
this
.
constructor
.
_timestampAttributes
.
updatedAt
&&
defaults
[
this
.
constructor
.
_timestampAttributes
.
updatedAt
])
{
this
.
dataValues
[
this
.
constructor
.
_timestampAttributes
.
updatedAt
]
=
Utils
.
toDefaultValue
(
defaults
[
this
.
constructor
.
_timestampAttributes
.
updatedAt
],
this
.
sequelize
.
options
.
dialect
);
delete
defaults
[
this
.
constructor
.
_timestampAttributes
.
updatedAt
];
}
if
(
this
.
constructor
.
_timestampAttributes
.
deletedAt
&&
defaults
[
this
.
constructor
.
_timestampAttributes
.
deletedAt
])
{
this
.
dataValues
[
this
.
constructor
.
_timestampAttributes
.
deletedAt
]
=
Utils
.
toDefaultValue
(
defaults
[
this
.
constructor
.
_timestampAttributes
.
deletedAt
],
this
.
sequelize
.
options
.
dialect
);
delete
defaults
[
this
.
constructor
.
_timestampAttributes
.
deletedAt
];
}
if
(
Object
.
keys
(
defaults
).
length
)
{
for
(
key
in
defaults
)
{
if
(
values
[
key
]
===
undefined
)
{
this
.
set
(
key
,
Utils
.
toDefaultValue
(
defaults
[
key
],
this
.
sequelize
.
options
.
dialect
),
defaultsOptions
);
delete
values
[
key
];
}
}
}
}
this
.
set
(
values
,
options
);
}
// validateIncludedElements should have been called before this method
// validateIncludedElements should have been called before this method
static
_paranoidClause
(
model
,
options
=
{})
{
static
_paranoidClause
(
model
,
options
=
{})
{
// Apply on each include
// Apply on each include
...
@@ -3058,118 +3163,6 @@ class Model {
...
@@ -3058,118 +3163,6 @@ class Model {
}
}
/**
/**
* Builds a new model instance.
* @param {Object} [values={}] an object of key value pairs
* @param {Object} [options]
* @param {Boolean} [options.raw=false] If set to true, values will ignore field and virtual setters.
* @param {Boolean} [options.isNewRecord=true]
* @param {Array} [options.include] an array of include options - Used to build prefetched/included model instances. See `set`
*/
constructor
(
values
,
options
)
{
values
=
values
||
{};
options
=
_
.
extend
({
isNewRecord
:
true
,
_schema
:
this
.
constructor
.
_schema
,
_schemaDelimiter
:
this
.
constructor
.
_schemaDelimiter
},
options
||
{});
if
(
options
.
attributes
)
{
options
.
attributes
=
options
.
attributes
.
map
(
attribute
=>
Array
.
isArray
(
attribute
)
?
attribute
[
1
]
:
attribute
);
}
if
(
!
options
.
includeValidated
)
{
this
.
constructor
.
_conformOptions
(
options
,
this
.
constructor
);
if
(
options
.
include
)
{
this
.
constructor
.
_expandIncludeAll
(
options
);
this
.
constructor
.
_validateIncludedElements
(
options
);
}
}
this
.
dataValues
=
{};
this
.
_previousDataValues
=
{};
this
.
_changed
=
{};
this
.
_modelOptions
=
this
.
constructor
.
options
;
this
.
_options
=
options
||
{};
this
.
__eagerlyLoadedAssociations
=
[];
/**
* Returns true if this instance has not yet been persisted to the database
* @property isNewRecord
* @return {Boolean}
*/
this
.
isNewRecord
=
options
.
isNewRecord
;
/**
* Returns the Model the instance was created from.
* @see {@link Model}
* @property Model
* @return {Model}
*/
this
.
_initValues
(
values
,
options
);
}
_initValues
(
values
,
options
)
{
let
defaults
;
let
key
;
values
=
values
&&
_
.
clone
(
values
)
||
{};
if
(
options
.
isNewRecord
)
{
defaults
=
{};
if
(
this
.
constructor
.
_hasDefaultValues
)
{
defaults
=
_
.
mapValues
(
this
.
constructor
.
_defaultValues
,
valueFn
=>
{
const
value
=
valueFn
();
return
value
&&
value
instanceof
Utils
.
SequelizeMethod
?
value
:
_
.
cloneDeep
(
value
);
});
}
// set id to null if not passed as value, a newly created dao has no id
// removing this breaks bulkCreate
// do after default values since it might have UUID as a default value
if
(
this
.
constructor
.
primaryKeyAttribute
&&
!
defaults
.
hasOwnProperty
(
this
.
constructor
.
primaryKeyAttribute
))
{
defaults
[
this
.
constructor
.
primaryKeyAttribute
]
=
null
;
}
if
(
this
.
constructor
.
_timestampAttributes
.
createdAt
&&
defaults
[
this
.
constructor
.
_timestampAttributes
.
createdAt
])
{
this
.
dataValues
[
this
.
constructor
.
_timestampAttributes
.
createdAt
]
=
Utils
.
toDefaultValue
(
defaults
[
this
.
constructor
.
_timestampAttributes
.
createdAt
],
this
.
sequelize
.
options
.
dialect
);
delete
defaults
[
this
.
constructor
.
_timestampAttributes
.
createdAt
];
}
if
(
this
.
constructor
.
_timestampAttributes
.
updatedAt
&&
defaults
[
this
.
constructor
.
_timestampAttributes
.
updatedAt
])
{
this
.
dataValues
[
this
.
constructor
.
_timestampAttributes
.
updatedAt
]
=
Utils
.
toDefaultValue
(
defaults
[
this
.
constructor
.
_timestampAttributes
.
updatedAt
],
this
.
sequelize
.
options
.
dialect
);
delete
defaults
[
this
.
constructor
.
_timestampAttributes
.
updatedAt
];
}
if
(
this
.
constructor
.
_timestampAttributes
.
deletedAt
&&
defaults
[
this
.
constructor
.
_timestampAttributes
.
deletedAt
])
{
this
.
dataValues
[
this
.
constructor
.
_timestampAttributes
.
deletedAt
]
=
Utils
.
toDefaultValue
(
defaults
[
this
.
constructor
.
_timestampAttributes
.
deletedAt
],
this
.
sequelize
.
options
.
dialect
);
delete
defaults
[
this
.
constructor
.
_timestampAttributes
.
deletedAt
];
}
if
(
Object
.
keys
(
defaults
).
length
)
{
for
(
key
in
defaults
)
{
if
(
values
[
key
]
===
undefined
)
{
this
.
set
(
key
,
Utils
.
toDefaultValue
(
defaults
[
key
],
this
.
sequelize
.
options
.
dialect
),
defaultsOptions
);
delete
values
[
key
];
}
}
}
}
this
.
set
(
values
,
options
);
}
/**
* A reference to the sequelize instance
* @see {@link Sequelize}
* @property sequelize
* @return {Sequelize}
*/
get
sequelize
()
{
return
this
.
constructor
.
sequelize
;
}
/**
* Get an object representing the query for this instance, use with `options.where`
* Get an object representing the query for this instance, use with `options.where`
*
*
* @property where
* @property where
...
@@ -3877,7 +3870,6 @@ class Model {
...
@@ -3877,7 +3870,6 @@ class Model {
*
*
* @return {Promise<undefined>}
* @return {Promise<undefined>}
*/
*/
destroy
(
options
)
{
destroy
(
options
)
{
options
=
_
.
extend
({
options
=
_
.
extend
({
hooks
:
true
,
hooks
:
true
,
...
@@ -3943,21 +3935,9 @@ class Model {
...
@@ -3943,21 +3935,9 @@ class Model {
const
deletedAt
=
this
.
get
(
this
.
constructor
.
_timestampAttributes
.
deletedAt
);
const
deletedAt
=
this
.
get
(
this
.
constructor
.
_timestampAttributes
.
deletedAt
);
const
isSet
=
deletedAt
!==
defaultValue
;
const
isSet
=
deletedAt
!==
defaultValue
;
// No need to check the value of deletedAt if it's equal to the default
// value. If so return the inverse of `isNotSet` since we are asking if
// the model *is* soft-deleted.
if
(
!
isSet
)
{
return
isSet
;
return
isSet
;
}
}
const
now
=
moment
();
const
deletedAtIsInTheFuture
=
moment
(
deletedAt
).
isAfter
(
now
);
// If deletedAt is a datetime in the future then the model is *not* soft-deleted.
// Therefore, return the inverse of `deletedAtIsInTheFuture`.
return
!
deletedAtIsInTheFuture
;
}
/**
/**
* Restore the row corresponding to this instance. Only available for paranoid models.
* Restore the row corresponding to this instance. Only available for paranoid models.
*
*
...
@@ -4073,7 +4053,6 @@ class Model {
...
@@ -4073,7 +4053,6 @@ class Model {
* @return {Boolean}
* @return {Boolean}
*/
*/
equals
(
other
)
{
equals
(
other
)
{
if
(
!
other
||
!
other
.
constructor
)
{
if
(
!
other
||
!
other
.
constructor
)
{
return
false
;
return
false
;
}
}
...
...
test/unit/instance/is-soft-deleted.test.js
View file @
060b766
...
@@ -58,20 +58,12 @@ describe(Support.getTestDialectTeaser('Instance'), () => {
...
@@ -58,20 +58,12 @@ describe(Support.getTestDialectTeaser('Instance'), () => {
}).
to
.
throw
(
'Model is not paranoid'
);
}).
to
.
throw
(
'Model is not paranoid'
);
});
});
it
(
'should return false if the soft-delete property is the same as '
+
it
(
'should return false if the soft-delete property is the same as the default value'
,
function
()
{
'the default value'
,
function
()
{
this
.
paranoidUser
.
setDataValue
(
'deletedAt'
,
null
);
this
.
paranoidUser
.
setDataValue
(
'deletedAt'
,
null
);
expect
(
this
.
paranoidUser
.
isSoftDeleted
()).
to
.
be
.
false
;
expect
(
this
.
paranoidUser
.
isSoftDeleted
()).
to
.
be
.
false
;
});
});
it
(
'should return false if the soft-delete property is set to a date in '
+
it
(
'should return true if the soft-delete property is set'
,
function
()
{
'the future'
,
function
()
{
this
.
paranoidUser
.
setDataValue
(
'deletedAt'
,
moment
().
add
(
5
,
'days'
).
format
());
expect
(
this
.
paranoidUser
.
isSoftDeleted
()).
to
.
be
.
false
;
});
it
(
'should return true if the soft-delete property is set to a date '
+
'before now'
,
function
()
{
this
.
paranoidUser
.
setDataValue
(
'deletedAt'
,
moment
().
subtract
(
5
,
'days'
).
format
());
this
.
paranoidUser
.
setDataValue
(
'deletedAt'
,
moment
().
subtract
(
5
,
'days'
).
format
());
expect
(
this
.
paranoidUser
.
isSoftDeleted
()).
to
.
be
.
true
;
expect
(
this
.
paranoidUser
.
isSoftDeleted
()).
to
.
be
.
true
;
});
});
...
...
Write
Preview
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment