-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Namespace aggregates #20
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very cool. Since namespace
is being baked into the base Aggregate classes, I'd rather not have separate classes, and just have a required argument to the base function if namespace
's type is not undefined
.
And then we can (optionally) have a .for
helper if you want to specify the namespace once and have an api that injects it, along with some fancy types so the argument is (1) required if you specified a namespace document fn but didn't pass one to the constructure, (2) not allowed if you didn't specify a namespace fn, or already specified the namespace via for
.
Are you game for that?
README.md
Outdated
[string, number], | ||
DataModel, | ||
"leaderboard", | ||
Id<"games"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should use an object type param here if it can also work. Knowing what each parameter means is hard. What do you think of something like:
NamespacedTableAggregate<{
sortKey: [string, number],
DataModel: DataModel, // maybe just `DataModel,` works?
tableName: "leaderboard",
namespace: Id<"games">
}>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also tried for a bit but couldn't get working: having this type inferred from the parameters somehow. e.g. the namespace and sortKey types should be inferable somehow, since their return values below dictate the types. But I couldn't get it working when I tried
README.md
Outdated
Now when you need to aggregate within a game, you call `.get` to narrow down the | ||
computation to a single game. | ||
|
||
```ts | ||
const countTimesGamePlayed = await aggregateByGame.get(gameId).count(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now when you need to aggregate within a game, you call `.get` to narrow down the | |
computation to a single game. | |
```ts | |
const countTimesGamePlayed = await aggregateByGame.get(gameId).count(); | |
Now when you need to aggregate within a game, you call `.for` to narrow down the | |
computation to a single game. | |
```ts | |
const countTimesGamePlayed = await aggregateByGame.for(gameId).count(); |
example/convex/photos.ts
Outdated
handler: async (ctx, { offset, numItems }) => { | ||
const { key: firstPhotoCreationTime } = await photos.at(ctx, offset); | ||
handler: async (ctx, { offset, numItems, album }) => { | ||
const { key: firstPhotoCreationTime } = await photos.get(album).at(ctx, offset); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const { key: firstPhotoCreationTime } = await photos.get(album).at(ctx, offset); | |
const { key: firstPhotoCreationTime } = await photos.for(album).at(ctx, offset); |
src/client/index.ts
Outdated
protected component: UsedAPI, | ||
) {} | ||
|
||
get(namespace: Namespace): Aggregate<K, ID, Namespace> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
get(namespace: Namespace): Aggregate<K, ID, Namespace> { | |
for(namespace: Namespace): Aggregate<K, ID, Namespace> { |
@@ -1,12 +1,12 @@ | |||
import { v } from "convex/values"; | |||
import { Id } from "./_generated/dataModel.js"; | |||
import { DatabaseReader, query } from "./_generated/server.js"; | |||
import { getTree, p } from "./btree.js"; | |||
import { getTree, Namespace, p } from "./btree.js"; | |||
|
|||
export const display = query({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wow I've missed the existence of this - would be nice to document how to view / debug your state in the readme. One common thing for me is trying to figure out why some documents ended up busted - and finding myself crawling through the dashboard data to try to look for the data ordering. another utility I've wanted is for table aggregate: "refresh this document with the current doc value / sort key" - and a backfill utility to just crawl a table and re-calculate every doc would be handy in dev. maybe just copying from your example is enough there though
Co-authored-by: Ian Macartney <[email protected]>
Co-authored-by: Ian Macartney <[email protected]>
Co-authored-by: Ian Macartney <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good. The type names should be TitleCase even as object keys (I believe). I started adding inline suggestions, but doing a find & replace in an editor will likely be faster
README.md
Outdated
namespace: Id<"games">, | ||
key: number, | ||
dataModel: DataModel, | ||
tableName: "scores", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
namespace: Id<"games">, | |
key: number, | |
dataModel: DataModel, | |
tableName: "scores", | |
Namespace: Id<"games">, | |
Key: number, | |
DataModel: DataModel, | |
TableName: "scores", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and I'm not sure if that allows you to do just DataModel,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does not allow that. While i'm find-replacing, i was wondering if Key should be called SortKey
README.md
Outdated
namespace: undefined, | ||
key: number, | ||
dataModel: DataModel, | ||
tableName: "mytable", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
namespace: undefined, | |
key: number, | |
dataModel: DataModel, | |
tableName: "mytable", | |
Namespace: undefined, | |
Key: number, | |
DataModel: DataModel, | |
TableName: "mytable", |
README.md
Outdated
namespace: Id<"games">, | ||
key: [string, number], | ||
dataModel: DataModel, | ||
tableName: "leaderboard" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
namespace: Id<"games">, | |
key: [string, number], | |
dataModel: DataModel, | |
tableName: "leaderboard" | |
Namespace: Id<"games">, | |
Key: [string, number], | |
DataModel: DataModel, | |
TableName: "leaderboard" |
README.md
Outdated
namespace: undefined, | ||
key: null, | ||
dataModel: DataModel, | ||
tableName: "mytable", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
namespace: undefined, | |
key: null, | |
dataModel: DataModel, | |
tableName: "mytable", | |
Namespace: undefined, | |
Key: null, | |
DataModel: DataModel, | |
TableName: "mytable", |
README.md
Outdated
namespace: string, // album name | ||
key: number, // creation time | ||
dataModel: DataModel, | ||
tableName: "photos", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
namespace: string, // album name | |
key: number, // creation time | |
dataModel: DataModel, | |
tableName: "photos", | |
Namespace: string, // album name | |
Key: number, // creation time | |
DataModel: DataModel, | |
TableName: "photos", |
src/client/index.ts
Outdated
|
||
/// Aggregate queries. | ||
|
||
/** | ||
* Counts items between the given bounds. | ||
*/ | ||
async count(ctx: RunQueryCtx, bounds?: Bounds<K, ID>): Promise<number> { | ||
async count(ctx: RunQueryCtx, ...opts: NamespacedOpts<{ bounds: Bounds<K, ID> }, Namespace>): Promise<number> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
async count(ctx: RunQueryCtx, ...opts: NamespacedOpts<{ bounds: Bounds<K, ID> }, Namespace>): Promise<number> { | |
async count(ctx: RunQueryCtx, ...opts: NamespacedOpts<{ Bounds: Bounds<K, ID> }, Namespace>): Promise<number> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this one should be TitleCase. That would mean you call it like aggregate.count(ctx, { Bounds: { prefix: [username] } })
src/client/index.ts
Outdated
key: K, | ||
dataModel: DataModel, | ||
tableName: TableName, | ||
namespace: Namespace, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
key: K, | |
dataModel: DataModel, | |
tableName: TableName, | |
namespace: Namespace, | |
Key: K, | |
DataModel: DataModel, | |
TableName: TableName, | |
Namespace: Namespace, |
src/client/index.ts
Outdated
@@ -657,3 +745,31 @@ export function btreeItemToAggregateItem<K extends Key, ID extends string>({ | |||
sumValue: s, | |||
}; | |||
} | |||
|
|||
export type NamespacedArgs<Args, Namespace> = | |||
Args & { namespace: Namespace } | (Namespace extends undefined ? Args : never); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so you can provide namespace: undefined if you didn't specify one? I wonder if this works if that's not intended:
Args & (Namespace extends undefined ? object : { namespace: Namespace });
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is intended. It's useful for methods like min
that call other methods and pass in the namespace.
src/client/index.ts
Outdated
export type NamespacedOpts<Opts, Namespace> = | ||
[{ namespace: Namespace } & Opts] | ( | ||
Namespace extends undefined | ||
? [] | [Opts] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be possible to do with [Opts?]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL that syntax
Co-authored-by: Ian Macartney <[email protected]>
Sounds good. And SortKey does sound better
…On Wed, Nov 6, 2024 at 9:33 AM Lee Danilek ***@***.***> wrote:
Merged #20 <#20> into main.
—
Reply to this email directly, view it on GitHub
<#20 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AACZQW3VMX5YJW3D5EMC7STZ7JHINAVCNFSM6AAAAABREZ7VZ2VHI2DSMVQWIX3LMV45UABCJFZXG5LFIV3GK3TUJZXXI2LGNFRWC5DJN5XDWMJVGE2TKMRXHE4TONY>
.
You are receiving this because your review was requested.Message ID:
***@***.***>
|
Add namespacing to aggregates.
All of the data and even the APIs should be backwards-compatible.
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.