Commit 6520b26f authored by nanahira's avatar nanahira

better typing for relation

parent 70c8e590
...@@ -23,14 +23,15 @@ import { ConsoleLogger } from '@nestjs/common'; ...@@ -23,14 +23,15 @@ import { ConsoleLogger } from '@nestjs/common';
import { camelCase } from 'typeorm/util/StringUtils'; import { camelCase } from 'typeorm/util/StringUtils';
import _ from 'lodash'; import _ from 'lodash';
import { ClassType } from './utility/insert-field'; import { ClassType } from './utility/insert-field';
import { RecursiveKeyOf } from './utility/recursive-key-of';
export type EntityId<T extends { id: any }> = T['id']; export type EntityId<T extends { id: any }> = T['id'];
export interface RelationDef { export interface RelationDef<T> {
name: string; name: T;
inner?: boolean; inner?: boolean;
} }
export const Inner = (name: string): RelationDef => { export const Inner = <T>(name: T): RelationDef<T> => {
return { name, inner: true }; return { name, inner: true };
}; };
...@@ -39,7 +40,7 @@ export type ValidCrudEntity<T> = Record<string, any> & { ...@@ -39,7 +40,7 @@ export type ValidCrudEntity<T> = Record<string, any> & {
} & Partial<QueryWise<T> & DeletionWise & EntityHooks & PageSettingsFactory>; } & Partial<QueryWise<T> & DeletionWise & EntityHooks & PageSettingsFactory>;
export interface CrudOptions<T extends ValidCrudEntity<T>> { export interface CrudOptions<T extends ValidCrudEntity<T>> {
relations?: (string | RelationDef)[]; relations?: (RecursiveKeyOf<T> | RelationDef<RecursiveKeyOf<T>>)[];
extraGetQuery?: (qb: SelectQueryBuilder<T>) => void; extraGetQuery?: (qb: SelectQueryBuilder<T>) => void;
hardDelete?: boolean; hardDelete?: boolean;
} }
...@@ -52,7 +53,10 @@ export class CrudBase<T extends ValidCrudEntity<T>> { ...@@ -52,7 +53,10 @@ export class CrudBase<T extends ValidCrudEntity<T>> {
readonly entityPaginatedReturnMessageDto = PaginatedReturnMessageDto( readonly entityPaginatedReturnMessageDto = PaginatedReturnMessageDto(
this.entityClass, this.entityClass,
); );
readonly entityRelations: (string | RelationDef)[]; readonly entityRelations: (
| RecursiveKeyOf<T>
| RelationDef<RecursiveKeyOf<T>>
)[];
readonly extraGetQuery: (qb: SelectQueryBuilder<T>) => void; readonly extraGetQuery: (qb: SelectQueryBuilder<T>) => void;
readonly log = new ConsoleLogger(`${this.entityClass.name}Service`); readonly log = new ConsoleLogger(`${this.entityClass.name}Service`);
...@@ -191,7 +195,10 @@ export class CrudBase<T extends ValidCrudEntity<T>> { ...@@ -191,7 +195,10 @@ export class CrudBase<T extends ValidCrudEntity<T>> {
return camelCase(this.entityName); return camelCase(this.entityName);
} }
_applyRelationToQuery(qb: SelectQueryBuilder<T>, relation: RelationDef) { _applyRelationToQuery(
qb: SelectQueryBuilder<T>,
relation: RelationDef<RecursiveKeyOf<T>>,
) {
const { name } = relation; const { name } = relation;
const relationUnit = name.split('.'); const relationUnit = name.split('.');
const base = const base =
...@@ -209,7 +216,7 @@ export class CrudBase<T extends ValidCrudEntity<T>> { ...@@ -209,7 +216,7 @@ export class CrudBase<T extends ValidCrudEntity<T>> {
_applyRelationsToQuery(qb: SelectQueryBuilder<T>) { _applyRelationsToQuery(qb: SelectQueryBuilder<T>) {
for (const relation of this.entityRelations) { for (const relation of this.entityRelations) {
if (typeof relation === 'string') { if (typeof relation === 'string') {
this._applyRelationToQuery(qb, { name: relation }); this._applyRelationToQuery(qb, { name: relation as any });
} else { } else {
this._applyRelationToQuery(qb, relation); this._applyRelationToQuery(qb, relation);
} }
......
/* eslint-disable @typescript-eslint/ban-types */
export type RecursiveKeyOf<TObj extends Record<string, any>> = {
[TKey in keyof TObj & string]: RecursiveKeyOfHandleValue<
TObj[TKey],
`${TKey}`
>;
}[keyof TObj & string];
type RecursiveKeyOfInner<TObj extends Record<string, any>> = {
[TKey in keyof TObj & string]: RecursiveKeyOfHandleValue<
TObj[TKey],
`.${TKey}`
>;
}[keyof TObj & string];
type RecursiveKeyOfHandleValue<TValue, Text extends string> = TValue extends
| Function
| ((...args: any[]) => any)
| (new (...args: any[]) => any)
? never
: TValue extends Date | string | number | boolean
? never // Text
: TValue extends (infer TItem)[]
? Text | `${Text}${RecursiveKeyOfInner<TItem>}`
: TValue extends Record<string, any>
? Text | `${Text}${RecursiveKeyOfInner<TValue>}`
: never; // Text;
import { NestExpressApplication } from '@nestjs/platform-express'; import { NestExpressApplication } from '@nestjs/platform-express';
import { Controller, Injectable } from '@nestjs/common'; import { Controller, Injectable } from '@nestjs/common';
import { CrudService } from '../src/crud-base'; import { CrudService } from '../src/crud-base';
import { Gender, User } from './utility/user'; import { User } from './utility/user';
import { RestfulFactory } from '../src/decorators'; import { RestfulFactory } from '../src/decorators';
import { Test } from '@nestjs/testing'; import { InjectDataSource } from '@nestjs/typeorm';
import { InjectDataSource, TypeOrmModule } from '@nestjs/typeorm';
import { DataSource } from 'typeorm'; import { DataSource } from 'typeorm';
import request from 'supertest';
@Injectable() @Injectable()
class UserService extends CrudService(User) { class UserService extends CrudService(User) {
......
import { Entity, Index } from 'typeorm'; import { Entity, Index } from 'typeorm';
import { DateColumn, EnumColumn, IntColumn, NotChangeable, NotColumn, NotWritable, StringColumn } from '../../src/decorators'; import {
DateColumn,
EnumColumn,
IntColumn,
NotChangeable,
NotColumn,
NotWritable,
StringColumn,
} from '../../src/decorators';
import { IdBase, StringIdBase } from '../../src/bases'; import { IdBase, StringIdBase } from '../../src/bases';
export enum Gender { export enum Gender {
...@@ -7,6 +15,11 @@ export enum Gender { ...@@ -7,6 +15,11 @@ export enum Gender {
M = 'M', M = 'M',
} }
export class Book {
id: number;
name: string;
}
@Entity() @Entity()
export class User extends IdBase() { export class User extends IdBase() {
@Index() @Index()
...@@ -28,6 +41,8 @@ export class User extends IdBase() { ...@@ -28,6 +41,8 @@ export class User extends IdBase() {
@NotColumn() @NotColumn()
birthday: Date; birthday: Date;
books: Book[];
} }
@Entity() @Entity()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment