Video details

JS Monthly #17: Daniel Olavio Ferreira - Heavily Connected Data Applications


In my talk, I will be showing how complex it can get when having to deal with SQL table relations with some mainstream ORMs, such as TypeORM and Sequelize. I will compare them to how Prisma deals with it using a simple yet powerful schema syntax, and an intuitive query client.
The JS Monthly Meetup was organised by
Aris Markogiannakis (JS Monthly host) and hosted by Prisma. ✨ Join the Prisma Meetup group here:
Follow Daniel: Github: Twitter:
Next: 👉 Check Next video: Double up your component & integration tests with Supertest & Nock - 👉 Check Previous video: Anonymous Video Calling App Using Machine Learning -


We're going to go through now. Heavily connected data applications with Daniel. He's talking to us straight from Portugal. That's the main benefit of this online and world that we can connect with everyone. The floor is yours. I'm looking forward to know more, and we go from there. Thank you very much, Aries. Let me share my screen with you guys. So as Eric already introduced me, my name is Daniel, and I'll be talking about heavily connected data applications. That's a really big name for a very common problem that most of our developers have already faced once in a lifetime. If we didn't face it yet, don't worry. You will. Well, a little bit more about me before we start. I'm Daniel Lagya. I'm a software engineer. That's an amazing company, a technology company that's working in the world of connecting Brazil with logistics. So if you know Brazil, Brazil is a massive country, bigger than Europe. So it's a real big challenge, and we are very happy to tackle it. I'm as well a Prisma ambassador. So I'll be talking a little bit more about Prisma, and it's a tool that I have a lot of love for. If you want to know a little bit more about me, you can check my website at Danielavue Dev or my Twitter at Danielaviewbr. So. Okay, the first thing that we got to understand is what is the actual problem? What we're talking about here, what is the problem when we are talking about relational data in our databases and why it can get so hard? Because when you're talking about small applications, that's no problem. We can connect one table to the other. Many too many, one too many. That's not a big deal. But when it comes to very large applications, that could be a really big problem. So here's a really great quote from Robert C. Martin, and he says database schemas are notoriously volatile, extremely concrete, and highly dependent on. This is one reason why the interface between object oriented applications and databases is so difficult to manage and why scheme updates are generally painful. Well, if you don't know Robert, he's a writer of clean architecture, one of the greatest Bucks for a developer, and I could not agree more with him. If you ever needed to work on an application that had to talk with a really big database and the data had to be very connected. So all your models needed to understand and know about each other, and things needed to be in one place and another place, and things needed to know about itself. So it's very complex, and it can be really hard if you don't have the right tool to do it. So that's what we're looking for. What are the tools that are available to us as developers that we can use to make our lives a little bit easier? We are past the time that we had to create the queries by hand and write all our SQL queries and everything. Fortunately, we don't necessarily have to do that anymore. We still can't, but that's no longer necessary. We have great RMS. They're object relational mappings that help us connect our application to our database. So we're going to be looking at the three most used. Well, not the three most used, but some of the most used RMS in the market. Today. There are Sqlize typer and Prisma. So let's take a look. First of all, I want to let you guys know that I got all these examples from their docs. So trying to convince you that one is better or trying to use different queries, all of these examples are from their docs, so you can go to air and check it out. So the first one we are looking at Sqlize. It's very simple to define your models or your tables if you prefer to call it like that. But there's one problem that at least for me, it's a big deal that we cannot realize what we're doing exactly when we look at our first glance. So if I stop and read, okay, Sqlize, the find. I assume the movie is the name of my table, and then I have an object that defines what are my columns and what are their data types. But it doesn't look like very Tabley or doesn't resemble the table all that much. And if you look down a little bit more, we're defining our many to many relation radio between our movies and our actors. It's kind of hard to understand everything that's going on there and how it's connecting both of them. And when we look only to the movie model or to the actor model, we don't really see that it has a connection. So if we imagine that we would be defining all our tables in one page in one file and then defining all our relations in another file that could be a little bit confusing. So we wouldn't know. Okay. Do I have the information about the actor in the movie stable? Do I already have the relation or do I have to make two separate queries when I want to bring all that information? So that could be a problem, especially when you go to bigger applications. And it's not only you that's working on the project or many people working on it. Next, we have typer. I don't know about you guys, but this one falls very close to my heart. It was the first aurram that I used, and I believe it's a really good it has some really great features so different from simple eyes. You can already see that it looks a little bit more like a table, so you can see. Okay. It's well divided. So I know the ID is a column, then the name is a column. It even has the decorator telling me that's a column, the ID has the primary generated column. So I know. Ok, this might be generated in some way. And it's my primary key. If the person doesn't really understand that, it can be a little bit tricky. And when we go to the question model, we have all the data. And then in the end, we have the many to many relation in the joint table decorator telling that we have categories there that are of type category. That's the class that we defined previously. I think it's very good, but I feel like there are some tricky points when it comes to that. The first thing is that when we look at the category, we don't know, what is it referring to? So we don't know what has categories. So do my questions have categories or maybe do I have answers that have categories or posts or movies or actors? I don't know is what the relation that it has. So it can be a little bit tricky. And the second one that could be a little bit nitpicking, but it's not so beginner friendly. So we have names that we are used to, seeing as developers as many too many as primary keys join tables, but new developers or people that are just getting started in the world of programming, and they want to tackle databases. They're probably not going to understand what many too many is. They can understand. There are many things to many things. But what does it mean? It can be a little bit complex using this terminology sometimes. And lastly, we have Prisma. And as I said, I started with type of Ram, but nowadays I believe every single application that I've been able to develop the data models and the entire database. I've used Prisma, and there's a great reason for that. It's very intuitive. As you can see, Prisma is not like the others. First of all, we're not working in a JavaScript or type script file. We're working in what we call the Schema. Prisma is our Prisma file, and in here we have a little bit of a different syntax. And here we define our models as sort of JavaScript or TypeScript like objects. So you can see and you can divide these models in three columns that help you understand them a little bit better. So the first column, the one that's the furthest to the left. It's our name column. So that's what our column is going to be called for. The first one, we have our column names. It's going to be a T. The second column is the type. So what type is this column going to be? So in this case, this column is the type of integer, so it's an Int. And lastly, we have our decorator or options. We can call it that column where we can pass some extra configurations to Prisma so you can better build our table when it translates all of this into SQL. So we tag our column as an ID with the ID decorator, and we tag it with a default auto increment. So this makes the person tell our database. Okay, you're going to fill this value in the default way, so I don't have to pass the value when I want to create a new row in my disable, and I'm going to define it as an older increment. So it's going to start 12345 and so on. So forth. And I could pass maybe a CUAD or a Uuid if I wanted to generate my IDs in a different way. That was not sequential. And second, that's where I feel like Christmas shines so much. It's the posts in the next row. We have the posts that are tight post, and we have the square brackets that if you are used with TypeScript, or even if you use JavaScript or most of the languages, the square brackets tell you that that's an array or an array like object. So that tells us that, oh, I'm working with an array of posts or many posts and post is a model that I'm going to be defining right underneath that. So I have my post model where I have again, my ID that loves type and has my options over decorators. And then I have my categories again, the model that I just created right above and again is the type category, and it has the square brackets telling me that, OK, I have many categories so I can understand. Oh, in my post I can have many categories. And in my category I can have many posts associated with it. And the beautiful thing is that Prisma helps you so much with that. There are tools, especially for people who use vs code that help you so much the extension and all that there is to help you with Prisma. It's incredible. Okay. We saw very simple examples with one many to many relation, just two tables. Nothing major. But what about big applications when we're talking about large data and crazy relations and things can go south very fast in this type of scenarios. Unfortunately, I'm not going to be able to have time to show you and explain to you with all the three RM. So I'm going to be focusing on Prisma, but well, I think you guys already know my opinion. I believe it's one of the best tools that you can do that list. So here Firstly, we have our model, even though it only has four tables. It has a lot of connections and a lot of relations. So first to the left, we have our user table, and I'm going to try to read out the structure that I thought even though it's a little bit complex, you're going to see that it's not that hard to see an application that would have something like that. So one of our users can be a student in one of one class. One user can be a teacher in one class. The user can be also a student in many classes. Sorry, a user can have many grades. So if he's a student, he has many grades for his many classes, a class can only have one teacher. It may or may not have a teacher. It can be a self study class or something like that. A class may have many grades for its many students. A class may have one document associated with it. A grade has to be associated with a user, and a grade has to be associated with the class. So if it was graded on something, it has to be associated with the class that I was graded on. A document can only be associated with one class. A document can have many documents associated with it as if they were its children, and a document may be associated with a parent document or a main document if you wanted to call it. So as you see, even though we have only four tables, we have a lot of different relations. We have one to one or relation. We have many too many. We have many to one. We have selfrelations. So even though it's a very small database, it can get really complex. So let's get started defining our model. I'm just going to create here my user model. So with all the user stuff, D. Id first name, last name created at email and you're going to be seen, especially in the decorator's part that I'm using some things that are a little bit different. So as I said in the default, I'm given in the CUAD that's a different type similar to UUID, but it's a different generation method. I use the map decorator that it translates the name from what I want it to be in JavaScript to what's going to be in my database. So for example, the usual pattern that we use when we're writing or coding JavaScript is we have the first letter in lower case and the second word first letter is going to be in uppercase and so on and so forth. I believe that that's Kemill case, but in databases we usually use snake case that we divide words by the underscore, so I can translate that. That's a really good thing that Prisma allows me to do. I have created that. So I define it as a daytime type. I can set it to default as now, so I don't have to use a daytime now when I create my table. So if I forget, it doesn't matter. Prisma helps me do that. And again, the map function and the email. I tag it as a unique. So whenever a user signs up, I am guaranteed that email is only used once in my database, so I don't have to make validations in the back end or in the front end to deal with that. When I try to insert that into the database, if it's already there, it's going to error out. Okay, so let's go to the relations. The first relation that we have right there a user or a student may have many grades. So again, we see that we have the name of our column is going to be grades, and it has the type grade with the square brackets saying that it's going to be many grades. So a user can have many grades since it can have many classes. Since we're talking about classes right on that we have the classes relation. So we have a column named classes, and it's a type class with the square brackets. Again to show that one user can have many classes. And then we have the teaching class. And you're going to see this is a little bit different from the other ones because we have to define a few other things. Since we're making a relation with a table that we already made a relation with. That is classes. We have to create this relation that created with a little bit more information so that Prisma can better understand how it's going to be working with that relation. It's nothing major. So I create a name for my relation. I give the fields that it's going to be using in my model to find what it's unique ID and the reference in the class in the other table. So here, as you can see, I have a teaching class and it's a type class with a question Mark. Again, very similar to what we have in TypeScript that it says that it can be null. So I may or may not have a class, a teaching class associated with it. Same thing with the teaching class ID. That's the unique identifier that I have or my foreign key. And in the end, we have our last decorator that's for entire table. So I define my model with uppercase Q, but in singular in the database, I want it to be users, so I can map that as well. Next, we have the grade model. So again, the same boilerplate, the ID, the value that's going to be our actual grade. And then we have the actual definition of our relations. So the grade may be associated with a user, that user, and we have the Association that we have. So we use the app relation decorator saying, okay, you're going to be using the user ID as your key, and it's going to be referencing the ID in the user table. And again, we have the user ID, and we use the map function again to translate them into our database. Same thing for the class. So we have a class itself type class. Again, if you notice these ones don't have question marks. So in Prisma, when we don't have the question Mark, it means that it's mandatory to have that fuel. If it has a question Mark, it can be null or it can be empty. So in the class again, we have the relation with our class ID. That's our foreign key, and it references the ID in the class table. Again, we're mapping the name to grades instead of grade. We have now the class model. Again, boilerplate the ID, the name of the class, our relation with grades same as we had in the user model. So we have grade with the square brackets student, it's going to be a relation with user with square brackets. And then we have the teacher that's a user with customers because a class may or may not have a teaching T shirt. And again, we are using the app relation because we are making two separate relations with the user table as I talked previously, that's why we have to give it a name. So here we're referencing the class teacher as we did in the user model. And lastly, we have the document relation. So class may have a document associated with it. So it may or may not have a class document associated with it. So it's a document of that document with the question Mark. It has a relation that's going to be looking for the document ID as its foreign key and referencing the ID in the document table as its primary key. And we remapped the name of the table to classes. And lastly, we have the document. And here I think it's where it gets a little bit more tricky because we're going to be dealing with self relations. So again, boilerplate ID title content created at all the good stuff. That's all we're all used to that. But right here it's where we have something that's a little bit weird. So we have one column called complementary documents, that's of type documents and documents. It's the model that I'm defining right now. So it's sort of recursive, and I give it a relation of name documents to document. Underneath that I have a main document that subtype document with a question Mark, meaning that it may or may not have a main document. Again with the relation name of documented document and the field that it's going to be looking at the main document ID and referencing the ID. And underneath that we have the main document ID. That's a type string with a question Mark, because it can be optional because it may or may not be there. What we're doing is we're sort of joining all the parts that we needed to create these relations into one single table into one single model. And we are telling Prisma. Okay, so you're going to be able to reference yourself sort of like a common way, trying to create sort of a tree like structure. So I can be a document. And I can have many complementary documents that are associated with me. And I'm not going to have any parent document, any main documents associated. But the documents that are my complementary documents are going to have me as their main document. It can be kind of blurry, but I believe we're going to see that working a little bit better in the next few slides. And then we have the class relation again, very simple what we've seen before, and it's optional because our complementary documents are not associated with our class. They don't have to be. They could, but they don't have to be. So that's one perk that we have. Okay, after all that we created a model. It was very complex, but very easy to get it at the same time. How do we query all this data? How do we connect our database, what we just created to our API? How do we make this connection? That's where we start using the beautiful Prisma client. It's another very good tool that the Prism machine has developed for us. That's very simple to use. So here I have three different queries that could be used in this type of application. First of all, I'm going to actually be generating my data. So first of all, I instantiate my Prismaclient. I create a new instance of it, and then I'm going to start using it. So I'm just going to say, oh, wait, because it's an asynchronous function. Prisma the table that I want to work with. So in this case, I want to work with the user table. So I'm going to create Prisma user create, and I'm going to pass the options that I want. So for the data, I'm going to say that the email is Peter at mail. Com. The first name is Peter. Peter, the last name is Smith. And right here is some really interesting thing I'm going to say, okay, he has classes. And right there I can choose to either connect to a class or create or even if I don't know if this class already exists, I can say, oh, create or connect, and I can tell if it's already there. Just connect to that. If not, create this new class with the following instructions. We're not going to be using that for now, but it's a really good trick that you have with Prisma. So we create a new class with all the data that it needs. In this case, the only data that we need to pass to our class is the name. So we call it Prismal 101. Next, we're going to create our teacher. So we're going to do the same all over again. Await Prisma user create. So I'm going to pass all its data. So the email is Daniel at mail. Com. First name, Daniel last name, Ferrier, and the teaching class this time not the classes. It's going to be the class that we created already. So instead of saying create, we're going to be saying Connect and pass the name. That's a unique identifier. As we saw here, we could use any field that is either tag as an ID or as a unique that then Prisma can verify and validate that. It's only going to be finding one instance of that in our database. And then lastly, we're going to be grading a little bit. So now we're going to say await Prisma. Great. That's our table create. And we're going to say, okay, the data is the value. So we created the student eight in the class. It's going to be the Prismal one on one. So we're going to be connecting it to the Prismal one on one as we did before. And we're going to be connecting with the user. And again, we are going to use whatever field is tagged with the unique or the ID decorator. So in this case, remember that we use the unique decorator for the email and the user here. That's why we can use it in the connect. Awesome. Now we're going to be creating a few documents. So we're going to be creating the first document that's going to be called Complex Data relations. The content is going to be it's not that hard with Prisma, and we're going to be connecting it with the Prisma 101 class. Next, we are going to be creating our secondary document or a complementary document. So in order to do that, we're going to do the same. So title simple data relations content. It's very easy with Prisma. And now instead of saying that it has a class associated with it, we're going to associate it with a main document. So the main document is sort of our parent document, the one that's above us. So we're going to say connect with the document that has the title Complex Data relations. Again, we can do that with the title because we tag the title with the at unique decorator when we were describing our models. Now let's go and let's start clearing our data. And you can see that it's just as easy as creating our data. So we're going to use our instance of Prisma again, and we're going to choose a table. So class findmen. And there we're going to be able to pass a little bit more options so we can say where we can say, okay, what we're looking for. So we're looking for the class that has the name Prisma 101, and we can say, oh, I want you to include this relations. I want you to bring me all the students that this class has. I want you to bring me all the grades that this class have. I want you to bring me all the teacher that this class has, and I want you to bring me the document that's associated with this class, and that's all that you have to do to get all those relations in your query. We are going to see the result of that very shortly. Next, we want to find our students. So we want to know who are our students in our class. So we can just say Prisma user clientmanny. Where the teaching class? Sorry. We're going to bring the teacher from that class. We're going to be saying where teaching class in the name of a teaching class. So the Prisma 101. And that will bring me the teacher for that class. And remember, we're not querying for that in the classes table. We're quering for that in the users table. So that's really good. And that makes our life so much easier because it's so much more versatile to be able to prerefer data in different tables or in different environments. And lastly, we're going to be looking for our documents. So we're going to find all of our documents. So find many where the title. So here we are using a really good feature from Prisma that is the contains. So wherever the title contains the word relations. And I want you to include the complementary documents. So it's going to bring me all the instances that have the relations word in the title, and it's going to bring me as well. Always complementary documents. One thing that is really good to mention is that Prisma is 100% integrated with TypeScript. So whenever you type await, Prisma is going to show you all the tables that you have available. It generates all your tables and all your typings when you first create your schema. So it's a really great topic, but I'm not going to go in that with that because that would be a whole different talk. So okay, let's take a look of the results that we got with this query. So first of all, we're going to be looking at the first query, the find menu for our class and all its relations. So here I had to divide it in two separate boxes because it was way too big to fit in my screen. So we received an array because we asked for many. That's why you used find many, but we could have used find one or sorry, find unique find first and so on. But in this case, we use Find name. So it brought me the Prisma 101. It brought me the ID, the name, the document ID that it has associated with it the list of students. And this came because we asked it to bring it along with the include, same thing for the grades, the grades that brings me all the objects that are associated with it. The teacher again, because of our include and gives me the name of the teacher and all its data and the document that's associated with it. And again, all of its data. Next, we have our query for the teacher of a certain class, but made inside of the user table. And in this case, we didn't ask for it to bring the class as well. In this case, we only asked only bring me the user. I don't want to know any other information, the only thing that I want to know that he's the teacher for this class. So this is what we got here. We don't need to know extra information or we don't need to bring information that we don't really need at this query. That's a really great advantage. And again, it's in between square brackets because we use finance, so it's going to return to us an array with all the matching entries in our database. Lastly, we have the response for our documents, and in here I would like to spend a little bit more time because it can be a little bit weird what it's doing. The first entry goes from all the way to the top to the last document that we have there, and it has a title that's complex data relations, the content that it's not that hard with Prisma that created that the main document is set as no sense. This document doesn't have any parent document or main documents associated with it, but it has complementary documents. It has an array of complementary documents since it can have many, but in this case, it only has one. That is the simple data relations, and it's bringing me that because again, I used the include keyword, the include option and said, Bring me the complementary documents as well. So that's why it brought me the simple data relations. And underneath that we have again, the simple data relations. Why? Because it's another entry in our database, and we ask for all the entries that have the word relations, and it does have the word relations. So it's going to show up in our query when we look for that. And it showed up before because it wasn't a complementary documents, but it didn't have anything to do with the prere part. It had to do with the including part with the relation. And here you can see all the data again, the title, the content, and then the complementary documents. We don't have anything because it doesn't have any complementary documents or children documents. But we do have a main document ID that's referencing to the complex data relation that it's main document. So that's really interesting, because when we created this, we only said that there was something to do with another document when we were creating the simple data relations, and now it's showing up when we're creating for the complex data relations. That's very interesting how we can deal with that. And when it comes to creating our data, we don't have to create it previously, or we can actually reference to things that we already done or create an own spot and connect it afterwards. Well, that's all I had for you guys today. I thank you everyone for watching. I believe Aries is going to call up now and we're going to be able to answer a few questions if you have. That was excellent. I like this so much. Let me see. There was this question before. I don't know if we can answer it. How can we perform their special Mongo B query in Prisma? That's a really good question. I know that in Mongo we can use geospatial locations. That's going to save our latitude and longitude. And I believe we can query it saying, oh, I want it to be this far away from this point. I'm not quite sure that Prisma supports it right now, since we're still in preview mode. I don't think this feature is enabled, but you can always go to the Prisma slack and let people know and ask there. They're surely going to help you or in the Prisma docs, you can see the references there. They're really good to read. Yeah. When I first did learn about Prisma, I was using like a Google Map application with locations, and I was storing the longitude and the latitude into inside Prisma. But any kind of when I was getting the results back, I was finding some libraries that they were going to help me do my calculations and try to find it's quite helpful for Prisma to get the data. But I think for that kind of specific kind of function, you probably use something on top of that. Yes, probably. Yeah. You had like a journey coming to Priest mind. I don't know if also Luz wants to join us. Hello. Have you used Prize mine, Luis? I haven't. Personally, I thought it was really interesting. We use React Query Sarah and yeah, I think it would be really interesting to investigate this. It's quite useful for sometimes when you're in a startup, you want to start a project, you don't have a back end developer, you don't know where to start. Let's say you want to use Nips. You can create an API folder in your pages, you can host Prizma quite easily, and then you can just run things so quickly and you have the back end running for you. So yeah, that's how I started using it. But yeah, for a test person, would you see any kind of use anything that you would like to use from what you learn today? Yeah. So I guess one question I have is obviously it's super easy to set up your schemas and query, but how do you kind of structure your data so it doesn't get kind of out of. Yes, that's a great question. I believe that's the work the developer has to train a lot. I believe that's not necessarily on Christmas. Hence, it gives you a great tool to visualize how you're creating your data and to see how you're structuring it. So when you're going to be working with it, how you're going to clear you, how you're going to create your data. I believe Prisma helps you a lot, enabling you to look at all your tables and enabling you to look at your schema. And with the Prisma CLI, you can use the migrations everything to help you better try to better create versions for your database, but I believe that when it comes to actually knowing and making your application future proof that you're going to be able to scale well, it's a little bit more towards the developer, not necessarily with the tool. Yeah, I completely understand that. The thing is because of that type safety probably as well. It helps a lot from the test point of view, and you don't have to worry about sending like, a string that it tends to be an integer number. The type you with Fresno was the one thing that brought me into it, and all the rest made me stay. I remember I learned about Prisma in a YouTube video that was recommended. I was working with a Typo Ram, and I was pretty happy, but when I saw it has more integration with types, let's give it a try. And the schema was simple to use, and it was very interesting to query the data, and the application was under heavy development, so you would be able to see new versions coming out almost every week. I believe we just released the two point 30 release with a bunch of new features with new databases being supported. We just released the preview for MongoDB. So it's a really great tool that's growing so much, and I see so much being developed in the future as well. So that's why I'm sticking with Prisma. It's really good. So yes. Have you got any example of projects to use Prisma? And. It went really well. Yes. I actually have one great case. That's a situation that was similar to what we were saying that we had a project. It was a client's portal that we're developing for a client. And he said in the first meeting that he had a back end. We are going to have access to his API and everything like, oh, that's going to be all good. But in the end, there was no back end. He didn't have anything. He had his databases that he wanted us to use. It was everything on SQL Server, and I was like, oh, that's going to be a pain. Okay. So you're going to pay for us to do back. And then he was like, no, I want you guys to build a EUCLINE career in the front. And I was like, we're not going to be doing the queers in the front, and that's not going to work. Well. So we did what you said. We actually use Netjs and the API routes to protect the queers that we're making in the database so that it wouldn't get exposed in the front end. And it was super easy to set up. And at that time, I believe Prisma was just releasing the SQL Server integration, and after that, we actually had to move on from SQL Server because of Next JS. Since we're using a service environment, we went with Postgres and it was super easy to set up with the PG bouncer and everything. Prisma made it a great experience, and the project was a great success. The client in the end was very happy. We were able to actually use testing with Cypress, and we mocked our database calls and our API routes. So that was very good. So yeah, we were able to do something so much faster, even though it was probably not in the best way. It was a little bit rushed in some parts and the API routes, some things were a little bit crammed. It was still very work and very easy to navigate. And when other developers came in to join the work, they could easily understand what was happening. They could easily understand the data models and how everything was talking to each other. That's probably because you mentioned testing and Cypress. That brings me to ask a question to Louis. Maybe you can answer as well. How would you use knock with Prisma because it's a third party. So. What is your take? I don't know whether you need knock in this scenario because Christmas abstraction layer kind of does the job for you because you've got your typing on your data and everything like that. I don't think you should use it. Going back to my choose the right tool for the job. It reminds me when I was doing the classes with Luz, we're using density framework from net. That's very similar. Even when I was using K. Php, you were able to create your models and everything. Everything was like NVC and you are running one command and it was generating all this stuff for you, and you are able to generate your data and start using using queries similar to what Krisma does. But things move on a lot to the front end, and it's quite powerful that we have this kind of tools. But yeah, it's great.