Write LINQ and get query objects of different kinds for different processors.
LINQxy is a standard for data querying in TypeScript. It's a proxy translating LINQ queries into different query objects for different libraries (depends on plugins). You can write LINQ and use it to query MongoDB, TypeORM, ZangoDB (IndexDB) or anything else.
- tst-expression - C# like expression
- tst-reflect - runtime reflection
Lets have an interface of the data record we want to query.
enum Gender {
Female,
Male,
Unspecified,
}
interface IPerson {
name: string;
age: number;
xp: number;
}
interface IEmployee extends IPerson {
work: string;
salary: number;
}
And a generic usage.
import { Queryable } from "linqxy";
const someFilterObject = { workDescKeywords: [ "javascript", "typescript" ] };
const empQuery = Queryable.create<IEmployee>()
.filter(emp => emp.xp > 5 && !emp.name.startsWith("Jo"))
.filterIf(emp => someFilterObject.workDescKeywords.contains(emp.work), !!someFilterObject.workDescKeywords)
.map(emp => ({
name: emp.name,
xp: emp.xp
}));
Result of the empQuery
variable is Queryable object which can be build into eg. TypeORM.
Same example with TypeORM plugin will look like:
import { Queryable } from "linqxy-typeorm";
import Employee from "./Employee";
const someFilterObject = { workDescKeywords: [ "javascript", "typescript" ] };
const emps = await Queryable.create(Employee)
.filter(emp => emp.xp >= 5 && !emp.name.startsWith("Jo"))
.filterIf(emp => someFilterObject.workDescKeywords.contains(emp.work), !!someFilterObject.workDescKeywords)
.map(emp => ({
name: emp.name,
xp: emp.xp
}))
.find();
Which is translated into query:
await connection.getRepository(Employee).find({
xp: MoreThanOrEqual(5),
name: Not(Like("Jo%")),
work: In(["javascript", "typescript"])
});
Sorry to JavaScript users, but LINQxy uses TypeScript transformer typescript-expression-transformer. See the repo of the expression transformer for more information.
Is there a volunteer to create the Babel transform plugin?
class Queryable<TRecord>
{
filter(Expresson<(r: TRecord) => boolean> expression): Queryable<TRecord> {}
filterIf(Expresson<(r: TRecord) => boolean> expression, condition: boolean): Queryable<TRecord> {}
innerJoin<T, R>(
target: T[] | Queryable<T>,
on: Expression<(first: TRecord, second: T) => boolean>,
result: Expression<(first: TRecord, second: T) => R>
): Queryable<TRecord> {}
map<R>(Expresson<(r: TRecord) => R> expression): Queryable<R> {}
}
Plugins must implement IQueryGenerator interface. See wiky. TODO
Optionaly, it can extend Queryable object and provide some extra functionality. Eg. like TypeORM plugin:
import { Queryable as BaseQueryable} from "linqxy";
import { Generator as TypeORMGenerator } from "./Generator";
class Queryable<TRecord> extends BaseQueryable
{
static create<TEntity>(type: typeof T): Queryable<TRecord> {}
async find(): Promise<Array<TRecord>> {
return await connection.getRepository(this.RecordType).find(this.build(TypeORMGenerator));
}
async findOne(): Promise<TRecord> {}
}