-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add way to load entitles as stand alone (#3)
* inital: implmemnt basic logic to load typeorm models to typescript * ts: add estlint to script * .github: add ci workflow of lint * ts: install sqlite and mssql drivers * create integration test dir * rename * add preitier * add way to load as standalone * .github: add test for the standalone in the ci * fix comment
- Loading branch information
Showing
9 changed files
with
183 additions
and
68 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,66 +1,45 @@ | ||
import { DataSource, EntitySchema, Table, TableForeignKey } from "typeorm"; | ||
import { ConnectionMetadataBuilder } from "typeorm/connection/ConnectionMetadataBuilder"; | ||
import { EntityMetadataValidator } from "typeorm/metadata-builder/EntityMetadataValidator"; | ||
import { View } from "typeorm/schema-builder/view/View"; | ||
#! /usr/bin/env ts-node-script | ||
|
||
export type Dialect = "mysql" | "postgres" | "mariadb" | "sqlite" | "mssql"; | ||
import yargs from "yargs"; | ||
import { hideBin } from "yargs/helpers"; | ||
import { Dialect, loadEntities } from "./load"; | ||
import * as fs from "fs"; | ||
|
||
// Load typeorm entities and return SQL statements describing the schema of the entities. | ||
export async function loadEntities( | ||
dialect: Dialect, | ||
// eslint-disable-next-line @typescript-eslint/ban-types | ||
entities: (Function | EntitySchema | string)[], | ||
) { | ||
const mockDB = new DataSource({ | ||
type: dialect, | ||
database: ":memory:", | ||
}); | ||
const driver = mockDB.driver; | ||
const metadataBuilder = new ConnectionMetadataBuilder(mockDB); | ||
const entityMetadataValidator = new EntityMetadataValidator(); | ||
const queryRunner = mockDB.createQueryRunner(); | ||
queryRunner.enableSqlMemory(); | ||
|
||
const entityMetadatas = await metadataBuilder.buildEntityMetadatas(entities); | ||
// validate all created entity metadatas to make sure user created entities are valid and correct | ||
entityMetadataValidator.validateMany( | ||
entityMetadatas.filter((metadata) => metadata.tableType !== "view"), | ||
driver, | ||
); | ||
|
||
// create tables statements | ||
for (const metadata of entityMetadatas) { | ||
if (metadata.tableType === "view") { | ||
continue; | ||
} | ||
const table = Table.create(metadata, driver); | ||
await queryRunner.createTable(table); | ||
} | ||
|
||
// create foreign keys statements, | ||
// executed after all tables created since foreign keys can reference tables that were created afterwards. | ||
for (const metadata of entityMetadatas) { | ||
const table = Table.create(metadata, driver); | ||
const foreignKeys = metadata.foreignKeys.map((foreignKeyMetadata) => | ||
TableForeignKey.create(foreignKeyMetadata, driver), | ||
); | ||
await queryRunner.createForeignKeys(table, foreignKeys); | ||
} | ||
|
||
// create views | ||
for (const metadata of entityMetadatas) { | ||
if (metadata.tableType !== "view") { | ||
continue; | ||
const y = yargs(hideBin(process.argv)) | ||
.usage( | ||
"npx @ariga/ts-atlas-provider-typeorm load --path ./models --dialect mysql", | ||
) | ||
.alias("h", "help"); | ||
y.command( | ||
"load", | ||
"load sql state of typeorm entities", | ||
{ | ||
path: { | ||
type: "string", | ||
demandOption: true, | ||
describe: "Path to models folder", | ||
}, | ||
dialect: { | ||
type: "string", | ||
choices: ["mysql", "postgres", "sqlite", "mariadb", "mssql"], | ||
demandOption: true, | ||
describe: "Dialect of database", | ||
}, | ||
}, | ||
async function (argv) { | ||
try { | ||
const path = argv.path; | ||
if (!fs.existsSync(path)) { | ||
throw new Error(`path ${path} does not exist`); | ||
} | ||
const sql = await loadEntities(argv.dialect as Dialect, [path + "/*.ts"]); | ||
console.log(sql); | ||
} catch (e) { | ||
if (e instanceof Error) { | ||
console.error(e.message); | ||
} else { | ||
console.error(e); | ||
} | ||
} | ||
const view = View.create(metadata, driver); | ||
await queryRunner.createView(view, false); | ||
} | ||
|
||
let sql = ""; | ||
const memorySql = queryRunner.getMemorySql(); | ||
memorySql.upQueries.forEach((query) => { | ||
sql += query.query + ";\n"; | ||
}); | ||
queryRunner.clearSqlMemory(); | ||
return sql; | ||
} | ||
}, | ||
).parse(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { DataSource, EntitySchema, Table, TableForeignKey } from "typeorm"; | ||
import { ConnectionMetadataBuilder } from "typeorm/connection/ConnectionMetadataBuilder"; | ||
import { EntityMetadataValidator } from "typeorm/metadata-builder/EntityMetadataValidator"; | ||
import { View } from "typeorm/schema-builder/view/View"; | ||
|
||
export type Dialect = "mysql" | "postgres" | "mariadb" | "sqlite" | "mssql"; | ||
|
||
// Load typeorm entities and return SQL statements describing the schema of the entities. | ||
export async function loadEntities( | ||
dialect: Dialect, | ||
// eslint-disable-next-line @typescript-eslint/ban-types | ||
entities: (Function | EntitySchema | string)[], | ||
) { | ||
const mockDB = new DataSource({ | ||
type: dialect, | ||
database: ":memory:", | ||
}); | ||
const driver = mockDB.driver; | ||
const metadataBuilder = new ConnectionMetadataBuilder(mockDB); | ||
const entityMetadataValidator = new EntityMetadataValidator(); | ||
const queryRunner = mockDB.createQueryRunner(); | ||
queryRunner.enableSqlMemory(); | ||
|
||
const entityMetadatas = await metadataBuilder.buildEntityMetadatas(entities); | ||
// validate all created entity metadatas to make sure user created entities are valid and correct | ||
entityMetadataValidator.validateMany( | ||
entityMetadatas.filter((metadata) => metadata.tableType !== "view"), | ||
driver, | ||
); | ||
|
||
// create tables statements | ||
for (const metadata of entityMetadatas) { | ||
if (metadata.tableType === "view") { | ||
continue; | ||
} | ||
const table = Table.create(metadata, driver); | ||
await queryRunner.createTable(table); | ||
} | ||
|
||
// creating foreign keys statements are executed after all tables created since foreign keys can reference tables that were created afterwards. | ||
for (const metadata of entityMetadatas) { | ||
const table = Table.create(metadata, driver); | ||
const foreignKeys = metadata.foreignKeys.map((foreignKeyMetadata) => | ||
TableForeignKey.create(foreignKeyMetadata, driver), | ||
); | ||
await queryRunner.createForeignKeys(table, foreignKeys); | ||
} | ||
|
||
// create views | ||
for (const metadata of entityMetadatas) { | ||
if (metadata.tableType !== "view") { | ||
continue; | ||
} | ||
const view = View.create(metadata, driver); | ||
await queryRunner.createView(view, false); | ||
} | ||
|
||
const memorySql = queryRunner.getMemorySql(); | ||
const queries = memorySql.upQueries.map((query) => query.query); | ||
queryRunner.clearSqlMemory(); | ||
return queries.join(";\n"); | ||
} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
variable "dialect" { | ||
type = string | ||
} | ||
|
||
locals { | ||
dev_url = { | ||
mysql = "docker://mysql/8/dev" | ||
postgres = "docker://postgres/15" | ||
sqlite = "sqlite://file::memory:?cache=shared" | ||
}[var.dialect] | ||
} | ||
|
||
data "external_schema" "typeorm" { | ||
program = [ | ||
"npx", | ||
"../", | ||
"load", | ||
"--path", "./entities", | ||
"--dialect", var.dialect, | ||
] | ||
} | ||
|
||
env "typeorm" { | ||
src = data.external_schema.typeorm.url | ||
dev = local.dev_url | ||
migration { | ||
dir = "file://migrations/${var.dialect}" | ||
} | ||
format { | ||
migrate { | ||
diff = "{{ sql . \" \" }}" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters