Is it possible to add and query server-generated read-only timestamps like “createdAt” and “updatedAt” in a graph graphql schema? If so, how? I looked through all the docs but could not see any mention of this.
Thanks!
Is it possible to add and query server-generated read-only timestamps like “createdAt” and “updatedAt” in a graph graphql schema? If so, how? I looked through all the docs but could not see any mention of this.
Thanks!
Looks like you want to auto fill values for DateTime fields in a GraphQL type. For example:
type User {
id: ID!
name: String
createdAt: DateTime @default(expr: $now)
}
Then when you want to add a User, the createdAt field should get automatically filled by the server with the current time on server.
We don’t have this kind of functionality at the moment. But, we are planning to add it later in the future. Not sure when we will be able to release it.
Thanks for the info! I’lll admit I am a bit surprised you don’t already have a mechanism for server generated timestamps and they are quite critical for many applications. With that said, I look forward to seeing them implemented. You may also want to look at adding directives like used here: graphql-genie/sdl.md at master · genie-team/graphql-genie · GitHub (search down for createdTimestamp and @updatedTimestamp), as I’m not sure from your example how updatedAt could be handled with $now.
Thanks for reporting this. It looks like an interesting and necessary feature. We have added this to our roadmap.
Is it safe to assume that the way to do this in the mean time is with custom mutations?
https://graphql.dgraph.io/custom/mutation
Dgraph generates an
addPost
mutation from those types, but we want to do something extra. We don’t want theauthor
to come in with the mutation, that should get filled in from the JWT of the logged in user. Also, thedatePublished
shouldn’t be in the input; it should be set as the current time at point of mutation. Maybe we also have some community guidelines about what might constitute an offensivetitle
ortext
in a post. Maybe users can only post if they have enough community credit.We’ll need custom code to do all that, so we can write a custom function that takes in only the title and text of the new post. Internally, it can check that the title and text satisfy the guidelines and that this user has enough credit to make a post. If those checks pass, it then builds a full post object by adding the current time as the
datePublished
and adding theauthor
from the JWT information it gets from the forward header. It can then call theaddPost
mutation constructed by Dgraph to add the post into Dgraph and returns the resulting post as its GraphQL output.
Thanks! Looking forward to seeing server generated timestamps implemented.
Yeah! you could surely do it that way for now.
Any update on this? I think that this functionality is super-important.
@abhimanyusinghgaur How do you guys keep track of feature requests? Is there some overview about their status?
@amaster507 Could you give an example how to do this with custom mutations? I
@maaft, 20.11 should be out as I have been informed next month. When this arrives, I believe the lambda directive will best handle this use case. This was exemplified on the October community call which you can view: https://youtu.be/XryDxyb0fT4?t=3073 ← that link starts at the lambda part.
In that video they show an example on how to implement the @lambda directive with Slash-Graphql.
Can you ELI5 if (and potenitally how) I can use this with the “normal” dgraph-executables? (alpha and zero)
Edit: I’m seeing a --graphql_lambda_url flag for dgraph alpha I guess I will start from there.
Yeah! You can have a look at this docker-compose file. You will find how to set-up a lambda service running along with Alpha and Zero. Notice how the --graphql_lambda_url
flag is passed to the Alpha.
These files will also be useful:
newAuthor
function inside this script)The documentation for lambda is not yet there, but it would surely be out by 20.11 release.
Thank you very much @abhimanyusinghgaur!
Feature requests from Discuss are discussed on a weekly basis, and added to our internal backlog. A public status overview may not be available. But, till now we have posted our roadmap on an annual basis. And, going forward we have been considering all the feedback from the community to make our roadmap more visible.
About this particular one, It didn’t make it to 20.11 release, instead we added @lambda
as that covers a broad range of cases. I will confirm and let you know whether we still plan to work on this particular request, as @lambda
is there.
We will be working on it for the 21.03
release.
Okay, thank you.
Is there a rough ETA for 21.03 ?
Just trying to figure out if it makes sense to start building our stack with @lambda now on the latest
-release or if we should roll without @lambda for the moment.
EDIT:
I guess the only documentation for @lambda is the code itself for now?
Edit2:
Am I correct that for implementing createdAt
and updatedAt
timestamps I would have to mirror every add-
and update-
mutation to Javascript? That’s honestly very super complicated and you would have to track and maintain two files instead of just the gql-schema. I hope there will be @createdAt and @updatedAt directives instead! If I’m wrong though, I’m happy to hear otherwise.
21.03 = 2021 March
Major releases are named as yy.mm
for the year and month when they will be available.
Yeah! At present, there is no documentation, you can follow the sample setup I had shared yesterday.
Along with that, you can also have a look at the integration tests for @lambda
. The documentation for the feature is in progress, and should be out in a couple of weeks.
Yeah! with @lambda
you will have to do that. That would be complex and also less performant. We will notify you as soon as we are done implementing the new features.
Alright, thank you very much for your answers! We will not use @lambda
then and wait for @createdAt
and @updatedAt
directives instead. In the meantime, clients will just have to deliver these timestamps on their own (which of course could be a security issue).
Hi! Is there any progress on this?
No progress yet, But it is one of the features we are aiming for 21.03 release.
Thanks
Here is my updated thoughts on the matter. Can we make it mongoDB like. Mongoose v8.0.3: Schemas
With a directive @timestamps( createdAt: Boolean, updatedAt: Boolean )
It could be used the following way:
type Post @timestamps { # defaults both createdAt and updatedAt to true
id: ID
title: String!
}
The predicate _createdAt
and _updatedAt
should be added to the list of reserved names.
If a user needed to manually set or update the _createdAt
or _updatedAt
I believe it should be allowed through DQL only. Meaning that GraphQL does not allow any input for these values other than searching.
Cons: There is no way to timestamp edges without either using facets or a linking type. Facets are further out than 21.03 I believe and even then are not first rate citizens. Like many other implementations of timestamps, it does not indicate which predicates/edges were updated, just that there was something updated. With other databases using joining tables it is possible to update timestamps in a join table without updating timestamps on the tables that were joined.
Pros: All timestamps are handled 100% by the rewriting methods in Go. These timestamps are directly immutable by a user within GraphQL. This ensures that the _createdAt
is true and was not updated by a later GraphQL mutation. Auto updating timestamps on nodes when edges are mutated, gives a sync script the ability to refresh the data for that entire node and their referenced edges.
Implementation:
@timestamp
directive, it gets the _createdAt
predicate added with the equivalent of new Date()
@timestamp
directive, the _updatedAt
predicate is set to the equivalent of new Date()
@hasInverse
directive, then both nodes on either side are updated with the _updatedAt
predicate with the equivalent of new Date()
.This would then generate this GraphQL schema:
type Post {
id: ID
title: String!
_createdAt: DateTime!
_updatedAt: DateTime
}
input PostFilter {
id: [ID!]
_createdAt: DateTimeFilter
_updatedAt: DateTimeFilter
has: PostHasFilter
and: [PostFilter]
or: [PostFilter]
not: PostFilter
}
enum PostHasFilter {
"title"
"_createdAt" # seems kinda silly having a required field, but following precedents already set.
"_updatedAt"
}
input PostOrder {
asc: PostOrderable
desc: PostOrderable
then: PostOrder
}
enum PostOrderable {
"title"
"_createdAt"
"_updatedAt"
}
type PostAggregateResult {
count: Int
titleMin: String
titleMax: String
_createdAtMin: DateTime
_createdAtMax: DateTime
_updatedAtMin: DateTime
_updatedAtMax: DateTime
}
input AddPostInput {
title: String!
# Notice, do not include _createdAt and _updatedAt here because they are handled internally
}
type AddPostPayload {
post(
filter: PostFilter
order: PostOrder
first: Int
offset: Int
): [Post]
numUids: Int
}
input UpdatePostInput {
filter: PostFilter!
set: PostPatch
remove: PostPatch
}
input PostPatch {
title: String
# Notice, do not include _createdAt and _updatedAt here because they are handled internally
}
type UpdatePostPayload {
post(
filter: PostFilter
order: PostOrder
first: Int
offset: Int
): [Post]
numUids: Int
}
type DeletePostPayload {
post(
filter: PostFilter
order: PostOrder
first: Int
offset: Int
): [Post]
msg: String
numUids: Int
}
PostRef {
id: ID
title: String
# Notice, do not include _createdAt and _updatedAt here because they are handled internally
}
type Query {
getPost(id: ID!): Post
queryPost(
filter: PostFilter
first: Int
offset: Int
order: PostOrder
): [Post]
aggregatePost(filter: PostFilter): PostAggregateResult
}
type Mutation {
addPost(input: [AddPostInput!]!): AddPostPayload
updatePost(input: UpdatePostInput!): UpdatePostPayload
deletePost(filter: PostFilter!): DeletePostPayload
}
Which would translate roughly to this DQL schema:
Post.title: string .
Post._createdAt: dateTime @index(hour) .
Post._updatedAt: dateTime @index(hour) .
Maybe the index should be configurable from the @timestamp directive, hmm…
Alternatively, the _createdAt
and _updatedAt
GraphQL fields could all map to the same two predicates. This would make DQL statements easier to get a list of everything that was updated filtering on a single predicate. However, this may degrade distributed performance for larger databases as the number of predicates that could be sharded is dropped leaving a large amount of work always in a single alpha/group.
After Thoughts through PM:
So would that be sortable?
Timestamps would be sortable but not mutable directly. Meaning in GraphQL you couldn’t do set: {_createdAt: "2020-01-20"}
as that is reserved only for the add mutation or when doing any input ref that creates new.
What if you needed to update a time stamp? For instance for importing data with current timestamps
for importing, I think it should go 100% into DQL if you are importing something that has a preset timestamp. Anything imported using GraphQL you could create your own DateTime field and write to that instead. That would allow to do:
Sounds good. Just seems like there needs to be some sort of way to modify that. Not super easily of course since it should only be used in special cases
It would be modifiable through DQL. I think that is the preferred method anyways. Thinking of GraphQL as the API and DQL as the database language. It would be similar to a REST API serving MySQL. In MySQL you could update the timestamps as needed, but when using the REST API, the timestamps are all handled internally blindly, outside of your control.