TypeORM viewEntity

I'm a full-stack developer from South Africa 🇿🇦. I love writing about JavaScript, HTML and CSS.
Search for a command to run...

I'm a full-stack developer from South Africa 🇿🇦. I love writing about JavaScript, HTML and CSS.
Entities in TypeORM represent database tables or connections. However, there is another form of object we may use . A database view can be mapped using the viewEntity. If you've never heard of a database view, it's a view of a certain database result.
Most of you know me for my consistency, a golden arrow in my blog series. I've written 1000 articles in 1008 days! Almost an article a day, and my honeymoon was the only holiday I ever took. I'm super proud of this achievement; it has been a fantasti...

It's not the first time I'll be talking about community. I think it's an essential aspect of any successful tool. This shows in my previous explorations of Astro, Medusa, and now Vendure as well. All these products thrive in a super open, welcoming, ...

The cool part about Vendure is how easy it is to set up and how abstract each layer is. Basically, we get the following elements: External database Server Worker Admin UI Frontend While this is amazing, it also brings a bit of complexity when it co...

The previous article looked at customizing Vendure on a data and process level. In this article, we'll look at customizing emails, as they are often a big part of a webshop system. We'll be looking at two different layers of customization for customi...

Even though Vendure is a pretty significant project out of the box, in some cases, we might want to go in and modify some elements to work to our specific use case. In this article, I'll take a high-level look at some elements we can customize within...

We had a brief first-look at TypeORM, an excellent ORM system for managing your database.
I wrote about this first as I was transitioning to Prisma, this is not finished, but I found some fantastic elements of TypeORM I wanted to showcase in the meantime.
And for this article, that is something called a viewEntity.
In broad terms, TypeORM has entities that reflect database tables or connections.
But there is another type of entity we can leverage. The viewEntity can be used to map to a database view.
If you have never heard of database views, this is a view of a particular result of a database.
Let's take our initial TypeORM project as a starting point.
Note: You can find it here on GitHub.
We have something called a photo table in this project, which has all our photos.
These photos can be either published or not. We could also add a simple view entity that can only show the published photos.
That way, we always perform that specific query, instead of repeating ourselves with something like andWhere(photo.isPublished).
We write the view entity the same as a normal entity, but you can give them an exact name.
Let's use publishedPhoto for our one.
We have two ways of defining the actual view entity query, which can be either a raw SQL query like this:
@ViewEntity({
expression: `
SELECT "*"
FROM "Photo"
WHERE "isPublished" = true`
})
Or via the query builder, which would look like this.
@ViewEntity({
expression: (connection: Connection) =>
connection
.createQueryBuilder()
.select('*')
.from(Photo, 'photo')
.where('photo.isPublished = true')
})
I like the query builder a bit more, as it's cleaner in my eyes.
This is a very simple query, but you can enhance the query and even include multiple joins, a small example could be:
@ViewEntity({
expression: (connection: Connection) =>
connection
.createQueryBuilder()
.select('photo.*', 'user.firstName')
.from(Photo, 'photo')
.leftJoin(User, 'user', 'photo.userId = user.id')
.where('post.isPublished = true'),
})
Once the view entity is done, we still need to set up the returned columns.
These are called viewColumn, and we can add them in our class export like this:
export class PublishedPhoto {
@ViewColumn()
id: string;
@ViewColumn()
name: string;
@ViewColumn()
views: number;
}
You can, of course, add whichever columns you'd like to show here.
To load the view entity, we have two options. The first is to create a new migration and manually add all the queries to replicate this view entity.
This would be the preferred way of keeping everything in sync. However, since we haven't used migrations yet, let's use the sync command.
(But it can cause some odd syncs and is a bit more unpredictable for a production application)
npm run typeorm -- schema:sync
Once it's done, you should see the view added to your database.

You can even see it shows only one result, while my database has two pictures. One is published, and the other one is not.
Let's first create an endpoint to retrieve all photos to see the difference.
Open up your index.ts file and add the route of the following photo.
fastify.get('/photos', async (request, reply) => {
const photos = await connection.manager.find(Photo);
return { photos };
});
If we now run our application (npm run start) and visit the page, we should see all our photos.

Now we can swap out the Photo entity with our newly created view entity, which will use instead.
fastify.get('/photos', async (request, reply) => {
const photos = await connection.manager.find(PublishedPhoto);
return { photos };
});

As you can see, view entities can be super easy for specific combinations that you'd always have to do.
Think about published or deleted or even hidden items.
You can also find this in the GitHub repo.
Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on Facebook or Twitter