.NET LINQ for Javascript, written by TypeScript.
- Provide
IQueryable<T>
, it's reusable, also variable and useiterator list
for holding query and execute. - Contains almost the original .NET and some extends methods.
- Support
Promise
like a input source.
let query = Queryable
.from(nations)
.join(continents, (x, y) => x.areaId === y.id)
.groupBy(o => o.y.areaName)
.select(x => {
return {
area: x.key,
total: Queryable.fromSync(x.items).count() // Here will return number, not Promise<number>
}
})
const asyncData = query.toList() // Will return Promise<{area:string, total:number}>
asyncData.then(data => {
console.log(data);
// [
// {area: 'Euro': total: 2},
// {area:'South Ameria', total: 1}
// ]
});
This document will use below data to make examples :
let players = new Promise((resolve, reject) => {
// skills: attack, stamia, speed, shoot
console.log('get players...');
setTimeout(() => {
resolve([
{ name: 'Ronaldo', overall: 96, nationId: 1, skills: [96, 85, 87, 91] },
{ name: 'Messi', overall: 98, nationId: 2, skills: [97, 85, 91, 93] },
{ name: 'Mbappe', overall: 86, nationId: 3, skills: [89, 81, 95, 83] },
{ name: 'Matial', overall: 81, nationId: 3, skills: [81, 80, 89, 81] },
{ name: 'Salah', overall: 89, nationId: 4, skills: [88, 82, 97, 86] }
]);
}, 1000);
})
let nations: Promise<{ id, name, areaId }[]> = new Promise(resolve => {
console.log('get nations...');
setTimeout(() => {
resolve([
{ id: 1, name: 'Portugal', areaId: 1 },
{ id: 2, name: 'Argentina', areaId: 2 },
{ id: 3, name: 'France', areaId: 1 },
{ id: 4, name: 'Egypt', areaId: 3 }
]);
}, 2000);
})
let continents = new Promise<{ id, areaName }[]>(resolve => {
console.log('get continents...');
setTimeout(() => {
resolve([
{ id: 1, areaName: 'Euro' },
{ id: 2, areaName: 'South America' },
]);
}, 2300);
})
All data source will be converted to Promise
notwithstanding that source is Promise or noramlly array data. Then once we call toList()
, count()
, first()
... or any execute methods
it will be return a Promise
.
let query = Queryable
.from(nations)
.join(continents, (x, y) => x.areaId === y.id)
.groupBy(o => o.y.areaName)
const asyncData = query.count() // Will return Promise<number>
asyncData.then(num => {
console.log(num);
// 2
})
It's often use inside sub-query which are after all data already retrieved successfully or you make sure the input source is sync data like as Array
.
let query = Queryable
.from(nations)
.join(continents, (x, y) => x.areaId === y.id)
.groupBy(o => o.y.areaName)
.select(x => {
return {
area: x.key,
total: Queryable.fromSync(x.items).count() // Here will return number, not Promise<number>
}
})
const asyncData = query.toList() // Will return Promise<{area:string, total:number}>
asyncData.then(data => {
console.log(data);
// [
// {area: 'Euro': total: 2},
// {area:'South Ameria', total: 1}
// ]
});
> More: at
from
method, all input sources atfrom, join, leftJoin
methods,... will be converted to Promise and use Promise.all to execute and then use Iterator collection to query data and once faced excuting methods like astoList(), first()
it will return data which be inside a Promise.
Make new IMethods
instance from a exists Queryable
. New one will keep the Iterator collection
and source
but not affect to previous Queryable
.
It's useful when we make the common Queryable
and then use it to many other places.
// Just where over > 85
let query = Queryable
.from(players)
.where(x => x.overall > 85);
// Continue from `query` and select player and nation
let query1 = query.clone()
.join(nations, (x, y) => x.nationId === y.id)
.select(o => {
return {
playerName: o.x.name,
nation: o.y.name
}
});
// Continue from `query` and calculate real overall each players
let query2 = query.clone()
.select(o => {
return {
name: o.name,
realOverall: Queryable.fromSync(o.skills).avarage()
}
}).orderByDescending(x => x.realOverall);
query.toList().then(data => console.table(data));
// name overall nationId skills
// ------- ------- -------- -----------
// Ronaldo 96 1 96,85,87,91
// Messi 98 2 97,85,91,93
// Mbappe 86 3 89,81,95,83
// Salah 89 4 88,82,97,86
query1.toList().then(data => console.table(data));
// playerName nation
// ---------- ---------
// Ronaldo Portugal
// Messi Argentina
// Mbappe France
// Salah Egypt
query2.toList().then(data => console.table(data));
// name realOverall
// ------- -----------
// Messi 91.5
// Ronaldo 89.75
// Salah 88.25
// Mbappe 87
let query = Queryable
.from(players)
.where(x => x.overall > 85);
query.toList().then(data => console.table(data));
// name overall nationId skills
// ------- ------- -------- -----------
// Ronaldo 96 1 96,85,87,91
// Messi 98 2 97,85,91,93
// Mbappe 86 3 89,81,95,83
// Salah 89 4 88,82,97,86
let query = Queryable
.from(players)
.where(x => x.overall > 85)
.select(o => {
return {
name: o.name,
realOverall: Queryable.fromSync(o.skills).avarage()
}
query.toList().then(data => console.table(data));
// name realOverall
// ------- -----------
// Messi 91.5
// Ronaldo 89.75
// Salah 88.25
// Mbappe 87
- from
- where
- select
- selectMany
- join
- leftJoin
- groupJoin
- orderBy
- orderByDescending
- take
- takeWhile
- skip
- skipWhile
- groupBy
- distinct
- concat
- zip
- union
- intersect
- except
- first :
Promise<T>
- firstOrDefault :
Promise<T | null>
- last :
Promise<T>
- lastOrDefault :
Promise<T | null>
- single
- singleOrDefault
- elementAt
- elementAtOrDefault
- orderByDescending
- defaultIfEmpty
- contains
- reserve
- sequenceEqual
- any :
Promise<boolean>
- all
- count :
Promise<number>
- min :
Promise<number>
- max :
Promise<number>
- sum :
Promise<number>
- average
- aggregate
- toList :
Promise<T[]>