-
-
Notifications
You must be signed in to change notification settings - Fork 542
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
POST (createOne) operation semantics behaviour for a resource that already exists #236
Comments
Not sure if there is a better way but ended up implementing my own version via inheriting from TypeOrmCrudService to provide the semantics expected of POST operation. Is there any progress relating to feature requests #226 and #209 to facilitate overriding behaviour in TypeOrmCrudService? export class MyTypeOrmCrudService<T> extends TypeOrmCrudService<T> {
constructor(protected repo: Repository<T>) {
super(repo);
}
/**
* Create one
* The createOne method is overriden to provide the following semantics.
* If the entity exists a ConflictException is thrown.
* If the entity does not exist then it is saved in the repository.
*
* Requires typescript 3.1.6 due to a bug/issue with typescript compiler
* and the typeorm library when using `this.repo.findOne(entity)`
* Refer to:
* - https://github.com/microsoft/TypeScript/issues/21592
* - https://github.com/typeorm/typeorm/pull/4470
*
* If using VSCode, use local typescript compiler in settings.json file
* `{
* "typescript.tsdk": "node_modules/typescript/lib"
* }`
*
* Alternatively, modify typeorm-find-options/FindConditions.d.ts as detailed in code snippet
* below to address excessive stack depth error when using this.repo.findOne(entity)
* see typeorm issue #4470 @ https://github.com/typeorm/typeorm/pull/4470 (awaiting merge)
* `export declare type FindConditions<T> = {
* [P in keyof T]?: T[P] extends never ? FindConditions<T[P]> | FindOperator<FindConditions<T[P]>> : FindConditions<T[P]> | FindOperator<FindConditions<T[P]>>;
* };`
* @param req
* @param dto
*/
public async createOne(req: CrudRequest, dto: T): Promise<T> {
const entity: T = this.createEntity(dto, req.parsed.paramsFilter);
/* istanbul ignore if */
if (!entity) {
this.throwBadRequestException(`Empty data. Nothing to save.`);
}
// we have to pass entity as any here to avoid typeorm issue #4470 with
// typescript compiler 3.1.6
const result = await this.repo.findOne(<any>entity);
if (result) {
this.throwConflictException('Attempt to save duplicate entity');
}
return this.repo.save<any>(entity);
}
private get entityClassType(): ClassType<T> {
return this.repo.target as ClassType<T>;
}
protected createEntity(dto: T, paramsFilter: QueryFilter[]): T {
/* istanbul ignore if */
if (!isObject(dto)) {
return undefined;
}
if (hasLength(paramsFilter)) {
for (const filter of paramsFilter) {
dto[filter.field] = filter.value;
}
}
/* istanbul ignore if */
if (!hasLength(objKeys(dto))) {
return undefined;
}
return dto instanceof this.entityClassType ? dto : plainToClass(this.entityClassType, dto);
}
protected throwConflictException(name: string): ConflictException {
throw new ConflictException(`${name} not found`);
}
} |
Hey guys! Here is some example of implementing such a kind of Unique validator. As you can see, it could be used not for just for checking primary keys uniqueness. Moreover such an approach does not require any modifications of this library at all. This approach is flexible and works perfect. Also note that it won't work unless you set up DI container ( |
Thanks for responding @zarv1k, appreciated and very helpful, thank you :) I will take a look at the validators approach for future consideration, since I have already adopted a solution that derives from TypeOrmCrudService. I can now use Typeorm 3.6.3 which fixes the bug described in the document header of my custom class, MyTypeOrmCrudService::createOne, posted earlier in this issue. Moving forward, whatever is decided, I think it would be useful if the official documentation for the library explained the default semantics for createOne and highlighted the options for overriding the default behaviour, e.g. via validators. This would be useful for new users that are considering adopting the library. |
Although I agree that most of the validation must be done in the validation layer, like uniqueness of a username or something like this, I don't think we should reimplement the logic for checking if a primary key is unique or not. That's counter intuitive for most of the databases that provide CRUD capabilities and it's a bug for me since when one calls the I believe all of this could be resolved by changing the call to |
I agree with the points made by @cleivson. For new users like myself, this was confusing and counter intuitive. Whatever outcome is decided, I think that the official documentation should definitely explain the current default semantics for the From the perspective of new users or businesses that are considering using the library.......if the decision is made that this is not a bug then it would be helpful if workarounds for overriding the default behaviour were officially documented and/or demonstrated with a small example playground repository/application. Near the time of originally posting I tried using insert but encountered problems with cascades and relations... /**
* Inserts a given entity into the database.
* Unlike save method executes a primitive operation without cascades, relations and other operations included.
* Executes fast and efficient INSERT query.
* Does not check if entity exist in the database, so query will fail if duplicate entity is being inserted.
*/
insert(entity: QueryDeepPartialEntity<Entity>|(QueryDeepPartialEntity<Entity>[])): Promise<InsertResult> {
return this.manager.insert(this.metadata.target as any, entity);
} |
yeah, friends, that's all pretty much interesting.
|
Hi @zMotivat0r,
|
Hi,
I am new to the library and have a query regarding the default semantics/behaviour of POST (createOne) in typeorm-crud.service.ts. This uses the save method on the typeorm repository, which means that if the resource already exists then existing property values are updated.
Does the crud library provide a way to override this behaviour so that if a resource already exists then a 409 error status is thrown?
I have included the source code below that I am using for my entity, controller and service....
Entity
Controller
Service
The text was updated successfully, but these errors were encountered: