Skip to content

Commit

Permalink
feature - support soft remove recursively
Browse files Browse the repository at this point in the history
  • Loading branch information
oxeye-or committed Feb 20, 2024
1 parent 83567f5 commit 34a9235
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 12 deletions.
2 changes: 2 additions & 0 deletions docs/data-source-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ Different RDBMS-es have their own specific options.
Note that for MongoDB database it does not create schema, because MongoDB is schemaless.
Instead, it syncs just by creating indices.

- `synchronizeWithoutDrops` - Indicates if synchronize should not drop columns, tables and more

- `migrationsRun` - Indicates if migrations should be auto run on every application launch.
As an alternative, you can use CLI and run migration:run command.

Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "typeorm",
"private": true,
"name": "@oxeye/typeorm",
"private": false,
"version": "0.3.20",
"description": "Data-Mapper ORM for TypeScript, ES7, ES6, ES5. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, MongoDB databases.",
"license": "MIT",
Expand Down Expand Up @@ -66,10 +66,10 @@
},
"repository": {
"type": "git",
"url": "https://github.com/typeorm/typeorm.git"
"url": "https://github.com/ox-eye/ox-typeorm.git"
},
"bugs": {
"url": "https://github.com/typeorm/typeorm/issues"
"url": "https://github.com/ox-eye/ox-typeorm/issues"
},
"homepage": "https://typeorm.io",
"tags": [
Expand Down
3 changes: 3 additions & 0 deletions src/connection/options-reader/ConnectionOptionsEnvReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ export class ConnectionOptionsEnvReader {
synchronize: OrmUtils.toBoolean(
PlatformTools.getEnvVariable("TYPEORM_SYNCHRONIZE"),
),
synchronizeWithoutDrops: OrmUtils.toBoolean(
PlatformTools.getEnvVariable("TYPEORM_SYNCHRONIZE_WITHOUT_DROPS")
),
dropSchema: OrmUtils.toBoolean(
PlatformTools.getEnvVariable("TYPEORM_DROP_SCHEMA"),
),
Expand Down
5 changes: 5 additions & 0 deletions src/data-source/BaseDataSourceOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ export interface BaseDataSourceOptions {
*/
readonly synchronize?: boolean

/**
* Indicates if synchronize should not drop columns and tables
*/
readonly synchronizeWithoutDrops?: boolean;

/**
* Indicates if migrations should be auto run on every application launch.
* Alternative to it, you can use CLI and run migrations:run command.
Expand Down
39 changes: 39 additions & 0 deletions src/persistence/SubjectExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { OrmUtils } from "../util/OrmUtils"
import { UpdateResult } from "../query-builder/result/UpdateResult"
import { ObjectUtils } from "../util/ObjectUtils"
import { InstanceChecker } from "../util/InstanceChecker"
import {RelationMetadata} from "../metadata/RelationMetadata";
import {OracleDriver} from "../driver/oracle/OracleDriver";

/**
* Executes all database operations (inserts, updated, deletes) that must be executed
Expand Down Expand Up @@ -829,6 +831,10 @@ export class SubjectExecutor {
}

updateResult = await softDeleteQueryBuilder.execute()

for (const relation of subject.metadata.relations) {
await this.executeSoftRemoveRecursive(relation, [Reflect.get(subject.identifier, subject.metadata.primaryColumns[0].propertyName)]);
}
}

subject.generatedMap = updateResult.generatedMaps[0]
Expand Down Expand Up @@ -866,6 +872,39 @@ export class SubjectExecutor {
)
}

/**
* Execute soft remove recursively.
*/
protected async executeSoftRemoveRecursive(relation: RelationMetadata, ids: any[]): Promise<void> {
if (relation.isCascadeSoftRemove){
let primaryPropertyName = relation.inverseEntityMetadata.primaryColumns[0].propertyName;
let updateResult: UpdateResult;
let softDeleteQueryBuilder = this.queryRunner
.manager
.createQueryBuilder()
.softDelete()
.from(relation.inverseEntityMetadata.target)
.returning([primaryPropertyName])
.updateEntity(this.options && this.options.reload === false ? false : true)
.callListeners(false);
softDeleteQueryBuilder.where(`${relation.inverseSidePropertyPath} in (:...ids)`, {ids: ids});
updateResult = await softDeleteQueryBuilder.execute();
let parentIds;
// Only in oracle the returning value is a list of the affected row primary keys and not list of dictionary
if (this.queryRunner.connection.driver instanceof OracleDriver){
parentIds = updateResult.raw[0];
}
else {
parentIds = updateResult.raw.map((row: any) => row[Object.keys(row)[0]]);
}
if (parentIds.length) {
for (const subRelation of relation.inverseEntityMetadata.relations) {
await this.executeSoftRemoveRecursive(subRelation, parentIds);
}
}
}
}

/**
* Recovers all given subjects in the database.
*/
Expand Down
23 changes: 15 additions & 8 deletions src/schema-builder/RdbmsSchemaBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,20 +213,27 @@ export class RdbmsSchemaBuilder implements SchemaBuilder {
* Order of operations matter here.
*/
protected async executeSchemaSyncOperationsInProperOrder(): Promise<void> {
await this.dropOldViews()
await this.dropOldForeignKeys()
await this.dropOldIndices()
await this.dropOldChecks()
await this.dropOldExclusions()
await this.dropCompositeUniqueConstraints()
if (!this.connection.options.synchronizeWithoutDrops) {
await this.dropOldViews()
await this.dropOldForeignKeys()
await this.dropOldIndices()
await this.dropOldChecks()
await this.dropOldExclusions()
await this.dropCompositeUniqueConstraints()
}

// await this.renameTables();
await this.renameColumns()
await this.changeTableComment()
await this.createNewTables()
await this.dropRemovedColumns()
if (!this.connection.options.synchronizeWithoutDrops) {
await this.dropRemovedColumns();
}
await this.addNewColumns()
await this.updatePrimaryKeys()
await this.updateExistColumns()
if (!this.connection.options.synchronizeWithoutDrops) {
await this.updateExistColumns()
}
await this.createNewIndices()
await this.createNewChecks()
await this.createNewExclusions()
Expand Down

0 comments on commit 34a9235

Please sign in to comment.