Open KnorpelSenf opened 2 years ago
It seems unfamiliar to use dots, Why do you use them instead of objects? Something like Prisma way:
const count = await ctx.history
.messages.select({
where: {
id: ctx.chat.id,
from: { id: ctx.from.id }
}
}).count();
I find dots a bit easier to read and a bit easier to write. They translate into English prose, which is nice. It's familiar from chai.js
to check object structures.
But to be honest, I don't have too strong opinions about it—if people agree that objects are better than dots, feel free to change it.
How would disjunctions look (queries with OR)?
Inspired by Prisma, it could be like this:
const count = await ctx.history .messages.select({
where: {
and: {
or: [
{ from: { username: "someusername" } },
{ from: { id: 1234 } },
],
id: ctx.chat.id,
}
}
}).count();
But I find working with nested objects is hard a little bit
Maybe making something in the middle will be easier like this:
const count = ctx.history.select
.where({ chat: { id: ctx.chat.id } })
.or([
{ from: { id: 1234 } },
{ from: { username: "someusername" } }
])
.count();
Maybe making something in the middle will be easier like this:
const count = ctx.history.select .where({ chat: { id: ctx.chat.id } }) .or([ { from: { id: 1234 } }, { from: { username: "someusername" } } ]) .count();
Do you find this better because you are familiar with Prisma, or because it is more readable than this?
const count = ctx.history.select.messages
.where.chat.id.is(ctx.chat.id)
.and.where.from.id.is(1234).or.username.is("someusername")
.count()
Maybe making something in the middle will be easier like this:
const count = ctx.history.select .where({ chat: { id: ctx.chat.id } }) .or([ { from: { id: 1234 } }, { from: { username: "someusername" } } ]) .count();
Do you find this better because you are familiar with Prisma, or because it is more readable than this?
const count = ctx.history.select.messages .where.chat.id.is(ctx.chat.id) .and.where.from.id.is(1234).or.username.is("someusername") .count()
I find this easier to read and write but and/or queries confused me
and/or queries confused me
Can you elaborate?
and/or queries confused me
Can you elaborate?
const count = ctx.history.select.messages
.where.chat.id.is(ctx.chat.id)
.and.where.from.id.is(1234).or.username.is("someusername")
.count()
How can I make sure it is:
chat.id === ctx.chat.id && (from.id === 1234 || from.username === "someusername")
Not this:
(chat.id === ctx.chat.id && from.id === 1234) || from.username === "someusername"
And what about if I want the second one?
Ah so it's about operator precedence, I see.
Using .
will go one level deeper and basically create brackets. Basically, messages.where.chat.id.is(3).and.title.is("Friends")
translates to this:
messages
where
-> chat
-> id is 3
-> AND title is "Friends"
You can go back to the top and add more clauses by using where
again: The query messages.where.chat.id.is(3).and.title.is("Friends").and.where.text.exists
translates to this:
messages
-> where
-> chat
-> id is 3
-> AND title is "Friends"
-> AND where
-> text exists
Naturally, this will have the following precedence: (chat.id == 3 && chat.title == "Friends") && !!text
.
Thus, you can do messages.where.chat.id.is(ctx.chat.id).and.where.from.id.is(1234).or.username.is("someusername")
which translates to
messages
-> where
-> chat
-> id is ctx.chat.id
-> AND where
-> from
-> id is 1234
-> OR username is "someusername"
and therefore gives you the desired
chat.id === ctx.chat.id && (from.id === 1234 || from.username === "someusername")
In addition, if things stay on the same level, this will be done with &&
before ||
like in JS. In other words, doing a.and.b.or.c
will be interpreted as a && b || c
and hence turn into (a && b) || c
because &&
binds stronger than ||
.
In contrast, if you wanted to test for
(chat.id === ctx.chat.id && from.id === 1234) || from.username === "someusername"
you would have to combine the chat
and the from
into one, and then add a second check for from
. Hence, you can use messages.where.chat.id.is(ctx.chat.id).and.where.from.id.is(1234).or.where.from.username.is("someusername")
because it translates to
messages
-> where
-> chat
-> id is ctx.chat.id
-> AND where
-> from
-> id is 1234
-> OR where
-> from
-> username is "someusername"
which gives you the desired
(chat.id === ctx.chat.id && from.id === 1234) || from.username === "someusername"
Does this make more sense now?
Now it is clear :)
I definitely prefer {"chat.id": 123}
over chat.id.is(123)
. The first one is way easier to read for me because in the second one values and operators are mixed together.
const count = ctx.history.select.messages
.where({"chat.id": ctx.chat.id})
.and.where({"from.id": 1234}).or({username: "someusername"})
.count()
The problem is that this way we can't use custom operators like < or >.
Mongo works around this with {$lt: 123}
and I don't like this approach.
kysely uses arrays and strings like this ['id', '<', 123]
and I like it.
Maybe we can use arrays too?
const count = ctx.history.select.messages
.where([
["chat.id", "=", ctx.chat.id],
[
["from.id", "=", 1234],
"or",
["username", "=", "someusername"],
],
])
.count()
I find that syntax okay, too. I don't really feel like implementing it because this will take a huge effort, but I'm sure it's possible.
Do you always have to wrap stuff in double arrays, or can we just use where(["text", "exists"])
?
This is a list of pending tasks that need to be addressed in order to bring this plugin from the current state to stable.
messages.from.id(3)
and so on) to the defined query language{ update: Update } | { call: { method: string, payload: any, result: any } }
so that we can query things)Naturally, we will also need JSDocs, a page on https://grammy.dev, and the usual yada yada with feedback loops from the community and iterative improvements until all edge cases are ruled out.
CONTRIBUTIONS ARE WELCOME!