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 5b8fe6c5
authored
Jun 28, 2017
by
Ali Taheri Moghaddar
Committed by
Felix Becker
Jun 28, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix(indexes): fix composite index issue (#7854)
1 parent
38e8bd12
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
66 additions
and
39 deletions
lib/dialects/mssql/query-generator.js
lib/dialects/mysql/query-generator.js
lib/dialects/postgres/query-generator.js
lib/dialects/sqlite/query-generator.js
lib/model.js
lib/query-interface.js
test/integration/model/sync.test.js
test/unit/model/indexes.test.js
lib/dialects/mssql/query-generator.js
View file @
5b8fe6c
...
@@ -322,7 +322,7 @@ const QueryGenerator = {
...
@@ -322,7 +322,7 @@ const QueryGenerator = {
return
sql
;
return
sql
;
},
},
upsertQuery
(
tableName
,
insertValues
,
updateValues
,
where
,
rawAttributes
)
{
upsertQuery
(
tableName
,
insertValues
,
updateValues
,
where
,
model
)
{
const
targetTableAlias
=
this
.
quoteTable
(
`
${
tableName
}
_target`
);
const
targetTableAlias
=
this
.
quoteTable
(
`
${
tableName
}
_target`
);
const
sourceTableAlias
=
this
.
quoteTable
(
`
${
tableName
}
_source`
);
const
sourceTableAlias
=
this
.
quoteTable
(
`
${
tableName
}
_source`
);
const
primaryKeysAttrs
=
[];
const
primaryKeysAttrs
=
[];
...
@@ -333,15 +333,27 @@ const QueryGenerator = {
...
@@ -333,15 +333,27 @@ const QueryGenerator = {
//Obtain primaryKeys, uniquekeys and identity attrs from rawAttributes as model is not passed
//Obtain primaryKeys, uniquekeys and identity attrs from rawAttributes as model is not passed
for
(
const
key
in
rawAttributes
)
{
for
(
const
key
in
model
.
rawAttributes
)
{
if
(
rawAttributes
[
key
].
primaryKey
)
{
if
(
model
.
rawAttributes
[
key
].
primaryKey
)
{
primaryKeysAttrs
.
push
(
rawAttributes
[
key
].
field
||
key
);
primaryKeysAttrs
.
push
(
model
.
rawAttributes
[
key
].
field
||
key
);
}
}
if
(
rawAttributes
[
key
].
unique
)
{
if
(
model
.
rawAttributes
[
key
].
unique
)
{
uniqueAttrs
.
push
(
rawAttributes
[
key
].
field
||
key
);
uniqueAttrs
.
push
(
model
.
rawAttributes
[
key
].
field
||
key
);
}
}
if
(
rawAttributes
[
key
].
autoIncrement
)
{
if
(
model
.
rawAttributes
[
key
].
autoIncrement
)
{
identityAttrs
.
push
(
rawAttributes
[
key
].
field
||
key
);
identityAttrs
.
push
(
model
.
rawAttributes
[
key
].
field
||
key
);
}
}
//Add unique indexes defined by indexes option to uniqueAttrs
for
(
const
index
of
model
.
options
.
indexes
)
{
if
(
index
.
unique
&&
index
.
fields
)
{
for
(
const
field
of
index
.
fields
)
{
const
fieldName
=
typeof
field
===
'string'
?
field
:
field
.
name
||
field
.
attribute
;
if
(
uniqueAttrs
.
indexOf
(
fieldName
)
===
-
1
&&
model
.
rawAttributes
[
fieldName
])
{
uniqueAttrs
.
push
(
fieldName
);
}
}
}
}
}
}
...
...
lib/dialects/mysql/query-generator.js
View file @
5b8fe6c
...
@@ -150,7 +150,7 @@ const QueryGenerator = {
...
@@ -150,7 +150,7 @@ const QueryGenerator = {
return
`ALTER TABLE
${
this
.
quoteTable
(
tableName
)}
CHANGE
${
attrString
.
join
(
', '
)}
;`
;
return
`ALTER TABLE
${
this
.
quoteTable
(
tableName
)}
CHANGE
${
attrString
.
join
(
', '
)}
;`
;
},
},
upsertQuery
(
tableName
,
insertValues
,
updateValues
,
where
,
rawAttributes
,
options
)
{
upsertQuery
(
tableName
,
insertValues
,
updateValues
,
where
,
model
,
options
)
{
options
.
onDuplicate
=
'UPDATE '
;
options
.
onDuplicate
=
'UPDATE '
;
options
.
onDuplicate
+=
Object
.
keys
(
updateValues
).
map
(
key
=>
{
options
.
onDuplicate
+=
Object
.
keys
(
updateValues
).
map
(
key
=>
{
...
@@ -158,7 +158,7 @@ const QueryGenerator = {
...
@@ -158,7 +158,7 @@ const QueryGenerator = {
return
key
+
'=VALUES('
+
key
+
')'
;
return
key
+
'=VALUES('
+
key
+
')'
;
}).
join
(
', '
);
}).
join
(
', '
);
return
this
.
insertQuery
(
tableName
,
insertValues
,
rawAttributes
,
options
);
return
this
.
insertQuery
(
tableName
,
insertValues
,
model
.
rawAttributes
,
options
);
},
},
deleteQuery
(
tableName
,
where
,
options
)
{
deleteQuery
(
tableName
,
where
,
options
)
{
...
...
lib/dialects/postgres/query-generator.js
View file @
5b8fe6c
...
@@ -355,9 +355,9 @@ const QueryGenerator = {
...
@@ -355,9 +355,9 @@ const QueryGenerator = {
return
this
.
fn
(
fnName
,
tableName
,
body
,
returns
,
language
);
return
this
.
fn
(
fnName
,
tableName
,
body
,
returns
,
language
);
},
},
upsertQuery
(
tableName
,
insertValues
,
updateValues
,
where
,
rawAttributes
,
options
)
{
upsertQuery
(
tableName
,
insertValues
,
updateValues
,
where
,
model
,
options
)
{
const
insert
=
this
.
insertQuery
(
tableName
,
insertValues
,
rawAttributes
,
options
);
const
insert
=
this
.
insertQuery
(
tableName
,
insertValues
,
model
.
rawAttributes
,
options
);
const
update
=
this
.
updateQuery
(
tableName
,
updateValues
,
where
,
options
,
rawAttributes
);
const
update
=
this
.
updateQuery
(
tableName
,
updateValues
,
where
,
options
,
model
.
rawAttributes
);
// The numbers here are selected to match the number of affected rows returned by MySQL
// The numbers here are selected to match the number of affected rows returned by MySQL
return
this
.
exceptionFn
(
return
this
.
exceptionFn
(
...
...
lib/dialects/sqlite/query-generator.js
View file @
5b8fe6c
...
@@ -208,10 +208,10 @@ const QueryGenerator = {
...
@@ -208,10 +208,10 @@ const QueryGenerator = {
return
"SELECT name FROM `sqlite_master` WHERE type='table' and name!='sqlite_sequence';"
;
return
"SELECT name FROM `sqlite_master` WHERE type='table' and name!='sqlite_sequence';"
;
},
},
upsertQuery
(
tableName
,
insertValues
,
updateValues
,
where
,
rawAttributes
,
options
)
{
upsertQuery
(
tableName
,
insertValues
,
updateValues
,
where
,
model
,
options
)
{
options
.
ignoreDuplicates
=
true
;
options
.
ignoreDuplicates
=
true
;
const
sql
=
this
.
insertQuery
(
tableName
,
insertValues
,
rawAttributes
,
options
)
+
' '
+
this
.
updateQuery
(
tableName
,
updateValues
,
where
,
options
,
rawAttributes
);
const
sql
=
this
.
insertQuery
(
tableName
,
insertValues
,
model
.
rawAttributes
,
options
)
+
' '
+
this
.
updateQuery
(
tableName
,
updateValues
,
where
,
options
,
model
.
rawAttributes
);
return
sql
;
return
sql
;
},
},
...
...
lib/model.js
View file @
5b8fe6c
...
@@ -843,20 +843,7 @@ class Model {
...
@@ -843,20 +843,7 @@ class Model {
}
}
});
});
this
.
options
.
indexes
=
this
.
options
.
indexes
.
map
(
index
=>
{
this
.
options
.
indexes
=
this
.
options
.
indexes
.
map
(
this
.
_conformIndex
);
index
=
this
.
_conformIndex
(
index
);
//Add unique indexes to rawAttributes
if
(
index
.
unique
&&
index
.
fields
)
{
for
(
const
field
of
index
.
fields
)
{
const
fieldName
=
typeof
field
===
'string'
?
field
:
field
.
name
||
field
.
attribute
;
if
(
this
.
rawAttributes
[
fieldName
])
{
this
.
rawAttributes
[
fieldName
].
unique
=
this
.
attributes
[
fieldName
].
unique
=
index
.
name
||
index
.
unique
;
}
}
}
return
index
;
});
this
.
sequelize
.
modelManager
.
addModel
(
this
);
this
.
sequelize
.
modelManager
.
addModel
(
this
);
...
...
lib/query-interface.js
View file @
5b8fe6c
...
@@ -572,7 +572,7 @@ class QueryInterface {
...
@@ -572,7 +572,7 @@ class QueryInterface {
options
.
type
=
QueryTypes
.
UPSERT
;
options
.
type
=
QueryTypes
.
UPSERT
;
options
.
raw
=
true
;
options
.
raw
=
true
;
const
sql
=
this
.
QueryGenerator
.
upsertQuery
(
tableName
,
valuesByField
,
updateValues
,
where
,
model
.
rawAttributes
,
options
);
const
sql
=
this
.
QueryGenerator
.
upsertQuery
(
tableName
,
valuesByField
,
updateValues
,
where
,
model
,
options
);
return
this
.
sequelize
.
query
(
sql
,
options
).
then
(
rowCount
=>
{
return
this
.
sequelize
.
query
(
sql
,
options
).
then
(
rowCount
=>
{
if
(
rowCount
===
undefined
)
{
if
(
rowCount
===
undefined
)
{
return
rowCount
;
return
rowCount
;
...
...
test/integration/model/sync.test.js
View file @
5b8fe6c
...
@@ -79,5 +79,37 @@ describe(Support.getTestDialectTeaser('Model'), () => {
...
@@ -79,5 +79,37 @@ describe(Support.getTestDialectTeaser('Model'), () => {
expect
(
data
.
dataValues
.
age
).
to
.
eql
(
'1'
);
expect
(
data
.
dataValues
.
age
).
to
.
eql
(
'1'
);
});
});
});
});
it
(
'should properly create composite index without affecting individual fields'
,
function
()
{
const
testSync
=
this
.
sequelize
.
define
(
'testSync'
,
{
name
:
Sequelize
.
STRING
,
age
:
Sequelize
.
STRING
},
{
indexes
:
[{
unique
:
true
,
fields
:
[
'name'
,
'age'
]}]});
return
this
.
sequelize
.
sync
()
.
then
(()
=>
testSync
.
create
({
name
:
'test'
}))
.
then
(()
=>
testSync
.
create
({
name
:
'test2'
}))
.
then
(()
=>
testSync
.
create
({
name
:
'test3'
}))
.
then
(()
=>
testSync
.
create
({
age
:
'1'
}))
.
then
(()
=>
testSync
.
create
({
age
:
'2'
}))
.
then
(()
=>
testSync
.
create
({
name
:
'test'
,
age
:
'1'
}))
.
then
(()
=>
testSync
.
create
({
name
:
'test'
,
age
:
'2'
}))
.
then
(()
=>
testSync
.
create
({
name
:
'test2'
,
age
:
'2'
}))
.
then
(()
=>
testSync
.
create
({
name
:
'test3'
,
age
:
'2'
}))
.
then
(()
=>
testSync
.
create
({
name
:
'test3'
,
age
:
'1'
}))
.
then
(
data
=>
{
expect
(
data
.
dataValues
.
name
).
to
.
eql
(
'test3'
);
expect
(
data
.
dataValues
.
age
).
to
.
eql
(
'1'
);
});
});
it
(
'should properly create composite index that fails on constraint violation'
,
function
()
{
const
testSync
=
this
.
sequelize
.
define
(
'testSync'
,
{
name
:
Sequelize
.
STRING
,
age
:
Sequelize
.
STRING
},
{
indexes
:
[{
unique
:
true
,
fields
:
[
'name'
,
'age'
]}]});
return
this
.
sequelize
.
sync
()
.
then
(()
=>
testSync
.
create
({
name
:
'test'
,
age
:
'1'
}))
.
then
(()
=>
testSync
.
create
({
name
:
'test'
,
age
:
'1'
}))
.
then
(
data
=>
expect
(
data
).
not
.
to
.
be
.
ok
,
error
=>
expect
(
error
).
to
.
be
.
ok
);
});
});
});
});
});
test/unit/model/indexes.test.js
View file @
5b8fe6c
...
@@ -39,7 +39,7 @@ describe(Support.getTestDialectTeaser('Model'), () => {
...
@@ -39,7 +39,7 @@ describe(Support.getTestDialectTeaser('Model'), () => {
expect
(
Model
.
options
.
indexes
[
1
].
unique
).
to
.
eql
(
true
);
expect
(
Model
.
options
.
indexes
[
1
].
unique
).
to
.
eql
(
true
);
});
});
it
(
'should set rawAttributes when indexes are defined via options'
,
()
=>
{
it
(
'should
not
set rawAttributes when indexes are defined via options'
,
()
=>
{
const
User
=
current
.
define
(
'User'
,
{
const
User
=
current
.
define
(
'User'
,
{
username
:
DataTypes
.
STRING
username
:
DataTypes
.
STRING
},
{
},
{
...
@@ -49,11 +49,10 @@ describe(Support.getTestDialectTeaser('Model'), () => {
...
@@ -49,11 +49,10 @@ describe(Support.getTestDialectTeaser('Model'), () => {
}]
}]
});
});
expect
(
User
.
rawAttributes
.
username
).
to
.
have
.
property
(
'unique'
);
expect
(
User
.
rawAttributes
.
username
.
unique
).
to
.
be
.
undefined
;
expect
(
User
.
rawAttributes
.
username
.
unique
).
to
.
be
.
true
;
});
});
it
(
'should set rawAttributes when composite unique indexes are defined via options'
,
()
=>
{
it
(
'should
not
set rawAttributes when composite unique indexes are defined via options'
,
()
=>
{
const
User
=
current
.
define
(
'User'
,
{
const
User
=
current
.
define
(
'User'
,
{
name
:
DataTypes
.
STRING
,
name
:
DataTypes
.
STRING
,
address
:
DataTypes
.
STRING
address
:
DataTypes
.
STRING
...
@@ -64,11 +63,8 @@ describe(Support.getTestDialectTeaser('Model'), () => {
...
@@ -64,11 +63,8 @@ describe(Support.getTestDialectTeaser('Model'), () => {
}]
}]
});
});
expect
(
User
.
rawAttributes
.
name
).
to
.
have
.
property
(
'unique'
);
expect
(
User
.
rawAttributes
.
name
.
unique
).
to
.
be
.
undefined
;
expect
(
User
.
rawAttributes
.
name
.
unique
).
to
.
be
.
equal
(
'users_name_address'
);
expect
(
User
.
rawAttributes
.
address
.
unique
).
to
.
be
.
undefined
;
expect
(
User
.
rawAttributes
.
address
).
to
.
have
.
property
(
'unique'
);
expect
(
User
.
rawAttributes
.
address
.
unique
).
to
.
be
.
equal
(
'users_name_address'
);
});
});
});
});
});
});
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