Skip to content

Instantly share code, notes, and snippets.

@OliveiraCleidson
Created June 10, 2023 18:31
Show Gist options
  • Save OliveiraCleidson/dbe59e9e109c7d2e59a712429c51e8a1 to your computer and use it in GitHub Desktop.
Save OliveiraCleidson/dbe59e9e109c7d2e59a712429c51e8a1 to your computer and use it in GitHub Desktop.
export class Fruta {
id: number;
name: string;
price: number;
}
class Animal {
id: number;
name: string;
age: number;
basedLocations: string[];
affiliation: Animal;
preferredFood: Fruta[];
}
export type Fields<T> = keyof T;
export type RecursiveWhere<Model> = {
[propOfType in Fields<Model>]?: Model[propOfType] extends Primitive
? Operation<Model, propOfType>
: Model[propOfType] extends Array<infer ArrayType>
? RecursiveWhere<ArrayType>
: RecursiveWhere<Model[propOfType]>;
};
export type FindOptions<Model, SelectedFields extends Array<Fields<any>>> = {
fields?: SelectedFields;
where?: RecursiveWhere<Model>;
limit?: number;
offset?: number;
};
// Funciona em todos os tipos
// Tem que ser o mesmo tipo da propriedade
// $eq = equals
// $ne = not equals
// Tem que ser um array do mesmo tipo da propriedade
// $in = in
// $nin = not in
// Funciona apenas em tipos númericos
// $gt = greater than
// $gte = greater than or equal to
// $lt = less than
// $lte = less than or equal to
type Equals<
Model,
Field extends Fields<Model>,
> = Model[Field] extends Array<any>
? any
: {
$eq?: Model[Field];
};
type NotEquals<
Model,
Field extends Fields<Model>,
> = Model[Field] extends Array<any>
? any
: {
$ne?: Model[Field];
};
type In<Model, Field extends Fields<Model>> = Model[Field] extends Array<any>
? { $in?: Model[Field] }
: {
$in?: Array<Model[Field]>;
};
type NotIn<Model, Field extends Fields<Model>> = Model[Field] extends Array<any>
? {
$nin?: Model[Field];
}
: {
$nin?: Array<Model[Field]>;
};
type GreaterThan<
Model,
Field extends Fields<Model>,
> = Model[Field] extends number
? {
$gt?: Model[Field];
}
: any;
type GreaterThanOrEqual<
Model,
Field extends Fields<Model>,
> = Model[Field] extends number
? {
$gte?: Model[Field];
}
: any;
type LessThan<Model, Field extends Fields<Model>> = Model[Field] extends number
? {
$lt?: Model[Field];
}
: any;
type LessThanOrEqual<
Model,
Field extends Fields<Model>,
> = Model[Field] extends number
? {
$lte?: Model[Field];
}
: any;
type Primitive = (string | number | boolean) | Array<string | number | boolean>;
export type Operation<Model, Field extends Fields<Model>> = Equals<
Model,
Field
> &
NotEquals<Model, Field> &
In<Model, Field> &
NotIn<Model, Field> &
GreaterThan<Model, Field> &
GreaterThanOrEqual<Model, Field> &
LessThan<Model, Field> &
LessThanOrEqual<Model, Field>;
export interface Repository<T> {
find<SelectedFields extends Array<Fields<T>>>(
options?: FindOptions<T, SelectedFields>,
): Pick<T, SelectedFields[number]>[];
}
const frutaRepository: Repository<Fruta>;
const animalRepository: Repository<Animal>;
const result = frutaRepository.find({
fields: ['name', 'price'],
where: {
name: {
$eq: 'Banana',
$nin: ['Pera', 'Maçã'],
},
price: {},
},
});
const otherResult = animalRepository.find({
fields: ['name', 'age', 'affiliation'],
where: {
age: {},
affiliation: {
affiliation: {
age: {},
affiliation: {},
},
},
preferredFood: {},
},
});
otherResult[0].name;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment