
Lesson Description
The "Modeling & Saving Locations" Lesson is part of the full, Domain Modeling for Humans and AI course featured in this preview video. Here's what you'd learn in this lesson:
Mike shows how to parse file data into a model, validate it with a JSON schema, and use a server-side service to create and save location records. He handles async operations and returns the data for UI display, ensuring data integrity throughout.
Transcript from the "Modeling & Saving Locations" Lesson
[00:00:00]
>> Mike North: So we're going to look in our location service. This is source services location.ts in our server and we've got a couple to-dos here. We've got the need to parse some data into a model. Then we're going to implement the actual calculation. And up here we can see we've got our getAllLocations field here.
[00:00:32]
So let's see what this is printing out. This location's fine. This returns a promise that resolves to an array of locations and we'll keep returning that and we'll log those locations to the console. Let's see what we get. So we're gonna have to in our UI load this.
[00:01:08]
We wanna see that we're making a network request to locations. And here's the request that's being made. Well, it's just kind of a naked list request and we're getting an array of empty locations here. So we're gonna trace this through. We can also see locations is empty. So part of this is because we're going to end up creating these locations as part of reading a data file.
[00:01:36]
And if you look, I'll show you where it is. But it's already being loaded just so you can kinda see where this is coming from. Temperature-ranges.yml and so here we've got a name, region, country, monthly temperatures and we've got a temperature range and there's a little bit of a tuple here with the value and either C or F.
[00:02:00]
In this case we have a little bit of an easier job, everything's in Celsius. We don't need to worry about converting quite yet. So where is that coming from? Well, we've got parsed data here. Let's see what that looks like. Great. So the file's being read and you should see in your console we've got name, region, country and then monthly temperatures.
[00:02:27]
But this is just as JSON. We're just reading this file and it's coming through as JSON. So what we need to do is create. We can start by just creating the list of locations and we should start seeing those pop up in the dropdown because we can already see the requests being made.
[00:02:44]
We can see what we're getting back is an empty array here and we should see that start to populate with something. So let's get to it here. Here it looks like we've got a top level object and actually just to avoid driving myself crazy here. I'm gonna get rid of my other log just so we can tell which is which, which is the contents of the file versus which is that locations, right?
[00:03:15]
All right, so we've got locations, which makes sense if we look at our temperature ranges file, top level property locations there. So we could say, sorry, going to the right place here. It's the first of the todos parse data is currently of type JSON value. What we can do is feed that through a JSON schema to validate that it looks the way it's supposed to.
[00:03:50]
>> Mike North: So we can do up here, we could say, let's just keep it real simple for now. So we've got location file data is z object and we'll import zod. And we've got locations, which is a z.object. And within that object, what do we have? Name, region and country, all strings.
[00:04:26]
>> Mike North: Then we've got monthly temperatures, it's an array of something. I can't really see what's in there in my console. But if we look over here, we've got month and it looks like we're going from 1 through 12. So we should probably make sure we convert that back, subtract one.
[00:04:52]
We wanna get a line with the date constructor, like the JavaScript date object. So we've got month, which is an integer, and then temperature range. Let's just copy this and make it real easy for us to see up here.
>> Mike North: Really it's like that month. And sorry, this was monthly temperatures, z.array.
[00:05:20]
And what's in the array? Each member has a month, which is a number, better yet, an integer. And we could add some of the validation that you prompted earlier, Seth. Like we could say it's a min of 1 and a max of 12, the files 1 through 12 for sure.
[00:05:46]
Then we've got temperature range, which is another object, and we've got a min and a max, and they're of the same type. And that type is a z., I'm not gonna get very helpful autocomplete if I do it that way. We could say z is a tuple, which lets us like who here knows what a tuple is?
[00:06:15]
What's a tuple?
>> Male Student 1: A pair of two values together.
>> Mike North: Yeah, it could even be more than two. But the significance is positionally, you know, the types of these things. If we were to model this just an array, it would be array of strings are numbers. And that's not quite right.
[00:06:37]
We know the first position is a number and we know the second position is going to be C or F. And so what we can do there is say we've got a tuple and we're going to provide the two items. The first is a number and then the second, we could say it's a string.
[00:06:57]
Although to get to line up really nicely with our type checking, what we really want is C or F, right? The union type of literally C or literally F. Well, zod can do that.
>> Mike North: I think this has to be an array, but I'll do that in a sec.
[00:07:22]
>> Mike North: Here we go, boom. Little formatting here.
>> Mike North: What is going on? It's z, it's an array of these objects. Month does not exist.
>> Mike North: Let me get rid of this and see what happens.
>> Mike North: That's the element type. Classic mistake. Here it's this. I can't just pass an object in here.
[00:08:02]
It's a zod object like that. You have to give it that nice little wrapper. Sorry, is that sufficiently wrapped?
>> Male Student 2: Yeah, duplicate that line.
>> Mike North: Let me take a step back and make sure. Yeah, I believe you. I just wanna make sure I'm doing this in the right order here.
[00:08:23]
There you go. So there's my object. Close parentheses, format. Okay, great. So we've got name, region, country. Here's our temperatures. It's an array. Here's the schema for a member of the array and it's got all this stuff going. So what we can do now is say, sorry, what did we call it?
[00:08:46]
LocationFileData.parse(ParsedData), and what are we gonna get out? File data and it's never read, but here's its type. And look at that. And so let's print that to the console. I'm gonna do (JSON.stringify) just so that we can see it in its full depth and it doesn't get truncated.
[00:09:30]
>> Mike North: And let's see. Get rid of this console log so it doesn't kinda interfere. And look at this, it kinda looks the same. Interesting, Locations, expected object, received array.
>> Mike North: So this is a validation error here. Just checking this. We've got locations. Checking our schema.
>> Mike North: Interesting.
>> Female Student 1: Is that c.object supposed to be z.array?
[00:10:10]
>> Mike North: Yes.
>> Male Student 3: Well, but it's an array of objects. So we gonna even wrap.
>> Mike North: Yep, easiest way. Like that, good catch.
>> Mike North: So that's the close of the, yeah, just a friend. Wonderful, look at that. We've got our full depth data there. So let's now turn this into records, so we can close that.
[00:10:42]
And we're gonna go use our little outline here, so we can get to the right function. So we're gonna want to get into load temperature data. Here we are, we've got our file data, we've logged it to the console. Now what we wanna do is say, fileData.locations.map. And we'll say.
[00:11:11]
And then here we're gonna take in one locdata and we're going to. What we wanna return is a promise that resolves to a location.
>> Mike North: Is this the right location? Yep, there's the entity right there. And of course, we're getting all kinds of nagging cuz we certainly have done nothing to live up to that contract that the function has.
[00:11:47]
And here's our location data. So what we wanna do is we're gonna say, actually up here we could just get what's called the repo for the location. In the DDD world and in the type ORM world you can think of this as the way that you engage with your collection of a certain entity type.
[00:12:17]
>> Mike North: And we're gonna say AppDataSource. And remember, this is the file that contains all of our entities here. This is all the things it knows about. And we're gonna say getRepository for location. And if we hover over that we can say, it's a repository that's generic over location here and in here we can say, locRepo.create and we can pass parameters in here.
[00:12:48]
And what does this return?
>> Mike North: It returns a location. So we're gonna create it and then we're gonna save it, at which point we will have a record and we should see things in that dropdown. So what do we need in here? We need name.
>> Mike North: We need region, or what do we call it?
[00:13:23]
I think he called it the same thing here. Yeah, region, we need country and most importantly we need commas. And then let's see if this is enough.
>> Mike North: So what we're doing here is, we're creating the record and you can think of this as you're just creating an instance of the class.
[00:13:54]
And then when we save it, that's where it goes to the database, that's where it gets its ID. And you can look at Save, it returns a promise that resolves to its location. This is what actually persists things. Now you've got a promise that resolves or an array of promises that resolve to a location.
[00:14:13]
Now this is gonna be interesting. We'll probably end up with a race condition here, which we'll refactor our way out of it. But we're gonna parse this file and we're gonna kick off a bunch of attempts to save to this database and let's see what happens. It's gonna be like a lot of contention over this table.
[00:14:31]
Interesting.
>> Mike North: Looks like it may have worked. I'm surprised SQLite is able to keep up with that. We'll look at the right way to do it.
>> Mike North: We'll look at the right way to do it in a sec here. But let's take a look at our database and see if anything happened, what happened?
[00:14:54]
So location. Hey, look at that. We've got seven locations here. So creating seven things concurrently is fine for this apparently. What you could have also done is a for loop with an await where one by one you're creating each of those locations. I tried to tease out some lock contention here where we're trying to do many writes at the same time, but here we go.
[00:15:22]
We've got our list of locations. Our job is to return them. So we're gonna await promise.resolve locations. And let's see what happens in our UI.
>> Male Student 4: Don't you wanna do promise to all?
>> Mike North: Thanks.
>> Mike North: Hey, look at that. Got a lot of stuff coming back. And sure enough, here's our drop down.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops