gid-oss / dataui-nestjs-crud Goto Github PK
View Code? Open in Web Editor NEWThis project forked from rewiko/crud
NestJs CRUD for RESTful APIs
Home Page: https://github.com/nestjsx/crud/wiki
License: MIT License
This project forked from rewiko/crud
NestJs CRUD for RESTful APIs
Home Page: https://github.com/nestjsx/crud/wiki
License: MIT License
I am having trouble with the following error.
The version of Typescript seems to be old.
Hi.
First of all : thinks you for your fork ! ;-)
Subject :
CrudRequest
object is pass between Controller and Service. But on this object we dont store any context informations as authenticate user for exemple : (this is nice to have auth user object on service (stored on native Request
object))Do you think it's possible to store extra informations on CrudRequest
object and in particular auth. user?
Request
object is not possible : risk of producing strange case with singleton service (switch to Scope=Request by nestJs), but store auth user information seen to be possible.Request
object with nesths-crud configuration auth
. sample configuration ;CrudConfigService.load({
params: {
[...]
},
auth: {
property: 'user',
},
[...]
* CurdRequest interface can became :
export interface CrudRequest {
parsed: ParsedRequestParams;
options: CrudRequestOptions;
auth: any; // according to configuration
extra: any; // any params for business logic
}
public.decorator.ts
export const Public = () => SetMetadata('isPublicEndPoint', true);
main.ts
import { CrudConfigService } from '@dataui/crud';
CrudConfigService.load({
routes: {
getOneBase: { decorators: [Public()] }
},
});
import { AppModule } from './app.module';
import { Public } from './public.decorator.ts'
error:
getOneBase: { decorators: [(0, auth_decorator_1.Public)()] },
^
ReferenceError: Cannot access 'auth_decorator_1' before initialization
solution
solved by importing Public
before CrudConfigService.load()
I want to transform the body before creating a resource.
I know we can use interceptors or overriding the crud methods, but creating an interceptor class for each route is overkill and harder than implementing the crud from scratch.
there is a lighter solution, a transform function that takes the body (or maybe the request) and returns the new body (or request)
@Crud({
model: { ... },
routes: {
createOneBase: {
// or transform(req) => newReq
transform(body: MyEntity ) => ({ ...body, status:"ok" })
}
}
})
I am getting that error on GET method with 3 join levels.
Example:
2 join level works: http://localhost:3000/entity-a?join=entityB&join=entityB.entityC
3 join level NOT works: http://localhost:3000/entity-a?join=entityB&join=entityB.entityC&join=entityB.entityC.entityD
Repository with bug reproduction
https://github.com/GabrielArsenio/nest-crud-bug-join
Hey, just wanted to let you know that the npm package refers to incorrect/unknown repository URL (https://github.com/dataui/crud)!
we can implement the interface CrudController<Entity>
, is there a way to provide a class that extends CrudController
instead of the original one?
CrudConfigService.load({
CrudController: ExtendedCrudController
})
class ExtendedCrudController extends CrudController{
additionalMethod(req){
return this.service.something();
}
}
sure we can create a class from scratch that implements CrudController, but in this case we'll need to implement all methods from scratch, unless the class itself is exposed
// suppose that there is a class named CrudControllerClass is exposed by this library
class ExtendedCrudController extends CrudControllerClass{}
// and in the controller
class MyController extends ExtendedCrudController{}
I have two Entities, but I don't know how to implement ManyToMany in Curd
Category Entity
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"
@Entity()
export class Category {
@PrimaryGeneratedColumn()
id: number
@Column()
name: string
}
Question Entity
import {
Entity,
PrimaryGeneratedColumn,
Column,
ManyToMany,
JoinTable,
} from "typeorm"
import { Category } from "./Category"
@Entity()
export class Question {
@PrimaryGeneratedColumn()
id: number
@Column()
title: string
@Column()
text: string
@ManyToMany(() => Category)
@JoinTable()
categories: Category[]
}
How can I insert, update, find, and delete ManyToMany in Crud?
I haven't found a good solution at the moment🙁
I want to include the soft deleted rows for all getOneBase
operations, but not getManyBase
CrudConfigService.load({
getOneBase: {
query:{
withDeleted: true,
}
}
})
also, ...
@Override()
getOne(@parsedReq() req: any){
let options = { withDeleted: true, }
return this.base.getOneBase(req, options)
}
creating a new custom method doesn't give the same signature as the inherited getOneBase
@GET()
findOne(@Req() req: any){
// won't work as expected, and all queries must be implemented manually, such as filter, ...
// there is no exposed functionality to convert req into parsed req, even `(@ParsedReq() req)` gives undefined
return this.base.getOneBase(req)
}
I want to add additional methods that are typically similar to the existing ones.
for example, I want to add /me
that is similar to getManyBase
and getOneBase
, but also keep /
that getManyBase offers.
but also, I want it to simulate getOneBase
with minor changes.
the only way I found till now is to manually implement it from scratch
export class UsersController implements CrudController<UserEntity>{
constructor( ... ){}
// without any modifications, this should be same as `/`
@GET("/me")
getUserInfo(req){
req.user = getCurrentuser()
return this.base.getOneBase(req)
}
}
Is there a way to use CrudRequest in a custom endpoint and to have access in Query Params and their functionality? For example to have something like that:
custom endpoint: /something/3/stats?filter[0]=price||$lte||100
@Get('/:id/stats')
async getStatistics(
@Param('id') id:number,
@ParsedRequest() req: CrudRequest
) {
. . .
}
and to have access to these Query Params and the way they works:
or how to extend the functionality that the Query Params have?
Any change to add this function by default on CRUD config?
Something like that:
@Crud({
model: {
type: MyModel,
},
routes: {
deleteOneBase: {
softDelete: true,
},
},
})
@Controller('my-models')
export class MyModelController implements CrudController<MyModel> {
constructor(public service: MyModelService) {}
}
Sometimes your system need to add filter conditions after the HTTP request parsed.
For example you would like to filter records by current login user ID.
You would be like to do it as following:
public async getRecordsByUserId(req: CrudRequest, userId: number) {
req.parsed.join.push({
field: 'user',
});
const builder = await this.createBuilder(req.parsed, req.options, true);
builder.andWhere('User.id = :userId', { userId });
return this.doGetMany(builder, req.parsed, req.options);
}
As given in the docs when sending the query string like
http://localhost:3100/Customers?join=facilities||id,status||on[0]=facilities.status||$eq||Archived&filter[0]=id||$eq||4
the join condition gets omitted because the join key is not intercepted correctly, key value pair is coming as
key= join=facilities||id,status||on
value= facilities.status||$eq||Archived
But we actually need
key= join
value= facilities||id,status||on[0]=facilities.status||$eq||Archived
Hello folks,
currently the generated operationId
for example looks like this getOneBaseUsersControllerUserEntity
,
is there a way to customize this ?
Hello,
all the documentation related links in the readme are broken:
https://github.com/dataui/crud/wiki#why
https://github.com/dataui/crud/wiki/Controllers#description
https://github.com/dataui/crud/wiki/Services#description
https://github.com/dataui/crud/wiki/Requests#description
in docs there is an example to override a method like this
get base(): CrudController<Hero> {
return this;
}
@Override()
getMany(
@ParsedRequest() req: CrudRequest,
) {
return this.base.getManyBase(req);
}
however, the base methods such as getManyBase
is typed to return a promise or undefined
so, the previous snippet makes TS to give this error
Cannot invoke an object which is possibly 'undefined'.ts(2722)
we can make an ugly workaround and edit our code to be
return this.base.getManyBase?.(req);
this also makes TS complain again because the overrides method i.e. getMany()
should return Promise only, not promise or undefined
We get this warning in many files, is this some option we could use to fix it or it needs a change in this package?
WARNING in ./node_modules/@dataui/crud-request/lib/interfaces/create-query-params.interface.js
Module Warning (from ./node_modules/source-map-loader/dist/cjs.js):
Failed to parse source map from 'D:\R\project-frontend\node_modules\@dataui\crud-request\src\interfaces\create-query-params.interface.ts' file: Error: ENOENT: no such file or directory, open 'D:\R\project-front
end\node_modules\@dataui\crud-request\src\interfaces\create-query-params.interface.ts'
Thanks
First of all, thanks a lot for this fork and for keeping the lib alive, been using it since the guy from original library disappeared. The issue is that npm links to the wrong repo and so finding this one is really hard. The only direct link is in the issues for original lib.
in this line
Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey);
Reflect doesn't have a static method called defineMetadata
, it is defined by reflect-metadata
which must be imported as a side effect like this:
import "reflect-metadata";
//Now we can use Reflect.defineMetadata()
the file uses it doesn't import reflect-metadata
though it is add to dependencies
https://www.npmjs.com/package/@dataui/crud
the links in the npm package description leads to 404 pages
Can you please please add the code of this PR into your package?
We really need to be able to query in an array!
Thanks a lot!
As far as I understand to make soft delete cascade possible in TYPEORM we need to set { cascade : true }
in children
After that when we delete the parent => children will be also deleted
The thing is that to make it work with soft delete we need to pass entity with its children to soft delete method
But when I add join to the DELETE endpoint join does not happening, even if i add eager join.
So how do you handle cascade soft delete with this lib?
P.S (using TYPEORM)
When using with deleted from the query builder
.setIncludeDeleted(1)
the relations included via @crud decorator are not being fetched if they have been deleted.
This is because builder.withDeleted(); is being called after the joins are created.
Hi everyone,
First of all, I'd like to extend my gratitude to the maintainers for your efforts in keeping this project both usable and up-to-date.
I'm encountering an issue when using the @Crud
controller's params
option, specifically when it involves ManyToOne
relationships. Below is a description of the problem and the technical context:
Dependencies:
"dependencies": {
"@dataui/crud": "^5.3.3",
"@dataui/crud-typeorm": "^5.3.3",
"@nestjs/common": "10.3.7",
"@nestjs/config": "3.2.2",
"@nestjs/core": "10.3.7",
"@nestjs/platform-express": "10.3.7",
"@nestjs/swagger": "7.3.1",
"@nestjs/typeorm": "10.0.2",
"class-transformer": "0.5.1",
"class-validator": "0.14.0",
"pg": "8.11.2",
"reflect-metadata": "0.1.13",
"typeorm": "0.3.20"
}
Relevant Code:
import { Crud, CrudController } from '@dataui/crud';
import { Controller } from '@nestjs/common';
import { ArticleService } from './article.service';
import { Article } from './entities/article.entity';
@Controller('/author/:authorId/article')
@Crud({
model: {
type: Article,
},
params: {
authorId: {
field: 'author',
type: 'number',
},
},
})
export class ArticleController implements CrudController<Article> {
constructor(public service: ArticleService) {}
}
import { Author } from 'src/author/entities/author.entity';
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class Article {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@ManyToOne(() => Author, {
nullable: false,
})
author: Author;
}
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class Author {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
}
Issue:
When I make a GET request to /author/1/article
, I encounter a 500 error with the following log:
error: error: column Article.authorId.id does not exist
ERROR [ExceptionsHandler] column Article.authorId.id does not exist
QueryFailedError: column Article.authorId.id does not exist
at PostgresQueryRunner.query (./api/src/driver/postgres/PostgresQueryRunner.ts:331:19)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at SelectQueryBuilder.loadRawResults (./api/src/query-builder/SelectQueryBuilder.ts:3805:25)
at SelectQueryBuilder.executeEntitiesAndRawResults (./api/src/query-builder/SelectQueryBuilder.ts:3551:26)
at SelectQueryBuilder.getRawAndEntities (./api/src/query-builder/SelectQueryBuilder.ts:1670:29)
at SelectQueryBuilder.getMany (./api/src/query-builder/SelectQueryBuilder.ts:1760:25)
The generated SQL query:
query failed: SELECT "Article"."id" AS "Article_id", "Article"."title" AS "Article_title", "Article"."authorId" FROM "article" "Article" WHERE ("Article"."authorId.id" = $1) -- PARAMETERS: [1]
Further Investigation:
I discovered that the TypeOrmCrudService
utilizes the getFieldWithAlias
function, potentially mishandling the mapping of properties to database columns. This function relies on entityColumnsHash
, which is initialized using TypeORM's column metadata in onInitMapEntityColumns. Intriguingly, TypeORM provides a databasePath = 'authorId.id'
, which doesn't seem correct.
Modifying the initialization line in the TypeOrmCrudService
to use databaseName
instead of databasePath
appears to solve the issue:
this.entityColumnsHash[prop.propertyName] = prop.databaseName;
Although this adjustment resolves the immediate problem, I'm uncertain if it's the correct fix, or if the underlying issue might be within TypeORM itself.
I would appreciate any help or comments
I'm encountering an error when using getMany with joins and pagination. The issue seems to be related to duplicate column names in the query results.
some time we need some endpoint public and some with Auth then how we can handle this
NestJS CRUD currently allows for joining related entities in queries. However, there is limited control over the join condition itself.
This feature request proposes the addition of join filters, allowing users to specify a WHERE condition within the ON clause of a join.
Introduce a new property within the QueryJoin type of crud-request. This property could be named on and accept array of objects of type QueryFilter representing the WHERE condition for the join.
Example:
export declare type QueryJoin = {
field: string;
select?: QueryField[];
on?: QueryFilter[]; // New property
};
This functionality would allow users to specify conditions within the join, like so:
query.setJoin({
field: 'author',
select: ['name', 'image'],
on: [{ field: 'author.id', operator: 'eq', value: 123 }], // Filter by specific author ID
});
By implementing join filters, dataui-nestjs-crud would provide greater control over join conditions, enabling more sophisticated data retrieval scenarios.
node_modules/@dataui/crud/lib/interfaces/auth-options.interface.d.ts(2,31): error TS2307: Cannot find module '@dataui/crud-util/src' or its corresponding type declarations.
import { SCondition } from '@dataui/crud-request/lib/types/request-query.types';
import { ObjectLiteral } from 'crud-util/src';
export interface AuthGlobalOptions {
property?: string;
}
export interface AuthOptions {
property?: string;
filter?: (req: any) => SCondition | void;
or?: (req: any) => SCondition | void;
persist?: (req: any) => ObjectLiteral;
}
to
import { SCondition } from '@dataui/crud-request/lib/types/request-query.types';
import { ObjectLiteral } from '@dataui/crud-util/lib/types/object-literal.type';
export interface AuthGlobalOptions {
property?: string;
}
export interface AuthOptions {
property?: string;
filter?: (req: any) => SCondition | void;
or?: (req: any) => SCondition | void;
persist?: (req: any) => ObjectLiteral;
}
export helper files in index.ts, so we can create a custom decorator to add Swagger props to custom routes.
also, this package can expose CrudSwagger()
decorator to add similar swagger props to that used by @Crud()
replace export * from './crud/crud-routes.factory';
with export * from './crud';
expose CrudSwagger()
decorator
usage:
@Crud(...)
export class MyController implements implements CrudController<MyEntity>{
@Get("me")
@CrudSwagger()
customRoute(){
return this.service.getUserInfo()
}
}
@zaro Hi Team, first of all amazing job on forking this and maintaining it. I was wondering if we have already added the support for Aggregate functions (SUM, MIN, MAX) and GroupBy clause or it still under consideration?
after setup @crud()
with typescript as mentioned in the docs, I opened the swagger UI to try out the routes that are created by this package.
it works, but I noticed that the schema is always empty
solution:
solved by adding @nestjs/swagger
to plugins
nest-cli.json
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true,
"plugins": [
{
"name": "@nestjs/swagger",
"options": {
"introspectComments": true,
"classValidatorShim": true
}
}
]
}
}
This is an issue from the original repository but still relevant, so I am reposting the issue here.
Original issue: nestjsx#551
When declaring the filter
option inside of the @Crud()
decorator for a controller it is only working when provided as a static object. When I use the documented QueryFilterFunction
, as described [in the docs (https://github.com/nestjsx/crud/wiki/Controllers#filter), the first parameter is receiving undefined and all filters are ignored.
I need to extend any incoming filters with some persisted filters based on the current date for the records. Using new Date() in the static object generates a matching static date-value and therefore breaks my intent. The solution makes sense to use a factory function to merge the search options, but so long as the incoming ```SCondition```` is empty that is impossible.
I'm using the latest releases for the following libraries.
"@nestjs/typeorm": "~7.1.0",
"@nestjsx/crud": "~4.6.2",
"@nestjsx/crud-typeorm": "~4.6.2",
"typeorm": "~0.2.25"
This issue reports a minor typo in the main.yml file. The command used to start Docker Compose services has an extra hyphen before docker compose.
run: docker-compose up -d
run: docker compose up -d
The hyphen before docker compose is unnecessary and might lead to errors when executing the command. Removing this hyphen ensures the command runs smoothly.
This typo could potentially cause the docker-compose up -d command to fail, preventing the intended action of starting all Docker Compose services in detached mode.
Simply remove the hyphen before docker compose in the main.yml file.
Example of the search parameter (based on seeds)
{ name: { $eq: 'Project1' }, companyId: { $or: { $notnull: true, $eq: 1 } } }
Expectation:
The result is one project with the name Project1
Result:
Received all projects, filter name: { $eq: 'Project1' }
is ignoring
Hi all,
I have a problem that the library is not updating a foreign key when calling tha API with PATCH.
@Entity('pricetypes')
export class PriceType extends BaseEntity {
@Column({ name: 'group_id' })
groupId: number;
@ManyToOne(() => Group, group => group.pricetypes)
@JoinColumn({ name: 'group_id', referencedColumnName: 'id' })
group: Group;
// ...more attributes
}
export abstract class BaseEntity {
@ApiProperty({ description: 'Unique identifier of the entity' })
@PrimaryGeneratedColumn()
id: number;
// ..more properties
}
@Entity('groups')
export class Group extends BaseEntity {
@Column({ type: 'varchar', length: 100 })
name: string;
@Column({ type: 'text' })
note: string;
@OneToMany(() => PriceType, priceType => priceType.group, {eager: true})
pricetypes: PriceType[];
}
export class CreatePriceTypeDto {
@ApiProperty()
@IsNotEmpty()
@IsNumber()
groupId: number;
// .. more attributes
}
export class UpdatePriceTypeDto extends PartialType(CreatePriceTypeDto) {}
When creating a pricetype
everything works as expected, but when updating a pricetype
and changing the referenced groupId
, nothing happens, the FK groupId
is not updated. (Any non-relational column is updated correctly):
curl -X 'PATCH' \
'http://localhost:3000/pricetype/2' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"groupId": 3
}'
Result: groupId
is still the same. Also inside the database.
{
"id": 2,
"groupId": 2
// ... more properties
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.