Skip to content

Commit

Permalink
Merge pull request #24 from get-convex/ian/optional-namespace
Browse files Browse the repository at this point in the history
optional namespace
  • Loading branch information
ianmacartney authored Dec 2, 2024
2 parents b2fbc05 + 4b38aa5 commit e956059
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 50 deletions.
5 changes: 0 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,12 +214,10 @@ import { mutation as rawMutation } from "./_generated/server";
import { TableAggregate } from "@convex-dev/aggregate";

const aggregate = new TableAggregate<{
Namespace: undefined;
Key: number;
DataModel: DataModel;
TableName: "mytable";
}>(components.aggregate, {
namespace: (doc) => undefined, // disable namespacing.
sortKey: (doc) => doc._creationTime, // Allows querying across time ranges.
sumValue: (doc) => doc.value, // The value to be used in `.sum` calculations.
});
Expand Down Expand Up @@ -308,12 +306,10 @@ If you don't need the ordering, partitioning, or summing behavior of

```ts
const randomize = new TableAggregate<{
Namespace: undefined;
Key: null;
DataModel: DataModel;
TableName: "mytable";
}>(components.aggregate, {
namespace: (doc) => undefined,
sortKey: (doc) => null,
});
```
Expand Down Expand Up @@ -397,7 +393,6 @@ import { DirectAggregate } from "@convex-dev/aggregate";
// Note the `id` should be unique to be a tie-breaker in case two data points
// have the same key.
const aggregate = new DirectAggregate<{
Namespace: undefined;
Key: number;
Id: string;
}>(components.aggregate);
Expand Down
4 changes: 0 additions & 4 deletions example/convex/leaderboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,17 @@ export const migrations = new Migrations<DataModel>(components.migrations);
export const run = migrations.runner();

const aggregateByScore = new TableAggregate<{
Namespace: undefined;
Key: number;
DataModel: DataModel;
TableName: "leaderboard";
}>(components.aggregateByScore, {
namespace: (_doc) => undefined,
sortKey: (doc) => doc.score,
});
const aggregateScoreByUser = new TableAggregate<{
Key: [string, number];
DataModel: DataModel;
TableName: "leaderboard";
Namespace: undefined;
}>(components.aggregateScoreByUser, {
namespace: (_doc) => undefined,
sortKey: (doc) => [doc.name, doc.score],
sumValue: (doc) => doc.score,
});
Expand Down
2 changes: 0 additions & 2 deletions example/convex/shuffle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,8 @@ import Rand from "rand-seed";
const randomize = new TableAggregate<{
DataModel: DataModel;
TableName: "music";
Namespace: undefined;
Key: null;
}>(components.music, {
namespace: () => undefined,
sortKey: () => null,
});

Expand Down
1 change: 0 additions & 1 deletion example/convex/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { DirectAggregate } from "@convex-dev/aggregate";
import { components } from "./_generated/api";

const stats = new DirectAggregate<{
Namespace: undefined;
Key: number;
Id: string;
}>(components.stats);
Expand Down
24 changes: 12 additions & 12 deletions example/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

78 changes: 52 additions & 26 deletions src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -491,17 +491,19 @@ export class Aggregate<
export type DirectAggregateType<
K extends Key,
ID extends string,
Namespace extends ConvexValue | undefined,
Namespace extends ConvexValue | undefined = undefined,
> = {
Key: K;
Id: ID;
Namespace: Namespace;
Namespace?: Namespace;
};
type AnyDirectAggregateType = DirectAggregateType<
Key,
string,
ConvexValue | undefined
>;
type DirectAggregateNamespace<T extends AnyDirectAggregateType> =
"Namespace" extends keyof T ? T["Namespace"] : undefined;

