Skip to content

Commit

Permalink
Working version
Browse files Browse the repository at this point in the history
  • Loading branch information
nihalbhatnagar committed Dec 9, 2024
1 parent d2d0a0d commit efbed3d
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 29 deletions.
19 changes: 15 additions & 4 deletions etc/api.report.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,17 @@ export interface DataValueWireToClient {
}[];
}

// @public (undocumented)
export type DeriveClause<Q extends ObjectOrInterfaceDefinition> = {
[key: string]: (baseObjectSet: BaseDeriveObjectSet<Q>) => DerivedPropertyDefinition<ObjectMetadata.Property>;
};

// @public (undocumented)
export type DerivedPropertyDefinition<T extends ObjectMetadata.Property> = {
definitionId: unknown;
type: T;
};

// Warning: (ae-forgotten-export) The symbol "AggregatableDeriveObjectSet" needs to be exported by the entry point index.d.ts
//
// @public (undocumented)
Expand Down Expand Up @@ -606,7 +617,6 @@ export interface ObjectSet<Q extends ObjectOrInterfaceDefinition = any, _UNUSED
};
readonly subtract: (...objectSets: ReadonlyArray<CompileTimeMetadata<Q>["objectSet"]>) => this;
readonly union: (...objectSets: ReadonlyArray<CompileTimeMetadata<Q>["objectSet"]>) => this;
// Warning: (ae-forgotten-export) The symbol "DeriveClause" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "DerivedPropertyExtendedObjectDefinition" needs to be exported by the entry point index.d.ts
//
// (undocumented)
Expand Down Expand Up @@ -963,12 +973,13 @@ export type TimeSeriesQuery = {
// @public (undocumented)
export type TwoDimensionalQueryAggregationDefinition = AggregationKeyDataType<"date" | "double" | "timestamp">;

// Warning: (ae-forgotten-export) The symbol "AGG_FOR_TYPE" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "StringAggregateOption" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "NumericAggregateOption" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "PropertyValueClientToWire" needs to be exported by the entry point index.d.ts
//
// @public (undocumented)
export type ValidAggregationKeys<Q extends ObjectOrInterfaceDefinition> = keyof ({
[KK in AggregatableKeys<Q> as `${KK & string}:${AGG_FOR_TYPE<PropertyValueClientToWire[CompileTimeMetadata<Q>["properties"][KK]["type"]]>}`]?: any;
export type ValidAggregationKeys<Q extends ObjectOrInterfaceDefinition, StringOptions extends string = StringAggregateOption, NumericOptions extends string = NumericAggregateOption> = keyof ({
[KK in AggregatableKeys<Q> as `${KK & string}:${number extends PropertyValueClientToWire[CompileTimeMetadata<Q>["properties"][KK]["type"]] ? NumericOptions : string extends PropertyValueClientToWire[CompileTimeMetadata<Q>["properties"][KK]["type"]] ? StringOptions : never}`]?: any;
} & {
$count?: any;
});
Expand Down
3 changes: 1 addition & 2 deletions packages/api/src/derivedProperties/DeriveClause.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,8 @@ export type DerivedPropertyDefinition<

export type DeriveClause<
Q extends ObjectOrInterfaceDefinition,
P extends ObjectMetadata.Property,
> = {
[key: string]: (
baseObjectSet: BaseDeriveObjectSet<Q>,
) => DerivedPropertyDefinition<P>;
) => DerivedPropertyDefinition<ObjectMetadata.Property>;
};
24 changes: 21 additions & 3 deletions packages/api/src/derivedProperties/DeriveObjectSet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ interface FilterableDeriveObjectSet<
export type StringDeriveAggregateOption =
| "approximateDistinct"
| "exactDistinct"
| "approximatePercentile"
| "collectToSet"
| "collectToList";
export type NumericDeriveAggregateOption =
Expand All @@ -65,7 +66,8 @@ export type NumericDeriveAggregateOption =
| "collectToSet"
| "collectToList"
| "approximateDistinct"
| "exactDistinct";
| "exactDistinct"
| "approximatePercentile";

interface AggregatableDeriveObjectSet<
Q extends ObjectOrInterfaceDefinition,
Expand All @@ -78,8 +80,24 @@ interface AggregatableDeriveObjectSet<
>,
>(
aggregationSpecifier: V,
opts?: { limit: number },
) => DerivedPropertyDefinition<PropertyDef<"integer">>;
opts?: V extends `${any}:${infer P}`
? P extends "collectToSet" | "collectToList" ? { limit: number }
: P extends "approximatePercentile" ? { percentile: number }
: never
: never,
) => DerivedPropertyDefinition<
V extends `${infer N}:${infer P}` ? P extends
| "collectToList"
| "collectToSet" ? PropertyDef<
CompileTimeMetadata<Q>["properties"][N]["type"],
"nullable",
"array"
>
: P extends "approximateDistinct" | "exactDistinct" | "$count"
? PropertyDef<"integer">
: PropertyDef<"double">
: never
>;
}

