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 c7104a4c
authored
Mar 21, 2015
by
Mick Hansen
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(model/instance): nested creation support, fixes/changes to the excellent work of @mbroadst
1 parent
b284b53c
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
230 additions
and
121 deletions
lib/instance.js
test/integration/instance/save.test.js → test/integration/model/create/include.test.js
lib/instance.js
View file @
c7104a4
...
...
@@ -2,6 +2,10 @@
var
Utils
=
require
(
'./utils'
)
,
Mixin
=
require
(
'./associations/mixin'
)
,
BelongsTo
=
require
(
'./associations/belongs-to'
)
,
HasOne
=
require
(
'./associations/has-one'
)
,
HasMany
=
require
(
'./associations/has-many'
)
,
BelongsToMany
=
require
(
'./associations/belongs-to-many'
)
,
InstanceValidator
=
require
(
'./instance-validator'
)
,
DataTypes
=
require
(
'./data-types'
)
,
Promise
=
require
(
"./promise"
)
...
...
@@ -431,7 +435,7 @@ module.exports = (function() {
if
(
!
isEmpty
)
{
childOptions
=
{
isNewRecord
:
false
,
isNewRecord
:
this
.
isNewRecord
,
isDirty
:
false
,
include
:
include
.
include
,
includeNames
:
include
.
includeNames
,
...
...
@@ -501,7 +505,8 @@ module.exports = (function() {
var
self
=
this
,
updatedAtAttr
=
this
.
Model
.
_timestampAttributes
.
updatedAt
,
createdAtAttr
=
this
.
Model
.
_timestampAttributes
.
createdAt
,
hook
=
self
.
isNewRecord
?
'Create'
:
'Update'
;
,
hook
=
self
.
isNewRecord
?
'Create'
:
'Update'
,
wasNewRecord
=
this
.
isNewRecord
;
if
(
updatedAtAttr
&&
options
.
fields
.
indexOf
(
updatedAtAttr
)
===
-
1
)
{
options
.
fields
.
push
(
updatedAtAttr
);
...
...
@@ -579,31 +584,20 @@ module.exports = (function() {
}
}).
then
(
function
()
{
if
(
!
options
.
fields
.
length
)
return
this
;
// create relational data for BelongsTo
var
relationPromises
=
[];
Object
.
keys
(
this
.
dataValues
).
forEach
(
function
(
dataValue
)
{
if
(
_
.
has
(
self
.
options
.
includeMap
,
dataValue
))
{
var
includeModel
=
self
.
options
.
includeMap
[
dataValue
].
model
;
var
includeAssociation
=
self
.
options
.
includeMap
[
dataValue
].
association
;
if
(
includeAssociation
.
associationType
===
'BelongsTo'
)
{
var
includeData
=
self
.
dataValues
[
dataValue
].
dataValues
;
var
relationPromise
=
includeModel
.
create
(
includeData
).
then
(
function
(
result
)
{
result
.
_originalDataValue
=
dataValue
;
result
.
_identifierField
=
includeAssociation
.
identifierField
;
return
result
;
});
relationPromises
.
push
(
relationPromise
);
}
}
});
return
Promise
.
all
(
relationPromises
).
then
(
function
(
instances
)
{
instances
.
forEach
(
function
(
instance
)
{
delete
self
.
dataValues
[
instance
.
_originalDataValue
];
self
.
dataValues
[
instance
.
_identifierField
]
=
instance
.
id
;
if
(
!
this
.
isNewRecord
)
return
this
;
if
(
!
this
.
options
.
include
||
!
this
.
options
.
include
.
length
)
return
this
;
// Nested creation for BelongsTo relations
return
Promise
.
map
(
this
.
options
.
include
.
filter
(
function
(
include
)
{
return
include
.
association
instanceof
BelongsTo
;
}),
function
(
include
)
{
var
instance
=
self
.
get
(
include
.
as
);
if
(
!
instance
)
return
Promise
.
resolve
();
return
instance
.
save
({
transaction
:
options
.
transaction
}).
then
(
function
()
{
return
self
[
include
.
association
.
accessors
.
set
](
instance
,
{
save
:
false
});
});
});
})
...
...
@@ -670,44 +664,38 @@ module.exports = (function() {
return
result
;
})
.
tap
(
function
(
result
)
{
// handle HasOne/HasMany/BelongsToMany relations
var
relationPromises
=
[];
Object
.
keys
(
self
.
dataValues
).
forEach
(
function
(
dataValue
)
{
if
(
_
.
has
(
self
.
options
.
includeMap
,
dataValue
))
{
var
includeModel
=
self
.
options
.
includeMap
[
dataValue
].
model
;
var
includeAssociation
=
self
.
options
.
includeMap
[
dataValue
].
association
;
if
(
includeAssociation
.
associationType
===
'HasOne'
)
{
var
includeData
=
self
.
dataValues
[
dataValue
].
dataValues
;
includeData
[
includeAssociation
.
identifierField
]
=
result
.
id
;
relationPromises
.
push
(
includeModel
.
create
(
includeData
));
}
else
if
(
includeAssociation
.
associationType
===
'HasMany'
)
{
self
.
dataValues
[
dataValue
].
forEach
(
function
(
record
)
{
var
includeData
=
record
.
dataValues
;
includeData
[
includeAssociation
.
identifierField
]
=
result
.
id
;
relationPromises
.
push
(
includeModel
.
create
(
includeData
));
});
}
else
if
(
includeAssociation
.
associationType
===
'BelongsToMany'
)
{
var
throughModel
=
includeAssociation
.
throughModel
;
var
identifierField
=
includeAssociation
.
identifierField
;
var
foreignIdentifierField
=
includeAssociation
.
foreignIdentifierField
;
self
.
dataValues
[
dataValue
].
forEach
(
function
(
record
)
{
var
includeData
=
record
.
dataValues
;
var
promise
=
includeModel
.
create
(
includeData
).
then
(
function
(
associatedRecord
)
{
var
throughData
=
{};
throughData
[
identifierField
]
=
result
.
id
;
throughData
[
foreignIdentifierField
]
=
associatedRecord
.
id
;
return
throughModel
.
create
(
throughData
);
if
(
!
wasNewRecord
)
return
;
if
(
!
self
.
options
.
include
||
!
self
.
options
.
include
.
length
)
return
;
// Nested creation for HasOne/HasMany/BelongsToMany relations
return
Promise
.
map
(
self
.
options
.
include
.
filter
(
function
(
include
)
{
return
!
(
include
.
association
instanceof
BelongsTo
);
}),
function
(
include
)
{
var
instances
=
self
.
get
(
include
.
as
)
,
instance
=
instances
;
if
(
!
instances
)
return
Promise
.
resolve
();
if
(
Array
.
isArray
(
instances
)
&&
!
instances
.
length
)
return
Promise
.
resolve
();
if
(
Array
.
isArray
(
instances
))
{
return
Promise
.
map
(
instances
,
function
(
instance
)
{
if
(
include
.
association
instanceof
BelongsToMany
)
{
return
instance
.
save
({
transaction
:
options
.
transaction
}).
then
(
function
()
{
var
values
=
{};
values
[
include
.
association
.
foreignKey
]
=
self
.
get
(
self
.
Model
.
primaryKeyAttribute
,
{
raw
:
true
});
values
[
include
.
association
.
otherKey
]
=
instance
.
get
(
instance
.
Model
.
primaryKeyAttribute
,
{
raw
:
true
});
return
include
.
association
.
throughModel
.
create
(
values
);
});
relationPromises
.
push
(
promise
);
});
}
}
else
{
instance
.
set
(
include
.
association
.
identifier
,
self
.
get
(
self
.
Model
.
primaryKeyAttribute
,
{
raw
:
true
}));
return
instance
.
save
({
transaction
:
options
.
transaction
});
}
});
}
else
{
instance
.
set
(
include
.
association
.
identifier
,
self
.
get
(
self
.
Model
.
primaryKeyAttribute
,
{
raw
:
true
}));
return
instance
.
save
({
transaction
:
options
.
transaction
});
}
});
return
Promise
.
all
(
relationPromises
);
});
});
});
...
...
test/integration/
instance/sav
e.test.js
→
test/integration/
model/create/includ
e.test.js
View file @
c7104a4
'use strict'
;
var
chai
=
require
(
'chai'
)
,
Sequelize
=
require
(
'../../../index'
)
,
Sequelize
=
require
(
'../../../
../
index'
)
,
expect
=
chai
.
expect
,
Support
=
require
(
__dirname
+
'/../support'
)
,
Support
=
require
(
__dirname
+
'/../
../
support'
)
,
dialect
=
Support
.
getTestDialect
()
,
DataTypes
=
require
(
__dirname
+
'/../../../lib/data-types'
)
,
DataTypes
=
require
(
__dirname
+
'/../../../
../
lib/data-types'
)
,
Promise
=
Sequelize
.
Promise
;
chai
.
config
.
includeStack
=
true
;
describe
(
Support
.
getTestDialectTeaser
(
'
Instance
'
),
function
()
{
describe
(
'
sav
e'
,
function
()
{
describe
(
Support
.
getTestDialectTeaser
(
'
Model
'
),
function
()
{
describe
(
'
creat
e'
,
function
()
{
describe
(
'include'
,
function
()
{
it
(
'should
sav
e data for BelongsTo relations'
,
function
()
{
it
(
'should
creat
e data for BelongsTo relations'
,
function
()
{
var
Product
=
this
.
sequelize
.
define
(
'Product'
,
{
title
:
Sequelize
.
STRING
});
...
...
@@ -24,31 +24,62 @@ describe(Support.getTestDialectTeaser('Instance'), function() {
Product
.
belongsTo
(
User
);
var
product
=
Product
.
build
({
id
:
1
,
title
:
'Chair'
,
User
:
{
id
:
1
,
first_name
:
'Mick'
,
last_name
:
'Hansen'
}
},
{
include
:
[
User
]
});
return
this
.
sequelize
.
sync
({
force
:
true
}).
then
(
function
()
{
return
product
.
save
().
then
(
function
(
savedProduct
)
{
return
Product
.
find
({
return
Product
.
create
({
title
:
'Chair'
,
User
:
{
first_name
:
'Mick'
,
last_name
:
'Broadstone'
}
},
{
include
:
[
User
]
}).
then
(
function
(
savedProduct
)
{
return
Product
.
findOne
({
where
:
{
id
:
savedProduct
.
id
},
include
:
[
User
]
}).
then
(
function
(
persistedProduct
)
{
expect
(
persistedProduct
.
User
).
to
.
be
.
ok
;
expect
(
persistedProduct
.
User
.
first_name
).
to
.
be
.
equal
(
'Mick'
);
expect
(
persistedProduct
.
User
.
last_name
).
to
.
be
.
equal
(
'Broadstone'
);
});
});
});
});
it
(
'should create data for BelongsTo relations with alias'
,
function
()
{
var
Product
=
this
.
sequelize
.
define
(
'Product'
,
{
title
:
Sequelize
.
STRING
});
var
User
=
this
.
sequelize
.
define
(
'User'
,
{
first_name
:
Sequelize
.
STRING
,
last_name
:
Sequelize
.
STRING
});
var
Creator
=
Product
.
belongsTo
(
User
,
{
as
:
'creator'
});
return
this
.
sequelize
.
sync
({
force
:
true
}).
then
(
function
()
{
return
Product
.
create
({
title
:
'Chair'
,
creator
:
{
first_name
:
'Matt'
,
last_name
:
'Hansen'
}
},
{
include
:
[
Creator
]
}).
then
(
function
(
savedProduct
)
{
return
Product
.
findOne
({
where
:
{
id
:
savedProduct
.
id
},
include
:
[
Creator
]
}).
then
(
function
(
persistedProduct
)
{
expect
(
persistedProduct
.
creator
).
to
.
be
.
ok
;
expect
(
persistedProduct
.
creator
.
first_name
).
to
.
be
.
equal
(
'Matt'
);
expect
(
persistedProduct
.
creator
.
last_name
).
to
.
be
.
equal
(
'Hansen'
);
});
});
});
});
it
(
'should
sav
e data for HasMany relations'
,
function
()
{
it
(
'should
creat
e data for HasMany relations'
,
function
()
{
var
Product
=
this
.
sequelize
.
define
(
'Product'
,
{
title
:
Sequelize
.
STRING
});
...
...
@@ -58,19 +89,17 @@ describe(Support.getTestDialectTeaser('Instance'), function() {
Product
.
hasMany
(
Tag
);
var
product
=
Product
.
build
({
id
:
1
,
title
:
'Chair'
,
Tags
:
[
{
id
:
1
,
name
:
'Alpha'
},
{
id
:
2
,
name
:
'Beta'
}
]
},
{
include
:
[
Tag
]
});
return
this
.
sequelize
.
sync
({
force
:
true
}).
then
(
function
()
{
return
product
.
save
().
then
(
function
(
savedProduct
)
{
return
Product
.
create
({
id
:
1
,
title
:
'Chair'
,
Tags
:
[
{
id
:
1
,
name
:
'Alpha'
},
{
id
:
2
,
name
:
'Beta'
}
]
},
{
include
:
[
Tag
]
}).
then
(
function
(
savedProduct
)
{
return
Product
.
find
({
where
:
{
id
:
savedProduct
.
id
},
include
:
[
Tag
]
...
...
@@ -82,7 +111,39 @@ describe(Support.getTestDialectTeaser('Instance'), function() {
});
});
it
(
'should save data for HasOne relations'
,
function
()
{
it
(
'should create data for HasMany relations with alias'
,
function
()
{
var
Product
=
this
.
sequelize
.
define
(
'Product'
,
{
title
:
Sequelize
.
STRING
});
var
Tag
=
this
.
sequelize
.
define
(
'Tag'
,
{
name
:
Sequelize
.
STRING
});
var
Categories
=
Product
.
hasMany
(
Tag
,
{
as
:
'categories'
});
return
this
.
sequelize
.
sync
({
force
:
true
}).
then
(
function
()
{
return
Product
.
create
({
id
:
1
,
title
:
'Chair'
,
categories
:
[
{
id
:
1
,
name
:
'Alpha'
},
{
id
:
2
,
name
:
'Beta'
}
]
},
{
include
:
[
Categories
]
}).
then
(
function
(
savedProduct
)
{
return
Product
.
find
({
where
:
{
id
:
savedProduct
.
id
},
include
:
[
Categories
]
}).
then
(
function
(
persistedProduct
)
{
expect
(
persistedProduct
.
categories
).
to
.
be
.
ok
;
expect
(
persistedProduct
.
categories
.
length
).
to
.
equal
(
2
);
});
});
});
});
it
(
'should create data for HasOne relations'
,
function
()
{
var
User
=
this
.
sequelize
.
define
(
'User'
,
{
username
:
Sequelize
.
STRING
});
...
...
@@ -93,17 +154,15 @@ describe(Support.getTestDialectTeaser('Instance'), function() {
User
.
hasOne
(
Task
);
var
user
=
User
.
build
({
username
:
'Muzzy'
,
Task
:
{
title
:
'Eat Clocks'
}
},
{
include
:
[
Task
]
});
return
this
.
sequelize
.
sync
({
force
:
true
}).
then
(
function
()
{
return
user
.
save
().
then
(
function
(
savedUser
)
{
return
User
.
create
({
username
:
'Muzzy'
,
Task
:
{
title
:
'Eat Clocks'
}
},
{
include
:
[
Task
]
}).
then
(
function
(
savedUser
)
{
return
User
.
find
({
where
:
{
id
:
savedUser
.
id
},
include
:
[
Task
]
...
...
@@ -114,7 +173,39 @@ describe(Support.getTestDialectTeaser('Instance'), function() {
});
});
it
(
'should save data for BelongsToMany relations'
,
function
()
{
it
(
'should create data for HasOne relations with alias'
,
function
()
{
var
User
=
this
.
sequelize
.
define
(
'User'
,
{
username
:
Sequelize
.
STRING
});
var
Task
=
this
.
sequelize
.
define
(
'Task'
,
{
title
:
Sequelize
.
STRING
});
var
Job
=
User
.
hasOne
(
Task
,
{
as
:
'job'
});
return
this
.
sequelize
.
sync
({
force
:
true
}).
then
(
function
()
{
return
User
.
create
({
username
:
'Muzzy'
,
job
:
{
title
:
'Eat Clocks'
}
},
{
include
:
[
Job
]
}).
then
(
function
(
savedUser
)
{
return
User
.
find
({
where
:
{
id
:
savedUser
.
id
},
include
:
[
Job
]
}).
then
(
function
(
persistedUser
)
{
expect
(
persistedUser
.
job
).
to
.
be
.
ok
;
});
});
});
});
it
(
'should create data for BelongsToMany relations'
,
function
()
{
var
User
=
this
.
sequelize
.
define
(
'User'
,
{
username
:
DataTypes
.
STRING
});
...
...
@@ -124,22 +215,19 @@ describe(Support.getTestDialectTeaser('Instance'), function() {
active
:
DataTypes
.
BOOLEAN
});
User
.
belongsToMany
(
Task
);
Task
.
belongsToMany
(
User
);
var
user
=
User
.
build
({
username
:
'John'
,
Tasks
:
[
{
title
:
'Get rich'
,
active
:
true
},
{
title
:
'Die trying'
,
active
:
false
}
]
},
{
include
:
[
Task
]
});
User
.
belongsToMany
(
Task
,
{
through
:
'user_task'
});
Task
.
belongsToMany
(
User
,
{
through
:
'user_task'
});
var
tasks
=
[];
return
this
.
sequelize
.
sync
({
force
:
true
}).
then
(
function
()
{
return
user
.
save
().
then
(
function
(
savedUser
)
{
return
User
.
create
({
username
:
'John'
,
Tasks
:
[
{
title
:
'Get rich'
,
active
:
true
},
{
title
:
'Die trying'
,
active
:
false
}
]
},
{
include
:
[
Task
]
}).
then
(
function
(
savedUser
)
{
return
User
.
find
({
where
:
{
id
:
savedUser
.
id
},
include
:
[
Task
]
...
...
@@ -151,6 +239,39 @@ describe(Support.getTestDialectTeaser('Instance'), function() {
});
});
it
(
'should create data for BelongsToMany relations with alias'
,
function
()
{
var
User
=
this
.
sequelize
.
define
(
'User'
,
{
username
:
DataTypes
.
STRING
});
var
Task
=
this
.
sequelize
.
define
(
'Task'
,
{
title
:
DataTypes
.
STRING
,
active
:
DataTypes
.
BOOLEAN
});
var
Jobs
=
User
.
belongsToMany
(
Task
,
{
through
:
'user_job'
,
as
:
'jobs'
});
Task
.
belongsToMany
(
User
,
{
through
:
'user_job'
});
return
this
.
sequelize
.
sync
({
force
:
true
}).
then
(
function
()
{
return
User
.
create
({
username
:
'John'
,
jobs
:
[
{
title
:
'Get rich'
,
active
:
true
},
{
title
:
'Die trying'
,
active
:
false
}
]
},
{
include
:
[
Jobs
]
}).
then
(
function
(
savedUser
)
{
return
User
.
find
({
where
:
{
id
:
savedUser
.
id
},
include
:
[
Jobs
]
}).
then
(
function
(
persistedUser
)
{
expect
(
persistedUser
.
jobs
).
to
.
be
.
ok
;
expect
(
persistedUser
.
jobs
.
length
).
to
.
equal
(
2
);
});
});
});
});
});
});
});
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