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 bce3d9aa
authored
May 30, 2018
by
Gareth Oakley
Committed by
Sushant
May 30, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(query-generator): Generate INSERTs using bind parameters (#9431)
1 parent
b05abdd4
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
390 additions
and
100 deletions
lib/data-types.js
lib/dialects/abstract/query-generator.js
lib/dialects/mssql/query.js
lib/dialects/postgres/data-types.js
lib/dialects/postgres/query-generator.js
lib/dialects/sqlite/query-generator.js
test/integration/data-types.test.js
test/integration/dialects/postgres/dao.test.js
test/integration/json.test.js
test/integration/model/create.test.js
test/support.js
test/unit/dialects/abstract/query-generator.test.js
test/unit/dialects/mysql/query-generator.test.js
test/unit/dialects/postgres/data-types.test.js
test/unit/dialects/postgres/query-generator.test.js
test/unit/dialects/sqlite/query-generator.test.js
test/unit/sql/insert.test.js
lib/data-types.js
View file @
bce3d9a
...
@@ -33,6 +33,12 @@ ABSTRACT.prototype.stringify = function stringify(value, options) {
...
@@ -33,6 +33,12 @@ ABSTRACT.prototype.stringify = function stringify(value, options) {
}
}
return
value
;
return
value
;
};
};
ABSTRACT
.
prototype
.
bindParam
=
function
bindParam
(
value
,
options
)
{
if
(
this
.
_bindParam
)
{
return
this
.
_bindParam
(
value
,
options
);
}
return
options
.
bindParam
(
this
.
stringify
(
value
,
options
));
};
function
STRING
(
length
,
binary
)
{
function
STRING
(
length
,
binary
)
{
const
options
=
typeof
length
===
'object'
&&
length
||
{
length
,
binary
};
const
options
=
typeof
length
===
'object'
&&
length
||
{
length
,
binary
};
...
@@ -274,16 +280,22 @@ DECIMAL.prototype.validate = function validate(value) {
...
@@ -274,16 +280,22 @@ DECIMAL.prototype.validate = function validate(value) {
for
(
const
floating
of
[
FLOAT
,
DOUBLE
,
REAL
])
{
for
(
const
floating
of
[
FLOAT
,
DOUBLE
,
REAL
])
{
floating
.
prototype
.
escape
=
false
;
floating
.
prototype
.
escape
=
false
;
floating
.
prototype
.
_
stringify
=
function
_stringify
(
value
)
{
floating
.
prototype
.
_
value
=
function
_value
(
value
)
{
if
(
isNaN
(
value
))
{
if
(
isNaN
(
value
))
{
return
"'NaN'"
;
return
'NaN'
;
}
else
if
(
!
isFinite
(
value
))
{
}
else
if
(
!
isFinite
(
value
))
{
const
sign
=
value
<
0
?
'-'
:
''
;
const
sign
=
value
<
0
?
'-'
:
''
;
return
"'"
+
sign
+
"Infinity'"
;
return
sign
+
'Infinity'
;
}
}
return
value
;
return
value
;
};
};
floating
.
prototype
.
_stringify
=
function
_stringify
(
value
)
{
return
"'"
+
this
.
_value
(
value
)
+
"'"
;
};
floating
.
prototype
.
_bindParam
=
function
_bindParam
(
value
,
options
)
{
return
options
.
bindParam
(
this
.
_value
(
value
));
};
}
}
function
BOOLEAN
()
{
function
BOOLEAN
()
{
...
@@ -529,6 +541,17 @@ BLOB.prototype._hexify = function _hexify(hex) {
...
@@ -529,6 +541,17 @@ BLOB.prototype._hexify = function _hexify(hex) {
return
"X'"
+
hex
+
"'"
;
return
"X'"
+
hex
+
"'"
;
};
};
BLOB
.
prototype
.
_bindParam
=
function
_bindParam
(
value
,
options
)
{
if
(
!
Buffer
.
isBuffer
(
value
))
{
if
(
Array
.
isArray
(
value
))
{
value
=
Buffer
.
from
(
value
);
}
else
{
value
=
Buffer
.
from
(
value
.
toString
());
}
}
return
options
.
bindParam
(
value
);
};
function
RANGE
(
subtype
)
{
function
RANGE
(
subtype
)
{
const
options
=
_
.
isPlainObject
(
subtype
)
?
subtype
:
{
subtype
};
const
options
=
_
.
isPlainObject
(
subtype
)
?
subtype
:
{
subtype
};
...
@@ -703,6 +726,9 @@ GEOMETRY.prototype.escape = false;
...
@@ -703,6 +726,9 @@ GEOMETRY.prototype.escape = false;
GEOMETRY
.
prototype
.
_stringify
=
function
_stringify
(
value
,
options
)
{
GEOMETRY
.
prototype
.
_stringify
=
function
_stringify
(
value
,
options
)
{
return
'GeomFromText('
+
options
.
escape
(
Wkt
.
convert
(
value
))
+
')'
;
return
'GeomFromText('
+
options
.
escape
(
Wkt
.
convert
(
value
))
+
')'
;
};
};
GEOMETRY
.
prototype
.
_bindParam
=
function
_bindParam
(
value
,
options
)
{
return
'GeomFromText('
+
options
.
bindParam
(
Wkt
.
convert
(
value
))
+
')'
;
};
function
GEOGRAPHY
(
type
,
srid
)
{
function
GEOGRAPHY
(
type
,
srid
)
{
const
options
=
_
.
isPlainObject
(
type
)
?
type
:
{
type
,
srid
};
const
options
=
_
.
isPlainObject
(
type
)
?
type
:
{
type
,
srid
};
...
@@ -721,6 +747,9 @@ GEOGRAPHY.prototype.escape = false;
...
@@ -721,6 +747,9 @@ GEOGRAPHY.prototype.escape = false;
GEOGRAPHY
.
prototype
.
_stringify
=
function
_stringify
(
value
,
options
)
{
GEOGRAPHY
.
prototype
.
_stringify
=
function
_stringify
(
value
,
options
)
{
return
'GeomFromText('
+
options
.
escape
(
Wkt
.
convert
(
value
))
+
')'
;
return
'GeomFromText('
+
options
.
escape
(
Wkt
.
convert
(
value
))
+
')'
;
};
};
GEOGRAPHY
.
prototype
.
_bindParam
=
function
_bindParam
(
value
,
options
)
{
return
'GeomFromText('
+
options
.
bindParam
(
Wkt
.
convert
(
value
))
+
')'
;
};
for
(
const
helper
of
Object
.
keys
(
helpers
))
{
for
(
const
helper
of
Object
.
keys
(
helpers
))
{
for
(
const
DataType
of
helpers
[
helper
])
{
for
(
const
DataType
of
helpers
[
helper
])
{
...
...
lib/dialects/abstract/query-generator.js
View file @
bce3d9a
...
@@ -106,6 +106,8 @@ class QueryGenerator {
...
@@ -106,6 +106,8 @@ class QueryGenerator {
const
modelAttributeMap
=
{};
const
modelAttributeMap
=
{};
const
fields
=
[];
const
fields
=
[];
const
values
=
[];
const
values
=
[];
const
bind
=
[];
const
bindParam
=
this
.
bindParam
(
bind
);
let
query
;
let
query
;
let
valueQuery
=
'<%= tmpTable %>INSERT<%= ignoreDuplicates %> INTO <%= table %> (<%= attributes %>)<%= output %> VALUES (<%= values %>)'
;
let
valueQuery
=
'<%= tmpTable %>INSERT<%= ignoreDuplicates %> INTO <%= table %> (<%= attributes %>)<%= output %> VALUES (<%= values %>)'
;
let
emptyQuery
=
'<%= tmpTable %>INSERT<%= ignoreDuplicates %> INTO <%= table %><%= output %>'
;
let
emptyQuery
=
'<%= tmpTable %>INSERT<%= ignoreDuplicates %> INTO <%= table %><%= output %>'
;
...
@@ -169,7 +171,14 @@ class QueryGenerator {
...
@@ -169,7 +171,14 @@ class QueryGenerator {
}
}
}
}
if
(
_
.
get
(
this
,
[
'sequelize'
,
'options'
,
'dialectOptions'
,
'prependSearchPath'
])
||
options
.
searchPath
)
{
// Not currently supported with search path (requires output of multiple queries)
options
.
bindParam
=
false
;
}
if
(
this
.
_dialect
.
supports
.
EXCEPTION
&&
options
.
exception
)
{
if
(
this
.
_dialect
.
supports
.
EXCEPTION
&&
options
.
exception
)
{
// Not currently supported with bind parameters (requires output of multiple queries)
options
.
bindParam
=
false
;
// Mostly for internal use, so we expect the user to know what he's doing!
// Mostly for internal use, so we expect the user to know what he's doing!
// pg_temp functions are private per connection, so we never risk this function interfering with another one.
// pg_temp functions are private per connection, so we never risk this function interfering with another one.
if
(
semver
.
gte
(
this
.
sequelize
.
options
.
databaseVersion
,
'9.2.0'
))
{
if
(
semver
.
gte
(
this
.
sequelize
.
options
.
databaseVersion
,
'9.2.0'
))
{
...
@@ -211,7 +220,11 @@ class QueryGenerator {
...
@@ -211,7 +220,11 @@ class QueryGenerator {
identityWrapperRequired
=
true
;
identityWrapperRequired
=
true
;
}
}
if
(
value
instanceof
Utils
.
SequelizeMethod
||
options
.
bindParam
===
false
)
{
values
.
push
(
this
.
escape
(
value
,
modelAttributeMap
&&
modelAttributeMap
[
key
]
||
undefined
,
{
context
:
'INSERT'
}));
values
.
push
(
this
.
escape
(
value
,
modelAttributeMap
&&
modelAttributeMap
[
key
]
||
undefined
,
{
context
:
'INSERT'
}));
}
else
{
values
.
push
(
this
.
format
(
value
,
modelAttributeMap
&&
modelAttributeMap
[
key
]
||
undefined
,
{
context
:
'INSERT'
},
bindParam
));
}
}
}
}
}
}
}
...
@@ -234,7 +247,13 @@ class QueryGenerator {
...
@@ -234,7 +247,13 @@ class QueryGenerator {
].
join
(
' '
);
].
join
(
' '
);
}
}
return
_
.
template
(
query
,
this
.
_templateSettings
)(
replacements
);
query
=
_
.
template
(
query
,
this
.
_templateSettings
)(
replacements
);
// Used by Postgres upsertQuery and calls to here with options.exception set to true
const
result
=
{
query
};
if
(
options
.
bindParam
!==
false
)
{
result
.
bind
=
bind
;
}
return
result
;
}
}
/**
/**
...
@@ -967,15 +986,7 @@ class QueryGenerator {
...
@@ -967,15 +986,7 @@ class QueryGenerator {
return
this
.
handleSequelizeMethod
(
value
);
return
this
.
handleSequelizeMethod
(
value
);
}
else
{
}
else
{
if
(
field
&&
field
.
type
)
{
if
(
field
&&
field
.
type
)
{
if
(
this
.
typeValidation
&&
field
.
type
.
validate
&&
value
)
{
this
.
validate
(
value
,
field
,
options
);
if
(
options
.
isList
&&
Array
.
isArray
(
value
))
{
for
(
const
item
of
value
)
{
field
.
type
.
validate
(
item
,
options
);
}
}
else
{
field
.
type
.
validate
(
value
,
options
);
}
}
if
(
field
.
type
.
stringify
)
{
if
(
field
.
type
.
stringify
)
{
// Users shouldn't have to worry about these args - just give them a function that takes a single arg
// Users shouldn't have to worry about these args - just give them a function that takes a single arg
...
@@ -995,6 +1006,53 @@ class QueryGenerator {
...
@@ -995,6 +1006,53 @@ class QueryGenerator {
return
SqlString
.
escape
(
value
,
this
.
options
.
timezone
,
this
.
dialect
);
return
SqlString
.
escape
(
value
,
this
.
options
.
timezone
,
this
.
dialect
);
}
}
bindParam
(
bind
)
{
return
value
=>
{
bind
.
push
(
value
);
return
'$'
+
bind
.
length
;
};
}
/*
Returns a bind parameter representation of a value (e.g. a string, number or date)
@private
*/
format
(
value
,
field
,
options
,
bindParam
)
{
options
=
options
||
{};
if
(
value
!==
null
&&
value
!==
undefined
)
{
if
(
value
instanceof
Utils
.
SequelizeMethod
)
{
throw
new
Error
(
'Cannot pass SequelizeMethod as a bind parameter - use escape instead'
);
}
else
{
if
(
field
&&
field
.
type
)
{
this
.
validate
(
value
,
field
,
options
);
if
(
field
.
type
.
bindParam
)
{
return
field
.
type
.
bindParam
(
value
,
{
escape
:
_
.
identity
,
field
,
timezone
:
this
.
options
.
timezone
,
operation
:
options
.
operation
,
bindParam
});
}
}
}
}
return
bindParam
(
value
);
}
/*
Validate a value against a field specification
@private
*/
validate
(
value
,
field
,
options
)
{
if
(
this
.
typeValidation
&&
field
.
type
.
validate
&&
value
)
{
if
(
options
.
isList
&&
Array
.
isArray
(
value
))
{
for
(
const
item
of
value
)
{
field
.
type
.
validate
(
item
,
options
);
}
}
else
{
field
.
type
.
validate
(
value
,
options
);
}
}
}
isIdentifierQuoted
(
identifier
)
{
isIdentifierQuoted
(
identifier
)
{
return
QuoteHelper
.
isIdentifierQuoted
(
identifier
);
return
QuoteHelper
.
isIdentifierQuoted
(
identifier
);
}
}
...
...
lib/dialects/mssql/query.js
View file @
bce3d9a
...
@@ -41,6 +41,9 @@ class Query extends AbstractQuery {
...
@@ -41,6 +41,9 @@ class Query extends AbstractQuery {
paramType
.
typeOptions
=
{
precision
:
30
,
scale
:
15
};
paramType
.
typeOptions
=
{
precision
:
30
,
scale
:
15
};
}
}
}
}
if
(
Buffer
.
isBuffer
(
value
))
{
paramType
.
type
=
TYPES
.
VarBinary
;
}
return
paramType
;
return
paramType
;
}
}
...
...
lib/dialects/postgres/data-types.js
View file @
bce3d9a
...
@@ -433,6 +433,9 @@ module.exports = BaseTypes => {
...
@@ -433,6 +433,9 @@ module.exports = BaseTypes => {
GEOMETRY
.
prototype
.
_stringify
=
function
_stringify
(
value
,
options
)
{
GEOMETRY
.
prototype
.
_stringify
=
function
_stringify
(
value
,
options
)
{
return
'ST_GeomFromGeoJSON('
+
options
.
escape
(
JSON
.
stringify
(
value
))
+
')'
;
return
'ST_GeomFromGeoJSON('
+
options
.
escape
(
JSON
.
stringify
(
value
))
+
')'
;
};
};
GEOMETRY
.
prototype
.
_bindParam
=
function
_bindParam
(
value
,
options
)
{
return
'ST_GeomFromGeoJSON('
+
options
.
bindParam
(
value
)
+
')'
;
};
function
GEOGRAPHY
(
type
,
srid
)
{
function
GEOGRAPHY
(
type
,
srid
)
{
if
(
!
(
this
instanceof
GEOGRAPHY
))
return
new
GEOGRAPHY
(
type
,
srid
);
if
(
!
(
this
instanceof
GEOGRAPHY
))
return
new
GEOGRAPHY
(
type
,
srid
);
...
@@ -469,6 +472,9 @@ module.exports = BaseTypes => {
...
@@ -469,6 +472,9 @@ module.exports = BaseTypes => {
GEOGRAPHY
.
prototype
.
_stringify
=
function
_stringify
(
value
,
options
)
{
GEOGRAPHY
.
prototype
.
_stringify
=
function
_stringify
(
value
,
options
)
{
return
'ST_GeomFromGeoJSON('
+
options
.
escape
(
JSON
.
stringify
(
value
))
+
')'
;
return
'ST_GeomFromGeoJSON('
+
options
.
escape
(
JSON
.
stringify
(
value
))
+
')'
;
};
};
GEOGRAPHY
.
prototype
.
bindParam
=
function
bindParam
(
value
,
options
)
{
return
'ST_GeomFromGeoJSON('
+
options
.
bindParam
(
value
)
+
')'
;
};
let
hstore
;
let
hstore
;
function
HSTORE
()
{
function
HSTORE
()
{
...
@@ -491,12 +497,18 @@ module.exports = BaseTypes => {
...
@@ -491,12 +497,18 @@ module.exports = BaseTypes => {
};
};
HSTORE
.
prototype
.
escape
=
false
;
HSTORE
.
prototype
.
escape
=
false
;
HSTORE
.
prototype
.
_
stringify
=
function
_stringify
(
value
)
{
HSTORE
.
prototype
.
_
value
=
function
_value
(
value
)
{
if
(
!
hstore
)
{
if
(
!
hstore
)
{
// All datatype files are loaded at import - make sure we don't load the hstore parser before a hstore is instantiated
// All datatype files are loaded at import - make sure we don't load the hstore parser before a hstore is instantiated
hstore
=
require
(
'./hstore'
);
hstore
=
require
(
'./hstore'
);
}
}
return
"'"
+
hstore
.
stringify
(
value
)
+
"'"
;
return
hstore
.
stringify
(
value
);
};
HSTORE
.
prototype
.
_stringify
=
function
_stringify
(
value
)
{
return
"'"
+
this
.
_value
(
value
)
+
"'"
;
};
HSTORE
.
prototype
.
_bindParam
=
function
_bindParam
(
value
,
options
)
{
return
options
.
bindParam
(
this
.
_value
(
value
));
};
};
BaseTypes
.
HSTORE
.
types
.
postgres
=
{
BaseTypes
.
HSTORE
.
types
.
postgres
=
{
...
@@ -533,10 +545,9 @@ module.exports = BaseTypes => {
...
@@ -533,10 +545,9 @@ module.exports = BaseTypes => {
};
};
RANGE
.
prototype
.
escape
=
false
;
RANGE
.
prototype
.
escape
=
false
;
RANGE
.
prototype
.
_
stringify
=
function
_stringify
(
values
,
options
)
{
RANGE
.
prototype
.
_
value
=
function
_value
(
values
,
options
)
{
if
(
!
Array
.
isArray
(
values
))
{
if
(
!
Array
.
isArray
(
values
))
{
return
"'"
+
this
.
options
.
subtype
.
stringify
(
values
,
options
)
+
"'::"
+
return
this
.
options
.
subtype
.
stringify
(
values
,
options
);
this
.
toCastType
();
}
}
const
valueInclusivity
=
[
true
,
false
];
const
valueInclusivity
=
[
true
,
false
];
...
@@ -560,7 +571,21 @@ module.exports = BaseTypes => {
...
@@ -560,7 +571,21 @@ module.exports = BaseTypes => {
// Array.map does not preserve extra array properties
// Array.map does not preserve extra array properties
valuesStringified
.
inclusive
=
valueInclusivity
;
valuesStringified
.
inclusive
=
valueInclusivity
;
return
'\''
+
range
.
stringify
(
valuesStringified
)
+
'\''
;
return
range
.
stringify
(
valuesStringified
);
};
RANGE
.
prototype
.
_stringify
=
function
_stringify
(
values
,
options
)
{
const
value
=
this
.
_value
(
values
,
options
);
if
(
!
Array
.
isArray
(
values
))
{
return
`'
${
value
}
'::`
+
this
.
toCastType
();
}
return
`'
${
value
}
'`
;
};
RANGE
.
prototype
.
_bindParam
=
function
_bindParam
(
values
,
options
)
{
const
value
=
this
.
_value
(
values
,
options
);
if
(
!
Array
.
isArray
(
values
))
{
return
options
.
bindParam
(
value
)
+
'::'
+
this
.
toCastType
();
}
return
options
.
bindParam
(
value
);
};
};
BaseTypes
.
RANGE
.
types
.
postgres
=
{
BaseTypes
.
RANGE
.
types
.
postgres
=
{
...
@@ -569,8 +594,11 @@ module.exports = BaseTypes => {
...
@@ -569,8 +594,11 @@ module.exports = BaseTypes => {
};
};
BaseTypes
.
ARRAY
.
prototype
.
escape
=
false
;
BaseTypes
.
ARRAY
.
prototype
.
escape
=
false
;
BaseTypes
.
ARRAY
.
prototype
.
_stringify
=
function
_stringify
(
values
,
options
)
{
BaseTypes
.
ARRAY
.
prototype
.
_value
=
function
_value
(
values
,
options
)
{
let
str
=
'ARRAY['
+
values
.
map
(
value
=>
{
return
values
.
map
(
value
=>
{
if
(
options
&&
options
.
bindParam
&&
this
.
type
&&
this
.
type
.
_value
)
{
return
this
.
type
.
_value
(
value
,
options
);
}
if
(
this
.
type
&&
this
.
type
.
stringify
)
{
if
(
this
.
type
&&
this
.
type
.
stringify
)
{
value
=
this
.
type
.
stringify
(
value
,
options
);
value
=
this
.
type
.
stringify
(
value
,
options
);
...
@@ -579,7 +607,10 @@ module.exports = BaseTypes => {
...
@@ -579,7 +607,10 @@ module.exports = BaseTypes => {
}
}
}
}
return
options
.
escape
(
value
);
return
options
.
escape
(
value
);
},
this
).
join
(
','
)
+
']'
;
},
this
);
};
BaseTypes
.
ARRAY
.
prototype
.
_stringify
=
function
_stringify
(
values
,
options
)
{
let
str
=
'ARRAY['
+
this
.
_value
(
values
,
options
).
join
(
','
)
+
']'
;
if
(
this
.
type
)
{
if
(
this
.
type
)
{
const
Utils
=
require
(
'../../utils'
);
const
Utils
=
require
(
'../../utils'
);
...
@@ -597,6 +628,9 @@ module.exports = BaseTypes => {
...
@@ -597,6 +628,9 @@ module.exports = BaseTypes => {
return
str
;
return
str
;
};
};
BaseTypes
.
ARRAY
.
prototype
.
_bindParam
=
function
_bindParam
(
values
,
options
)
{
return
options
.
bindParam
(
this
.
_value
(
values
,
options
));
};
function
ENUM
(
options
)
{
function
ENUM
(
options
)
{
if
(
!
(
this
instanceof
ENUM
))
return
new
ENUM
(
options
);
if
(
!
(
this
instanceof
ENUM
))
return
new
ENUM
(
options
);
...
...
lib/dialects/postgres/query-generator.js
View file @
bce3d9a
...
@@ -344,17 +344,18 @@ class PostgresQueryGenerator extends AbstractQueryGenerator {
...
@@ -344,17 +344,18 @@ class PostgresQueryGenerator extends AbstractQueryGenerator {
upsertQuery
(
tableName
,
insertValues
,
updateValues
,
where
,
model
,
options
)
{
upsertQuery
(
tableName
,
insertValues
,
updateValues
,
where
,
model
,
options
)
{
const
primaryField
=
this
.
quoteIdentifier
(
model
.
primaryKeyField
);
const
primaryField
=
this
.
quoteIdentifier
(
model
.
primaryKeyField
);
let
insert
=
this
.
insertQuery
(
tableName
,
insertValues
,
model
.
rawAttributes
,
options
);
const
insertOptions
=
_
.
defaults
({
bindParam
:
false
},
options
);
const
insert
=
this
.
insertQuery
(
tableName
,
insertValues
,
model
.
rawAttributes
,
insertOptions
);
let
update
=
this
.
updateQuery
(
tableName
,
updateValues
,
where
,
options
,
model
.
rawAttributes
);
let
update
=
this
.
updateQuery
(
tableName
,
updateValues
,
where
,
options
,
model
.
rawAttributes
);
insert
=
insert
.
replace
(
'RETURNING *'
,
`RETURNING
${
primaryField
}
INTO primary_key`
);
insert
.
query
=
insert
.
query
.
replace
(
'RETURNING *'
,
`RETURNING
${
primaryField
}
INTO primary_key`
);
update
=
update
.
replace
(
'RETURNING *'
,
`RETURNING
${
primaryField
}
INTO primary_key`
);
update
=
update
.
replace
(
'RETURNING *'
,
`RETURNING
${
primaryField
}
INTO primary_key`
);
return
this
.
exceptionFn
(
return
this
.
exceptionFn
(
'sequelize_upsert'
,
'sequelize_upsert'
,
tableName
,
tableName
,
'OUT created boolean, OUT primary_key text'
,
'OUT created boolean, OUT primary_key text'
,
`
${
insert
}
created := true;`
,
`
${
insert
.
query
}
created := true;`
,
`
${
update
}
; created := false`
`
${
update
}
; created := false`
);
);
}
}
...
...
lib/dialects/sqlite/query-generator.js
View file @
bce3d9a
...
@@ -200,9 +200,13 @@ class SQLiteQueryGenerator extends MySqlQueryGenerator {
...
@@ -200,9 +200,13 @@ class SQLiteQueryGenerator extends MySqlQueryGenerator {
upsertQuery
(
tableName
,
insertValues
,
updateValues
,
where
,
model
,
options
)
{
upsertQuery
(
tableName
,
insertValues
,
updateValues
,
where
,
model
,
options
)
{
options
.
ignoreDuplicates
=
true
;
options
.
ignoreDuplicates
=
true
;
const
sql
=
this
.
insertQuery
(
tableName
,
insertValues
,
model
.
rawAttributes
,
options
)
+
' '
+
this
.
updateQuery
(
tableName
,
updateValues
,
where
,
options
,
model
.
rawAttributes
);
const
insert
=
this
.
insertQuery
(
tableName
,
insertValues
,
model
.
rawAttributes
,
options
);
const
update
=
this
.
updateQuery
(
tableName
,
updateValues
,
where
,
options
,
model
.
rawAttributes
);
return
sql
;
const
query
=
insert
.
query
+
' '
+
update
;
const
bind
=
insert
.
bind
;
return
{
query
,
bind
};
}
}
updateQuery
(
tableName
,
attrValueHash
,
where
,
options
,
attributes
)
{
updateQuery
(
tableName
,
attrValueHash
,
where
,
options
,
attributes
)
{
...
...
test/integration/data-types.test.js
View file @
bce3d9a
...
@@ -57,7 +57,7 @@ describe(Support.getTestDialectTeaser('DataTypes'), () => {
...
@@ -57,7 +57,7 @@ describe(Support.getTestDialectTeaser('DataTypes'), () => {
});
});
});
});
const
testSuccess
=
function
(
Type
,
value
)
{
const
testSuccess
=
function
(
Type
,
value
,
options
)
{
const
parse
=
Type
.
constructor
.
parse
=
sinon
.
spy
(
value
=>
{
const
parse
=
Type
.
constructor
.
parse
=
sinon
.
spy
(
value
=>
{
return
value
;
return
value
;
});
});
...
@@ -65,6 +65,12 @@ describe(Support.getTestDialectTeaser('DataTypes'), () => {
...
@@ -65,6 +65,12 @@ describe(Support.getTestDialectTeaser('DataTypes'), () => {
const
stringify
=
Type
.
constructor
.
prototype
.
stringify
=
sinon
.
spy
(
function
()
{
const
stringify
=
Type
.
constructor
.
prototype
.
stringify
=
sinon
.
spy
(
function
()
{
return
Sequelize
.
ABSTRACT
.
prototype
.
stringify
.
apply
(
this
,
arguments
);
return
Sequelize
.
ABSTRACT
.
prototype
.
stringify
.
apply
(
this
,
arguments
);
});
});
let
bindParam
;
if
(
options
&&
options
.
useBindParam
)
{
bindParam
=
Type
.
constructor
.
prototype
.
bindParam
=
sinon
.
spy
(
function
()
{
return
Sequelize
.
ABSTRACT
.
prototype
.
bindParam
.
apply
(
this
,
arguments
);
});
}
const
User
=
current
.
define
(
'user'
,
{
const
User
=
current
.
define
(
'user'
,
{
field
:
Type
field
:
Type
...
@@ -83,10 +89,17 @@ describe(Support.getTestDialectTeaser('DataTypes'), () => {
...
@@ -83,10 +89,17 @@ describe(Support.getTestDialectTeaser('DataTypes'), () => {
return
User
.
findAll
().
get
(
0
);
return
User
.
findAll
().
get
(
0
);
}).
then
(()
=>
{
}).
then
(()
=>
{
expect
(
parse
).
to
.
have
.
been
.
called
;
expect
(
parse
).
to
.
have
.
been
.
called
;
if
(
options
&&
options
.
useBindParam
)
{
expect
(
bindParam
).
to
.
have
.
been
.
called
;
}
else
{
expect
(
stringify
).
to
.
have
.
been
.
called
;
expect
(
stringify
).
to
.
have
.
been
.
called
;
}
delete
Type
.
constructor
.
parse
;
delete
Type
.
constructor
.
parse
;
delete
Type
.
constructor
.
prototype
.
stringify
;
delete
Type
.
constructor
.
prototype
.
stringify
;
if
(
options
&&
options
.
useBindParam
)
{
delete
Type
.
constructor
.
prototype
.
bindParam
;
}
});
});
};
};
...
@@ -117,18 +130,18 @@ describe(Support.getTestDialectTeaser('DataTypes'), () => {
...
@@ -117,18 +130,18 @@ describe(Support.getTestDialectTeaser('DataTypes'), () => {
}
}
if
(
current
.
dialect
.
supports
.
HSTORE
)
{
if
(
current
.
dialect
.
supports
.
HSTORE
)
{
it
(
'calls parse and
stringify
for HSTORE'
,
()
=>
{
it
(
'calls parse and
bindParam
for HSTORE'
,
()
=>
{
const
Type
=
new
Sequelize
.
HSTORE
();
const
Type
=
new
Sequelize
.
HSTORE
();
return
testSuccess
(
Type
,
{
test
:
42
,
nested
:
false
});
return
testSuccess
(
Type
,
{
test
:
42
,
nested
:
false
}
,
{
useBindParam
:
true
}
);
});
});
}
}
if
(
current
.
dialect
.
supports
.
RANGE
)
{
if
(
current
.
dialect
.
supports
.
RANGE
)
{
it
(
'calls parse and
stringify
for RANGE'
,
()
=>
{
it
(
'calls parse and
bindParam
for RANGE'
,
()
=>
{
const
Type
=
new
Sequelize
.
RANGE
(
new
Sequelize
.
INTEGER
());
const
Type
=
new
Sequelize
.
RANGE
(
new
Sequelize
.
INTEGER
());
return
testSuccess
(
Type
,
[
1
,
2
]);
return
testSuccess
(
Type
,
[
1
,
2
]
,
{
useBindParam
:
true
}
);
});
});
}
}
...
@@ -147,13 +160,13 @@ describe(Support.getTestDialectTeaser('DataTypes'), () => {
...
@@ -147,13 +160,13 @@ describe(Support.getTestDialectTeaser('DataTypes'), () => {
it
(
'calls parse and stringify for TIME'
,
()
=>
{
it
(
'calls parse and stringify for TIME'
,
()
=>
{
const
Type
=
new
Sequelize
.
TIME
();
const
Type
=
new
Sequelize
.
TIME
();
return
testSuccess
(
Type
,
new
Date
(
));
return
testSuccess
(
Type
,
moment
(
new
Date
()).
format
(
'HH:mm:ss'
));
});
});
it
(
'calls parse and stringify for BLOB'
,
()
=>
{
it
(
'calls parse and stringify for BLOB'
,
()
=>
{
const
Type
=
new
Sequelize
.
BLOB
();
const
Type
=
new
Sequelize
.
BLOB
();
return
testSuccess
(
Type
,
'foobar'
);
return
testSuccess
(
Type
,
'foobar'
,
{
useBindParam
:
true
}
);
});
});
it
(
'calls parse and stringify for CHAR'
,
()
=>
{
it
(
'calls parse and stringify for CHAR'
,
()
=>
{
...
@@ -208,27 +221,27 @@ describe(Support.getTestDialectTeaser('DataTypes'), () => {
...
@@ -208,27 +221,27 @@ describe(Support.getTestDialectTeaser('DataTypes'), () => {
}
}
});
});
it
(
'calls parse and
stringify
for DOUBLE'
,
()
=>
{
it
(
'calls parse and
bindParam
for DOUBLE'
,
()
=>
{
const
Type
=
new
Sequelize
.
DOUBLE
();
const
Type
=
new
Sequelize
.
DOUBLE
();
return
testSuccess
(
Type
,
1.5
);
return
testSuccess
(
Type
,
1.5
,
{
useBindParam
:
true
}
);
});
});
it
(
'calls parse and
stringify
for FLOAT'
,
()
=>
{
it
(
'calls parse and
bindParam
for FLOAT'
,
()
=>
{
const
Type
=
new
Sequelize
.
FLOAT
();
const
Type
=
new
Sequelize
.
FLOAT
();
if
(
dialect
===
'postgres'
)
{
if
(
dialect
===
'postgres'
)
{
// Postgres doesn't have float, maps to either decimal or double
// Postgres doesn't have float, maps to either decimal or double
testFailure
(
Type
);
testFailure
(
Type
);
}
else
{
}
else
{
return
testSuccess
(
Type
,
1.5
);
return
testSuccess
(
Type
,
1.5
,
{
useBindParam
:
true
}
);
}
}
});
});
it
(
'calls parse and
stringify
for REAL'
,
()
=>
{
it
(
'calls parse and
bindParam
for REAL'
,
()
=>
{
const
Type
=
new
Sequelize
.
REAL
();
const
Type
=
new
Sequelize
.
REAL
();
return
testSuccess
(
Type
,
1.5
);
return
testSuccess
(
Type
,
1.5
,
{
useBindParam
:
true
}
);
});
});
it
(
'calls parse and stringify for UUID'
,
()
=>
{
it
(
'calls parse and stringify for UUID'
,
()
=>
{
...
@@ -254,10 +267,10 @@ describe(Support.getTestDialectTeaser('DataTypes'), () => {
...
@@ -254,10 +267,10 @@ describe(Support.getTestDialectTeaser('DataTypes'), () => {
});
});
if
(
current
.
dialect
.
supports
.
GEOMETRY
)
{
if
(
current
.
dialect
.
supports
.
GEOMETRY
)
{
it
(
'calls parse and
stringify
for GEOMETRY'
,
()
=>
{
it
(
'calls parse and
bindParam
for GEOMETRY'
,
()
=>
{
const
Type
=
new
Sequelize
.
GEOMETRY
();
const
Type
=
new
Sequelize
.
GEOMETRY
();
return
testSuccess
(
Type
,
{
type
:
'Point'
,
coordinates
:
[
125.6
,
10.1
]
});
return
testSuccess
(
Type
,
{
type
:
'Point'
,
coordinates
:
[
125.6
,
10.1
]
}
,
{
useBindParam
:
true
}
);
});
});
it
(
'should parse an empty GEOMETRY field'
,
()
=>
{
it
(
'should parse an empty GEOMETRY field'
,
()
=>
{
...
...
test/integration/dialects/postgres/dao.test.js
View file @
bce3d9a
...
@@ -190,15 +190,15 @@ if (dialect.match(/^postgres/)) {
...
@@ -190,15 +190,15 @@ if (dialect.match(/^postgres/)) {
});
});
});
});
it
(
'should stringify hstore with insert'
,
function
()
{
it
(
'should
NOT
stringify hstore with insert'
,
function
()
{
return
this
.
User
.
create
({
return
this
.
User
.
create
({
username
:
'bob'
,
username
:
'bob'
,
email
:
[
'myemail@email.com'
],
email
:
[
'myemail@email.com'
],
settings
:
{
mailing
:
false
,
push
:
'facebook'
,
frequency
:
3
}
settings
:
{
mailing
:
false
,
push
:
'facebook'
,
frequency
:
3
}
},
{
},
{
logging
(
sql
)
{
logging
(
sql
)
{
const
expected
=
'\'"mailing"=>"false","push"=>"facebook","frequency"=>"3"\',\'"default"=>"\'\'value\'\'"\''
;
const
un
expected
=
'\'"mailing"=>"false","push"=>"facebook","frequency"=>"3"\',\'"default"=>"\'\'value\'\'"\''
;
expect
(
sql
.
indexOf
(
expected
)).
not
.
to
.
equal
(
-
1
);
expect
(
sql
).
not
.
to
.
include
(
unexpected
);
}
}
});
});
});
});
...
@@ -597,12 +597,13 @@ if (dialect.match(/^postgres/)) {
...
@@ -597,12 +597,13 @@ if (dialect.match(/^postgres/)) {
return
this
.
User
.
sync
({
force
:
true
});
return
this
.
User
.
sync
({
force
:
true
});
});
});
it
(
'should use
postgres "TIMESTAMP WITH TIME ZONE" instead of "DATETIM
E"'
,
function
()
{
it
(
'should use
bind params instead of "TIMESTAMP WITH TIME ZON
E"'
,
function
()
{
return
this
.
User
.
create
({
return
this
.
User
.
create
({
dates
:
[]
dates
:
[]
},
{
},
{
logging
(
sql
)
{
logging
(
sql
)
{
expect
(
sql
.
indexOf
(
'TIMESTAMP WITH TIME ZONE'
)).
to
.
be
.
greaterThan
(
0
);
expect
(
sql
).
not
.
to
.
contain
(
'TIMESTAMP WITH TIME ZONE'
);
expect
(
sql
).
not
.
to
.
contain
(
'DATETIME'
);
}
}
});
});
});
});
...
...
test/integration/json.test.js
View file @
bce3d9a
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
const
chai
=
require
(
'chai'
),
const
chai
=
require
(
'chai'
),
expect
=
chai
.
expect
,
expect
=
chai
.
expect
,
Support
=
require
(
'./support'
),
Support
=
require
(
'./support'
),
dialect
=
Support
.
getTestDialect
(),
Sequelize
=
Support
.
Sequelize
,
Sequelize
=
Support
.
Sequelize
,
current
=
Support
.
sequelize
,
current
=
Support
.
sequelize
,
DataTypes
=
Sequelize
.
DataTypes
;
DataTypes
=
Sequelize
.
DataTypes
;
...
@@ -26,19 +27,17 @@ describe('model', () => {
...
@@ -26,19 +27,17 @@ describe('model', () => {
});
});
});
});
it
(
'should
stringify
json with insert'
,
function
()
{
it
(
'should
use a placeholder for
json with insert'
,
function
()
{
return
this
.
User
.
create
({
return
this
.
User
.
create
({
username
:
'bob'
,
username
:
'bob'
,
emergency_contact
:
{
name
:
'joe'
,
phones
:
[
1337
,
42
]
}
emergency_contact
:
{
name
:
'joe'
,
phones
:
[
1337
,
42
]
}
},
{
},
{
fields
:
[
'id'
,
'username'
,
'document'
,
'emergency_contact'
],
fields
:
[
'id'
,
'username'
,
'document'
,
'emergency_contact'
],
logging
:
sql
=>
{
logging
:
sql
=>
{
const
expected
=
'\'{"name":"joe","phones":[1337,42]}\''
;
if
(
dialect
.
match
(
/^mysql/
))
{
const
expectedEscaped
=
'\'{\\"name\\":\\"joe\\",\\"phones\\":[1337,42]}\''
;
expect
(
sql
).
to
.
include
(
'?'
);
if
(
sql
.
indexOf
(
expected
)
===
-
1
)
{
expect
(
sql
.
indexOf
(
expectedEscaped
)).
not
.
to
.
equal
(
-
1
);
}
else
{
}
else
{
expect
(
sql
.
indexOf
(
expected
)).
not
.
to
.
equal
(
-
1
);
expect
(
sql
).
to
.
include
(
'$1'
);
}
}
}
}
});
});
...
...
test/integration/model/create.test.js
View file @
bce3d9a
...
@@ -940,7 +940,7 @@ describe(Support.getTestDialectTeaser('Model'), () => {
...
@@ -940,7 +940,7 @@ describe(Support.getTestDialectTeaser('Model'), () => {
}
}
});
});
it
(
'
casts empty arrays correctly
for postgresql insert'
,
function
()
{
it
(
'
does not cast arrays
for postgresql insert'
,
function
()
{
if
(
dialect
!==
'postgres'
)
{
if
(
dialect
!==
'postgres'
)
{
expect
(
''
).
to
.
equal
(
''
);
expect
(
''
).
to
.
equal
(
''
);
return
void
0
;
return
void
0
;
...
@@ -956,8 +956,8 @@ describe(Support.getTestDialectTeaser('Model'), () => {
...
@@ -956,8 +956,8 @@ describe(Support.getTestDialectTeaser('Model'), () => {
return
User
.
create
({
myvals
:
[],
mystr
:
[]},
{
return
User
.
create
({
myvals
:
[],
mystr
:
[]},
{
logging
(
sql
)
{
logging
(
sql
)
{
test
=
true
;
test
=
true
;
expect
(
sql
.
indexOf
(
'ARRAY[]::INTEGER[]'
)).
to
.
be
.
above
(
-
1
);
expect
(
sql
).
not
.
to
.
contain
(
'ARRAY[]::INTEGER[]'
);
expect
(
sql
.
indexOf
(
'ARRAY[]::VARCHAR(255)[]'
)).
to
.
be
.
above
(
-
1
);
expect
(
sql
).
not
.
to
.
contain
(
'ARRAY[]::VARCHAR(255)[]'
);
}
}
});
});
}).
then
(()
=>
{
}).
then
(()
=>
{
...
@@ -984,8 +984,8 @@ describe(Support.getTestDialectTeaser('Model'), () => {
...
@@ -984,8 +984,8 @@ describe(Support.getTestDialectTeaser('Model'), () => {
return
user
.
save
({
return
user
.
save
({
logging
(
sql
)
{
logging
(
sql
)
{
test
=
true
;
test
=
true
;
expect
(
sql
.
indexOf
(
'ARRAY[]::INTEGER[]'
)).
to
.
be
.
above
(
-
1
);
expect
(
sql
).
to
.
contain
(
'ARRAY[]::INTEGER[]'
);
expect
(
sql
.
indexOf
(
'ARRAY[]::VARCHAR(255)[]'
)).
to
.
be
.
above
(
-
1
);
expect
(
sql
).
to
.
contain
(
'ARRAY[]::VARCHAR(255)[]'
);
}
}
});
});
});
});
...
@@ -1139,7 +1139,7 @@ describe(Support.getTestDialectTeaser('Model'), () => {
...
@@ -1139,7 +1139,7 @@ describe(Support.getTestDialectTeaser('Model'), () => {
logging
(
sql
)
{
logging
(
sql
)
{
expect
(
sql
).
to
.
exist
;
expect
(
sql
).
to
.
exist
;
test
=
true
;
test
=
true
;
expect
(
sql
.
toUpperCase
()
.
indexOf
(
'INSERT'
)).
to
.
be
.
above
(
-
1
);
expect
(
sql
.
toUpperCase
()
).
to
.
contain
(
'INSERT'
);
}
}
});
});
}).
then
(()
=>
{
}).
then
(()
=>
{
...
...
test/support.js
View file @
bce3d9a
...
@@ -213,7 +213,8 @@ const Support = {
...
@@ -213,7 +213,8 @@ const Support = {
return
url
;
return
url
;
},
},
expectsql
(
query
,
expectations
)
{
expectsql
(
query
,
assertions
)
{
const
expectations
=
assertions
.
query
||
assertions
;
let
expectation
=
expectations
[
Support
.
sequelize
.
dialect
.
name
];
let
expectation
=
expectations
[
Support
.
sequelize
.
dialect
.
name
];
if
(
!
expectation
)
{
if
(
!
expectation
)
{
...
@@ -229,7 +230,12 @@ const Support = {
...
@@ -229,7 +230,12 @@ const Support = {
if
(
_
.
isError
(
query
))
{
if
(
_
.
isError
(
query
))
{
expect
(
query
.
message
).
to
.
equal
(
expectation
.
message
);
expect
(
query
.
message
).
to
.
equal
(
expectation
.
message
);
}
else
{
}
else
{
expect
(
query
).
to
.
equal
(
expectation
);
expect
(
query
.
query
||
query
).
to
.
equal
(
expectation
);
}
if
(
assertions
.
bind
)
{
const
bind
=
assertions
.
bind
[
Support
.
sequelize
.
dialect
.
name
]
||
assertions
.
bind
[
'default'
]
||
assertions
.
bind
;
expect
(
query
.
bind
).
to
.
deep
.
equal
(
bind
);
}
}
}
}
};
};
...
...
test/unit/dialects/abstract/query-generator.test.js
View file @
bce3d9a
...
@@ -93,5 +93,13 @@ describe('QueryGenerator', () => {
...
@@ -93,5 +93,13 @@ describe('QueryGenerator', () => {
.
should
.
be
.
equal
(
'foo LIKE bar'
);
.
should
.
be
.
equal
(
'foo LIKE bar'
);
});
});
});
});
describe
(
'format'
,
()
=>
{
it
(
'should throw an error if passed SequelizeMethod'
,
function
()
{
const
QG
=
getAbstractQueryGenerator
(
this
.
sequelize
);
const
value
=
this
.
sequelize
.
fn
(
'UPPER'
,
'test'
);
expect
(()
=>
QG
.
format
(
value
)).
to
.
throw
(
Error
);
});
});
});
});
test/unit/dialects/mysql/query-generator.test.js
View file @
bce3d9a
...
@@ -445,47 +445,83 @@ if (dialect === 'mysql') {
...
@@ -445,47 +445,83 @@ if (dialect === 'mysql') {
insertQuery
:
[
insertQuery
:
[
{
{
arguments
:
[
'myTable'
,
{
name
:
'foo'
}],
arguments
:
[
'myTable'
,
{
name
:
'foo'
}],
expectation
:
"INSERT INTO `myTable` (`name`) VALUES ('foo');"
expectation
:
{
query
:
'INSERT INTO `myTable` (`name`) VALUES ($1);'
,
bind
:
[
'foo'
]
}
},
{
},
{
arguments
:
[
'myTable'
,
{
name
:
"foo';DROP TABLE myTable;"
}],
arguments
:
[
'myTable'
,
{
name
:
"foo';DROP TABLE myTable;"
}],
expectation
:
"INSERT INTO `myTable` (`name`) VALUES ('foo\\';DROP TABLE myTable;');"
expectation
:
{
query
:
'INSERT INTO `myTable` (`name`) VALUES ($1);'
,
bind
:
[
"foo';DROP TABLE myTable;"
]
}
},
{
},
{
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
birthday
:
new
Date
(
Date
.
UTC
(
2011
,
2
,
27
,
10
,
1
,
55
))}],
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
birthday
:
new
Date
(
Date
.
UTC
(
2011
,
2
,
27
,
10
,
1
,
55
))}],
expectation
:
"INSERT INTO `myTable` (`name`,`birthday`) VALUES ('foo','2011-03-27 10:01:55');"
expectation
:
{
query
:
'INSERT INTO `myTable` (`name`,`birthday`) VALUES ($1,$2);'
,
bind
:
[
'foo'
,
new
Date
(
Date
.
UTC
(
2011
,
2
,
27
,
10
,
1
,
55
))]
}
},
{
},
{
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
foo
:
1
}],
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
foo
:
1
}],
expectation
:
"INSERT INTO `myTable` (`name`,`foo`) VALUES ('foo',1);"
expectation
:
{
query
:
'INSERT INTO `myTable` (`name`,`foo`) VALUES ($1,$2);'
,
bind
:
[
'foo'
,
1
]
}
},
{
},
{
arguments
:
[
'myTable'
,
{
data
:
new
Buffer
(
'Sequelize'
)
}],
arguments
:
[
'myTable'
,
{
data
:
new
Buffer
(
'Sequelize'
)
}],
expectation
:
"INSERT INTO `myTable` (`data`) VALUES (X'53657175656c697a65');"
expectation
:
{
query
:
'INSERT INTO `myTable` (`data`) VALUES ($1);'
,
bind
:
[
new
Buffer
(
'Sequelize'
)]
}
},
{
},
{
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
foo
:
1
,
nullValue
:
null
}],
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
foo
:
1
,
nullValue
:
null
}],
expectation
:
"INSERT INTO `myTable` (`name`,`foo`,`nullValue`) VALUES ('foo',1,NULL);"
expectation
:
{
query
:
'INSERT INTO `myTable` (`name`,`foo`,`nullValue`) VALUES ($1,$2,$3);'
,
bind
:
[
'foo'
,
1
,
null
]
}
},
{
},
{
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
foo
:
1
,
nullValue
:
null
}],
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
foo
:
1
,
nullValue
:
null
}],
expectation
:
"INSERT INTO `myTable` (`name`,`foo`,`nullValue`) VALUES ('foo',1,NULL);"
,
expectation
:
{
query
:
'INSERT INTO `myTable` (`name`,`foo`,`nullValue`) VALUES ($1,$2,$3);'
,
bind
:
[
'foo'
,
1
,
null
]
},
context
:
{
options
:
{
omitNull
:
false
}}
context
:
{
options
:
{
omitNull
:
false
}}
},
{
},
{
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
foo
:
1
,
nullValue
:
null
}],
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
foo
:
1
,
nullValue
:
null
}],
expectation
:
"INSERT INTO `myTable` (`name`,`foo`) VALUES ('foo',1);"
,
expectation
:
{
query
:
'INSERT INTO `myTable` (`name`,`foo`) VALUES ($1,$2);'
,
bind
:
[
'foo'
,
1
]
},
context
:
{
options
:
{
omitNull
:
true
}}
context
:
{
options
:
{
omitNull
:
true
}}
},
{
},
{
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
foo
:
1
,
nullValue
:
undefined
}],
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
foo
:
1
,
nullValue
:
undefined
}],
expectation
:
"INSERT INTO `myTable` (`name`,`foo`) VALUES ('foo',1);"
,
expectation
:
{
query
:
'INSERT INTO `myTable` (`name`,`foo`) VALUES ($1,$2);'
,
bind
:
[
'foo'
,
1
]
},
context
:
{
options
:
{
omitNull
:
true
}}
context
:
{
options
:
{
omitNull
:
true
}}
},
{
},
{
arguments
:
[
'myTable'
,
{
foo
:
false
}],
arguments
:
[
'myTable'
,
{
foo
:
false
}],
expectation
:
'INSERT INTO `myTable` (`foo`) VALUES (false);'
expectation
:
{
query
:
'INSERT INTO `myTable` (`foo`) VALUES ($1);'
,
bind
:
[
false
]
}
},
{
},
{
arguments
:
[
'myTable'
,
{
foo
:
true
}],
arguments
:
[
'myTable'
,
{
foo
:
true
}],
expectation
:
'INSERT INTO `myTable` (`foo`) VALUES (true);'
expectation
:
{
query
:
'INSERT INTO `myTable` (`foo`) VALUES ($1);'
,
bind
:
[
true
]
}
},
{
},
{
arguments
:
[
'myTable'
,
function
(
sequelize
)
{
arguments
:
[
'myTable'
,
function
(
sequelize
)
{
return
{
return
{
foo
:
sequelize
.
fn
(
'NOW'
)
foo
:
sequelize
.
fn
(
'NOW'
)
};
};
}],
}],
expectation
:
'INSERT INTO `myTable` (`foo`) VALUES (NOW());'
,
expectation
:
{
query
:
'INSERT INTO `myTable` (`foo`) VALUES (NOW());'
,
bind
:
[]
},
needsSequelize
:
true
needsSequelize
:
true
}
}
],
],
...
@@ -616,7 +652,8 @@ if (dialect === 'mysql') {
...
@@ -616,7 +652,8 @@ if (dialect === 'mysql') {
});
});
tests
.
forEach
(
test
=>
{
tests
.
forEach
(
test
=>
{
const
title
=
test
.
title
||
'MySQL correctly returns '
+
test
.
expectation
+
' for '
+
JSON
.
stringify
(
test
.
arguments
);
const
query
=
test
.
expectation
.
query
||
test
.
expectation
;
const
title
=
test
.
title
||
'MySQL correctly returns '
+
query
+
' for '
+
JSON
.
stringify
(
test
.
arguments
);
it
(
title
,
function
()
{
it
(
title
,
function
()
{
if
(
test
.
needsSequelize
)
{
if
(
test
.
needsSequelize
)
{
if
(
_
.
isFunction
(
test
.
arguments
[
1
]))
test
.
arguments
[
1
]
=
test
.
arguments
[
1
](
this
.
sequelize
);
if
(
_
.
isFunction
(
test
.
arguments
[
1
]))
test
.
arguments
[
1
]
=
test
.
arguments
[
1
](
this
.
sequelize
);
...
...
test/unit/dialects/postgres/data-types.test.js
0 → 100644
View file @
bce3d9a
'use strict'
;
const
chai
=
require
(
'chai'
),
expect
=
chai
.
expect
,
Support
=
require
(
__dirname
+
'/../../support'
),
dialect
=
Support
.
getTestDialect
(),
BaseTypes
=
require
(
__dirname
+
'/../../../../lib/data-types'
),
DataTypes
=
require
(
__dirname
+
'/../../../../lib/dialects/postgres/data-types'
)(
BaseTypes
),
QueryGenerator
=
require
(
'../../../../lib/dialects/postgres/query-generator'
);
if
(
dialect
.
match
(
/^postgres/
))
{
describe
(
'[POSTGRES Specific] DataTypes'
,
()
=>
{
beforeEach
(
function
()
{
this
.
queryGenerator
=
new
QueryGenerator
({
sequelize
:
this
.
sequelize
,
_dialect
:
this
.
sequelize
.
dialect
});
});
describe
(
'GEOMETRY'
,
()
=>
{
it
(
'should use bindParam fn'
,
function
()
{
const
value
=
{
type
:
'Point'
};
const
bind
=
[];
const
bindParam
=
this
.
queryGenerator
.
bindParam
(
bind
);
const
result
=
DataTypes
.
GEOMETRY
.
prototype
.
bindParam
(
value
,
{
bindParam
});
expect
(
result
).
to
.
equal
(
'ST_GeomFromGeoJSON($1)'
);
expect
(
bind
).
to
.
eql
([
value
]);
});
});
describe
(
'GEOGRAPHY'
,
()
=>
{
it
(
'should use bindParam fn'
,
function
()
{
const
value
=
{
type
:
'Point'
};
const
bind
=
[];
const
bindParam
=
this
.
queryGenerator
.
bindParam
(
bind
);
const
result
=
DataTypes
.
GEOGRAPHY
.
prototype
.
bindParam
(
value
,
{
bindParam
});
expect
(
result
).
to
.
equal
(
'ST_GeomFromGeoJSON($1)'
);
expect
(
bind
).
to
.
eql
([
value
]);
});
});
});
}
test/unit/dialects/postgres/query-generator.test.js
View file @
bce3d9a
This diff is collapsed.
Click to expand it.
test/unit/dialects/sqlite/query-generator.test.js
View file @
bce3d9a
...
@@ -364,42 +364,78 @@ if (dialect === 'sqlite') {
...
@@ -364,42 +364,78 @@ if (dialect === 'sqlite') {
insertQuery
:
[
insertQuery
:
[
{
{
arguments
:
[
'myTable'
,
{
name
:
'foo'
}],
arguments
:
[
'myTable'
,
{
name
:
'foo'
}],
expectation
:
"INSERT INTO `myTable` (`name`) VALUES ('foo');"
expectation
:
{
query
:
'INSERT INTO `myTable` (`name`) VALUES ($1);'
,
bind
:
[
'foo'
]
}
},
{
},
{
arguments
:
[
'myTable'
,
{
name
:
"'bar'"
}],
arguments
:
[
'myTable'
,
{
name
:
"'bar'"
}],
expectation
:
"INSERT INTO `myTable` (`name`) VALUES ('''bar''');"
expectation
:
{
query
:
'INSERT INTO `myTable` (`name`) VALUES ($1);'
,
bind
:
[
"'bar'"
]
}
},
{
},
{
arguments
:
[
'myTable'
,
{
data
:
new
Buffer
(
'Sequelize'
)
}],
arguments
:
[
'myTable'
,
{
data
:
new
Buffer
(
'Sequelize'
)
}],
expectation
:
"INSERT INTO `myTable` (`data`) VALUES (X'53657175656c697a65');"
expectation
:
{
query
:
'INSERT INTO `myTable` (`data`) VALUES ($1);'
,
bind
:
[
new
Buffer
(
'Sequelize'
)]
}
},
{
},
{
arguments
:
[
'myTable'
,
{
name
:
'bar'
,
value
:
null
}],
arguments
:
[
'myTable'
,
{
name
:
'bar'
,
value
:
null
}],
expectation
:
"INSERT INTO `myTable` (`name`,`value`) VALUES ('bar',NULL);"
expectation
:
{
query
:
'INSERT INTO `myTable` (`name`,`value`) VALUES ($1,$2);'
,
bind
:
[
'bar'
,
null
]
}
},
{
},
{
arguments
:
[
'myTable'
,
{
name
:
'bar'
,
value
:
undefined
}],
arguments
:
[
'myTable'
,
{
name
:
'bar'
,
value
:
undefined
}],
expectation
:
"INSERT INTO `myTable` (`name`,`value`) VALUES ('bar',NULL);"
expectation
:
{
query
:
'INSERT INTO `myTable` (`name`,`value`) VALUES ($1,$2);'
,
bind
:
[
'bar'
,
undefined
]
}
},
{
},
{
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
birthday
:
moment
(
'2011-03-27 10:01:55 +0000'
,
'YYYY-MM-DD HH:mm:ss Z'
).
toDate
()}],
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
birthday
:
moment
(
'2011-03-27 10:01:55 +0000'
,
'YYYY-MM-DD HH:mm:ss Z'
).
toDate
()}],
expectation
:
"INSERT INTO `myTable` (`name`,`birthday`) VALUES ('foo','2011-03-27 10:01:55.000 +00:00');"
expectation
:
{
query
:
'INSERT INTO `myTable` (`name`,`birthday`) VALUES ($1,$2);'
,
bind
:
[
'foo'
,
moment
(
'2011-03-27 10:01:55 +0000'
,
'YYYY-MM-DD HH:mm:ss Z'
).
toDate
()]
}
},
{
},
{
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
value
:
true
}],
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
value
:
true
}],
expectation
:
"INSERT INTO `myTable` (`name`,`value`) VALUES ('foo',1);"
expectation
:
{
query
:
'INSERT INTO `myTable` (`name`,`value`) VALUES ($1,$2);'
,
bind
:
[
'foo'
,
true
]
}
},
{
},
{
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
value
:
false
}],
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
value
:
false
}],
expectation
:
"INSERT INTO `myTable` (`name`,`value`) VALUES ('foo',0);"
expectation
:
{
query
:
'INSERT INTO `myTable` (`name`,`value`) VALUES ($1,$2);'
,
bind
:
[
'foo'
,
false
]
}
},
{
},
{
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
foo
:
1
,
nullValue
:
null
}],
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
foo
:
1
,
nullValue
:
null
}],
expectation
:
"INSERT INTO `myTable` (`name`,`foo`,`nullValue`) VALUES ('foo',1,NULL);"
expectation
:
{
query
:
'INSERT INTO `myTable` (`name`,`foo`,`nullValue`) VALUES ($1,$2,$3);'
,
bind
:
[
'foo'
,
1
,
null
]
}
},
{
},
{
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
foo
:
1
,
nullValue
:
null
}],
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
foo
:
1
,
nullValue
:
null
}],
expectation
:
"INSERT INTO `myTable` (`name`,`foo`,`nullValue`) VALUES ('foo',1,NULL);"
,
expectation
:
{
query
:
'INSERT INTO `myTable` (`name`,`foo`,`nullValue`) VALUES ($1,$2,$3);'
,
bind
:
[
'foo'
,
1
,
null
]
},
context
:
{
options
:
{
omitNull
:
false
}}
context
:
{
options
:
{
omitNull
:
false
}}
},
{
},
{
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
foo
:
1
,
nullValue
:
null
}],
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
foo
:
1
,
nullValue
:
null
}],
expectation
:
"INSERT INTO `myTable` (`name`,`foo`) VALUES ('foo',1);"
,
expectation
:
{
query
:
'INSERT INTO `myTable` (`name`,`foo`) VALUES ($1,$2);'
,
bind
:
[
'foo'
,
1
]
},
context
:
{
options
:
{
omitNull
:
true
}}
context
:
{
options
:
{
omitNull
:
true
}}
},
{
},
{
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
foo
:
1
,
nullValue
:
undefined
}],
arguments
:
[
'myTable'
,
{
name
:
'foo'
,
foo
:
1
,
nullValue
:
undefined
}],
expectation
:
"INSERT INTO `myTable` (`name`,`foo`) VALUES ('foo',1);"
,
expectation
:
{
query
:
'INSERT INTO `myTable` (`name`,`foo`) VALUES ($1,$2);'
,
bind
:
[
'foo'
,
1
]
},
context
:
{
options
:
{
omitNull
:
true
}}
context
:
{
options
:
{
omitNull
:
true
}}
},
{
},
{
arguments
:
[
'myTable'
,
function
(
sequelize
)
{
arguments
:
[
'myTable'
,
function
(
sequelize
)
{
...
@@ -407,7 +443,10 @@ if (dialect === 'sqlite') {
...
@@ -407,7 +443,10 @@ if (dialect === 'sqlite') {
foo
:
sequelize
.
fn
(
'NOW'
)
foo
:
sequelize
.
fn
(
'NOW'
)
};
};
}],
}],
expectation
:
'INSERT INTO `myTable` (`foo`) VALUES (NOW());'
,
expectation
:
{
query
:
'INSERT INTO `myTable` (`foo`) VALUES (NOW());'
,
bind
:
[]
},
needsSequelize
:
true
needsSequelize
:
true
}
}
],
],
...
@@ -547,7 +586,8 @@ if (dialect === 'sqlite') {
...
@@ -547,7 +586,8 @@ if (dialect === 'sqlite') {
});
});
tests
.
forEach
(
test
=>
{
tests
.
forEach
(
test
=>
{
const
title
=
test
.
title
||
'SQLite correctly returns '
+
test
.
expectation
+
' for '
+
JSON
.
stringify
(
test
.
arguments
);
const
query
=
test
.
expectation
.
query
||
test
.
expectation
;
const
title
=
test
.
title
||
'SQLite correctly returns '
+
query
+
' for '
+
JSON
.
stringify
(
test
.
arguments
);
it
(
title
,
function
()
{
it
(
title
,
function
()
{
if
(
test
.
needsSequelize
)
{
if
(
test
.
needsSequelize
)
{
if
(
_
.
isFunction
(
test
.
arguments
[
1
]))
test
.
arguments
[
1
]
=
test
.
arguments
[
1
](
this
.
sequelize
);
if
(
_
.
isFunction
(
test
.
arguments
[
1
]))
test
.
arguments
[
1
]
=
test
.
arguments
[
1
](
this
.
sequelize
);
...
...
test/unit/sql/insert.test.js
View file @
bce3d9a
...
@@ -27,13 +27,16 @@ describe(Support.getTestDialectTeaser('SQL'), () => {
...
@@ -27,13 +27,16 @@ describe(Support.getTestDialectTeaser('SQL'), () => {
};
};
expectsql
(
sql
.
insertQuery
(
User
.
tableName
,
{
user_name
:
'triggertest'
},
User
.
rawAttributes
,
options
),
expectsql
(
sql
.
insertQuery
(
User
.
tableName
,
{
user_name
:
'triggertest'
},
User
.
rawAttributes
,
options
),
{
{
mssql
:
'declare @tmp table ([id] INTEGER,[user_name] NVARCHAR(255));INSERT INTO [users] ([user_name]) OUTPUT INSERTED.[id],INSERTED.[user_name] into @tmp VALUES (N\'triggertest\');select * from @tmp;'
,
query
:
{
postgres
:
'INSERT INTO "users" ("user_name") VALUES (\'triggertest\') RETURNING *;'
,
mssql
:
'declare @tmp table ([id] INTEGER,[user_name] NVARCHAR(255));INSERT INTO [users] ([user_name]) OUTPUT INSERTED.[id],INSERTED.[user_name] into @tmp VALUES ($1);select * from @tmp;'
,
default
:
"INSERT INTO `users` (`user_name`) VALUES ('triggertest');"
postgres
:
'INSERT INTO "users" ("user_name") VALUES ($1) RETURNING *;'
,
});
default
:
'INSERT INTO `users` (`user_name`) VALUES ($1);'
},
bind
:
[
'triggertest'
]
});
});
});
});
});
describe
(
'dates'
,
()
=>
{
describe
(
'dates'
,
()
=>
{
it
(
'formats the date correctly when inserting'
,
()
=>
{
it
(
'formats the date correctly when inserting'
,
()
=>
{
...
@@ -51,10 +54,16 @@ describe(Support.getTestDialectTeaser('SQL'), () => {
...
@@ -51,10 +54,16 @@ describe(Support.getTestDialectTeaser('SQL'), () => {
expectsql
(
timezoneSequelize
.
dialect
.
QueryGenerator
.
insertQuery
(
User
.
tableName
,
{
date
:
new
Date
(
Date
.
UTC
(
2015
,
0
,
20
))},
User
.
rawAttributes
,
{}),
expectsql
(
timezoneSequelize
.
dialect
.
QueryGenerator
.
insertQuery
(
User
.
tableName
,
{
date
:
new
Date
(
Date
.
UTC
(
2015
,
0
,
20
))},
User
.
rawAttributes
,
{}),
{
{
postgres
:
'INSERT INTO "users" ("date") VALUES (\'2015-01-20 01:00:00.000 +01:00\');'
,
query
:
{
sqlite
:
'INSERT INTO `users` (`date`) VALUES (\'2015-01-20 00:00:00.000 +00:00\');'
,
postgres
:
'INSERT INTO "users" ("date") VALUES ($1);'
,
mssql
:
'INSERT INTO [users] ([date]) VALUES (N\'2015-01-20 01:00:00.000 +01:00\');'
,
mssql
:
'INSERT INTO [users] ([date]) VALUES ($1);'
,
mysql
:
"INSERT INTO `users` (`date`) VALUES ('2015-01-20 01:00:00');"
default
:
'INSERT INTO `users` (`date`) VALUES ($1);'
},
bind
:
{
sqlite
:
[
'2015-01-20 00:00:00.000 +00:00'
],
mysql
:
[
'2015-01-20 01:00:00'
],
default
:
[
'2015-01-20 01:00:00.000 +01:00'
]
}
});
});
});
});
...
@@ -73,10 +82,16 @@ describe(Support.getTestDialectTeaser('SQL'), () => {
...
@@ -73,10 +82,16 @@ describe(Support.getTestDialectTeaser('SQL'), () => {
expectsql
(
timezoneSequelize
.
dialect
.
QueryGenerator
.
insertQuery
(
User
.
tableName
,
{
date
:
new
Date
(
Date
.
UTC
(
2015
,
0
,
20
,
1
,
2
,
3
,
89
))},
User
.
rawAttributes
,
{}),
expectsql
(
timezoneSequelize
.
dialect
.
QueryGenerator
.
insertQuery
(
User
.
tableName
,
{
date
:
new
Date
(
Date
.
UTC
(
2015
,
0
,
20
,
1
,
2
,
3
,
89
))},
User
.
rawAttributes
,
{}),
{
{
postgres
:
'INSERT INTO "users" ("date") VALUES (\'2015-01-20 02:02:03.089 +01:00\');'
,
query
:
{
sqlite
:
'INSERT INTO `users` (`date`) VALUES (\'2015-01-20 01:02:03.089 +00:00\');'
,
postgres
:
'INSERT INTO "users" ("date") VALUES ($1);'
,
mssql
:
'INSERT INTO [users] ([date]) VALUES (N\'2015-01-20 02:02:03.089 +01:00\');'
,
mssql
:
'INSERT INTO [users] ([date]) VALUES ($1);'
,
mysql
:
"INSERT INTO `users` (`date`) VALUES ('2015-01-20 02:02:03.089');"
default
:
'INSERT INTO `users` (`date`) VALUES ($1);'
},
bind
:
{
sqlite
:
[
'2015-01-20 01:02:03.089 +00:00'
],
mysql
:
[
'2015-01-20 02:02:03.089'
],
default
:
[
'2015-01-20 02:02:03.089 +01:00'
]
}
});
});
});
});
});
});
...
...
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