interface SingleLinkDeriveObjectSet<
Expand Down
14 changes: 9 additions & 5 deletions packages/api/src/objectSet/ObjectSet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ import type { AggregateOpts } from "../aggregate/AggregateOpts.js";
import type { AggregateOptsThatErrorsAndDisallowsOrderingWithMultipleGroupBy } from "../aggregate/AggregateOptsThatErrors.js";
import type { AggregationsResults } from "../aggregate/AggregationsResults.js";
import type { WhereClause } from "../aggregate/WhereClause.js";
import type { DeriveClause } from "../derivedProperties/DeriveClause.js";
import type {
DeriveClause,
DerivedPropertyDefinition,
} from "../derivedProperties/DeriveClause.js";
import type {
AsyncIterArgs,
Augments,
Expand Down Expand Up @@ -259,8 +262,7 @@ export interface ObjectSet<
) => { unsubscribe: () => void };

readonly withProperties: <
D extends DeriveClause<Q, any>,
P extends ObjectMetadata.Property,
D extends DeriveClause<Q>,
>(
clause: D,
) => ObjectSet<
Expand All @@ -273,11 +275,13 @@ export interface ObjectSet<

type DerivedPropertyExtendedObjectDefinition<
K extends ObjectOrInterfaceDefinition,
D extends DeriveClause<K, any>,
D extends DeriveClause<K>,
> = {
__DefinitionMetadata: {
properties: {
[T in Extract<keyof D, string>]: ReturnType<D[T]>;
[T in Extract<keyof D, string>]: D[T] extends
(baseObjectSet: any) => DerivedPropertyDefinition<infer P> ? P
: never;
};
};
} & K;
20 changes: 19 additions & 1 deletion packages/client/src/derivedProperties/createDerivedObjectSet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export function createDeriveObjectSet<Q extends ObjectOrInterfaceDefinition>(
where: modernToLegacyWhereClause(clause, objectType),
}, definitionMap);
},
aggregate: (aggregation: string, opt) => {
aggregate: (aggregation: string, opt: any) => {
const definitionId = globalThis.crypto.randomUUID();
const splitAggregation = aggregation.split(":");
invariant(splitAggregation.length === 2, "Invalid aggregation format");
Expand All @@ -78,6 +78,24 @@ export function createDeriveObjectSet<Q extends ObjectOrInterfaceDefinition>(
selectedPropertyApiName: aggregationPropertyName,
};
break;
case "approximatePercentile":
aggregationOperationDefinition = {
type: "approximatePercentile",
selectedPropertyApiName: aggregationPropertyName,
approximatePercentile: opt?.percentile ?? .5,
};
break;
case "collectToSet":
case "collectToList":
const collectionType = aggregationOperation === "collectToSet"
? "collectSet"
: "collectList";
aggregationOperationDefinition = {
type: collectionType,
selectedPropertyApiName: aggregationPropertyName,
limit: opt?.limit ?? 100,
};
break;
default:
invariant(
false,
Expand Down
116 changes: 102 additions & 14 deletions packages/client/src/objectSet/ObjectSet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -440,14 +440,15 @@ describe("ObjectSet", () => {
describe("Derived Properties Object Set", () => {
it("does not allow aggregate or selectProperty before a link type is selected", () => {
client(Employee).withProperties({
// @ts-expect-error
"derivedPropertyName": (base) => base.aggregate("derivedObjectSet"),
"derivedPropertyName": (base) =>
// @ts-expect-error
base.aggregate("employeeId:exactDistinct"),
});

client(Employee).withProperties({
"derivedPropertyName": (base) =>
// @ts-expect-error
base.selectProperty("derivedObjectSet"),
base.selectProperty("employeeId"),
});
});

Expand All @@ -465,7 +466,8 @@ describe("ObjectSet", () => {
});
});

it("correctly narrows types of aggregate function", () => {
// Executed code fails since we're providing bad strings to the function
it.fails("correctly narrows types of aggregate function", () => {
client(Employee).withProperties({
"derivedPropertyName": (base) => {
// @ts-expect-error
Expand All @@ -483,7 +485,7 @@ describe("ObjectSet", () => {
});

it("correctly narrows types of selectProperty function", () => {
const objectSet = client(Employee).withProperties({
client(Employee).withProperties({
"derivedPropertyName": (base) => {
// @ts-expect-error
base.pivotTo("lead").selectProperty("notAProperty");
Expand All @@ -497,25 +499,44 @@ describe("ObjectSet", () => {
client(Employee).withProperties({
"derivedPropertyName": (base) =>
base.pivotTo("lead").aggregate("employeeId:sum"),
// SHOULD REMOVE, TYPE SHOULD BE ACCURATE
// @ts-expect-error
}).where({ "derivedPropertyName": { "$eq": 3 } });

client(Employee).withProperties({
"derivedPropertyName": (base) =>
base.pivotTo("lead").aggregate("employeeId:collectToList"),
}).where({ "derivedPropertyName": { "$isNull": false } })
// @ts-expect-error
.where({ "derivedPropertyName": { "$eq": [1, 2] } });

client(Employee).withProperties({
"derivedPropertyName": (base) =>
base.pivotTo("lead").aggregate("employeeId:collectToSet"),
// SHOULD REMOVE, TYPE SHOULD BE ACCURATE
}).where({ "derivedPropertyName": { "$isNull": false } })
// @ts-expect-error
}).where({ "derivedPropertyName": { "$eq": [1, 2, 3] } });
.where({ "derivedPropertyName": { "$eq": [1, 2] } });

client(Employee).withProperties({
"derivedPropertyName": (base) =>
base.pivotTo("lead").selectProperty("employeeId"),
// SHOULD REMOVE, TYPE SHOULD BE ACCURATE
// @ts-expect-error
}).where({ "derivedPropertyName": { "$eq": 3 } });

// Other properties are consistently types
client(Employee).withProperties({
"derivedPropertyName": (base) =>
base.pivotTo("lead").selectProperty("startDate"),
}).where({ "derivedPropertyName": { "$eq": "datetimeFilter" } });
});

it("correctly types multiple property definitions in one clause", () => {
client(Employee).withProperties({
"derivedPropertyName": (base) =>
base.pivotTo("lead").aggregate("employeeId:sum"),
"derivedPropertyName2": (base) =>
base.pivotTo("lead").selectProperty("fullName"),
}).where({ "derivedPropertyName": { "$eq": 3 } })
.where({ "derivedPropertyName2": { "$eq": "name" } });
});

it("ensures other properties are consistently typed", () => {
client(Employee).withProperties({
"derivedPropertyName": (base) =>
base.pivotTo("lead").selectProperty("employeeId"),
Expand All @@ -528,7 +549,11 @@ describe("ObjectSet", () => {
});

it("allows fetching derived properties with correctly typed Osdk.Instance types", async () => {
const objectSet = client(Employee).fetchOne(50030);
const objectWithRdp = await client(Employee).withProperties({
"derivedPropertyName": (base) =>
base.pivotTo("lead").selectProperty("employeeId"),
}).fetchOne(50035);
expect(objectWithRdp.derivedPropertyName).toBe(1);
});

describe("withPropertiesObjectSet", () => {
Expand All @@ -538,7 +563,7 @@ describe("ObjectSet", () => {
type: "methodInput",
}, map);

const clause: DeriveClause<Employee, ObjectMetadata.Property> = {
const clause: DeriveClause<Employee> = {
"derivedPropertyName": (base) =>
base.pivotTo("lead").selectProperty("employeeId"),
};
Expand All @@ -562,6 +587,69 @@ describe("ObjectSet", () => {
}
`);
});

it("correctly handles multiple definitions in one clause", () => {
const map = new Map<string, DerivedPropertyDefinition>();
const deriveObjectSet = createDeriveObjectSet(Employee, {
type: "methodInput",
}, map);

const clause: DeriveClause<Employee> = {
"derivedPropertyName": (base) =>
base.pivotTo("lead").aggregate("startDate:approximatePercentile", {
percentile: 0.5,
}),

"secondaryDerivedPropertyName": (base) =>
base.pivotTo("lead").aggregate("fullName:collectToSet", {
limit: 10,
}),
};

const result = clause["derivedPropertyName"](deriveObjectSet);
const definition = map.get(result.definitionId as string);

const secondResult = clause["secondaryDerivedPropertyName"](
deriveObjectSet,
);
const secondDefinition = map.get(secondResult.definitionId as string);

expect(definition).toMatchInlineSnapshot(`
{
"objectSet": {
"link": "lead",
"objectSet": {
"type": "methodInput",
},
"type": "searchAround",
},
"operation": {
"approximatePercentile": 0.5,
"selectedPropertyApiName": "startDate",
"type": "approximatePercentile",
},
"type": "selection",
}
`);

expect(secondDefinition).toMatchInlineSnapshot(`
{
"objectSet": {
"link": "lead",
"objectSet": {
"type": "methodInput",
},
"type": "searchAround",
},
"operation": {
"limit": 10,
"selectedPropertyApiName": "fullName",
"type": "collectSet",
},
"type": "selection",
}
`);
});
});
});

Expand Down
Loading

0 comments on commit efbed3d

Please sign in to comment.