Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
小 白蛋
Nocobase
Commits
eaea8a71
Commit
eaea8a71
authored
2 years ago
by
ChengLei Shao
Committed by
chenos
2 years ago
Browse files
Options
Download
Email Patches
Plain Diff
feat: limit database identifier (#908)
parent
76f5754e
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
packages/core/database/src/__tests__/collection.test.ts
+47
-0
packages/core/database/src/__tests__/collection.test.ts
packages/core/database/src/__tests__/fields/belongs-to-field.test.ts
+35
-0
...re/database/src/__tests__/fields/belongs-to-field.test.ts
packages/core/database/src/__tests__/fields/belongs-to-many-field.test.ts
+45
-0
...tabase/src/__tests__/fields/belongs-to-many-field.test.ts
packages/core/database/src/__tests__/fields/has-many-field.test.ts
+22
-0
...core/database/src/__tests__/fields/has-many-field.test.ts
packages/core/database/src/__tests__/fields/has-one-field.test.ts
+21
-0
.../core/database/src/__tests__/fields/has-one-field.test.ts
packages/core/database/src/collection.ts
+12
-2
packages/core/database/src/collection.ts
packages/core/database/src/database.ts
+3
-1
packages/core/database/src/database.ts
packages/core/database/src/errors/identifier-error.ts
+6
-0
packages/core/database/src/errors/identifier-error.ts
packages/core/database/src/fields/belongs-to-field.ts
+4
-0
packages/core/database/src/fields/belongs-to-field.ts
packages/core/database/src/fields/belongs-to-many-field.ts
+11
-0
packages/core/database/src/fields/belongs-to-many-field.ts
packages/core/database/src/fields/field.ts
+1
-0
packages/core/database/src/fields/field.ts
packages/core/database/src/fields/has-many-field.ts
+6
-1
packages/core/database/src/fields/has-many-field.ts
packages/core/database/src/fields/has-one-field.ts
+9
-1
packages/core/database/src/fields/has-one-field.ts
packages/core/database/src/utils.ts
+9
-0
packages/core/database/src/utils.ts
with
231 additions
and
5 deletions
+231
-5
packages/core/database/src/__tests__/collection.test.ts
+
47
-
0
View file @
eaea8a71
import
{
Collection
}
from
'
../collection
'
;
import
{
Database
}
from
'
../database
'
;
import
{
mockDatabase
}
from
'
./index
'
;
import
{
IdentifierError
}
from
'
../errors/identifier-error
'
;
describe
(
'
collection
'
,
()
=>
{
let
db
:
Database
;
...
...
@@ -258,4 +259,50 @@ describe('collection sync', () => {
expect
(
tableFields
[
'
postId
'
]).
toBeDefined
();
expect
(
tableFields
[
'
tagId
'
]).
toBeDefined
();
});
test
(
'
limit table name length
'
,
async
()
=>
{
const
longName
=
'
this_is_a_very_long_table_name_that_should_be_truncated_this_is_a_very_long_table_name_that_should_be_truncated
'
;
let
error
;
try
{
const
collection
=
new
Collection
(
{
name
:
longName
,
fields
:
[{
type
:
'
string
'
,
name
:
'
test
'
}],
},
{
database
:
db
,
},
);
}
catch
(
e
)
{
error
=
e
;
}
expect
(
error
).
toBeInstanceOf
(
IdentifierError
);
});
test
(
'
limit field name length
'
,
async
()
=>
{
const
longFieldName
=
'
this_is_a_very_long_field_name_that_should_be_truncated_this_is_a_very_long_field_name_that_should_be_truncated
'
;
let
error
;
try
{
const
collection
=
new
Collection
(
{
name
:
'
test
'
,
fields
:
[{
type
:
'
string
'
,
name
:
longFieldName
}],
},
{
database
:
db
,
},
);
}
catch
(
e
)
{
error
=
e
;
}
expect
(
error
).
toBeInstanceOf
(
IdentifierError
);
});
});
This diff is collapsed.
Click to expand it.
packages/core/database/src/__tests__/fields/belongs-to-field.test.ts
+
35
-
0
View file @
eaea8a71
import
{
Database
}
from
'
../../database
'
;
import
{
mockDatabase
}
from
'
../
'
;
import
{
IdentifierError
}
from
'
../../errors/identifier-error
'
;
describe
(
'
belongs to field
'
,
()
=>
{
let
db
:
Database
;
...
...
@@ -28,12 +29,16 @@ describe('belongs to field', () => {
{
type
:
'
belongsTo
'
,
name
:
'
post
'
},
],
});
expect
(
Comment
.
model
.
associations
.
post
).
toBeUndefined
();
const
Post
=
db
.
collection
({
name
:
'
posts
'
,
fields
:
[{
type
:
'
string
'
,
name
:
'
title
'
}],
});
const
association
=
Comment
.
model
.
associations
.
post
;
expect
(
Comment
.
model
.
associations
.
post
).
toBeDefined
();
expect
(
association
.
foreignKey
).
toBe
(
'
postId
'
);
// @ts-ignore
...
...
@@ -77,11 +82,41 @@ describe('belongs to field', () => {
const
association
=
Comment
.
model
.
associations
.
post
;
expect
(
association
).
toBeDefined
();
expect
(
association
.
foreignKey
).
toBe
(
'
postKey
'
);
// @ts-ignore
expect
(
association
.
targetKey
).
toBe
(
'
key
'
);
expect
(
Comment
.
model
.
rawAttributes
[
'
postKey
'
]).
toBeDefined
();
});
it
(
'
should throw error when foreignKey is too long
'
,
async
()
=>
{
const
Post
=
db
.
collection
({
name
:
'
posts
'
,
fields
:
[{
type
:
'
string
'
,
name
:
'
key
'
,
unique
:
true
}],
});
const
longForeignKey
=
'
a
'
.
repeat
(
128
);
let
error
;
try
{
const
Comment
=
db
.
collection
({
name
:
'
comments1
'
,
fields
:
[
{
type
:
'
belongsTo
'
,
name
:
'
post
'
,
targetKey
:
'
key
'
,
foreignKey
:
longForeignKey
,
},
],
});
}
catch
(
e
)
{
error
=
e
;
}
expect
(
error
).
toBeInstanceOf
(
IdentifierError
);
});
it
(
'
custom name and target
'
,
async
()
=>
{
const
Comment
=
db
.
collection
({
name
:
'
comments
'
,
...
...
This diff is collapsed.
Click to expand it.
packages/core/database/src/__tests__/fields/belongs-to-many-field.test.ts
+
45
-
0
View file @
eaea8a71
import
{
mockDatabase
}
from
'
../
'
;
import
{
Database
}
from
'
../../database
'
;
import
{
IdentifierError
}
from
'
../../errors/identifier-error
'
;
describe
(
'
belongs to many field
'
,
()
=>
{
let
db
:
Database
;
...
...
@@ -58,4 +59,48 @@ describe('belongs to many field', () => {
expect
(
PostTag
.
model
.
rawAttributes
[
'
postId
'
]).
toBeDefined
();
expect
(
PostTag
.
model
.
rawAttributes
[
'
tagId
'
]).
toBeDefined
();
});
it
(
'
should throw error when foreignKey is too long
'
,
async
()
=>
{
const
Post
=
db
.
collection
({
name
:
'
posts
'
,
fields
:
[
{
type
:
'
string
'
,
name
:
'
name
'
},
{
type
:
'
belongsToMany
'
,
name
:
'
tags
'
,
foreignKey
:
'
a
'
.
repeat
(
128
)
},
],
});
let
error
;
try
{
const
Tag
=
db
.
collection
({
name
:
'
tags
'
,
fields
:
[{
type
:
'
string
'
,
name
:
'
name
'
}],
});
}
catch
(
e
)
{
error
=
e
;
}
expect
(
error
).
toBeInstanceOf
(
IdentifierError
);
});
it
(
'
should throw error when through is too long
'
,
async
()
=>
{
const
Post
=
db
.
collection
({
name
:
'
posts
'
,
fields
:
[
{
type
:
'
string
'
,
name
:
'
name
'
},
{
type
:
'
belongsToMany
'
,
name
:
'
tags
'
,
through
:
'
a
'
.
repeat
(
128
)
},
],
});
let
error
;
try
{
const
Tag
=
db
.
collection
({
name
:
'
tags
'
,
fields
:
[{
type
:
'
string
'
,
name
:
'
name
'
}],
});
}
catch
(
e
)
{
error
=
e
;
}
expect
(
error
).
toBeInstanceOf
(
IdentifierError
);
});
});
This diff is collapsed.
Click to expand it.
packages/core/database/src/__tests__/fields/has-many-field.test.ts
+
22
-
0
View file @
eaea8a71
import
{
Database
}
from
'
../../database
'
;
import
{
mockDatabase
}
from
'
../
'
;
import
{
makeWatchHost
}
from
'
ts-loader/dist/servicesHost
'
;
import
{
IdentifierError
}
from
'
../../errors/identifier-error
'
;
describe
(
'
has many field
'
,
()
=>
{
let
db
:
Database
;
...
...
@@ -149,4 +150,25 @@ describe('has many field', () => {
Comment
.
removeField
(
'
post
'
);
expect
(
Comment
.
model
.
rawAttributes
.
postId
).
toBeUndefined
();
});
it
(
'
should throw error when foreignKey is too long
'
,
async
()
=>
{
const
longForeignKey
=
'
a
'
.
repeat
(
64
);
const
Post
=
db
.
collection
({
name
:
'
posts
'
,
fields
:
[{
type
:
'
hasMany
'
,
name
:
'
comments
'
,
foreignKey
:
longForeignKey
}],
});
let
error
;
try
{
const
Comment
=
db
.
collection
({
name
:
'
comments
'
,
fields
:
[{
type
:
'
belongsTo
'
,
name
:
'
post
'
}],
});
}
catch
(
e
)
{
error
=
e
;
}
expect
(
error
).
toBeInstanceOf
(
IdentifierError
);
});
});
This diff is collapsed.
Click to expand it.
packages/core/database/src/__tests__/fields/has-one-field.test.ts
+
21
-
0
View file @
eaea8a71
import
{
Database
}
from
'
../../database
'
;
import
{
mockDatabase
}
from
'
../
'
;
import
{
IdentifierError
}
from
'
../../errors/identifier-error
'
;
describe
(
'
has many field
'
,
()
=>
{
let
db
:
Database
;
...
...
@@ -64,4 +65,24 @@ describe('has many field', () => {
Profile
.
removeField
(
'
user
'
);
expect
(
Profile
.
model
.
rawAttributes
.
userId
).
toBeUndefined
();
});
it
(
'
should throw error when foreignKey is too long
'
,
async
()
=>
{
const
longForeignKey
=
'
a
'
.
repeat
(
128
);
const
User
=
db
.
collection
({
name
:
'
users
'
,
fields
:
[{
type
:
'
hasOne
'
,
name
:
'
profile
'
,
foreignKey
:
longForeignKey
}],
});
let
error
;
try
{
const
Profile
=
db
.
collection
({
name
:
'
profiles
'
,
fields
:
[{
type
:
'
belongsTo
'
,
name
:
'
user
'
}],
});
}
catch
(
e
)
{
error
=
e
;
}
expect
(
error
).
toBeInstanceOf
(
IdentifierError
);
});
});
This diff is collapsed.
Click to expand it.
packages/core/database/src/collection.ts
+
12
-
2
View file @
eaea8a71
...
...
@@ -7,13 +7,13 @@ import {
QueryInterfaceDropTableOptions
,
SyncOptions
,
Transactionable
,
Utils
Utils
,
}
from
'
sequelize
'
;
import
{
Database
}
from
'
./database
'
;
import
{
Field
,
FieldOptions
}
from
'
./fields
'
;
import
{
Model
}
from
'
./model
'
;
import
{
Repository
}
from
'
./repository
'
;
import
{
md5
}
from
'
./utils
'
;
import
{
checkIdentifier
,
md5
}
from
'
./utils
'
;
export
type
RepositoryType
=
typeof
Repository
;
...
...
@@ -67,8 +67,11 @@ export class Collection<
constructor
(
options
:
CollectionOptions
,
context
?:
CollectionContext
)
{
super
();
this
.
checkOptions
(
options
);
this
.
context
=
context
;
this
.
options
=
options
;
this
.
bindFieldEventListener
();
this
.
modelInit
();
this
.
setFields
(
options
.
fields
);
...
...
@@ -76,6 +79,10 @@ export class Collection<
this
.
setSortable
(
options
.
sortable
);
}
private
checkOptions
(
options
:
CollectionOptions
)
{
checkIdentifier
(
options
.
name
);
}
private
sequelizeModelOptions
()
{
const
{
name
,
tableName
}
=
this
.
options
;
return
{
...
...
@@ -160,6 +167,8 @@ export class Collection<
}
setField
(
name
:
string
,
options
:
FieldOptions
):
Field
{
checkIdentifier
(
name
);
const
{
database
}
=
this
.
context
;
const
field
=
database
.
buildField
(
...
...
@@ -169,6 +178,7 @@ export class Collection<
collection
:
this
,
},
);
this
.
removeField
(
name
);
this
.
fields
.
set
(
name
,
field
);
this
.
emit
(
'
field.afterAdd
'
,
field
);
...
...
This diff is collapsed.
Click to expand it.
packages/core/database/src/database.ts
+
3
-
1
View file @
eaea8a71
...
...
@@ -14,7 +14,7 @@ import {
Sequelize
,
SyncOptions
,
Transactionable
,
Utils
Utils
,
}
from
'
sequelize
'
;
import
{
SequelizeStorage
,
Umzug
}
from
'
umzug
'
;
import
{
Collection
,
CollectionOptions
,
RepositoryType
}
from
'
./collection
'
;
...
...
@@ -361,9 +361,11 @@ export class Database extends EventEmitter implements AsyncEmitter {
buildField
(
options
,
context
:
FieldContext
)
{
const
{
type
}
=
options
;
const
Field
=
this
.
fieldTypes
.
get
(
type
);
if
(
!
Field
)
{
throw
Error
(
`unsupported field type
${
type
}
`
);
}
return
new
Field
(
options
,
context
);
}
...
...
This diff is collapsed.
Click to expand it.
packages/core/database/src/errors/identifier-error.ts
0 → 100644
+
6
-
0
View file @
eaea8a71
export
class
IdentifierError
extends
Error
{
constructor
(
message
:
string
)
{
super
(
message
);
this
.
name
=
'
IdentifierError
'
;
}
}
This diff is collapsed.
Click to expand it.
packages/core/database/src/fields/belongs-to-field.ts
+
4
-
0
View file @
eaea8a71
import
{
omit
}
from
'
lodash
'
;
import
{
BelongsToOptions
as
SequelizeBelongsToOptions
,
Utils
}
from
'
sequelize
'
;
import
{
BaseRelationFieldOptions
,
RelationField
}
from
'
./relation-field
'
;
import
{
checkIdentifier
}
from
'
../utils
'
;
export
class
BelongsToField
extends
RelationField
{
static
type
=
'
belongsTo
'
;
...
...
@@ -42,10 +43,13 @@ export class BelongsToField extends RelationField {
this
.
options
.
foreignKey
=
association
.
foreignKey
;
}
checkIdentifier
(
this
.
options
.
foreignKey
);
if
(
!
this
.
options
.
sourceKey
)
{
// @ts-ignore
this
.
options
.
sourceKey
=
association
.
sourceKey
;
}
this
.
collection
.
addIndex
([
this
.
options
.
foreignKey
]);
return
true
;
}
...
...
This diff is collapsed.
Click to expand it.
packages/core/database/src/fields/belongs-to-many-field.ts
+
11
-
0
View file @
eaea8a71
...
...
@@ -2,6 +2,7 @@ import { omit } from 'lodash';
import
{
BelongsToManyOptions
as
SequelizeBelongsToManyOptions
,
Utils
}
from
'
sequelize
'
;
import
{
Collection
}
from
'
../collection
'
;
import
{
MultipleRelationFieldOptions
,
RelationField
}
from
'
./relation-field
'
;
import
{
checkIdentifier
}
from
'
../utils
'
;
export
class
BelongsToManyField
extends
RelationField
{
get
through
()
{
...
...
@@ -23,6 +24,7 @@ export class BelongsToManyField extends RelationField {
database
.
addPendingField
(
this
);
return
false
;
}
const
through
=
this
.
through
;
let
Through
:
Collection
;
...
...
@@ -33,6 +35,7 @@ export class BelongsToManyField extends RelationField {
Through
=
database
.
collection
({
name
:
through
,
});
Object
.
defineProperty
(
Through
.
model
,
'
isThrough
'
,
{
value
:
true
});
}
...
...
@@ -49,15 +52,23 @@ export class BelongsToManyField extends RelationField {
if
(
!
this
.
options
.
foreignKey
)
{
this
.
options
.
foreignKey
=
association
.
foreignKey
;
}
checkIdentifier
(
this
.
options
.
foreignKey
);
if
(
!
this
.
options
.
sourceKey
)
{
this
.
options
.
sourceKey
=
association
.
sourceKey
;
}
if
(
!
this
.
options
.
otherKey
)
{
this
.
options
.
otherKey
=
association
.
otherKey
;
}
checkIdentifier
(
this
.
options
.
otherKey
);
if
(
!
this
.
options
.
through
)
{
this
.
options
.
through
=
this
.
through
;
}
Through
.
addIndex
([
this
.
options
.
foreignKey
]);
Through
.
addIndex
([
this
.
options
.
otherKey
]);
return
true
;
...
...
This diff is collapsed.
Click to expand it.
packages/core/database/src/fields/field.ts
+
1
-
0
View file @
eaea8a71
...
...
@@ -9,6 +9,7 @@ import {
}
from
'
sequelize
'
;
import
{
Collection
}
from
'
../collection
'
;
import
{
Database
}
from
'
../database
'
;
import
{
checkIdentifier
}
from
'
../utils
'
;
export
interface
FieldContext
{
database
:
Database
;
...
...
This diff is collapsed.
Click to expand it.
packages/core/database/src/fields/has-many-field.ts
+
6
-
1
View file @
eaea8a71
...
...
@@ -5,10 +5,11 @@ import {
ForeignKeyOptions
,
HasManyOptions
,
HasManyOptions
as
SequelizeHasManyOptions
,
Utils
Utils
,
}
from
'
sequelize
'
;
import
{
Collection
}
from
'
../collection
'
;
import
{
MultipleRelationFieldOptions
,
RelationField
}
from
'
./relation-field
'
;
import
{
checkIdentifier
}
from
'
../utils
'
;
export
interface
HasManyFieldOptions
extends
HasManyOptions
{
/**
...
...
@@ -98,6 +99,7 @@ export class HasManyField extends RelationField {
as
:
this
.
name
,
foreignKey
:
this
.
foreignKey
,
});
// inverse relation
// this.TargetModel.belongsTo(collection.model);
...
...
@@ -107,6 +109,9 @@ export class HasManyField extends RelationField {
if
(
!
this
.
options
.
foreignKey
)
{
this
.
options
.
foreignKey
=
association
.
foreignKey
;
}
checkIdentifier
(
this
.
options
.
foreignKey
);
if
(
!
this
.
options
.
sourceKey
)
{
// @ts-ignore
this
.
options
.
sourceKey
=
association
.
sourceKey
;
...
...
This diff is collapsed.
Click to expand it.
packages/core/database/src/fields/has-one-field.ts
+
9
-
1
View file @
eaea8a71
...
...
@@ -5,10 +5,11 @@ import {
ForeignKeyOptions
,
HasOneOptions
,
HasOneOptions
as
SequelizeHasOneOptions
,
Utils
Utils
,
}
from
'
sequelize
'
;
import
{
Collection
}
from
'
../collection
'
;
import
{
BaseRelationFieldOptions
,
RelationField
}
from
'
./relation-field
'
;
import
{
checkIdentifier
}
from
'
../utils
'
;
export
interface
HasOneFieldOptions
extends
HasOneOptions
{
/**
...
...
@@ -92,21 +93,28 @@ export class HasOneField extends RelationField {
database
.
addPendingField
(
this
);
return
false
;
}
const
association
=
collection
.
model
.
hasOne
(
Target
,
{
constraints
:
false
,
...
omit
(
this
.
options
,
[
'
name
'
,
'
type
'
,
'
target
'
]),
as
:
this
.
name
,
foreignKey
:
this
.
foreignKey
,
});
// 建立关系之后从 pending 列表中删除
database
.
removePendingField
(
this
);
if
(
!
this
.
options
.
foreignKey
)
{
this
.
options
.
foreignKey
=
association
.
foreignKey
;
}
checkIdentifier
(
this
.
options
.
foreignKey
);
if
(
!
this
.
options
.
sourceKey
)
{
// @ts-ignore
this
.
options
.
sourceKey
=
association
.
sourceKey
;
}
let
tcoll
:
Collection
;
if
(
this
.
target
===
collection
.
name
)
{
tcoll
=
collection
;
...
...
This diff is collapsed.
Click to expand it.
packages/core/database/src/utils.ts
+
9
-
0
View file @
eaea8a71
import
crypto
from
'
crypto
'
;
import
{
Model
}
from
'
./model
'
;
import
{
IdentifierError
}
from
'
./errors/identifier-error
'
;
type
HandleAppendsQueryOptions
=
{
templateModel
:
any
;
...
...
@@ -49,3 +50,11 @@ export async function handleAppendsQuery(options: HandleAppendsQueryOptions) {
export
function
md5
(
value
:
string
)
{
return
crypto
.
createHash
(
'
md5
'
).
update
(
value
).
digest
(
'
hex
'
);
}
const
MAX_IDENTIFIER_LENGTH
=
63
;
export
function
checkIdentifier
(
value
:
string
)
{
if
(
value
.
length
>
MAX_IDENTIFIER_LENGTH
)
{
throw
new
IdentifierError
(
`Identifier
${
value
}
is too long`
);
}
}
This diff is collapsed.
Click to expand it.
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
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 comment