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 fe06b45c
authored
Dec 04, 2017
by
Sushant
Committed by
GitHub
Dec 04, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(datatypes): array(enum) support for PostgreSQL (#8738)
1 parent
f5fcf164
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
353 additions
and
52 deletions
.travis.yml
docker-compose.yml
docs/models-definition.md
lib/dialects/postgres/connection-manager.js
lib/dialects/postgres/data-types.js
lib/dialects/postgres/query-generator.js
lib/query-interface.js
lib/utils.js
package.json
test/integration/data-types.test.js
test/integration/dialects/postgres/dao.test.js
test/integration/support.js
.travis.yml
View file @
fe06b45
...
@@ -36,6 +36,7 @@ before_script:
...
@@ -36,6 +36,7 @@ before_script:
-
"
if
[
$POSTGRES_VER
];
then
sudo
mount
-t
ramfs
tmpfs
/mnt/sequelize-postgres-ramdisk;
fi"
-
"
if
[
$POSTGRES_VER
];
then
sudo
mount
-t
ramfs
tmpfs
/mnt/sequelize-postgres-ramdisk;
fi"
-
"
if
[
$MYSQL_VER
];
then
sudo
mkdir
/mnt/sequelize-mysql-ramdisk;
fi"
-
"
if
[
$MYSQL_VER
];
then
sudo
mkdir
/mnt/sequelize-mysql-ramdisk;
fi"
-
"
if
[
$MYSQL_VER
];
then
sudo
mount
-t
ramfs
tmpfs
/mnt/sequelize-mysql-ramdisk;
fi"
-
"
if
[
$MYSQL_VER
];
then
sudo
mount
-t
ramfs
tmpfs
/mnt/sequelize-mysql-ramdisk;
fi"
# setup docker
# setup docker
-
"
if
[
$POSTGRES_VER
]
||
[
$MYSQL_VER
];
then
docker-compose
up
-d
${POSTGRES_VER}
${MYSQL_VER};
fi"
-
"
if
[
$POSTGRES_VER
]
||
[
$MYSQL_VER
];
then
docker-compose
up
-d
${POSTGRES_VER}
${MYSQL_VER};
fi"
-
"
if
[
$MYSQL_VER
];
then
docker
run
--link
${MYSQL_VER}:db
-e
CHECK_PORT=3306
-e
CHECK_HOST=db
--net
sequelize_default
giorgos/takis;
fi"
-
"
if
[
$MYSQL_VER
];
then
docker
run
--link
${MYSQL_VER}:db
-e
CHECK_PORT=3306
-e
CHECK_HOST=db
--net
sequelize_default
giorgos/takis;
fi"
...
...
docker-compose.yml
View file @
fe06b45
...
@@ -15,7 +15,7 @@ services:
...
@@ -15,7 +15,7 @@ services:
# PostgreSQL
# PostgreSQL
postgres-95
:
postgres-95
:
image
:
camptocamp/postgi
s:9.5
image
:
sushantdhiman/postgre
s:9.5
environment
:
environment
:
POSTGRES_USER
:
sequelize_test
POSTGRES_USER
:
sequelize_test
POSTGRES_PASSWORD
:
sequelize_test
POSTGRES_PASSWORD
:
sequelize_test
...
...
docs/models-definition.md
View file @
fe06b45
...
@@ -140,6 +140,7 @@ Sequelize.BOOLEAN // TINYINT(1)
...
@@ -140,6 +140,7 @@ Sequelize.BOOLEAN // TINYINT(1)
Sequelize
.
ENUM
(
'value 1'
,
'value 2'
)
// An ENUM with allowed values 'value 1' and 'value 2'
Sequelize
.
ENUM
(
'value 1'
,
'value 2'
)
// An ENUM with allowed values 'value 1' and 'value 2'
Sequelize
.
ARRAY
(
Sequelize
.
TEXT
)
// Defines an array. PostgreSQL only.
Sequelize
.
ARRAY
(
Sequelize
.
TEXT
)
// Defines an array. PostgreSQL only.
Sequelize
.
ARRAY
(
Sequelize
.
ENUM
)
// Defines an array of ENUM. PostgreSQL only.
Sequelize
.
JSON
// JSON column. PostgreSQL, SQLite and MySQL only.
Sequelize
.
JSON
// JSON column. PostgreSQL, SQLite and MySQL only.
Sequelize
.
JSONB
// JSONB column. PostgreSQL only.
Sequelize
.
JSONB
// JSONB column. PostgreSQL only.
...
@@ -198,6 +199,14 @@ sequelize.define('model', {
...
@@ -198,6 +199,14 @@ sequelize.define('model', {
})
})
```
```
### Array(ENUM)
Its only supported with PostgreSQL.
Array(Enum) type require special treatment. Whenever Sequelize will talk to database it has to typecast Array values with ENUM name.
So this enum name must follow this pattern
`enum_<table_name>_<col_name>`
. If you are using
`sync`
then correct name will automatically be generated.
### Range types
### Range types
Since range types have extra information for their bound inclusion/exclusion it's not
Since range types have extra information for their bound inclusion/exclusion it's not
...
@@ -246,7 +255,7 @@ range.inclusive // [false, true]
...
@@ -246,7 +255,7 @@ range.inclusive // [false, true]
Make sure you turn that into a serializable format before serialization since array
Make sure you turn that into a serializable format before serialization since array
extra properties will not be serialized.
extra properties will not be serialized.
#### Special Cases
**Special Cases**
```
js
```
js
// empty range:
// empty range:
...
...
lib/dialects/postgres/connection-manager.js
View file @
fe06b45
...
@@ -148,23 +148,70 @@ class ConnectionManager extends AbstractConnectionManager {
...
@@ -148,23 +148,70 @@ class ConnectionManager extends AbstractConnectionManager {
}
}
}
}
// oids for hstore and geometry are dynamic - so select them at connection time
if
(
query
)
{
const
supportedVersion
=
this
.
sequelize
.
options
.
databaseVersion
!==
0
&&
semver
.
gte
(
this
.
sequelize
.
options
.
databaseVersion
,
'8.3.0'
);
return
connection
.
query
(
query
);
if
(
dataTypes
.
HSTORE
.
types
.
postgres
.
oids
.
length
===
0
&&
supportedVersion
)
{
}
query
+=
'SELECT typname, oid, typarray FROM pg_type WHERE typtype = \'b\' AND typname IN (\'hstore\', \'geometry\', \'geography\')'
;
}).
tap
(
connection
=>
{
if
(
dataTypes
.
GEOGRAPHY
.
types
.
postgres
.
oids
.
length
===
0
&&
dataTypes
.
GEOMETRY
.
types
.
postgres
.
oids
.
length
===
0
&&
dataTypes
.
HSTORE
.
types
.
postgres
.
oids
.
length
===
0
&&
dataTypes
.
ENUM
.
types
.
postgres
.
oids
.
length
===
0
)
{
return
this
.
_refreshDynamicOIDs
(
connection
);
}
});
}
}
return
new
Promise
((
resolve
,
reject
)
=>
connection
.
query
(
query
,
(
error
,
result
)
=>
error
?
reject
(
error
)
:
resolve
(
result
))).
then
(
results
=>
{
disconnect
(
connection
)
{
return
new
Promise
(
resolve
=>
{
connection
.
end
();
resolve
();
});
}
validate
(
connection
)
{
return
connection
.
_invalid
===
undefined
;
}
_refreshDynamicOIDs
(
connection
)
{
const
databaseVersion
=
this
.
sequelize
.
options
.
databaseVersion
;
const
supportedVersion
=
'8.3.0'
;
// Check for supported version
if
(
(
databaseVersion
&&
semver
.
gte
(
databaseVersion
,
supportedVersion
))
===
false
)
{
return
Promise
.
resolve
();
}
// Refresh dynamic OIDs for some types
// These include, Geometry / HStore / Enum
return
(
connection
||
this
.
sequelize
).
query
(
"SELECT typname, typtype, oid, typarray FROM pg_type WHERE (typtype = 'b' AND typname IN ('hstore', 'geometry', 'geography')) OR (typtype = 'e')"
).
then
(
results
=>
{
const
result
=
Array
.
isArray
(
results
)
?
results
.
pop
()
:
results
;
const
result
=
Array
.
isArray
(
results
)
?
results
.
pop
()
:
results
;
// Reset OID mapping for dynamic type
[
dataTypes
.
postgres
.
GEOMETRY
,
dataTypes
.
postgres
.
HSTORE
,
dataTypes
.
postgres
.
GEOGRAPHY
,
dataTypes
.
postgres
.
ENUM
].
forEach
(
type
=>
{
type
.
types
.
postgres
.
oids
=
[];
type
.
types
.
postgres
.
array_oids
=
[];
});
for
(
const
row
of
result
.
rows
)
{
for
(
const
row
of
result
.
rows
)
{
let
type
;
let
type
;
if
(
row
.
typname
===
'geometry'
)
{
if
(
row
.
typname
===
'geometry'
)
{
type
=
dataTypes
.
postgres
.
GEOMETRY
;
type
=
dataTypes
.
postgres
.
GEOMETRY
;
}
else
if
(
row
.
typname
===
'hstore'
)
{
}
else
if
(
row
.
typname
===
'hstore'
)
{
type
=
dataTypes
.
postgres
.
HSTORE
;
type
=
dataTypes
.
postgres
.
HSTORE
;
}
else
if
(
row
.
typname
===
'geography'
)
{
}
else
if
(
row
.
typname
===
'geography'
)
{
type
=
dataTypes
.
postgres
.
GEOGRAPHY
;
type
=
dataTypes
.
postgres
.
GEOGRAPHY
;
}
else
if
(
row
.
typtype
===
'e'
)
{
type
=
dataTypes
.
postgres
.
ENUM
;
}
}
type
.
types
.
postgres
.
oids
.
push
(
row
.
oid
);
type
.
types
.
postgres
.
oids
.
push
(
row
.
oid
);
...
@@ -173,18 +220,6 @@ class ConnectionManager extends AbstractConnectionManager {
...
@@ -173,18 +220,6 @@ class ConnectionManager extends AbstractConnectionManager {
this
.
_refreshTypeParser
(
type
);
this
.
_refreshTypeParser
(
type
);
}
}
});
});
});
}
disconnect
(
connection
)
{
return
new
Promise
(
resolve
=>
{
connection
.
end
();
resolve
();
});
}
validate
(
connection
)
{
return
connection
.
_invalid
===
undefined
;
}
}
}
}
...
...
lib/dialects/postgres/data-types.js
View file @
fe06b45
...
@@ -574,12 +574,37 @@ module.exports = BaseTypes => {
...
@@ -574,12 +574,37 @@ module.exports = BaseTypes => {
},
this
).
join
(
','
)
+
']'
;
},
this
).
join
(
','
)
+
']'
;
if
(
this
.
type
)
{
if
(
this
.
type
)
{
str
+=
'::'
+
this
.
toSql
();
const
Utils
=
require
(
'../../utils'
);
let
castKey
=
this
.
toSql
();
if
(
this
.
type
instanceof
BaseTypes
.
ENUM
)
{
castKey
=
Utils
.
addTicks
(
Utils
.
generateEnumName
(
options
.
field
.
Model
.
getTableName
(),
options
.
field
.
fieldName
),
'"'
)
+
'[]'
;
}
str
+=
'::'
+
castKey
;
}
}
return
str
;
return
str
;
};
};
function
ENUM
(
options
)
{
if
(
!
(
this
instanceof
ENUM
))
return
new
ENUM
(
options
);
BaseTypes
.
ENUM
.
apply
(
this
,
arguments
);
}
inherits
(
ENUM
,
BaseTypes
.
ENUM
);
ENUM
.
parse
=
function
(
value
)
{
return
value
;
};
BaseTypes
.
ENUM
.
types
.
postgres
=
{
oids
:
[],
array_oids
:
[]
};
const
exports
=
{
const
exports
=
{
DECIMAL
,
DECIMAL
,
BLOB
,
BLOB
,
...
@@ -598,7 +623,8 @@ module.exports = BaseTypes => {
...
@@ -598,7 +623,8 @@ module.exports = BaseTypes => {
GEOMETRY
,
GEOMETRY
,
GEOGRAPHY
,
GEOGRAPHY
,
HSTORE
,
HSTORE
,
RANGE
RANGE
,
ENUM
};
};
_
.
forIn
(
exports
,
(
DataType
,
key
)
=>
{
_
.
forIn
(
exports
,
(
DataType
,
key
)
=>
{
...
...
lib/dialects/postgres/query-generator.js
View file @
fe06b45
...
@@ -496,11 +496,24 @@ const QueryGenerator = {
...
@@ -496,11 +496,24 @@ const QueryGenerator = {
}
}
let
type
;
let
type
;
if
(
attribute
.
type
instanceof
DataTypes
.
ENUM
)
{
if
(
if
(
attribute
.
type
.
values
&&
!
attribute
.
values
)
attribute
.
values
=
attribute
.
type
.
values
;
attribute
.
type
instanceof
DataTypes
.
ENUM
||
(
attribute
.
type
instanceof
DataTypes
.
ARRAY
&&
attribute
.
type
.
type
instanceof
DataTypes
.
ENUM
)
)
{
const
enumType
=
attribute
.
type
.
type
||
attribute
.
type
;
let
values
=
attribute
.
values
;
if
(
enumType
.
values
&&
!
attribute
.
values
)
{
values
=
enumType
.
values
;
}
if
(
Array
.
isArray
(
values
)
&&
values
.
length
>
0
)
{
type
=
'ENUM('
+
_
.
map
(
values
,
value
=>
this
.
escape
(
value
)).
join
(
', '
)
+
')'
;
if
(
attribute
.
type
instanceof
DataTypes
.
ARRAY
)
{
type
+=
'[]'
;
}
if
(
Array
.
isArray
(
attribute
.
values
)
&&
attribute
.
values
.
length
>
0
)
{
type
=
'ENUM('
+
_
.
map
(
attribute
.
values
,
value
=>
this
.
escape
(
value
)).
join
(
', '
)
+
')'
;
}
else
{
}
else
{
throw
new
Error
(
"Values for ENUM haven't been defined."
);
throw
new
Error
(
"Values for ENUM haven't been defined."
);
}
}
...
@@ -736,8 +749,9 @@ const QueryGenerator = {
...
@@ -736,8 +749,9 @@ const QueryGenerator = {
pgEnumName
(
tableName
,
attr
,
options
)
{
pgEnumName
(
tableName
,
attr
,
options
)
{
options
=
options
||
{};
options
=
options
||
{};
const
tableDetails
=
this
.
extractTableDetails
(
tableName
,
options
);
const
tableDetails
=
this
.
extractTableDetails
(
tableName
,
options
);
let
enumName
=
'"enum_'
+
tableDetails
.
tableName
+
'_'
+
attr
+
'"'
;
let
enumName
=
Utils
.
addTicks
(
Utils
.
generateEnumName
(
tableDetails
.
tableName
,
attr
),
'"'
)
;
// pgListEnums requires the enum name only, without the schema
// pgListEnums requires the enum name only, without the schema
if
(
options
.
schema
!==
false
&&
tableDetails
.
schema
)
{
if
(
options
.
schema
!==
false
&&
tableDetails
.
schema
)
{
...
@@ -745,7 +759,6 @@ const QueryGenerator = {
...
@@ -745,7 +759,6 @@ const QueryGenerator = {
}
}
return
enumName
;
return
enumName
;
},
},
pgListEnums
(
tableName
,
attrName
,
options
)
{
pgListEnums
(
tableName
,
attrName
,
options
)
{
...
...
lib/query-interface.js
View file @
fe06b45
...
@@ -177,8 +177,14 @@ class QueryInterface {
...
@@ -177,8 +177,14 @@ class QueryInterface {
const
promises
=
[];
const
promises
=
[];
for
(
i
=
0
;
i
<
keyLen
;
i
++
)
{
for
(
i
=
0
;
i
<
keyLen
;
i
++
)
{
if
(
attributes
[
keys
[
i
]].
type
instanceof
DataTypes
.
ENUM
)
{
const
attribute
=
attributes
[
keys
[
i
]];
sql
=
this
.
QueryGenerator
.
pgListEnums
(
tableName
,
attributes
[
keys
[
i
]].
field
||
keys
[
i
],
options
);
const
type
=
attribute
.
type
;
if
(
type
instanceof
DataTypes
.
ENUM
||
(
type
instanceof
DataTypes
.
ARRAY
&&
type
.
type
instanceof
DataTypes
.
ENUM
)
//ARRAY sub type is ENUM
)
{
sql
=
this
.
QueryGenerator
.
pgListEnums
(
tableName
,
attribute
.
field
||
keys
[
i
],
options
);
promises
.
push
(
this
.
sequelize
.
query
(
promises
.
push
(
this
.
sequelize
.
query
(
sql
,
sql
,
_
.
assign
({},
options
,
{
plain
:
true
,
raw
:
true
,
type
:
QueryTypes
.
SELECT
})
_
.
assign
({},
options
,
{
plain
:
true
,
raw
:
true
,
type
:
QueryTypes
.
SELECT
})
...
@@ -191,17 +197,24 @@ class QueryInterface {
...
@@ -191,17 +197,24 @@ class QueryInterface {
let
enumIdx
=
0
;
let
enumIdx
=
0
;
for
(
i
=
0
;
i
<
keyLen
;
i
++
)
{
for
(
i
=
0
;
i
<
keyLen
;
i
++
)
{
if
(
attributes
[
keys
[
i
]].
type
instanceof
DataTypes
.
ENUM
)
{
const
attribute
=
attributes
[
keys
[
i
]];
const
type
=
attribute
.
type
;
const
enumType
=
type
.
type
||
type
;
if
(
type
instanceof
DataTypes
.
ENUM
||
(
type
instanceof
DataTypes
.
ARRAY
&&
enumType
instanceof
DataTypes
.
ENUM
)
//ARRAY sub type is ENUM
)
{
// If the enum type doesn't exist then create it
// If the enum type doesn't exist then create it
if
(
!
results
[
enumIdx
])
{
if
(
!
results
[
enumIdx
])
{
sql
=
this
.
QueryGenerator
.
pgEnum
(
tableName
,
attribute
s
[
keys
[
i
]].
field
||
keys
[
i
],
attributes
[
keys
[
i
]]
,
options
);
sql
=
this
.
QueryGenerator
.
pgEnum
(
tableName
,
attribute
.
field
||
keys
[
i
],
enumType
,
options
);
promises
.
push
(
this
.
sequelize
.
query
(
promises
.
push
(
this
.
sequelize
.
query
(
sql
,
sql
,
_
.
assign
({},
options
,
{
raw
:
true
})
_
.
assign
({},
options
,
{
raw
:
true
})
));
));
}
else
if
(
!!
results
[
enumIdx
]
&&
!!
model
)
{
}
else
if
(
!!
results
[
enumIdx
]
&&
!!
model
)
{
const
enumVals
=
this
.
QueryGenerator
.
fromArray
(
results
[
enumIdx
].
enum_value
);
const
enumVals
=
this
.
QueryGenerator
.
fromArray
(
results
[
enumIdx
].
enum_value
);
const
vals
=
model
.
rawAttributes
[
keys
[
i
]]
.
values
;
const
vals
=
enumType
.
values
;
vals
.
forEach
((
value
,
idx
)
=>
{
vals
.
forEach
((
value
,
idx
)
=>
{
// reset out after/before options since it's for every enum value
// reset out after/before options since it's for every enum value
...
@@ -217,7 +230,7 @@ class QueryInterface {
...
@@ -217,7 +230,7 @@ class QueryInterface {
valueOptions
.
after
=
vals
[
idx
-
1
];
valueOptions
.
after
=
vals
[
idx
-
1
];
}
}
valueOptions
.
supportsSearchPath
=
false
;
valueOptions
.
supportsSearchPath
=
false
;
promises
.
push
(
this
.
sequelize
.
query
(
this
.
QueryGenerator
.
pgEnumAdd
(
tableName
,
keys
[
i
],
value
,
valueOptions
),
valueOptions
));
promises
.
push
(
this
.
sequelize
.
query
(
this
.
QueryGenerator
.
pgEnumAdd
(
tableName
,
attribute
.
field
||
keys
[
i
],
value
,
valueOptions
),
valueOptions
));
}
}
});
});
enumIdx
++
;
enumIdx
++
;
...
@@ -238,7 +251,17 @@ class QueryInterface {
...
@@ -238,7 +251,17 @@ class QueryInterface {
});
});
sql
=
this
.
QueryGenerator
.
createTableQuery
(
tableName
,
attributes
,
options
);
sql
=
this
.
QueryGenerator
.
createTableQuery
(
tableName
,
attributes
,
options
);
return
Promise
.
all
(
promises
).
then
(()
=>
{
return
Promise
.
all
(
promises
)
.
tap
(()
=>
{
// If ENUM processed, then refresh OIDs
if
(
promises
.
length
)
{
return
this
.
sequelize
.
dialect
.
connectionManager
.
_refreshDynamicOIDs
()
.
then
(()
=>
{
return
this
.
sequelize
.
refreshTypes
(
DataTypes
.
postgres
);
});
}
})
.
then
(()
=>
{
return
this
.
sequelize
.
query
(
sql
,
options
);
return
this
.
sequelize
.
query
(
sql
,
options
);
});
});
});
});
...
...
lib/utils.js
View file @
fe06b45
...
@@ -612,3 +612,17 @@ function isWhereEmpty(obj) {
...
@@ -612,3 +612,17 @@ function isWhereEmpty(obj) {
return
_
.
isEmpty
(
obj
)
&&
getOperators
(
obj
).
length
===
0
;
return
_
.
isEmpty
(
obj
)
&&
getOperators
(
obj
).
length
===
0
;
}
}
exports
.
isWhereEmpty
=
isWhereEmpty
;
exports
.
isWhereEmpty
=
isWhereEmpty
;
/**
* Returns ENUM name by joining table and column name
*
* @param {String} tableName
* @param {String} columnName
* @return {String}
* @private
*/
function
generateEnumName
(
tableName
,
columnName
)
{
return
'enum_'
+
tableName
+
'_'
+
columnName
;
}
exports
.
generateEnumName
=
generateEnumName
;
package.json
View file @
fe06b45
...
@@ -99,14 +99,15 @@
...
@@ -99,14 +99,15 @@
],
],
"main"
:
"index"
,
"main"
:
"index"
,
"options"
:
{
"options"
:
{
"env_cmd"
:
"./test/config/.docker.env"
,
"mocha"
:
"--globals setImmediate,clearImmediate --ui tdd --exit --check-leaks --colors -t 30000 --reporter spec"
"mocha"
:
"--globals setImmediate,clearImmediate --ui tdd --exit --check-leaks --colors -t 30000 --reporter spec"
},
},
"scripts"
:
{
"scripts"
:
{
"lint"
:
"eslint lib test --quiet"
,
"lint"
:
"eslint lib test --quiet"
,
"test"
:
"npm run teaser && npm run test-unit && npm run test-integration"
,
"test"
:
"npm run teaser && npm run test-unit && npm run test-integration"
,
"test-docker"
:
"npm run test-docker-unit && npm run test-docker-integration"
,
"test-docker"
:
"npm run test-docker-unit && npm run test-docker-integration"
,
"test-docker-unit"
:
"
env-cmd ./test/config/.docker.env
npm run test-unit"
,
"test-docker-unit"
:
"npm run test-unit"
,
"test-docker-integration"
:
"env-cmd
./test/config/.docker.env
npm run test-integration"
,
"test-docker-integration"
:
"env-cmd
$npm_package_options_env_cmd
npm run test-integration"
,
"docs"
:
"esdoc && cp docs/ROUTER esdoc/ROUTER"
,
"docs"
:
"esdoc && cp docs/ROUTER esdoc/ROUTER"
,
"teaser"
:
"node -e
\"
console.log('#'.repeat(process.env.DIALECT.length + 22) + '
\\
n# Running tests for ' + process.env.DIALECT + ' #
\\
n' + '#'.repeat(process.env.DIALECT.length + 22))
\"
"
,
"teaser"
:
"node -e
\"
console.log('#'.repeat(process.env.DIALECT.length + 22) + '
\\
n# Running tests for ' + process.env.DIALECT + ' #
\\
n' + '#'.repeat(process.env.DIALECT.length + 22))
\"
"
,
"test-unit"
:
"mocha $npm_package_options_mocha
\"
test/unit/**/*.js
\"
"
,
"test-unit"
:
"mocha $npm_package_options_mocha
\"
test/unit/**/*.js
\"
"
,
...
@@ -132,10 +133,10 @@
...
@@ -132,10 +133,10 @@
"test-mssql"
:
"cross-env DIALECT=mssql npm test"
,
"test-mssql"
:
"cross-env DIALECT=mssql npm test"
,
"test-all"
:
"npm run test-mysql && npm run test-sqlite && npm run test-postgres && npm run test-postgres-native && npm run test-mssql"
,
"test-all"
:
"npm run test-mysql && npm run test-sqlite && npm run test-postgres && npm run test-postgres-native && npm run test-mssql"
,
"cover"
:
"rimraf coverage && npm run teaser && npm run cover-integration && npm run cover-unit && npm run merge-coverage"
,
"cover"
:
"rimraf coverage && npm run teaser && npm run cover-integration && npm run cover-unit && npm run merge-coverage"
,
"cover-integration"
:
"cross-env COVERAGE=true
node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -t 6
0000 --exit --ui tdd
\"
test/integration/**/*.test.js
\"
&& node -e
\"
require('fs').renameSync('coverage/lcov.info', 'coverage/integration.info')
\"
"
,
"cover-integration"
:
"cross-env COVERAGE=true
./node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -t 3
0000 --exit --ui tdd
\"
test/integration/**/*.test.js
\"
&& node -e
\"
require('fs').renameSync('coverage/lcov.info', 'coverage/integration.info')
\"
"
,
"cover-unit"
:
"cross-env COVERAGE=true node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -t 30000 --exit --ui tdd
\"
test/unit/**/*.test.js
\"
&& node -e
\"
require('fs').renameSync('coverage/lcov.info', 'coverage/unit.info')
\"
"
,
"cover-unit"
:
"cross-env COVERAGE=true
./
node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -t 30000 --exit --ui tdd
\"
test/unit/**/*.test.js
\"
&& node -e
\"
require('fs').renameSync('coverage/lcov.info', 'coverage/unit.info')
\"
"
,
"merge-coverage"
:
"lcov-result-merger
\"
coverage/*.info
\"
\"
coverage/lcov.info
\"
"
,
"merge-coverage"
:
"lcov-result-merger
\"
coverage/*.info
\"
\"
coverage/lcov.info
\"
"
,
"sscce"
:
"env-cmd
./test/config/.docker.env
node sscce.js"
,
"sscce"
:
"env-cmd
$npm_package_options_env_cmd
node sscce.js"
,
"sscce-mysql"
:
"cross-env DIALECT=mysql npm run sscce"
,
"sscce-mysql"
:
"cross-env DIALECT=mysql npm run sscce"
,
"sscce-postgres"
:
"cross-env DIALECT=postgres npm run sscce"
,
"sscce-postgres"
:
"cross-env DIALECT=postgres npm run sscce"
,
"sscce-sqlite"
:
"cross-env DIALECT=sqlite npm run sscce"
,
"sscce-sqlite"
:
"cross-env DIALECT=sqlite npm run sscce"
,
...
...
test/integration/data-types.test.js
View file @
fe06b45
...
@@ -266,8 +266,11 @@ describe(Support.getTestDialectTeaser('DataTypes'), () => {
...
@@ -266,8 +266,11 @@ describe(Support.getTestDialectTeaser('DataTypes'), () => {
it
(
'calls parse and stringify for ENUM'
,
()
=>
{
it
(
'calls parse and stringify for ENUM'
,
()
=>
{
const
Type
=
new
Sequelize
.
ENUM
(
'hat'
,
'cat'
);
const
Type
=
new
Sequelize
.
ENUM
(
'hat'
,
'cat'
);
// No dialects actually allow us to identify that we get an enum back..
if
([
'postgres'
].
indexOf
(
dialect
)
!==
-
1
)
{
return
testSuccess
(
Type
,
'hat'
);
}
else
{
testFailure
(
Type
);
testFailure
(
Type
);
}
});
});
if
(
current
.
dialect
.
supports
.
GEOMETRY
)
{
if
(
current
.
dialect
.
supports
.
GEOMETRY
)
{
...
...
test/integration/dialects/postgres/dao.test.js
View file @
fe06b45
...
@@ -315,6 +315,38 @@ if (dialect.match(/^postgres/)) {
...
@@ -315,6 +315,38 @@ if (dialect.match(/^postgres/)) {
});
});
});
});
it
(
'should be able to create/drop multiple enums multiple times with field name (#7812)'
,
function
()
{
const
DummyModel
=
this
.
sequelize
.
define
(
'Dummy-pg'
,
{
username
:
DataTypes
.
STRING
,
theEnumOne
:
{
field
:
'oh_my_this_enum_one'
,
type
:
DataTypes
.
ENUM
,
values
:
[
'one'
,
'two'
,
'three'
]
},
theEnumTwo
:
{
field
:
'oh_my_this_enum_two'
,
type
:
DataTypes
.
ENUM
,
values
:
[
'four'
,
'five'
,
'six'
]
}
});
return
DummyModel
.
sync
({
force
:
true
}).
then
(()
=>
{
// now sync one more time:
return
DummyModel
.
sync
({
force
:
true
}).
then
(()
=>
{
// sync without dropping
return
DummyModel
.
sync
();
});
});
});
it
(
'should be able to add values to enum types'
,
function
()
{
it
(
'should be able to add values to enum types'
,
function
()
{
let
User
=
this
.
sequelize
.
define
(
'UserEnums'
,
{
let
User
=
this
.
sequelize
.
define
(
'UserEnums'
,
{
mood
:
DataTypes
.
ENUM
(
'happy'
,
'sad'
,
'meh'
)
mood
:
DataTypes
.
ENUM
(
'happy'
,
'sad'
,
'meh'
)
...
@@ -333,6 +365,161 @@ if (dialect.match(/^postgres/)) {
...
@@ -333,6 +365,161 @@ if (dialect.match(/^postgres/)) {
expect
(
enums
[
0
].
enum_value
).
to
.
equal
(
'{neutral,happy,sad,ecstatic,meh,joyful}'
);
expect
(
enums
[
0
].
enum_value
).
to
.
equal
(
'{neutral,happy,sad,ecstatic,meh,joyful}'
);
});
});
});
});
describe
(
'ARRAY(ENUM)'
,
()
=>
{
it
(
'should be able to ignore enum types that already exist'
,
function
()
{
const
User
=
this
.
sequelize
.
define
(
'UserEnums'
,
{
permissions
:
DataTypes
.
ARRAY
(
DataTypes
.
ENUM
([
'access'
,
'write'
,
'check'
,
'delete'
]))
});
return
User
.
sync
({
force
:
true
}).
then
(()
=>
User
.
sync
());
});
it
(
'should be able to create/drop enums multiple times'
,
function
()
{
const
User
=
this
.
sequelize
.
define
(
'UserEnums'
,
{
permissions
:
DataTypes
.
ARRAY
(
DataTypes
.
ENUM
([
'access'
,
'write'
,
'check'
,
'delete'
]))
});
return
User
.
sync
({
force
:
true
}).
then
(()
=>
User
.
sync
({
force
:
true
}));
});
it
(
'should be able to add values to enum types'
,
function
()
{
let
User
=
this
.
sequelize
.
define
(
'UserEnums'
,
{
permissions
:
DataTypes
.
ARRAY
(
DataTypes
.
ENUM
([
'access'
,
'write'
,
'check'
,
'delete'
]))
});
return
User
.
sync
({
force
:
true
}).
then
(()
=>
{
User
=
this
.
sequelize
.
define
(
'UserEnums'
,
{
permissions
:
DataTypes
.
ARRAY
(
DataTypes
.
ENUM
(
'view'
,
'access'
,
'edit'
,
'write'
,
'check'
,
'delete'
)
)
});
return
User
.
sync
();
}).
then
(()
=>
{
return
this
.
sequelize
.
getQueryInterface
().
pgListEnums
(
User
.
getTableName
());
}).
then
(
enums
=>
{
expect
(
enums
).
to
.
have
.
length
(
1
);
expect
(
enums
[
0
].
enum_value
).
to
.
equal
(
'{view,access,edit,write,check,delete}'
);
});
});
it
(
'should be able to insert new record'
,
function
()
{
const
User
=
this
.
sequelize
.
define
(
'UserEnums'
,
{
name
:
DataTypes
.
STRING
,
type
:
DataTypes
.
ENUM
(
'A'
,
'B'
,
'C'
),
owners
:
DataTypes
.
ARRAY
(
DataTypes
.
STRING
),
permissions
:
DataTypes
.
ARRAY
(
DataTypes
.
ENUM
([
'access'
,
'write'
,
'check'
,
'delete'
]))
});
return
User
.
sync
({
force
:
true
})
.
then
(()
=>
{
return
User
.
create
({
name
:
'file.exe'
,
type
:
'C'
,
owners
:
[
'userA'
,
'userB'
],
permissions
:
[
'access'
,
'write'
]
});
})
.
then
(
user
=>
{
expect
(
user
.
name
).
to
.
equal
(
'file.exe'
);
expect
(
user
.
type
).
to
.
equal
(
'C'
);
expect
(
user
.
owners
).
to
.
deep
.
equal
([
'userA'
,
'userB'
]);
expect
(
user
.
permissions
).
to
.
deep
.
equal
([
'access'
,
'write'
]);
});
});
it
(
'should fail when trying to insert foreign element on ARRAY(ENUM)'
,
function
()
{
const
User
=
this
.
sequelize
.
define
(
'UserEnums'
,
{
name
:
DataTypes
.
STRING
,
type
:
DataTypes
.
ENUM
(
'A'
,
'B'
,
'C'
),
owners
:
DataTypes
.
ARRAY
(
DataTypes
.
STRING
),
permissions
:
DataTypes
.
ARRAY
(
DataTypes
.
ENUM
([
'access'
,
'write'
,
'check'
,
'delete'
]))
});
return
expect
(
User
.
sync
({
force
:
true
}).
then
(()
=>
{
return
User
.
create
({
name
:
'file.exe'
,
type
:
'C'
,
owners
:
[
'userA'
,
'userB'
],
permissions
:
[
'cosmic_ray_disk_access'
]
});
})).
to
.
be
.
rejectedWith
(
/invalid input value for enum "enum_UserEnums_permissions": "cosmic_ray_disk_access"/
);
});
it
(
'should be able to find records'
,
function
()
{
const
User
=
this
.
sequelize
.
define
(
'UserEnums'
,
{
name
:
DataTypes
.
STRING
,
type
:
DataTypes
.
ENUM
(
'A'
,
'B'
,
'C'
),
permissions
:
DataTypes
.
ARRAY
(
DataTypes
.
ENUM
([
'access'
,
'write'
,
'check'
,
'delete'
]))
});
return
User
.
sync
({
force
:
true
})
.
then
(()
=>
{
return
User
.
bulkCreate
([{
name
:
'file1.exe'
,
type
:
'C'
,
permissions
:
[
'access'
,
'write'
]
},
{
name
:
'file2.exe'
,
type
:
'A'
,
permissions
:
[
'access'
,
'check'
]
},
{
name
:
'file3.exe'
,
type
:
'B'
,
permissions
:
[
'access'
,
'write'
,
'delete'
]
}]);
})
.
then
(()
=>
{
return
User
.
findAll
({
where
:
{
type
:
{
$in
:
[
'A'
,
'C'
]
},
permissions
:
{
$contains
:
[
'write'
]
}
}
});
})
.
then
(
users
=>
{
expect
(
users
.
length
).
to
.
equal
(
1
);
expect
(
users
[
0
].
name
).
to
.
equal
(
'file1.exe'
);
expect
(
users
[
0
].
type
).
to
.
equal
(
'C'
);
expect
(
users
[
0
].
permissions
).
to
.
deep
.
equal
([
'access'
,
'write'
]);
});
});
});
});
});
describe
(
'integers'
,
()
=>
{
describe
(
'integers'
,
()
=>
{
...
...
test/integration/support.js
View file @
fe06b45
'use strict'
;
'use strict'
;
const
Support
=
require
(
'../support'
),
const
Support
=
require
(
'../support'
);
dialect
=
Support
.
getTestDialect
();
before
(()
=>
{
if
(
dialect
!==
'postgres'
&&
dialect
!==
'postgres-native'
)
{
return
;
}
return
Support
.
sequelize
.
Promise
.
all
([
Support
.
sequelize
.
query
(
'CREATE EXTENSION IF NOT EXISTS hstore'
,
{
raw
:
true
}),
Support
.
sequelize
.
query
(
'CREATE EXTENSION IF NOT EXISTS btree_gist'
,
{
raw
:
true
})
]);
});
beforeEach
(
function
()
{
beforeEach
(
function
()
{
this
.
sequelize
.
test
.
trackRunningQueries
();
this
.
sequelize
.
test
.
trackRunningQueries
();
...
...
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