@typetron/framework 0.5.3 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc-old.js +208 -0
- package/Cache/Cache.ts +13 -0
- package/Cache/Stores/DatabaseStore.ts +120 -0
- package/Cache/Stores/FileStore.ts +69 -0
- package/Cache/Stores/MemoryStore.ts +71 -0
- package/Cache/index.ts +5 -0
- package/Cache/types.ts +4 -0
- package/Container/ClassResolver.ts +106 -0
- package/Container/Container.ts +144 -0
- package/Container/Contracts.ts +3 -0
- package/Container/Decorators.ts +20 -0
- package/Container/Metadata.ts +16 -0
- package/Container/Resolver.ts +27 -0
- package/Container/index.ts +5 -0
- package/Database/Clauses/Where.ts +0 -0
- package/Database/Connection.ts +52 -0
- package/Database/Decorators.ts +142 -0
- package/Database/Drivers/DatabaseDriver.ts +37 -0
- package/Database/Drivers/MySQL/Alter/index.ts +55 -0
- package/Database/Drivers/MySQL/ColumnDefinition.ts +16 -0
- package/Database/Drivers/MySQL/Create.ts +47 -0
- package/Database/Drivers/MySQL/MysqlDriver.ts +123 -0
- package/Database/Drivers/MySQL/Schema.ts +82 -0
- package/Database/Drivers/MySQL/index.ts +13 -0
- package/Database/Drivers/SQL/Schema.ts +73 -0
- package/Database/Drivers/SQL/Statements/Alter.ts +22 -0
- package/Database/Drivers/SQL/Statements/BaseStatement.ts +55 -0
- package/Database/Drivers/SQL/Statements/Delete.ts +20 -0
- package/Database/Drivers/SQL/Statements/Insert.ts +24 -0
- package/Database/Drivers/SQL/Statements/Select.ts +55 -0
- package/Database/Drivers/SQL/Statements/Update.ts +33 -0
- package/Database/Drivers/SQL/index.ts +8 -0
- package/Database/Drivers/SQLite/Create.ts +45 -0
- package/Database/Drivers/SQLite/Schema.ts +54 -0
- package/Database/Drivers/SQLite/SqliteDriver.ts +144 -0
- package/Database/Drivers/SQLite/index.ts +15 -0
- package/Database/Drivers/SchemaContract.ts +11 -0
- package/Database/Drivers/Statement.ts +16 -0
- package/Database/Drivers/index.ts +4 -0
- package/Database/Entity.ts +377 -0
- package/Database/EntityNotFoundError.ts +5 -0
- package/Database/EntityProxyHandler.ts +43 -0
- package/Database/EntityQuery.ts +197 -0
- package/Database/Expression.ts +3 -0
- package/Database/Fields.ts +816 -0
- package/Database/Helpers.ts +12 -0
- package/Database/List.ts +71 -0
- package/Database/Migrations/Migration.ts +10 -0
- package/Database/Migrations/MigrationHistory.ts +20 -0
- package/Database/Migrations/Migrator.ts +122 -0
- package/Database/Migrations/index.ts +3 -0
- package/Database/ORM/BaseRelationship.ts +10 -0
- package/Database/Query.ts +374 -0
- package/Database/Seeders/Seeder.ts +3 -0
- package/Database/Seeders/SeederManager.ts +27 -0
- package/Database/Seeders/index.ts +2 -0
- package/Database/StringExpression.ts +9 -0
- package/Database/Types.ts +165 -0
- package/Database/index.ts +23 -0
- package/Encryption/index.ts +51 -0
- package/Forms/Decorators.ts +29 -0
- package/Forms/Form.ts +70 -0
- package/Forms/FormFields.ts +36 -0
- package/Forms/index.ts +3 -0
- package/Framework/App.ts +10 -0
- package/Framework/Application.ts +118 -0
- package/Framework/Auth/Auth.ts +122 -0
- package/Framework/Auth/Authenticatable.ts +9 -0
- package/Framework/Auth/User.ts +27 -0
- package/Framework/Auth/index.ts +29 -0
- package/Framework/Config/AppConfig.ts +25 -0
- package/Framework/Config/AuthConfig.ts +9 -0
- package/Framework/Config/BaseConfig.ts +9 -0
- package/Framework/Config/CacheConfig.ts +38 -0
- package/Framework/Config/DatabaseConfig.ts +21 -0
- package/Framework/Config/MailConfig.ts +30 -0
- package/Framework/Config/index.ts +6 -0
- package/Framework/Middleware/AuthMiddleware.ts +31 -0
- package/Framework/Middleware/CorsMiddleware.ts +32 -0
- package/Framework/Middleware/StaticAssetsMiddleware.ts +76 -0
- package/Framework/Middleware/index.ts +2 -0
- package/Framework/Provider.ts +9 -0
- package/Framework/Providers/CacheProvider.ts +28 -0
- package/Framework/Providers/DatabaseProvider.ts +36 -0
- package/Framework/Providers/MailProvider.ts +31 -0
- package/Framework/Providers/WebsocketsProvider.ts +120 -0
- package/Framework/Resolvers/AuthResolver.ts +23 -0
- package/Framework/Resolvers/EntityResolver.ts +41 -0
- package/Framework/Resolvers/FormResolver.ts +37 -0
- package/Framework/RootDir.ts +1 -0
- package/Framework/index.ts +8 -0
- package/Frontend/Angular/index.ts +24 -0
- package/Frontend/Websockets/index.ts +86 -0
- package/Mail/MailAddress.ts +4 -0
- package/Mail/MailTransport.ts +6 -0
- package/Mail/Mailable.ts +16 -0
- package/Mail/Mailer.ts +27 -0
- package/Mail/PendingMail.ts +68 -0
- package/Mail/SentMessage.ts +20 -0
- package/Mail/Transports/MemoryTransport.ts +13 -0
- package/Mail/Transports/SendGridTransport.ts +95 -0
- package/Mail/index.ts +3 -0
- package/Models/Model.ts +41 -0
- package/Models/index.ts +54 -0
- package/Router/BaseController.ts +7 -0
- package/Router/Decorators.ts +224 -0
- package/Router/Guard.ts +10 -0
- package/Router/Http/Contracts.ts +4 -0
- package/Router/Http/ErrorHandler.ts +45 -0
- package/Router/Http/ErrorHandlerInterface.ts +6 -0
- package/Router/Http/Errors/HttpError.ts +15 -0
- package/Router/Http/Handler.ts +183 -0
- package/Router/Http/HttpRoute.ts +110 -0
- package/Router/Http/Middleware.ts +7 -0
- package/Router/Http/Request.ts +225 -0
- package/Router/Http/Response.ts +35 -0
- package/Router/Http/index.ts +85 -0
- package/Router/Metadata.ts +34 -0
- package/Router/Middleware.ts +16 -0
- package/Router/Request.ts +65 -0
- package/Router/Route.ts +16 -0
- package/Router/RouteNotFoundError.ts +5 -0
- package/Router/Router.ts +35 -0
- package/Router/Servers/index.ts +6 -0
- package/Router/Servers/node.ts +49 -0
- package/Router/Servers/uNetworking.ts +151 -0
- package/Router/Websockets/Handler.ts +82 -0
- package/Router/Websockets/Middleware.ts +7 -0
- package/Router/Websockets/Request.ts +3 -0
- package/Router/Websockets/WebsocketRoute.ts +61 -0
- package/Router/Websockets/index.ts +57 -0
- package/Router/Websockets/types.ts +23 -0
- package/Router/index.ts +6 -0
- package/Storage/File.ts +30 -0
- package/Storage/Image.ts +19 -0
- package/Storage/InvalidImage.ts +3 -0
- package/Storage/Storage.ts +98 -0
- package/Storage/index.ts +4 -0
- package/Storage/utils.ts +18 -0
- package/Support/Array.ts +184 -0
- package/Support/Math.ts +12 -0
- package/Support/Metadata.ts +31 -0
- package/Support/String.ts +38 -0
- package/Support/index.ts +19 -0
- package/Support/utils.ts +7 -0
- package/Testing/TestCase.ts +193 -0
- package/Validation/Rule.ts +9 -0
- package/Validation/RuleInterface.ts +10 -0
- package/Validation/Rules/Email.ts +20 -0
- package/Validation/Rules/FileExtension.ts +21 -0
- package/Validation/Rules/MaxLength.ts +17 -0
- package/Validation/Rules/MinLength.ts +18 -0
- package/Validation/Rules/Optional.ts +18 -0
- package/Validation/Rules/Required.ts +29 -0
- package/Validation/Validator.ts +7 -0
- package/Validation/index.ts +12 -0
- package/benchmark-index.js +20 -0
- package/benchmark.ts +47 -0
- package/package.json +7 -3
- package/tests/Cache/DatabaseStoreTest.ts +110 -0
- package/tests/Cache/FileStoreTest.ts +93 -0
- package/tests/Cache/MemoryStoreTest.ts +92 -0
- package/tests/Container/ContainerTest.ts +336 -0
- package/tests/Database/Drivers/MySQL/AlterTest.ts +100 -0
- package/tests/Database/Drivers/MySQL/CreateTest.ts +39 -0
- package/tests/Database/Drivers/MysqlDriverTest.ts +140 -0
- package/tests/Database/Drivers/SqliteDriverTest.ts +126 -0
- package/tests/Database/Entities/Article.ts +21 -0
- package/tests/Database/Entities/Profile.ts +21 -0
- package/tests/Database/Entities/Role.ts +15 -0
- package/tests/Database/Entities/User.ts +35 -0
- package/tests/Database/EntityRelationshipsTest.ts +475 -0
- package/tests/Database/EntityTest.ts +202 -0
- package/tests/Database/Migrations/RunnerTest.ts +96 -0
- package/tests/Database/Migrations/migrations/1.createUserTable.ts +12 -0
- package/tests/Database/Migrations/migrations/2.createArticlesTable.ts +12 -0
- package/tests/Database/QueryTest.ts +573 -0
- package/tests/Database/SchemaTest.ts +32 -0
- package/tests/Database/Seeders/RunnerTest.ts +30 -0
- package/tests/Database/Seeders/seeders/RandomSeeder.ts +10 -0
- package/tests/Database/utils.ts +16 -0
- package/tests/Forms/FormsTest.ts +59 -0
- package/tests/Framework/Middleware/StaticAssetsMiddlewareTest.ts +129 -0
- package/tests/Framework/Resolvers/EntityResolverTest.ts +48 -0
- package/tests/Framework/Router/RouterTest.ts +33 -0
- package/tests/Mail/MailerTest.ts +76 -0
- package/tests/Model/ModelTest.ts +183 -0
- package/tests/Router/HttpHandlerTest.ts +72 -0
- package/tests/Router/RequestTest.ts +77 -0
- package/tests/Router/WebSocketsHandlerTest.ts +51 -0
- package/tests/Storage/StorageTest.ts +97 -0
- package/tests/Support/ArrayTest.ts +167 -0
- package/tests/Support/StringTest.ts +18 -0
- package/tests/Validation/RulesTest.ts +54 -0
- package/types.d.ts +8 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { DatabaseDriver } from '../DatabaseDriver'
|
|
2
|
+
import { Connection, ConnectionConfig, createConnection, OkPacket } from 'mysql'
|
|
3
|
+
import { SqlValue } from '../../Types'
|
|
4
|
+
import { Create } from './Create'
|
|
5
|
+
import { Select } from '../SQL/Statements/Select'
|
|
6
|
+
import { Insert } from '../SQL/Statements/Insert'
|
|
7
|
+
import { Delete } from '../SQL/Statements/Delete'
|
|
8
|
+
import { Update } from '../SQL/Statements/Update'
|
|
9
|
+
import { Alter } from '../SQL/Statements/Alter'
|
|
10
|
+
import { SchemaContract } from '../SchemaContract'
|
|
11
|
+
import { Schema } from './Schema'
|
|
12
|
+
|
|
13
|
+
interface ColumnInfo {
|
|
14
|
+
name: string
|
|
15
|
+
type: string
|
|
16
|
+
nullable: 0 | 1
|
|
17
|
+
default?: string | number
|
|
18
|
+
autoIncrement: 0 | 1
|
|
19
|
+
primaryKey: 0 | 1
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class MysqlDriver extends DatabaseDriver {
|
|
23
|
+
connection: Connection
|
|
24
|
+
|
|
25
|
+
schema: SchemaContract = new Schema(this)
|
|
26
|
+
|
|
27
|
+
statements = {
|
|
28
|
+
create: Create,
|
|
29
|
+
select: Select,
|
|
30
|
+
insert: Insert,
|
|
31
|
+
delete: Delete,
|
|
32
|
+
update: Update,
|
|
33
|
+
alter: Alter,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
constructor(connectionConfig: ConnectionConfig) {
|
|
37
|
+
super()
|
|
38
|
+
this.connection = createConnection({
|
|
39
|
+
connectTimeout: 30000,
|
|
40
|
+
...connectionConfig,
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
this.connection.connect()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async truncate(table: string) {
|
|
47
|
+
await this.run(`TRUNCATE TABLE ${table}`)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
runRaw<T>(query: string, params: SqlValue[] = []): Promise<T | OkPacket> {
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
this.connection.query(query, params, (error, results, fields) => {
|
|
53
|
+
if (error) {
|
|
54
|
+
error.message += `in SQL: "${error.sql}"`
|
|
55
|
+
return reject(error)
|
|
56
|
+
}
|
|
57
|
+
resolve(results)
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async run(query: string, params: SqlValue[] = []) {
|
|
63
|
+
await this.runRaw(query, params)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async get<T>(query: string, params: SqlValue[] = []): Promise<T[]> {
|
|
67
|
+
return (await this.runRaw(query, params) as T[])
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async first<T>(query: string, params: SqlValue[] = []): Promise<T> {
|
|
71
|
+
return (await this.runRaw(query, params) as T[])?.[0]
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async insertOne(query: string, params: SqlValue[] = []): Promise<number> {
|
|
75
|
+
return (await this.runRaw(query, params) as OkPacket).insertId
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
tables() {
|
|
79
|
+
return this.get<{name: string}>(
|
|
80
|
+
`select TABLE_NAME as name
|
|
81
|
+
from information_schema.TABLES
|
|
82
|
+
WHERE table_schema = ?
|
|
83
|
+
`,
|
|
84
|
+
[this.connection.config.database]
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
tableExists(table: string): Promise<boolean> {
|
|
89
|
+
return this.first(
|
|
90
|
+
`select *
|
|
91
|
+
from information_schema.tables
|
|
92
|
+
where table_name = ?
|
|
93
|
+
and table_schema = ?
|
|
94
|
+
`,
|
|
95
|
+
[table, this.connection.config.database]
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async tableColumns(table: string) {
|
|
100
|
+
const columnsInfo = await this.get<ColumnInfo>(
|
|
101
|
+
`select cast(IS_NULLABLE = 'YES' as unsigned) as nullable,
|
|
102
|
+
cast(EXTRA = 'auto_increment' as unsigned) as autoIncrement,
|
|
103
|
+
cast(COLUMN_KEY = 'PRI' as unsigned) as primaryKey,
|
|
104
|
+
COLUMN_NAME as name,
|
|
105
|
+
DATA_TYPE as type,
|
|
106
|
+
COLUMN_DEFAULT as 'default'
|
|
107
|
+
from information_schema.COLUMNS
|
|
108
|
+
where table_name = ?
|
|
109
|
+
and table_schema = ?
|
|
110
|
+
`,
|
|
111
|
+
[table, this.connection.config.database]
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
return columnsInfo.map(info => ({
|
|
115
|
+
name: info.name,
|
|
116
|
+
type: info.type,
|
|
117
|
+
nullable: Boolean(info.nullable),
|
|
118
|
+
default: info.default,
|
|
119
|
+
autoIncrement: info.autoIncrement,
|
|
120
|
+
primaryKey: Boolean(info.primaryKey)
|
|
121
|
+
}))
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { ColumnField, Entity, Expression, PrimaryField } from '../..'
|
|
2
|
+
import { Schema as BaseSchema } from '../SQL/Schema'
|
|
3
|
+
import { Create } from './Create'
|
|
4
|
+
import { typesMatches } from '.'
|
|
5
|
+
import { ColumnDefinitionOptions } from '../SQL'
|
|
6
|
+
import { AddColumn, AddConstraint, Alter, Constraints, DropColumn, ModifyColumn } from './Alter'
|
|
7
|
+
|
|
8
|
+
export class Schema extends BaseSchema {
|
|
9
|
+
|
|
10
|
+
columnMetadataToColumnDefinition(metadata: ColumnField<Entity>) {
|
|
11
|
+
return {
|
|
12
|
+
name: metadata.column,
|
|
13
|
+
primaryKey: metadata.constructor === PrimaryField,
|
|
14
|
+
autoIncrement: Number(metadata.constructor === PrimaryField),
|
|
15
|
+
type: this.getColumnTypeBasedOnTypescriptType(metadata),
|
|
16
|
+
default: undefined,
|
|
17
|
+
nullable: true
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async create(table: string, columns: ColumnField<Entity>[]) {
|
|
22
|
+
const columnsDefinitions: ColumnDefinitionOptions[] = columns.map(column => this.columnMetadataToColumnDefinition(column))
|
|
23
|
+
const createStatement = new Create(table, columnsDefinitions)
|
|
24
|
+
|
|
25
|
+
await this.driver.run(createStatement.toSQL())
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
protected async syncTableColumns(table: string, columnsMetadata: ColumnField<Entity>[]) {
|
|
29
|
+
const columns = columnsMetadata.map(metadata => this.columnMetadataToColumnDefinition(metadata))
|
|
30
|
+
|
|
31
|
+
const tableColumns = await this.driver.tableColumns(table)
|
|
32
|
+
|
|
33
|
+
let alters: Expression[] = []
|
|
34
|
+
|
|
35
|
+
alters = alters.concat(
|
|
36
|
+
columns
|
|
37
|
+
.whereNotIn('name', tableColumns.pluck('name'))
|
|
38
|
+
.map(column => new AddColumn({...column, autoIncrement: undefined}))
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
columns.whereIn('name', tableColumns.pluck('name'))
|
|
42
|
+
.forEach(column => {
|
|
43
|
+
const typeInDB = tableColumns.findWhere('name', column.name)?.type
|
|
44
|
+
if (typeInDB !== column.type) {
|
|
45
|
+
alters.push(new ModifyColumn(column))
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
alters = alters.concat(
|
|
50
|
+
tableColumns
|
|
51
|
+
.whereNotIn('name', columns.pluck('name'))
|
|
52
|
+
.map(tableColumn => new DropColumn(tableColumn.name))
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
await this.driver.run(new Alter(table, alters).toSQL())
|
|
56
|
+
|
|
57
|
+
const additionalAlters: Expression[] = []
|
|
58
|
+
columns.forEach(column => {
|
|
59
|
+
const dbInfo = tableColumns.findWhere('name', column.name)
|
|
60
|
+
if (column.primaryKey && !dbInfo?.primaryKey) {
|
|
61
|
+
additionalAlters.push(new AddConstraint(column, Constraints.PrimaryKey))
|
|
62
|
+
}
|
|
63
|
+
if (column.autoIncrement && !dbInfo?.autoIncrement) {
|
|
64
|
+
additionalAlters.push(new ModifyColumn(column))
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
if (!additionalAlters.empty()) {
|
|
69
|
+
await this.driver.run(new Alter(table, additionalAlters).toSQL())
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private getColumnTypeBasedOnTypescriptType(column: ColumnField<Entity>) {
|
|
74
|
+
const typePrototype = Array.from(typesMatches.keys())
|
|
75
|
+
.find(key => column.type().prototype instanceof key) || String
|
|
76
|
+
|
|
77
|
+
return typesMatches.get(column.type())
|
|
78
|
+
?? typesMatches.get(column.constructor)
|
|
79
|
+
?? typesMatches.get(typePrototype)
|
|
80
|
+
?? typesMatches.get(String) as string
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Entity } from '../../Entity'
|
|
2
|
+
import { JSONField, PrimaryField } from '../../Fields'
|
|
3
|
+
|
|
4
|
+
// tslint:disable-next-line:no-any
|
|
5
|
+
export const typesMatches = new Map<any, string>([
|
|
6
|
+
[Entity, 'integer'],
|
|
7
|
+
[PrimaryField, `integer`],
|
|
8
|
+
[Number, 'integer'],
|
|
9
|
+
[String, 'varchar(255)'],
|
|
10
|
+
[Date, 'datetime'],
|
|
11
|
+
[JSONField, 'text'],
|
|
12
|
+
[Boolean, 'integer'],
|
|
13
|
+
])
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { SchemaContract } from '../SchemaContract'
|
|
2
|
+
import { BelongsToManyField, ColumnField, Entity, EntityConstructor, EntityMetadata } from '../..'
|
|
3
|
+
|
|
4
|
+
export abstract class Schema extends SchemaContract {
|
|
5
|
+
|
|
6
|
+
// async create(table: string, columns: ColumnField<Entity>[]) {
|
|
7
|
+
// const columnsSQLs = columns
|
|
8
|
+
// .filter(column => column.column)
|
|
9
|
+
// .map(columnMetadata => this.getColumnSql(columnMetadata))
|
|
10
|
+
//
|
|
11
|
+
// // @ts-ignore
|
|
12
|
+
// const createStatement = new Create({
|
|
13
|
+
// table,
|
|
14
|
+
// columns: columnsSQLs
|
|
15
|
+
// })
|
|
16
|
+
//
|
|
17
|
+
// await this.driver.run(createStatement.toSql())
|
|
18
|
+
// }
|
|
19
|
+
|
|
20
|
+
// async addColumn(table: string, column: ColumnField<Entity>) {
|
|
21
|
+
// await this.driver.run(`ALTER TABLE ${table}
|
|
22
|
+
// ADD ${this.getColumnSql(column)}(6)`)
|
|
23
|
+
// }
|
|
24
|
+
|
|
25
|
+
async synchronize(entitiesMetadata: EntityMetadata<Entity, Entity>[]) {
|
|
26
|
+
const pivotTables = new Map<string, ColumnField<Entity>[]>()
|
|
27
|
+
for await(const metadata of entitiesMetadata) {
|
|
28
|
+
const table = metadata.table as string
|
|
29
|
+
const belongsToManyFields = Object.values(metadata.inverseRelationships)
|
|
30
|
+
.filter(field => field instanceof BelongsToManyField) as BelongsToManyField<Entity, Entity>[]
|
|
31
|
+
|
|
32
|
+
belongsToManyFields.forEach(field => {
|
|
33
|
+
const entity = Entity as EntityConstructor<Entity>
|
|
34
|
+
const pivotTableColumns: ColumnField<Entity>[] = [
|
|
35
|
+
// new ColumnField(entity, 'id', () => PrimaryField, 'id'),
|
|
36
|
+
...[field.getParentForeignKey(), field.getRelatedForeignKey()].sort().map(columnName => {
|
|
37
|
+
return new ColumnField(entity, columnName, () => Number, columnName)
|
|
38
|
+
})
|
|
39
|
+
]
|
|
40
|
+
pivotTables.set(field.getPivotTable(), pivotTableColumns)
|
|
41
|
+
})
|
|
42
|
+
const tableInfo = await this.driver.tableExists(table)
|
|
43
|
+
if (!tableInfo) {
|
|
44
|
+
await this.create(table, Object.values({...metadata.columns, ...metadata.relationships}))
|
|
45
|
+
continue
|
|
46
|
+
}
|
|
47
|
+
await this.syncTableColumns(table, Object.values({...metadata.columns, ...metadata.relationships}))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
for await (const [name, columns] of pivotTables) {
|
|
51
|
+
const tableInfo = await this.driver.tableExists(name)
|
|
52
|
+
if (!tableInfo) {
|
|
53
|
+
await this.create(name, columns)
|
|
54
|
+
continue
|
|
55
|
+
}
|
|
56
|
+
await this.syncTableColumns(name, columns)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
protected abstract syncTableColumns(table: string, columns: ColumnField<Entity>[]): Promise<void>;
|
|
61
|
+
|
|
62
|
+
// protected getColumnSql(columnMetadata: ColumnField<Entity>): string {
|
|
63
|
+
// const columnType = columnMetadata.type()
|
|
64
|
+
// const type = Array.from(this.typesMatches.keys())
|
|
65
|
+
// .find(key =>
|
|
66
|
+
// key === columnMetadata.type() || columnType.prototype instanceof key || columnMetadata instanceof key
|
|
67
|
+
// ) || String
|
|
68
|
+
//
|
|
69
|
+
// const columnInfo = this.typesMatches.get(type)
|
|
70
|
+
//
|
|
71
|
+
// return `${columnMetadata.column} ${columnInfo}`
|
|
72
|
+
// }
|
|
73
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { BaseStatement } from './BaseStatement'
|
|
2
|
+
import { ColumnField, Entity } from '../../..'
|
|
3
|
+
|
|
4
|
+
export class Alter extends BaseStatement {
|
|
5
|
+
|
|
6
|
+
columns: ColumnField<Entity>[] = []
|
|
7
|
+
|
|
8
|
+
getColumns() {
|
|
9
|
+
return ''
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
toSQL() {
|
|
13
|
+
return `
|
|
14
|
+
ALTER
|
|
15
|
+
TABLE
|
|
16
|
+
${this.table}
|
|
17
|
+
(
|
|
18
|
+
${this.getColumns()}
|
|
19
|
+
)
|
|
20
|
+
`
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { wrap } from '../../../Helpers'
|
|
2
|
+
import { Statement } from '../../Statement'
|
|
3
|
+
|
|
4
|
+
export abstract class BaseStatement extends Statement {
|
|
5
|
+
|
|
6
|
+
get table() {
|
|
7
|
+
return wrap(this.components.table || '')
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
get wheres() {
|
|
11
|
+
const wheres = this.components.wheres || []
|
|
12
|
+
|
|
13
|
+
return wheres.map(where => {
|
|
14
|
+
this.bindings = this.bindings.concat(where.getValues())
|
|
15
|
+
return where.toSql()
|
|
16
|
+
}).join(' ').replace(/^(and |or )/i, '')
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get limit() {
|
|
20
|
+
const limit = this.components.limit
|
|
21
|
+
return limit ? `LIMIT ${limit.from}` + (limit.count ? `, ${limit.count}` : '') : ''
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
get joins() {
|
|
25
|
+
return this.components.joins.map(join => {
|
|
26
|
+
return `${join.type} JOIN ${wrap(join.table)} ON ${join.first} ${join.operator} ${join.second}`
|
|
27
|
+
}).join(' ')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get groups() {
|
|
31
|
+
if (!this.components.groups.length) {
|
|
32
|
+
return ''
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return `GROUP BY ` + this.components.groups.map(column => wrap(column)).join(', ')
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
get having() {
|
|
39
|
+
return ''
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
get orders() {
|
|
43
|
+
if (!this.components.orders?.length) {
|
|
44
|
+
return ''
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return 'ORDER BY ' + this.components.orders.map(order => `${wrap(order[0])} ${order[1]}`).join(', ')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
abstract toSQL(): string;
|
|
51
|
+
|
|
52
|
+
toString() {
|
|
53
|
+
return this.toSQL()
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { BaseStatement } from './BaseStatement'
|
|
2
|
+
|
|
3
|
+
export class Delete extends BaseStatement {
|
|
4
|
+
|
|
5
|
+
get wheres() {
|
|
6
|
+
if (!this.components.wheres.length) {
|
|
7
|
+
return ''
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return `WHERE ` + super.wheres
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
toSQL() {
|
|
14
|
+
return `
|
|
15
|
+
DELETE
|
|
16
|
+
FROM ${this.table} ${this.wheres} ${this.orders} ${this.limit}
|
|
17
|
+
`
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BaseStatement } from './BaseStatement'
|
|
2
|
+
import { wrap } from '../../../Helpers'
|
|
3
|
+
|
|
4
|
+
export class Insert extends BaseStatement {
|
|
5
|
+
|
|
6
|
+
get columns() {
|
|
7
|
+
const values = this.components.insert || []
|
|
8
|
+
|
|
9
|
+
return wrap(Object.keys(values.first() ?? {}))
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
get values() {
|
|
13
|
+
return (this.components.insert || []).map(valuesMap => {
|
|
14
|
+
const values = Object.values(valuesMap)
|
|
15
|
+
this.bindings = this.bindings.concat(values)
|
|
16
|
+
return '(' + [...Array(values.length)].map(() => '?').join(', ') + ')'
|
|
17
|
+
}).join(', ')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
toSQL() {
|
|
21
|
+
return `INSERT INTO ${this.table} (${this.columns})
|
|
22
|
+
VALUES ${this.values} `
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { BaseStatement } from './BaseStatement'
|
|
2
|
+
import { StringExpression } from '../../..'
|
|
3
|
+
import { wrap } from '../../../Helpers'
|
|
4
|
+
|
|
5
|
+
export class Select extends BaseStatement {
|
|
6
|
+
get distinct() {
|
|
7
|
+
return this.components.distinct ? 'DISTINCT ' : ''
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
get columns() {
|
|
11
|
+
let columns = this.components.columns || []
|
|
12
|
+
columns = columns.map(column => {
|
|
13
|
+
return column instanceof StringExpression ? column.value : wrap(column)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
const aggregate = this.components.aggregate
|
|
17
|
+
if (aggregate) {
|
|
18
|
+
columns.push(`${aggregate.function}(${wrap(aggregate.columns) || '*'}) as aggregate`)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!columns.length) {
|
|
22
|
+
return '*'
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return columns.join(', ')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get wheres() {
|
|
29
|
+
if (!this.components.wheres.length) {
|
|
30
|
+
return ''
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return `WHERE ${super.wheres}`
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
toSQL() {
|
|
37
|
+
return `
|
|
38
|
+
SELECT ${this.distinct}${this.columns}
|
|
39
|
+
FROM ${this.table} ${this.joins} ${this.wheres} ${this.groups}
|
|
40
|
+
${this.having}
|
|
41
|
+
${this.orders}
|
|
42
|
+
${this.limit}
|
|
43
|
+
`
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/*
|
|
48
|
+
const query = `SELECT *
|
|
49
|
+
FROM users
|
|
50
|
+
where name = 'john' -- where basic
|
|
51
|
+
or (age in (1, 2, 3) and age > 2) -- where nested
|
|
52
|
+
or age in (1, 2, 3) -- where in
|
|
53
|
+
or age in (SELECT age from users) -- where subSelect
|
|
54
|
+
`;
|
|
55
|
+
*/
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { BaseStatement } from './BaseStatement'
|
|
2
|
+
|
|
3
|
+
export class Update extends BaseStatement {
|
|
4
|
+
|
|
5
|
+
get wheres() {
|
|
6
|
+
if (!this.components.wheres.length) {
|
|
7
|
+
return ''
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return 'WHERE ' + super.wheres
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get columns() {
|
|
14
|
+
const columns = []
|
|
15
|
+
const values = this.components.update || {}
|
|
16
|
+
for (const column in values) {
|
|
17
|
+
if (values.hasOwnProperty(column)) {
|
|
18
|
+
this.bindings.push(values[column])
|
|
19
|
+
columns.push(`${column} = ?`)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return columns.join(', ')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
toSQL() {
|
|
26
|
+
return `
|
|
27
|
+
UPDATE
|
|
28
|
+
${this.table}
|
|
29
|
+
SET ${this.columns}
|
|
30
|
+
${this.wheres} ${this.orders} ${this.limit}
|
|
31
|
+
`
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { BaseStatement } from '../SQL/Statements/BaseStatement'
|
|
2
|
+
import { ColumnDefinitionOptions } from '../SQL'
|
|
3
|
+
|
|
4
|
+
export class Create extends BaseStatement {
|
|
5
|
+
|
|
6
|
+
constructor(table: string, public columns: ColumnDefinitionOptions[] = []) {
|
|
7
|
+
super({
|
|
8
|
+
table,
|
|
9
|
+
columns: [],
|
|
10
|
+
joins: [],
|
|
11
|
+
wheres: [],
|
|
12
|
+
groups: [],
|
|
13
|
+
orders: [],
|
|
14
|
+
having: []
|
|
15
|
+
})
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
toSQL() {
|
|
19
|
+
const definitions: string[] = this.getColumnsSQL(this.columns)
|
|
20
|
+
|
|
21
|
+
return `
|
|
22
|
+
CREATE TABLE ${this.table}
|
|
23
|
+
(
|
|
24
|
+
${definitions.join(', \n')}
|
|
25
|
+
)
|
|
26
|
+
`
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private getColumnsSQL(columns: ColumnDefinitionOptions[]) {
|
|
30
|
+
return columns.map(this.getColumnSQL)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private getColumnSQL(column: ColumnDefinitionOptions) {
|
|
34
|
+
const sqlParts = [column.name, column.type]
|
|
35
|
+
|
|
36
|
+
if (column.primaryKey) {
|
|
37
|
+
sqlParts.push('PRIMARY KEY')
|
|
38
|
+
}
|
|
39
|
+
if (column.autoIncrement) {
|
|
40
|
+
sqlParts.push('AUTOINCREMENT')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return sqlParts.join(' ')
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { ColumnField, Entity, PrimaryField } from '../..'
|
|
2
|
+
import { Schema as BaseSchema } from '../SQL/Schema'
|
|
3
|
+
import { Create } from './Create'
|
|
4
|
+
import { typesMatches } from '.'
|
|
5
|
+
import { ColumnDefinitionOptions } from '../SQL'
|
|
6
|
+
import { wrap } from '../../Helpers'
|
|
7
|
+
|
|
8
|
+
export class Schema extends BaseSchema {
|
|
9
|
+
|
|
10
|
+
columnMetadataToColumnDefinition(metadata: ColumnField<Entity>) {
|
|
11
|
+
return {
|
|
12
|
+
name: metadata.column,
|
|
13
|
+
primaryKey: metadata.constructor === PrimaryField,
|
|
14
|
+
autoIncrement: Number(metadata.constructor === PrimaryField),
|
|
15
|
+
type: this.getColumnTypeBasedOnTypescriptType(metadata),
|
|
16
|
+
default: undefined,
|
|
17
|
+
nullable: true
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async create(table: string, columns: ColumnField<Entity>[]) {
|
|
22
|
+
const columnsDefinitions: ColumnDefinitionOptions[] = columns.map(column => this.columnMetadataToColumnDefinition(column))
|
|
23
|
+
const createStatement = new Create(table, columnsDefinitions)
|
|
24
|
+
|
|
25
|
+
await this.driver.run(createStatement.toSQL())
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
protected async syncTableColumns(table: string, columnsMetadata: ColumnField<Entity>[]) {
|
|
29
|
+
const columns = columnsMetadata.map(metadata => this.columnMetadataToColumnDefinition(metadata))
|
|
30
|
+
const tableColumns = await this.driver.tableColumns(table)
|
|
31
|
+
|
|
32
|
+
if (tableColumns.length) {
|
|
33
|
+
const temporaryTableName = table + '_alter_tmp'
|
|
34
|
+
await this.create(temporaryTableName, columnsMetadata)
|
|
35
|
+
const columnList = wrap(columns.whereIn('name', tableColumns.pluck('name')).pluck('name'))
|
|
36
|
+
await this.driver.run(`INSERT INTO ${temporaryTableName}(${columnList})
|
|
37
|
+
SELECT ${columnList}
|
|
38
|
+
FROM ${table}`)
|
|
39
|
+
await this.driver.run(`DROP TABLE ${table}`)
|
|
40
|
+
await this.driver.run(`ALTER TABLE ${temporaryTableName} RENAME TO ${table}`)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private getColumnTypeBasedOnTypescriptType(column: ColumnField<Entity>) {
|
|
45
|
+
const typePrototype = Array.from(typesMatches.keys())
|
|
46
|
+
.find(key => column.type().prototype instanceof key) || String
|
|
47
|
+
|
|
48
|
+
return typesMatches.get(column.type())
|
|
49
|
+
?? typesMatches.get(column.constructor)
|
|
50
|
+
?? typesMatches.get(typePrototype)
|
|
51
|
+
?? typesMatches.get(String) as string
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
}
|