/**
* A DirectAggregate is an Aggregate where you can insert, delete, and replace
Expand All @@ -512,7 +514,7 @@ type AnyDirectAggregateType = DirectAggregateType<
*/
export class DirectAggregate<
T extends AnyDirectAggregateType,
> extends Aggregate<T["Key"], T["Id"], T["Namespace"]> {
> extends Aggregate<T["Key"], T["Id"], DirectAggregateNamespace<T>> {
/**
* Insert a new key into the data structure.
* The id should be unique.
Expand All @@ -525,7 +527,7 @@ export class DirectAggregate<
ctx: RunMutationCtx,
args: NamespacedArgs<
{ key: T["Key"]; id: T["Id"]; sumValue?: number },
T["Namespace"]
DirectAggregateNamespace<T>
>
): Promise<void> {
await this._insert(
Expand All @@ -542,7 +544,10 @@ export class DirectAggregate<
*/
async delete(
ctx: RunMutationCtx,
args: NamespacedArgs<{ key: T["Key"]; id: T["Id"] }, T["Namespace"]>
args: NamespacedArgs<
{ key: T["Key"]; id: T["Id"] },
DirectAggregateNamespace<T>
>
): Promise<void> {
await this._delete(ctx, namespaceFromArg(args), args.key, args.id);
}
Expand All @@ -553,10 +558,13 @@ export class DirectAggregate<
*/
async replace(
ctx: RunMutationCtx,
currentItem: NamespacedArgs<{ key: T["Key"]; id: T["Id"] }, T["Namespace"]>,
currentItem: NamespacedArgs<
{ key: T["Key"]; id: T["Id"] },
DirectAggregateNamespace<T>
>,
newItem: NamespacedArgs<
{ key: T["Key"]; sumValue?: number },
T["Namespace"]
DirectAggregateNamespace<T>
>
): Promise<void> {
await this._replace(
Expand All @@ -581,7 +589,7 @@ export class DirectAggregate<
ctx: RunMutationCtx,
args: NamespacedArgs<
{ key: T["Key"]; id: T["Id"]; sumValue?: number },
T["Namespace"]
DirectAggregateNamespace<T>
>
): Promise<void> {
await this._insertIfDoesNotExist(
Expand All @@ -594,16 +602,22 @@ export class DirectAggregate<
}
async deleteIfExists(
ctx: RunMutationCtx,
args: NamespacedArgs<{ key: T["Key"]; id: T["Id"] }, T["Namespace"]>
args: NamespacedArgs<
{ key: T["Key"]; id: T["Id"] },
DirectAggregateNamespace<T>
>
): Promise<void> {
await this._deleteIfExists(ctx, namespaceFromArg(args), args.key, args.id);
}
async replaceOrInsert(
ctx: RunMutationCtx,
currentItem: NamespacedArgs<{ key: T["Key"]; id: T["Id"] }, T["Namespace"]>,
currentItem: NamespacedArgs<
{ key: T["Key"]; id: T["Id"] },
DirectAggregateNamespace<T>
>,
newItem: NamespacedArgs<
{ key: T["Key"]; sumValue?: number },
T["Namespace"]
DirectAggregateNamespace<T>
>
): Promise<void> {
await this._replaceOrInsert(
Expand All @@ -622,19 +636,22 @@ export type TableAggregateType<
K extends Key,
DataModel extends GenericDataModel,
TableName extends TableNamesInDataModel<DataModel>,
Namespace extends ConvexValue | undefined,
Namespace extends ConvexValue | undefined = undefined,
> = {
Key: K;
DataModel: DataModel;
TableName: TableName;
Namespace: Namespace;
Namespace?: Namespace;
};

type AnyTableAggregateType = TableAggregateType<
Key,
GenericDataModel,
TableNamesInDataModel<GenericDataModel>,
ConvexValue | undefined
>;
type TableAggregateNamespace<T extends AnyTableAggregateType> =
"Namespace" extends keyof T ? T["Namespace"] : undefined;
type TableAggregateDocument<T extends AnyTableAggregateType> = DocumentByName<
T["DataModel"],
T["TableName"]
Expand All @@ -651,15 +668,24 @@ type TableAggregateTrigger<Ctx, T extends AnyTableAggregateType> = Trigger<
export class TableAggregate<T extends AnyTableAggregateType> extends Aggregate<
T["Key"],
GenericId<T["TableName"]>,
T["Namespace"]
TableAggregateNamespace<T>
> {
constructor(
component: UsedAPI,
private options: {
namespace: (d: TableAggregateDocument<T>) => T["Namespace"];
sortKey: (d: TableAggregateDocument<T>) => T["Key"];
sumValue?: (d: TableAggregateDocument<T>) => number;
}
} & (undefined extends TableAggregateNamespace<T>
? {
namespace?: (
d: TableAggregateDocument<T>
) => TableAggregateNamespace<T>;
}
: {
namespace: (
d: TableAggregateDocument<T>
) => TableAggregateNamespace<T>;
})
) {
super(component);
}
Expand All @@ -670,7 +696,7 @@ export class TableAggregate<T extends AnyTableAggregateType> extends Aggregate<
): Promise<void> {
await this._insert(
ctx,
this.options.namespace(doc),
this.options.namespace?.(doc),
this.options.sortKey(doc),
doc._id as TableAggregateId<T>,
this.options.sumValue?.(doc)
Expand All @@ -682,7 +708,7 @@ export class TableAggregate<T extends AnyTableAggregateType> extends Aggregate<
): Promise<void> {
await this._delete(
ctx,
this.options.namespace(doc),
this.options.namespace?.(doc),
this.options.sortKey(doc),
doc._id as TableAggregateId<T>
);
Expand All @@ -694,9 +720,9 @@ export class TableAggregate<T extends AnyTableAggregateType> extends Aggregate<
): Promise<void> {
await this._replace(
ctx,
this.options.namespace(oldDoc),
this.options.namespace?.(oldDoc),
this.options.sortKey(oldDoc),
this.options.namespace(newDoc),
this.options.namespace?.(newDoc),
this.options.sortKey(newDoc),
newDoc._id as TableAggregateId<T>,
this.options.sumValue?.(newDoc)
Expand All @@ -708,7 +734,7 @@ export class TableAggregate<T extends AnyTableAggregateType> extends Aggregate<
): Promise<void> {
await this._insertIfDoesNotExist(
ctx,
this.options.namespace(doc),
this.options.namespace?.(doc),
this.options.sortKey(doc),
doc._id as TableAggregateId<T>,
this.options.sumValue?.(doc)
Expand All @@ -720,7 +746,7 @@ export class TableAggregate<T extends AnyTableAggregateType> extends Aggregate<
): Promise<void> {
await this._deleteIfExists(
ctx,
this.options.namespace(doc),
this.options.namespace?.(doc),
this.options.sortKey(doc),
doc._id as TableAggregateId<T>
);
Expand All @@ -732,9 +758,9 @@ export class TableAggregate<T extends AnyTableAggregateType> extends Aggregate<
): Promise<void> {
await this._replaceOrInsert(
ctx,
this.options.namespace(oldDoc),
this.options.namespace?.(oldDoc),
this.options.sortKey(oldDoc),
this.options.namespace(newDoc),
this.options.namespace?.(newDoc),
this.options.sortKey(newDoc),
newDoc._id as TableAggregateId<T>,
this.options.sumValue?.(newDoc)
Expand All @@ -759,7 +785,7 @@ export class TableAggregate<T extends AnyTableAggregateType> extends Aggregate<
): Promise<number> {
const key = this.options.sortKey(doc);
return this.indexOf(ctx, key, {
namespace: this.options.namespace(doc),
namespace: this.options.namespace?.(doc),
...opts,
});
}
Expand Down Expand Up @@ -841,7 +867,7 @@ export type NamespacedArgs<Args, Namespace> =
| (Namespace extends undefined ? Args : never);
export type NamespacedOpts<Opts, Namespace> =
| [{ namespace: Namespace } & Opts]
| (Namespace extends undefined ? [Opts?] : never);
| (undefined extends Namespace ? [Opts?] : never);

function namespaceFromArg<Args extends object, Namespace>(
args: NamespacedArgs<Args, Namespace>
Expand Down

0 comments on commit e956059

Please sign in to comment.