mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
added a new table option skipSchemaSync to prevent schema-builder to sync a table with the database. Added a test in functional/connection/connection.ts
This commit is contained in:
parent
1c403fd107
commit
82b51b0348
@ -16,5 +16,10 @@ export interface TableOptions {
|
||||
* If you update this value and table is already created, it will not change table's engine type.
|
||||
*/
|
||||
readonly engine?: string;
|
||||
|
||||
/**
|
||||
* Specifies if this table will be skipped during schema synchronization.
|
||||
*/
|
||||
readonly skipSchemaSync?: boolean;
|
||||
|
||||
}
|
||||
|
||||
@ -11,7 +11,8 @@ export function ClassTableChild(tableName?: string, options?: TableOptions) {
|
||||
target: target,
|
||||
name: tableName,
|
||||
type: "class-table-child",
|
||||
orderBy: options && options.orderBy ? options.orderBy : undefined
|
||||
orderBy: options && options.orderBy ? options.orderBy : undefined,
|
||||
skipSchemaSync: (options && options.skipSchemaSync === true) || false
|
||||
};
|
||||
getMetadataArgsStorage().tables.add(args);
|
||||
};
|
||||
|
||||
@ -11,7 +11,8 @@ export function ClosureTable(name?: string, options?: TableOptions) {
|
||||
target: target,
|
||||
name: name,
|
||||
type: "closure",
|
||||
orderBy: options && options.orderBy ? options.orderBy : undefined
|
||||
orderBy: options && options.orderBy ? options.orderBy : undefined,
|
||||
skipSchemaSync: (options && options.skipSchemaSync === true) || false
|
||||
};
|
||||
getMetadataArgsStorage().tables.add(args);
|
||||
};
|
||||
|
||||
@ -14,6 +14,7 @@ export function Table(name?: string, options?: TableOptions) {
|
||||
type: "regular",
|
||||
orderBy: options && options.orderBy ? options.orderBy : undefined,
|
||||
engine: options && options.engine ? options.engine : undefined,
|
||||
skipSchemaSync: (options && options.skipSchemaSync === true) || false
|
||||
};
|
||||
getMetadataArgsStorage().tables.add(args);
|
||||
};
|
||||
|
||||
@ -41,6 +41,7 @@ export interface EntitySchema {
|
||||
* Specifies a property name by which queries will perform ordering by default when fetching rows.
|
||||
*/
|
||||
orderBy?: OrderByCondition;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -33,5 +33,10 @@ export interface TableMetadataArgs {
|
||||
* Table's database engine type (like "InnoDB", "MyISAM", etc).
|
||||
*/
|
||||
readonly engine?: string;
|
||||
|
||||
/**
|
||||
* Whether table must be synced during schema build or not
|
||||
*/
|
||||
readonly skipSchemaSync?: boolean;
|
||||
|
||||
}
|
||||
|
||||
@ -191,6 +191,7 @@ export class EntityMetadataBuilder {
|
||||
const allMergedArgs = metadataArgsStorage.getMergedTableMetadatas(entityClasses);
|
||||
allMergedArgs.forEach(mergedArgs => {
|
||||
|
||||
|
||||
const tables = [mergedArgs.table].concat(mergedArgs.children);
|
||||
tables.forEach(tableArgs => {
|
||||
|
||||
@ -207,6 +208,7 @@ export class EntityMetadataBuilder {
|
||||
|
||||
// create metadatas from args
|
||||
const argsForTable = mergedArgs.inheritance && mergedArgs.inheritance.type === "single-table" ? mergedArgs.table : tableArgs;
|
||||
|
||||
const table = new TableMetadata(argsForTable);
|
||||
const columns = mergedArgs.columns.map(args => {
|
||||
|
||||
@ -224,7 +226,6 @@ export class EntityMetadataBuilder {
|
||||
const discriminatorValueArgs = mergedArgs.discriminatorValues.find(discriminatorValueArgs => {
|
||||
return discriminatorValueArgs.target === tableArgs.target;
|
||||
});
|
||||
|
||||
// create a new entity metadata
|
||||
const entityMetadata = new EntityMetadata({
|
||||
target: tableArgs.target,
|
||||
@ -239,7 +240,6 @@ export class EntityMetadataBuilder {
|
||||
discriminatorValue: discriminatorValueArgs ? discriminatorValueArgs.value : (tableArgs.target as any).name // todo: pass this to naming strategy to generate a name
|
||||
}, lazyRelationsWrapper);
|
||||
entityMetadatas.push(entityMetadata);
|
||||
|
||||
// create entity's relations join tables
|
||||
entityMetadata.manyToManyRelations.forEach(relation => {
|
||||
const joinTableMetadata = mergedArgs.joinTables.findByProperty(relation.propertyName);
|
||||
|
||||
@ -32,6 +32,11 @@ export class TableMetadata {
|
||||
*/
|
||||
readonly engine?: string;
|
||||
|
||||
/**
|
||||
* Whether table must be synced during schema build or not
|
||||
*/
|
||||
readonly skipSchemaSync?: boolean;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Private Properties
|
||||
// ---------------------------------------------------------------------
|
||||
@ -64,6 +69,7 @@ export class TableMetadata {
|
||||
this._name = args.name;
|
||||
this._orderBy = args.orderBy;
|
||||
this.engine = args.engine;
|
||||
this.skipSchemaSync = args.skipSchemaSync;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
@ -95,11 +95,15 @@ export class SchemaBuilder {
|
||||
// Private Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
protected get entityToSyncMetadatas(): EntityMetadataCollection {
|
||||
return <EntityMetadataCollection>this.entityMetadatas.filter( metadata => !metadata.table.skipSchemaSync );
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all table schemas from the database.
|
||||
*/
|
||||
protected loadTableSchemas(): Promise<TableSchema[]> {
|
||||
const tableNames = this.entityMetadatas.map(metadata => metadata.table.name);
|
||||
const tableNames = this.entityToSyncMetadatas.map(metadata => metadata.table.name);
|
||||
return this.queryRunner.loadSchemaTables(tableNames, this.namingStrategy);
|
||||
}
|
||||
|
||||
@ -107,7 +111,7 @@ export class SchemaBuilder {
|
||||
* Drops all (old) foreign keys that exist in the table schemas, but do not exist in the entity metadata.
|
||||
*/
|
||||
protected async dropOldForeignKeys(): Promise<void> {
|
||||
await Promise.all(this.entityMetadatas.map(async metadata => {
|
||||
await Promise.all(this.entityToSyncMetadatas.map(async metadata => {
|
||||
|
||||
const tableSchema = this.tableSchemas.find(table => table.name === metadata.table.name);
|
||||
if (!tableSchema)
|
||||
@ -136,8 +140,7 @@ export class SchemaBuilder {
|
||||
* Primary key only can be created in conclusion with auto generated column.
|
||||
*/
|
||||
protected async createNewTables(): Promise<void> {
|
||||
await Promise.all(this.entityMetadatas.map(async metadata => {
|
||||
|
||||
await Promise.all(this.entityToSyncMetadatas.map(async metadata => {
|
||||
// check if table does not exist yet
|
||||
const existTableSchema = this.tableSchemas.find(table => table.name === metadata.table.name);
|
||||
if (existTableSchema)
|
||||
@ -157,7 +160,7 @@ export class SchemaBuilder {
|
||||
* We drop their keys too, since it should be safe.
|
||||
*/
|
||||
protected dropRemovedColumns() {
|
||||
return Promise.all(this.entityMetadatas.map(async metadata => {
|
||||
return Promise.all(this.entityToSyncMetadatas.map(async metadata => {
|
||||
const tableSchema = this.tableSchemas.find(table => table.name === metadata.table.name);
|
||||
if (!tableSchema) return;
|
||||
|
||||
@ -194,7 +197,7 @@ export class SchemaBuilder {
|
||||
* Columns are created without keys.
|
||||
*/
|
||||
protected addNewColumns() {
|
||||
return Promise.all(this.entityMetadatas.map(async metadata => {
|
||||
return Promise.all(this.entityToSyncMetadatas.map(async metadata => {
|
||||
const tableSchema = this.tableSchemas.find(table => table.name === metadata.table.name);
|
||||
if (!tableSchema)
|
||||
return;
|
||||
@ -220,7 +223,7 @@ export class SchemaBuilder {
|
||||
* Still don't create keys. Also we don't touch foreign keys of the changed columns.
|
||||
*/
|
||||
protected updateExistColumns() {
|
||||
return Promise.all(this.entityMetadatas.map(async metadata => {
|
||||
return Promise.all(this.entityToSyncMetadatas.map(async metadata => {
|
||||
const tableSchema = this.tableSchemas.find(table => table.name === metadata.table.name);
|
||||
if (!tableSchema)
|
||||
return;
|
||||
@ -267,7 +270,7 @@ export class SchemaBuilder {
|
||||
* Creates primary keys which does not exist in the table yet.
|
||||
*/
|
||||
protected updatePrimaryKeys() {
|
||||
return Promise.all(this.entityMetadatas.map(async metadata => {
|
||||
return Promise.all(this.entityToSyncMetadatas.map(async metadata => {
|
||||
const tableSchema = this.tableSchemas.find(table => table.name === metadata.table.name && !table.justCreated);
|
||||
if (!tableSchema)
|
||||
return;
|
||||
@ -297,7 +300,7 @@ export class SchemaBuilder {
|
||||
* Creates foreign keys which does not exist in the table yet.
|
||||
*/
|
||||
protected createForeignKeys() {
|
||||
return Promise.all(this.entityMetadatas.map(async metadata => {
|
||||
return Promise.all(this.entityToSyncMetadatas.map(async metadata => {
|
||||
const tableSchema = this.tableSchemas.find(table => table.name === metadata.table.name);
|
||||
if (!tableSchema)
|
||||
return;
|
||||
@ -321,7 +324,7 @@ export class SchemaBuilder {
|
||||
*/
|
||||
protected createIndices() {
|
||||
// return Promise.all(this.entityMetadatas.map(metadata => this.createIndices(metadata.table, metadata.indices)));
|
||||
return Promise.all(this.entityMetadatas.map(async metadata => {
|
||||
return Promise.all(this.entityToSyncMetadatas.map(async metadata => {
|
||||
const tableSchema = this.tableSchemas.find(table => table.name === metadata.table.name);
|
||||
if (!tableSchema)
|
||||
return;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import "reflect-metadata";
|
||||
import {expect} from "chai";
|
||||
import {Post} from "./entity/Post";
|
||||
import {View} from "./entity/View";
|
||||
import {Category} from "./entity/Category";
|
||||
import {setupTestingConnections, closeConnections, createTestingConnectionOptions} from "../../utils/test-utils";
|
||||
import {Connection} from "../../../src/connection/Connection";
|
||||
@ -14,6 +15,7 @@ import {ConnectionOptions} from "../../../src/connection/ConnectionOptions";
|
||||
import {CannotSyncNotConnectedError} from "../../../src/connection/error/CannotSyncNotConnectedError";
|
||||
import {NoConnectionForRepositoryError} from "../../../src/connection/error/NoConnectionForRepositoryError";
|
||||
import {RepositoryNotFoundError} from "../../../src/connection/error/RepositoryNotFoundError";
|
||||
import {DefaultNamingStrategy} from "../../../src/naming-strategy/DefaultNamingStrategy";
|
||||
import {FirstCustomNamingStrategy} from "./naming-strategy/FirstCustomNamingStrategy";
|
||||
import {SecondCustomNamingStrategy} from "./naming-strategy/SecondCustomNamingStrategy";
|
||||
import {CannotUseNamingStrategyNotConnectedError} from "../../../src/connection/error/CannotUseNamingStrategyNotConnectedError";
|
||||
@ -351,5 +353,19 @@ describe("Connection", () => {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("skip schema generation when skipSchemaSync option is used", function() {
|
||||
|
||||
let connections: Connection[];
|
||||
beforeEach(() => setupTestingConnections({ entities: [View] }).then(all => connections = all));
|
||||
afterEach(() => closeConnections(connections));
|
||||
it("database should be empty after schema sync", () => Promise.all(connections.map(async connection => {
|
||||
await connection.syncSchema(true);
|
||||
const queryRunner = await connection.driver.createQueryRunner();
|
||||
let schema = await queryRunner.loadSchemaTables(["view"], new DefaultNamingStrategy());
|
||||
expect(!schema.some( table => table.name === "view" )).to.be.true;
|
||||
})));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
14
test/functional/connection/entity/View.ts
Normal file
14
test/functional/connection/entity/View.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import {Table} from "../../../../src/decorator/tables/Table";
|
||||
import {PrimaryColumn} from "../../../../src/decorator/columns/PrimaryColumn";
|
||||
import {Column} from "../../../../src/decorator/columns/Column";
|
||||
|
||||
@Table("view", {skipSchemaSync: true})
|
||||
export class View {
|
||||
|
||||
@PrimaryColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
title: string;
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user