Skip to content

Commit

Permalink
wip aggregate
Browse files Browse the repository at this point in the history
  • Loading branch information
lroal committed May 8, 2024
1 parent 03dfd3b commit 6c0cc43
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 37 deletions.
82 changes: 49 additions & 33 deletions src/map.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,8 +359,13 @@ type MappedTable<T> = {
): Promise<StrategyToRowArray<FetchedProperties<T, FS>, T>>;
getAll(): Promise<StrategyToRowArray<FetchedProperties<T, {}>, T>>;
getAll<FS extends FetchingStrategy<T>>(
fetchingStrategy?: FS
fetchingStrategy: FS
): Promise<StrategyToRowArray<FetchedProperties<T, FS>, T>>;

aggregate<FS extends AggregateStrategy<T>>(
fetchingStrategy: FS
): Promise<StrategyToRowData<FetchedAggregateProperties<T, FS>>[]>;

count(filter?: Filter | PrimaryRowFilter<T>[]): Promise<number>;
delete(filter?: Filter | PrimaryRowFilter<T>[]): Promise<void>;
deleteCascade(filter?: Filter | PrimaryRowFilter<T>[]): Promise<void>;
Expand Down Expand Up @@ -560,14 +565,25 @@ type AllowedColumnsAndTablesConcurrency<T> = {
};


type FetchingStrategy<T> = FetchingStrategyBase<T> | AggType<T>
type FetchingStrategy<T> = FetchingStrategyBase<T> | AggType<T>

type AggregateStrategy<T> = AggregateStrategyBase<T> | AggType<T>

type AggType<T> = {
[name: string]: AggregationFunction<T>;
[name: string]: AggregationFunction<T>;
} & {
where?: (agg: MappedColumnsAndRelations<T>) => RawFilter;
where?: (agg: MappedColumnsAndRelations<T>) => RawFilter;
};


type AggregateStrategyBase<T> =
{
orderBy?:
| OrderBy<Extract<keyof AllowedColumns<T>, string>>[]
| OrderBy<Extract<keyof AllowedColumns<T>, string>>;
limit?: number;
offset?: number;
where?: (agg: MappedColumnsAndRelations<T>) => RawFilter;
};

type FetchingStrategyBase<T> = {
[K in keyof T &
Expand All @@ -582,40 +598,40 @@ type FetchingStrategyBase<T> = {
| OrderBy<Extract<keyof AllowedColumns<T>, string>>;
limit?: number;
offset?: number;
where?: (agg: MappedColumnsAndRelations<T>) => RawFilter;

};

type ExtractAggregates<Agg> = {
[K in keyof Agg as
Required<Agg>[K] extends (agg: Aggregate<infer V>) => ColumnSymbols
? K extends 'where'? never : K
: never
]: Agg[K] extends (agg: Aggregate<infer V>) => infer R ? R : never;
[K in keyof Agg as
Required<Agg>[K] extends (agg: Aggregate<infer V>) => ColumnSymbols
? K extends 'where' ? never : K
: never
]: Agg[K] extends (agg: Aggregate<infer V>) => infer R ? R : never;
}

type AggregationFunction<T> = (agg: Aggregate<T>) => ColumnSymbols;

type Aggregate<T> =
RelatedColumns<T> &
{
sum(fn: (x: AggregateColumns<T>) => NumericColumnSymbol): NumericColumnSymbol & NotNull;
avg(fn: (x: AggregateColumns<T>) => NumericColumnSymbol): NumericColumnSymbol & NotNull;
min(fn: (x: AggregateColumns<T>) => NumericColumnSymbol): NumericColumnSymbol & NotNull;
max(fn: (x: AggregateColumns<T>) => NumericColumnSymbol): NumericColumnSymbol & NotNull;
count(fn: (x: AggregateColumns<T>) => NumericColumnSymbol): NumericColumnSymbol & NotNull;
}
type Aggregate<T> =
RelatedColumns<T> &
{
sum(fn: (x: AggregateColumns<T>) => NumericColumnSymbol): NumericColumnSymbol & NotNull;
avg(fn: (x: AggregateColumns<T>) => NumericColumnSymbol): NumericColumnSymbol & NotNull;
min(fn: (x: AggregateColumns<T>) => NumericColumnSymbol): NumericColumnSymbol & NotNull;
max(fn: (x: AggregateColumns<T>) => NumericColumnSymbol): NumericColumnSymbol & NotNull;
count(fn: (x: AggregateColumns<T>) => NumericColumnSymbol): NumericColumnSymbol & NotNull;
}

type RelatedColumns<T> = RemoveNeverFlat<{
[K in keyof T]:
T[K] extends StringColumnTypeDef<infer M> ? StringColumnSymbol
:T[K] extends UuidColumnTypeDef<infer M> ? UuidColumnSymbol
:T[K] extends NumericColumnTypeDef<infer M> ? NumericColumnSymbol
:T[K] extends DateColumnTypeDef<infer M> ? DateColumnSymbol
:T[K] extends DateWithTimeZoneColumnTypeDef<infer M> ? DateWithTimeZoneColumnSymbol
:T[K] extends BinaryColumnTypeDef<infer M> ? BinaryColumnSymbol
:T[K] extends BooleanColumnTypeDef<infer M> ? BooleanColumnSymbol
:T[K] extends JSONColumnTypeDef<infer M> ? JSONColumnSymbol
:T[K] extends ManyRelation
: T[K] extends UuidColumnTypeDef<infer M> ? UuidColumnSymbol
: T[K] extends NumericColumnTypeDef<infer M> ? NumericColumnSymbol
: T[K] extends DateColumnTypeDef<infer M> ? DateColumnSymbol
: T[K] extends DateWithTimeZoneColumnTypeDef<infer M> ? DateWithTimeZoneColumnSymbol
: T[K] extends BinaryColumnTypeDef<infer M> ? BinaryColumnSymbol
: T[K] extends BooleanColumnTypeDef<infer M> ? BooleanColumnSymbol
: T[K] extends JSONColumnTypeDef<infer M> ? JSONColumnSymbol
: T[K] extends ManyRelation
? RelatedColumns<T[K]>
: T[K] extends RelatedTable
? RelatedColumns<T[K]>
Expand All @@ -635,7 +651,7 @@ type AggregateColumns<T> = RemoveNeverFlat<{
type AggregateColumns2<T> = RemoveNeverFlat<{
[K in keyof T]:
T[K] extends NumericColumnTypeDef<infer M> ? NumericColumnSymbol
:T[K] extends ManyRelation
: T[K] extends ManyRelation
? AggregateColumns2<T[K]>
: T[K] extends RelatedTable
? AggregateColumns2<T[K]>
Expand Down Expand Up @@ -975,6 +991,7 @@ type StrategyToRow<T, U> = StrategyToRowData<T> & {
delete(concurrency: Concurrency<U>): Promise<void>;
};


type StrategyToRowArray<T, U> = StrategyToRowData<T>[] & {
saveChanges(): Promise<void>;
saveChanges<C extends Concurrency<U>>(concurrency?: C): Promise<void>;
Expand Down Expand Up @@ -1046,7 +1063,8 @@ type ExtractColumnBools<T, TStrategy> = RemoveNever<{

type NegotiateNotNull<T> = T extends NotNull ? NotNull : {};

type FetchedProperties<T, TStrategy> = FetchedColumnProperties<T, TStrategy> & FetchedRelationProperties<T, TStrategy> & ExtractAggregates< TStrategy>
type FetchedProperties<T, TStrategy> = FetchedColumnProperties<T, TStrategy> & FetchedRelationProperties<T, TStrategy> & ExtractAggregates<TStrategy>
type FetchedAggregateProperties<T, TStrategy> = FetchedColumnProperties<T, TStrategy> & ExtractAggregates<TStrategy>


type FetchedRelationProperties<T, TStrategy> = RemoveNeverFlat<{
Expand Down Expand Up @@ -1182,8 +1200,7 @@ type StrategyToInsertRowData<T> = Omit<{
? M | null
: T[K] extends JSONColumnSymbol
? JsonType | null
: // : never
T[K] extends ManyRelation
: T[K] extends ManyRelation
? StrategyToInsertRowData<T[K]>[]
: StrategyToInsertRowData<T[K]>;
}, 'formulaDiscriminators' | 'columnDiscriminators' | 'map' | ' isManyRelation' | ' relatedTable' | ' isOneRelation'>
Expand Down Expand Up @@ -1602,7 +1619,6 @@ type MapPropertiesTo6<T, V extends number = 6> = {
[K in keyof T]: UnionOfTypes<MapPropertiesTo5<Omit<T, K>, V>>;
};
type UnionOfTypes<T> = T[keyof T];
// type CountProperties<T> = UnionOfTypes<MapPropertiesTo6<T>> | UnionOfTypes<MapPropertiesTo5<T>> | UnionOfTypes<MapPropertiesTo4<T>> | UnionOfTypes<MapPropertiesTo3<T>> | UnionOfTypes<MapPropertiesTo2<T>> | UnionOfTypes<MapPropertiesTo1<T>>;

interface RawFilter {
sql: string | (() => string);
Expand Down
68 changes: 64 additions & 4 deletions tests/getMany.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,69 @@ describe('getMany with column strategy', () => {
}
});

describe('getMany with aggregates', () => {
describe('aggregate', () => {

test('pg', async () => await verify('pg'));
test('oracle', async () => await verify('oracle'));
test('mssql', async () => await verify('mssql'));
if (major === 18)
test('mssqlNative', async () => await verify('mssqlNative'));
test('mysql', async () => await verify('mysql'));
test('sqlite', async () => await verify('sqlite'));
test('sap', async () => await verify('sap'));
test('http', async () => await verify('http'));

async function verify(dbName) {
const { db } = getDb(dbName);
const rows = await db.order.aggregate({
where: x => x.customer.name.notEqual(null),
id: x => x.id,
customerSum: x => x.sum(x => x.customer.id),
customerName: x => x.customer.name,
postalPlace: x => x.deliveryAddress.postalPlace,
maxLines: x => x.max(x => x.lines.id),
numberOfPackages: x => x.count(x => x.lines.packages.id),
sumPackages: x => x.sum(x => x.lines.packages.id),
balance: x => x.min(x => x.customer.balance),
});

//mssql workaround because datetime has no time offset
for (let i = 0; i < rows.length; i++) {
rows[i].orderDate = dateToISOString(new Date(rows[i].orderDate));
}

const date1 = new Date(2022, 0, 11, 9, 24, 47);
const date2 = new Date(2021, 0, 11, 12, 22, 45);
const expected = [
{
id: 1,
customerSum: 1,
customerName: 'George',
postalPlace: 'Jakobsli',
orderDate: dateToISOString(date1),
maxLines: 2,
numberOfPackages: 2,
sumPackages: 3,
balance: 177,
},
{
id: 2,
customerSum: 2,
customerName: 'Harry',
postalPlace: 'Surrey',
orderDate: dateToISOString(date2),
maxLines: 3,
numberOfPackages: 1,
sumPackages: 3,
balance: 200,
}
];

expect(rows).toEqual(expected);
}
}, 20000);

describe('aggregate each row', () => {

test('pg', async () => await verify('pg'));
test('oracle', async () => await verify('oracle'));
Expand All @@ -517,6 +579,7 @@ describe('getMany with aggregates', () => {
customerName: x => x.customer.name,
id2: x => x.id,
lines: {
id: true,
id2: x => x.id,
numberOfPackages: x => x.count(x => x.packages.id)
},
Expand All @@ -530,12 +593,10 @@ describe('getMany with aggregates', () => {
balance: x => x.min(x => x.customer.balance),
customerId2: x => x.sum(x => x.customer.id),
});

//mssql workaround because datetime has no time offset
for (let i = 0; i < rows.length; i++) {
rows[i].orderDate = dateToISOString(new Date(rows[i].orderDate));
}

const date1 = new Date(2022, 0, 11, 9, 24, 47);
const date2 = new Date(2021, 0, 11, 12, 22, 45);
const expected = [
Expand Down Expand Up @@ -588,7 +649,6 @@ describe('getMany with aggregates', () => {
}
];


expect(rows).toEqual(expected);
}
}, 20000);
Expand Down

0 comments on commit 6c0cc43

Please sign in to comment.