What database are you using for your apps these days?
If you're like most Python people, it's probably Postgres SQL.
If you roll with no SQL like me, you're probably using MongoDB.
Maybe you're even using a graph database focused more on relationships.
But there's a new Python database in town, and as you'll learn during this episode,
many critical Python libraries have come into existence because of it.
This database is called EdgeDB.
EdgeDB is built upon Postgres and implemented mostly in Python.
It's something of a marriage between traditional relational databases and an ORM.
Python's async and await keywords, UV loop, the high-performance asyncio event loop,
and asyncpg all have ties back to the creation of EdgeDB.
Yuri Selvanov, the co-founder and CEO of EdgeDB, PSF fellow, and Python core developers
here to tell us all about EdgeDB along with the history of many of these impactful
language features and packages.
This is Talk Python to Me, episode 355, recorded February 16th, 2022.
Welcome to Talk Python to Me, a weekly podcast on Python.
This is your host, Michael Kennedy.
Follow me on Twitter where I'm @mkennedy, and keep up with the show and listen to past
episodes at talkpython.fm.
And follow the show on Twitter via at Talk Python.
We've started streaming most of our episodes live on YouTube.
Subscribe to our YouTube channel over at talkpython.fm/youtube to get notified about upcoming
shows and be part of that episode.
This episode is brought to you by Sentry and SignalWire.
Use Sentry to find out about and fix errors when they happen and build real-time next-generation
video meeting rooms with SignalWire's API.
Transcripts for this and all of our episodes are brought to you by Assembly AI.
Do you need a great automatic speech-to-text API?
Get human-level accuracy in just a few lines of code.
Visit talkpython.fm/assemblyai.
Yuri, welcome to Talk Python to Me.
Yeah.
It's great to have you here.
We just met recently at Pi Bay down there.
So in honor of that, I wore my Pi Bay shirt today.
Oh my God, I forgot about that episode.
I probably should have worn my t-shirt.
Yeah, where's your Pi Bay shirt?
Yeah, yeah, yeah, yeah.
What a cool conference, huh?
It is.
I love small conferences.
I like small conferences.
And in the time of COVID and all of this madness, having a winter conference outside in California
at a beautiful food cart area where it's warm.
Oh, there were just so many things to like about that.
I got to tell you, it was great.
It was amazing.
It was the best day of the year for me, essentially.
Just being able to talk to people finally and see many friends was amazing.
We both gave talks there.
I talked about Flask and HTMX.
And you spoke about building a database engine, a whole database with Python.
And that was interesting.
So then I watched a little more and I just thought, wow, there are a lot of interesting pieces of
technology in and around this thing you built called Edge TV.
So I'm super excited to dive into that with you.
But before we do, let's just hear your story real quick.
How do you get into programming in Python?
So my co-founder, Elvis, and I met many years ago, probably 14 years ago or something like that,
working in a small Canadian company, building big enterprise software for companies like Walmart.
Back then, we were actually like the system that we were working on was written in PHP.
And I mean, we pushed PHP to the limits, but we always knew that, hey, when we start our own thing,
we will be looking for something new and fresh for us to tinker with.
And we looked around and we just like Python.
Liked it a lot.
Great syntax.
Fantastic.
Was that Django?
I mean, that's right around the time of the Django growth or was it something else that brought you in?
We started with Django.
We played with it a little, but actually like we just started building our own thing pretty much
immediately without looking like too deeply at existing frameworks or anything.
Yeah.
I get the sense that you and your co-founder are framework builders.
Yes.
Yes, we are.
Somebody asked me, maybe it was Guido, I don't remember anymore.
What was your first thing that you wrote on Python?
And I said, the function decorator.
I could just...
John Trayden.
Exactly.
Awesome.
So how about now?
What are you doing these days?
Working on EdgeDB full-time?
EdgeDB.
EdgeDB full-time exclusively.
Yeah.
We're building a great company here.
So that requires 100% of my attention.
Yeah.
I bet it does.
It's...
You can build a business on the side, but it's a hard time.
And you have this great article that talks about how you're going to build your favorite new database in a month,
but that it actually takes 10 years.
Do you like that, right?
Yeah, pretty much.
Yeah.
It was a long, sometimes painful journey.
And we didn't realize, like, right off the bat that we will be building a database, right?
We were building a Python framework.
And the Python ORM, essentially.
And granted, that ORM was...
Right.
A better way to talk to databases in Python was your idea, right?
Yeah.
Yeah, exactly.
But I guess you didn't have in mind that you would also build the database.
No idea.
Yeah.
Very cool.
Well, I think what you built is pretty interesting,
and people are going to enjoy checking it out.
But more so, I think what is pretty interesting is there's a lot of things in the Python space that we enjoy and we appreciate,
especially what I would consider to be the advantages of modern Python.
I don't know how you feel about it.
I know you've been deep in this world.
But to me, it seems like just two or three years ago, people building frameworks, you know, think FastAPI or Pydantic or stuff like that,
have really embraced the...
They've taken full advantage of Python 3, right?
They said, oh, look, we have these typing, we have typing, we have ASIC and away.
We have all these things that we can bring together.
And it really feels like that stuff is all starting to come together in a big way.
Is that over the last couple of years?
What do you think?
Yeah.
I also have this feeling that the ecosystem becomes more and more robust, that people build amazing systems with Python.
I think that asynchronous IO played a part in it for sure.
But I think that the other big thing that is happening to Python right now is strict typing.
mypy and the other similar tools.
This is what actually allows you to manage your code base at scale.
And this is just incredibly important.
So yeah, those two things I would say.
Absolutely.
And you talk, we're going to get into it when we get into the architecture and stuff, but you talk about using Cython for making parts of your Python code faster.
And of course, that relies heavily on typing.
Because you want to say, here's an int 64.
Don't turn it to a pi, you know, pi long object pointer.
We just want an int 64 that works on the stack really quickly, right?
Yeah, yeah, absolutely.
I mean, it's an open question.
Will Python ever enjoy strict typing that the Python interpreter actually takes care of to make things run faster or not?
But for Cython, it's absolutely critical.
And actually, I had this, sometimes I had this feeling that writing code in Cython is easier than in Python because, hey, I have a compiler.
Something mismatches.
I know it at the compile time, not the run time.
Yeah.
I suspect myPy is a little like that as well, right?
Exactly, exactly.
So when myPy started happening, because I was experimenting heavily with Cython before myPy became popular, when myPy finally became like this common thing to use.
Yeah, it was almost a revelation that we finally have this beautiful workflow with Python.
Well, I want to talk about some of the technologies that are sort of surrounding this larger project that you've been working on.
So over on GitHub, github.com/magic stack.
This is for, this is your company.
And one of the, you know, where sort of EdgeDB and all that is coming out of.
But there's a lot of interesting things happening here that I think people who see modern Python doing its thing are going to appreciate.
We talked about the async stuff and so on.
And so I wanted to kind of dive into some of those first that are sort of orbiting your projects that you all have created here.
So let's start with Magic Python.
Tell us what this Magic Python is about.
So Magic Python is a syntax highlighter.
It's actually used in VS Code by default.
So if you use VS Code and you edit Python in VS Code, this is the stuff that VS Code uses under the hood.
It was used by GitHub for years to highlight all Python code.
And recently I think GitHub switched to this tree sitter other Python highlighter.
But yeah, Magic Python was, and I guess is, incredibly popular.
It was born out of frustration actually because we were big fans of metaprogramming.
We abused Python a lot in interesting ways.
And one of the ways to abuse it was to push some meta information to function annotations.
It was before mypy and before typing.
So yeah, we just were like adding stuff to those annotations.
So we quickly discovered that built-in syntax highlighters in TextMate back then.
Back then I was using TextMate heavily.
They just couldn't highlight annotations.
So my goal was to basically, hey, can we create our own syntax highlighter for Python that would just take care of annotations?
And by the way, highlight all of the newer stuff that is available in Python 3.
Because back then Python 2 was still the king.
And Python 3 was kind of barely supported.
Interesting.
So a lot of the highlighters and editors and stuff really would highlight kind of based on Python 2 type syntax.
Exactly.
But I guess.
No, it's 20, whatever this was, in 2015 or something.
2015.
Yeah, yeah.
It was clear to me that Python 3 is the future.
But yeah, the industry was still kind of moving slowly towards it.
But the key innovation of Magic Python, and I think this is why I think it's a high quality thing, is unit tests.
So I'm a big fan of writing tests and having this test-driven development.
And the first thing after highlighting Hello World in TextMate, first thing for me was to figure out, can I actually build a unit test engine?
Because if you think of those syntax highlighters, it's essentially, it's a huge reg exp.
It's just mind-bogglingly, like huge, huge, huge reg exp.
And writing reg exp is hard.
Yeah.
But modifying them is much harder.
I was thinking about that.
Well, I was thinking down the road, you have a really interesting query syntax that's pretty rich and powerful for EdgeDB.
Yeah.
Did your experience writing Magic Python give you the ability to go like, oh, yeah, we can write this thing that parses this insane sort of complex language?
How much did this play into your ability to go beyond SQL?
I wouldn't say much.
I mean, we have syntax highlighters for our schema files and the EdgeQL.
They're pretty basic right now.
We just highlight keywords and literals.
We have some interesting plans about that.
And we can talk about that later.
I guess we'll be talking about it to be like implementing language server protocol for EdgeQL.
But the highlighter itself is pretty simple.
But I used this unit testing framework in those highlighters.
And this is what gives me peace of mind.
I know that EdgeQL highlight is just working when I'm adding like a new operator or a new keyword.
I don't have to just test it manually on some big file.
Yeah, absolutely.
Sort of speaking to that thing that I talked about, a lot of interesting stuff coming out of your work.
Adrian out there says, didn't know you also made HTTP tools as well.
Indeed, yeah, there's a lot of cool stuff that you've done.
So final thing on Magic Python.
Can I use it for other purposes than just VS Code, Sublime, and Atom?
Like if I wanted to build my own thing that, you know, printed out like terminal stuff or like even some other kind of UI app.
Could I use this more generally than the editors?
I haven't tried it myself.
But given that GitHub was using it to highlight the code, I believe that there must be some libraries and packages that just can consume this text-made inspired syntax and just highlight, I don't know, stuff you print into terminal.
I see.
So it comes out as text-made and then it just happens to these three editors with their...
Yeah, I think...
Sort of common heritage, understand that.
Yeah, yeah.
I think text-made started the revolution originally, then Sublime Text just inherited the format and then VS Code just decided, hey, we should just use it.
Yeah.
Cool.
Yeah, very cool.
All right.
So when you spoke about your journey towards creating this product in this business, you talked about how central having asynchronous IO and server work is going to be.
And of course that is true, right?
Not all databases, but most databases are able to be a point of extreme concurrency to the point that they can handle the processing, right?
So if you've got a web app, you can scale your web app out.
And if it's got two connections or 200 connections to the database, generally, that's fine.
The database is meant to sort of scale that vertically, I guess.
So you really talked about, well, if you're going to do this in Python, that probably means leveraging asyncio pretty strongly, right?
Yeah, yeah.
It was pretty clear that we need asynchronous IO.
As you said, databases have to handle lots of connections.
And also it's important to understand that most databases like Postgres, for example, the cost of establishing a new connection is pretty high.
So we wanted Edge.
And I mean, there are tools to mitigate that.
Like PG Bouncer, for example.
It's like middleware you put in front of PostgresQL to make connections cheaper.
And we just didn't want to have any of such tools as a requirement for Edge.
We just wanted it to work like natively out of the box without any configuration.
So yeah, we had to have cheap connections in terms of like how fast you can connect.
And also, I mean, if your connection is just hanging out there, we wanted to allow that essentially.
So we had to have a way to handle thousands, maybe hundreds of thousands, just concurrent connections that maybe are not super active, but just, I mean, open.
And asynchronous core is the only way how you would be able to do this.
Like not even like even if Python didn't have GIL, for example, you would still use asynchronous IO to tackle this problem.
This portion of Talk Python to me is brought to you by Sentry.
How would you like to remove a little stress from your life?
Do you worry that users may be encountering errors, slowdowns or crashes with your app right now?
Would you even know it until they sent you that support email?
How much better would it be to have the error or performance details immediately sent to you, including the call stack and values of local variables and the active user recorded in the report?
With Sentry, this is not only possible, it's simple.
In fact, we use Sentry on all the Talk Python web properties.
We've actually fixed a bug triggered by a user and had the upgrade ready to roll out as we got the support email.
That was a great email to write back.
Hey, we already saw your error and have already rolled out the fix.
Imagine their surprise.
Surprise and delight your users.
Create your Sentry account at talkpython.fm/sentry.
And if you sign up with the code talkpython, all one word, it's good for two free months of Sentry's business plan, which will give you up to 20 times as many monthly events as well as other features.
Create better software.
Delight your users and support the podcast.
Visit talkpython.fm/sentry and use the coupon code talkpython.
There's an overhead for threads and the context switching between the OS trying to figure out if that thread still needs to do stuff.
Yeah, you can't have hundreds of thousands of threads and be in a good place.
Yeah, but my concern wasn't even that.
Maybe we would be smart and implement some sort of M2 and scheduling or something like that.
I don't know.
It's just I don't believe that humans are good at writing threaded code.
Async await gives you this luxury of essentially seeing where you can actually give up control.
of the current code when it can await things and potentially switch the context, right?
So you can be smart about locking access to shared resources and things like that.
With threads, it's way, way harder.
Maybe with Rust, it's easier because, I mean, there is some compile time magic that can help you.
But with pretty much every other language, thread-based programming is very hard.
It is hard.
Well, I suspect many people, but not everyone out there listening knows that when you use the asyncio tasks and so on, at least by default, they run on a single thread.
There's not actual threading happening.
When you use threads or multiprocessing, you can get that true concurrency.
But this is different.
It's not really threads.
Yeah, it's different.
Basically, the idea for async await is to use it for IO bound code.
So if your code is doing like lots of IO, pushing data from multiple connections here and there, this is an ideal thing.
But if you're computing something like, I don't know, doing something, scientific computation or just use blocking IO or disk IO, it's best to offset that computation into a separate process.
But yeah, if you just want to handle a lot of IO in Python concurrently, asyncio is the way.
Yeah, the way that I like to think of asyncio and async and await is what you're scaling is you're scaling the waiting.
If you're waiting on anything, if I'm waiting on a database or waiting in the database version for the client to talk to me or not to talk to me, then you can basically take that period where you'd be waiting and turn that into predictive computational time.
I love it.
I think we should put this like straight into the ducks.
I've never thought about this week.
Because people tell me, I'll see these benchmarks and stuff said, oh, well, I did this thing where I overwhelmed the database and then it didn't go very fast when I did asyncio.
It's like, well, because there's no period in which you're waiting.
Like you're like constraining the resource beyond what it can take.
But if there was some sort of, oh, I'm waiting for this thing to get back to me.
Well, then all of a sudden there's your performance.
Okay.
So when I saw this come out, I was super excited.
I think this was 3.4.
My history reminds me correctly when this came out.
Is that, do you remember?
I think it was around 3.4 because the most important prerequisite.
I think so.
Because 3.5.
Yeah, go ahead.
Sorry.
Yeah, the most important prerequisite for asyncio to happen was actually the yield from syntax.
Probably not a lot of people remember about it.
But back then, asyncio required this like add-corting decorator and you would use yield from instead of await in your code.
So that PAP, so basically Python 3.3, I think, was a moratorium on modifying Python language.
So we had to wait for Python 3.4 to add yield from and then asyncio happened.
We made it happen.
Right.
That enabled it.
But when I remember when it came out, I was like super excited about this.
And I said like, oh, this is a harsh programming model.
This is really like direct and juggling those sorts of things.
And I had experience with C#, which had async and await keywords as well.
I'm like, gosh, I wish this language had async and await.
And then I didn't know you then, but I thank you because you authored PEP492 coroutines with async and await.
Basically, we have async and await in Python because of you, right?
Well, somewhat.
Yes.
I don't want to give you too much credit.
I did.
You created the PEP that said like, let's stop using yield from and continue and all these other things that you do.
I can tell you the entire backstory.
It's relatively short.
Yeah.
So basically we were trying to figure out like the future API for HDB, Python client back then when HDB wasn't doing a thing.
And we knew that we want to support asyncio in our future client.
But how do you actually have like a migration block?
Like you would have to say like try, finally accept, back, commit.
It's like a lot of code.
And we have context managers in Python, right?
So with the context manager, you would just say with transaction and just do all this magic behind the scenes.
But we didn't have an asynchronous version of with.
We had yield from.
But how do you kind of mush together yield from and with wasn't clear.
So I thought, hey, if we have like async keyword, we could have async with.
Then it was natural case.
We just should replace yield from with await because it was also familiar with C#.
And I also liked the short and neat syntax of async await.
And then the next thought was that, hey, what if you have a cursor to the database and just want to iterate over the rows and make it like prefetch those rows.
And this is how async four was born.
And then in about a couple of weeks, language summit happened.
I think it was in Montreal.
That was back on US in Montreal.
And I met with Guido.
I showed him like rough sketch and he said, yeah, let's do it.
I think I implemented the first prototype of this thing in the interpreter over a couple of nights.
Like I just called it like straight 48 hours.
I wanted to impress Guido.
And yeah, I just had this like rough implementation.
And then just over the course of like months and a half, I was refining it and writing this path.
And this is how it happened.
I think it all happened because of Guido.
Because first of all, he saw like clearly like this is an improvement to Yulthrom, like a big improvement.
It's a huge improvement.
It makes it incredibly approachable.
It's like you do what you normally do, but sometimes you might have to put the word await there.
Exactly.
But your mental model isn't about callbacks and weird stuff like that.
It's just like you write the regular code, but you sometimes need to await a thing.
And it's beautiful.
Yeah, exactly.
Exactly.
And yeah, I'm grateful to Guido because first of all, he recognized this thing and encouraged me.
And second of all, he actually like inspired lots and lots of refinements in this proposal.
And I was like working with him essentially all this time.
Like a discussion happened in Python, in Python dev.
And sometimes he and I exchanged emails and he proposed some ideas and I would just tweak the path.
Yeah, Guido was actually also behind this proposal to a big extent.
There's some mind-blowing stuff here, like the async with, for example, as you point out, right?
These are wild ideas, right?
Instead of just calling, just saying here, there can be a function.
You have async for, async with.
There's really neat things in here.
Actually, yeah, I think that still async with is pretty unique.
Like JavaScript, for example, is lucky because they have this nice syntax for declaring anonymous functions, right?
And so you can just say await transaction and pass a function.
And it's like a multi-line function.
You can do whatever you need.
You don't actually have to have something like async with in TypeScript or JavaScript.
But in many other languages, you would need something like this.
And pretty much, I think, we pioneered this idea in Python.
I think I saw a proposal to make using async in C#, but I'm not actively engaged with C# community.
So I'm not.
Maybe it was implemented.
Maybe not.
I don't know.
That would be the parallel, but I'm also not tracking it.
Yeah.
Okay.
This is really cool.
So awesome, awesome work on this PEP and getting this language.
Thank you.
Yeah.
So let's talk two more async I think real quick here before we get to EdgeDB.
Or actually, three.
One jumped the list just yesterday.
Absolutely.
Okay.
So when you're doing asyncio, there's this background event loop that looks at all the things that could be done and says, are any of them waiting?
Can we take that while it's waiting and put it aside and go do something else, right?
That way I scale the waiting story.
And there's an implementation for that in CPython.
But you all decided, you and Elvis, your co-founder, decided it would be nice if there was a faster, more optimized version of that part that does the checking and execution.
So you created this thing called UV loop, an ultra fast asyncio event loop.
It's incredibly easy to use, right?
Like to install it.
Two lines.
It's two lines, right?
You import and then you run install and you're good to go, which is fantastic.
Tell people about UV loop and how broadly, should this just be standard stuff we do in all of our code that uses async and await?
That's an interesting question.
Okay, let's jump in.
So UV loop wasn't the first thing that I created.
The first thing was actually HTTP tools.
Someone asked you about it like a few minutes ago.
So I just wanted to experiment with Cython.
I discovered Cython.
I thought, hey, this might actually be a useful tool and allow us to speed up Python a lot for some things like parsing HTTP, for example.
Right.
The tight loops.
Yeah.
Exactly.
So I look at Node.js and they used a C HTTP parser.
I think that parser was actually extracted from Nginx.
And yeah, just wrapped it in HTTP tools.
Just literally like 100 lines of code, maybe even less, maybe 50.
Just like a small wrapper over the C library.
And it worked.
And it worked great.
Then I, oh my God, I now have this superpower.
I can quickly.
What other things can I grab and wrap up and put it into PHP?
Exactly.
Because, I mean, you could do the same, but just like using Python C API, but you would end up writing like 3x, maybe 5x amount of code.
And using Cython just feels like magic.
So, yeah, it worked.
And then I was like, hmm.
Interesting.
So there is this libuv library that actually powers Node.js and it's cross-platform.
And it's super fast and Node.js is fast.
Maybe, just maybe, I can do the same.
I can just wrap it into Python and make a drop-in replacement for it eventually.
So I prototyped something relatively quickly.
Maybe in a few days.
Basically, I just implemented like a loop object and call soon.
Like, basically the staple of ACKIO.
The most basic thing.
And it worked.
It worked just fine.
I was able to implement call later.
And then I was able to run a coroutine like, await sleep one, print hello world.
And it worked.
And then I just, over the course of next several months, I think three, maybe four, maybe five months.
I was gradually implementing AsyncIO API.
I swearing a lot because I discovered that this API surface is just huge.
AsyncIO event loop is just, it's an enormous API actually.
And yeah, then we, we posted benchmarks and I think it went somewhat viral.
It was in HN.
I think it was like post number one on HN for a long time.
Yeah.
I think Brian and I covered it over on the Python Bytes podcast when it came out because it was, it was big news.
Yeah.
People are excited specifically because basically we showed that you can write some Python code, like a simple protocol parser, and it would be almost as fast as Go.
And sometimes it's on faster than the Node.js, which was surprising.
So yeah, I think a lot of people were excited about it.
Yeah, that's fantastic.
So the, the quick takeaway here is UV loop makes AsyncIO two to four times faster.
You've got some benchmarks for different situations and amount of data and so on with regard to sockets.
So let's wrap this one up with, is that a universal statement that you would recommend there?
UV loop.install?
It depends.
I think for production, it makes a lot of sense to use UV loop or you should try it because I mean, there are still some minor incompatibilities in UV loop.
That are really hard to track.
Maybe there is some behavior difference, or maybe there is a box simply using something that a lot of people are not using with UV loop.
And it's still a possibility.
So yeah, use it, use it with care in production.
In local development, I don't think you need it.
Like vanilla AsyncIO should be, should be plenty.
There is one more interesting thing about UV loop.
It's a package.
It's a package on PyPI.
So if we find the bug, we fix it and we publish a package.
You don't have to wait until Python 3.11.7 to get your bugs fixed.
Or improvements made.
Yeah.
Or improvements made.
Exactly.
So this kind of suggests that it's a great idea to use UV loop.
But on the other hand, we really haven't had like any emergency releases or anything in a long time.
We basically release almost like every year just to catch up with the latest Python version.
I would say that UV loop is pretty stable at this point.
Yeah.
Very cool.
Yeah.
It definitely seems neat.
I think also it's probably a context of when does it make sense, right?
If you're running three tasks and that's your whole program, who cares how fast the event loop is?
All right.
It's three tasks.
But if you have many, many fine grain, tons of little tasks and there's lots of, like how complex and how many tasks,
like basically how complex is the task coordination job of asyncio, right?
The more complicated it is, probably the better benefit you'll get from UV loop.
What do you think?
If you go deep in the details, I would say it's not so much about juggling tasks around.
It is more about performing IO in the most optimal way.
Okay.
And LibUV is just because it's so low level.
It just uses lots and lots of tricks under the hood to just do IO faster.
And the entire loop of like calling callbacks in the loop is just,
it's a tight loop in C essentially.
So it's much faster than a loop in Python.
So that actually, yeah, those two points.
But yeah, the performance improvement is noticeable usually.
Very noticeable with the UV loop.
Cool.
The benefit is if it's literally import UV loop, UV loop dot install.
Yeah.
Run your benchmarks.
Comment that line out.
Run your benchmarks again.
Exactly.
It's so easy to, you don't have to commit to it.
It's not like, oh, we're going to swap ORMs and try it again.
Exactly.
Yeah.
But I just love packages in Python that do this magic.
Like if you remember, there was this package called psycho created by Armin Grigo, creator
of PyPy.
You just import psycho, psycho install or something like that.
And boom, you have like an alternative CPython eval loop.
Your program just magically becomes five, ten times faster.
It's just magic.
So yeah, it's great when we can do something like this.
Yeah, that's fantastic.
Adrian has an interesting question.
I know this came up around requests a couple years ago.
He asks, could you give your thoughts on having things as part of the standard library?
Basically having UV loop in this case be part, you know, be the replacement for asyncio loop
rather than having an external package updated independently.
Yeah, it's an interesting question.
And I'm not super involved in conversations like this.
I know that Python core developers consider it actually separating standard library
and shipping of them aside so that it can have like its own release schedule.
I think it's sort of mitigated with Lukasz Lang actually speeding up the release cycle for
Python now.
It's being released like every year, which is amazing.
And I think the pressure is lower now to separating standard library.
As far as including UV loop as part of standard library, I'm not sure it's a good idea.
First of all, it's entirely in Cython.
It's like 50,000 lines of Cython or something like that.
We will have to either adopt Cython as like an official standard library tool or rewrite it in C.
And if you rewrite it in C, it's going to be 100,000 lines in C or something like that.
It will be huge.
So probably not going to happen anytime soon.
Maybe with things like mypyC, we can make it happen eventually.
Yeah, that's interesting.
But mypyC is still pretty early.
Right.
Okay.
Yeah, the conversation was had around that with regard to requests as well.
Maybe you're even part of it since you're a core developer.
But they decided not to make requests the new HTTP library of CPython because it would hobble requests.
Like it would mean requests could only be changed, you know, once every 12 months or something like that.
Right?
Yeah, I think one of the concerns with requests specifically, and I wasn't actively involved in those conversations at all.
But I think the concern that I heard was that HTTP is pretty wild and you often need to fix some security issues and bugs and you need to act quickly.
And if something as huge as requests and so fundamental as requests was part of standard library, we would just have to be like way more flexible about making bug releases for CPython.
But Python is just, it's such a huge thing, right?
Like operating systems bundle it, like multiple different workflows are centered around it.
It's just...
It runs on helicopters in Mars.
I mean, come on.
Exactly.
There's a lot of edge cases.
People are not thinking about it.
Exactly.
Just upgrading a separate library is so much easier than upgrading the entire Python thing.
So, yeah, I think this is why packages like requests for sure will stay out of standard library.
Yeah.
All right.
Final question before we move on from UV loop, because it's not even our main topic, but it is very interesting.
Teddy asks, are there any trade-offs of using UV loop as opposed to the native built-in one?
I think this is time for me to make a shout out because we still haven't implemented a couple of APIs that are in AsyncIO, like API balls protocol.
Maybe there is something else.
I just haven't got time to do it myself.
We are busy with SGB.
So if anyone wants to join the project and help, that would be great.
And that basically answers the question.
The fundamental APIs are already all there.
It's almost 100% compatible with UV loop.
No...
With vanilla AsyncIO.
No trade-offs except there are a couple of relatively new APIs, I think path 3.9 and path 3.10 that are still missing from UV loop and that we still should implement them.
Yeah.
To be a true replacement, right?
Yeah.
I think it's sent file and API balls and maybe something else.
Okay.
UV loop is running inside EdgeDB?
Yeah.
It powers the IO server.
Basically we use multi-processing architecture in EdgeDB.
We have a pool of compiler processes because this is like computation CPU heavy thing to compile your query.
And then there is a core IO process that just runs UV loop and quickly, quickly, quickly goes through your connections and pushing data between clients, posts, etc.
This portion of Talk Python to me is brought to you by SignalWire.
Let's kick this off with a question.
Do you need to add multi-party video calls to your website or app?
I'm talking about live video conference rooms that host 500 active participants, run in the browser and work within your existing stack, and even support 1080p without devouring the bandwidth and CPU on your users' devices.
SignalWire offers the APIs, the SDKs, and Edge networks around the world for building the realest of real-time voice and video communication apps,
apps with less than 50 milliseconds of latency.
Their core products use WebSockets to deliver 300% lower latency than APIs built on REST, making them ideal for apps where every millisecond of responsiveness makes a difference.
Now, you may wonder how they get 500 active participants in a browser-based app.
Most current approaches use a limited but more economical approach called SFU, or Selective Forwarding Units,
which leaves the work of mixing and decoding all those video and audio streams of every participant to each user's device.
Browser-based apps built on SFU struggle to support more than 20 interactive participants.
So SignalWire mixes all the video and audio feeds on the server and distributes a single unified stream back to every participant.
So you can build things like live streaming fitness studios where instructors demonstrate every move from multiple angles,
or even live shopping apps that highlight the charisma of the presenter and the charisma of the products they're pitching at the same time.
SignalWire comes from the team behind FreeSwitch, the open-source telecom infrastructure toolkit used by Amazon, Zoom, and tens of thousands of more to build mass-scale telecom products.
So sign up for your free account at talkpython.fm/signalwire, and be sure to mention Talk Python to me to receive an extra 5,000 video minutes.
That's talkpython.fm/signalwire and mention Talk Python to me for all those credits.
So another thing that came out just today, I know this is, I don't want to spend too much time on it, but there's a big new feature for tasks and async.io in Python 3.11 coming very soon.
And you just gave a shout out on Twitter yesterday saying that task groups is coming to async.io.
This is a way, because right now if you start two tasks, there's no way to say, well, if this one fails, don't even bother running that one, right?
They're fully independent.
This is a way to sort of create a dependency and control them as a set, right?
Tell us real quick about this.
I have an API for spawning tasks concurrently.
It's called async.io gatherer, but it's just a suboptimal API in many ways.
And this API is like way superior.
We have to credit Nathaniel J. Smith for his work on Trio and Trio Nursery specifically.
And Trio is, I mean, we can run an entirely different podcast episode just about Trio and async.
I actually had Nathaniel on, yeah, we talked about Trio on the show quite a while ago when it was fairly new.
It's an amazing thing and there are lots and lots of great ideas in Trio.
One of them is having this thing, it's called nursery in Trio and the async and the task groups,
async.io task groups, essentially, they just replicate this nursery idea.
They port it from Trio to async.io.
Like the bigger points about how this API works are all similar to Trio.
There are some details about how constellation works, et cetera, but most people probably won't really care about that one.
Yeah.
Okay.
Very cool.
It's great to see more innovation.
Yeah.
And the async.io.
Yeah.
But task groups, I'll just talk for a couple more minutes about task groups.
So task groups was like a more requested thing.
A lot of people wanted task groups in async.io.
And I was DMed like, sometimes I was DMed like on a daily basis entirely.
Like we promised us task groups.
When can we have our task groups?
So the big like elephant in the room with task groups is how do we handle exceptions?
Because multiple things can fail at the same time and the essential will propagate out of this async with task group.
You'll end up with a hierarchical tree of exceptions.
Exactly.
And we just had to figure it out.
And we had to figure it out in the core because if it was just some, I don't know, some exception class defined in async.io, then what would happen when you, when your async.io program crashed?
Right.
You wouldn't have like a correct state, a trace back in your terminal.
You wouldn't be able to understand what actually happened.
So we had to integrate this into trace backs and like a debug.
We needed to make sure that it's like a standard thing that tools like Sentry, for example, can take advantage of it and provide you like great visibility into what happens in your async application.
So we had to work in this exception group thing.
And there's this amazing new core developer, you read CatRiel and she spearheaded this effort of just implementing this and drafting a proposal and just doing it to completion essentially.
And it's because of her work, actually, task groups are finally a thing because task groups themselves, it's like 100 lines of code.
There is with comments, there is not much to them.
The huge thing is getting exception groups in.
And I believe Python is the first language that has this feature, like right in the syntax, right in the runtime model.
And this is also huge because I actually believe that Python now can be like one of the best languages to do concurrent programming.
And I don't know, maybe when we have JIT or something like that, it might actually match a goal in performance somewhat.
Yeah.
Would be ideal thing.
So while I'm looking at this syntax here, which I'll try to quickly simply communicate to people listening on audio.
It's an async with block.
So what you do is you'd say async with asyncio dot task group, and you create this task group and then you can create tasks within there that are all grouped together.
And then you also can do things like await stuff while you're in there.
It looks to me like one of the things that often I don't see possible in Python's async.
Previously, it's the ability to just fire off a task and have it sort of just run in the background to completion.
So you don't have to do like async or like run all or gather or any of those types of things.
Basically, the width block, we won't exit the width block until all the tasks are finished or until it fails.
One of those two, right?
Yeah.
That's a cool feature of it alone to just kind of say like, I don't need to kind of store up all the tasks and then make sure I'm waiting on them forever.
Like I can just kick them off and then like if they happen to start in this place, then they're going to finish when this width block finishes.
I'm even more excited about this than I was before.
Right, right, right.
It's a nice API to compose things in asyncio.
And I believe it's one of the bigger deals in the recent years.
So I'm super excited about this.
3.11 is out soon.
Exactly sure the release date.
I know it's in alpha stuff right now.
So it's getting real near.
Yeah, yeah, it should be should be close.
Yeah, for sure.
Awesome.
All right.
Last thing before we get to EdgeDB proper people.
I would say that Postgres is the most popular database for Python people doing database things, possibly with the exception of SQLite.
But that really counts for just like, oh, I'm doing testing or oh, I use this for this incredibly small, but like production level stuff.
Got to be Postgres, right?
Yeah, yeah.
It's fair to say.
Yeah, maybe throw in some MySQL and then like a little bit down, maybe some MongoDB, something like that.
But like, clearly, it seems like Postgres has a lot of interest for folks.
If you want to talk to it through async and await, which is exactly how you want to scale your database stuff.
A pretty popular library is this one called asyncpg, right?
Yep.
Yeah, you and Elvis created that, huh?
Yeah.
So yeah, it was an interesting experience.
Basically, we knew that the EdgeDB will be based on Postgres.
That was clear.
They won.
And we also knew that we have to have like this very high performance bridge, essentially, between Python and Postgres.
And it had to be asynchronous.
So there was no good asynchronous client for Postgres back at the time.
And we couldn't just use PsycAPG, the most popular Postgres driver, because it uses text encoding for data.
Maybe not anymore, but it used to have text encoding.
And we actually had to use binary for something.
So we just knew that, okay, we have to just jump in and explore Postgres protocol.
And we decided, okay, let's write the driver.
Yeah, this is how Async PG was born.
And I think what makes Async PG different, just besides that it implements binary protocol and it's asynchronous, it's API.
Because we were not basing it on the common Python DB API.
We basically designed an API to be as low level as possible, as close to Postgres semantics as possible.
So in DB API, there is this thing called cursor, which has nothing to do with the actual database cursors.
So we didn't want to replicate that.
So yeah, we just built like what we thought were proper primitives, working with Postgres as efficiently as possible.
We used binary protocol plus Async I/O.
And we of course use Cython to speed up like all the bottlenecks in it.
It's pretty much entirely in Cython actually.
And yeah, the result is just amazing to this day.
Async PG is like one of the fastest Postgres clients on the planet across all languages.
That's fascinating.
You can see that it beats Node.js and go pretty handily there.
Yeah, we should probably update this chart actually.
I'm pretty sure that they updated PG library for Node.js.
So this is outdated.
I think it's closer in performance to Async PG, but I think Async PG is still the fastest.
Yeah.
Cool.
Awesome.
So taking all these together, UV loop, Async and await in the language, Async PG, all of these are building up your skills to sort of almost build a database.
And so then you went on and actually did build a database, right?
Yeah, pretty much.
So we had this framework, which was like almost an arm in Python for many years.
And we built multiple different production applications with that.
We shipped applications that were deployed to GE, Cisco companies like that.
And we knew it's something interesting, but we also knew that it has to be bigger than just a Python or like it has to be a database.
It's a surprisingly long road to make something to go this path essentially, because you have to define a query link.
You have to define type system, you have to define standard library, you have to define protocols, how it works, how migrations work, all the different syntaxes for schema modeling.
It's a huge thing.
And yeah, with like all the right primitives in Python itself, we knew that we can start like morphing our code base into like this separate service essentially.
And yeah, that was the necessary and required groundwork to make HDB happen.
Without it, we would probably not succeed.
Cool.
So HDB really written in Python?
It is.
Mostly.
Yeah.
Mostly.
Entire like IO service server is essentially a Cython thing.
So it's in C and this is why if you look at benchmarks of HDB, it's actually pretty close to Postgres, to vanilla Postgres.
Like the overhead of HDB is super low.
That is only possible because of Cython and like all low level tips and tricks that we learned when we were working on UV loop and the asyncPG.
So we really optimize it a lot.
Yeah.
The compiler part, the thing that actually takes an HQL query and compiles it to SQL, that thing is pure Python and that runs in a separate process.
But we do some also tricks to make it fast.
Like we cache things aggressively.
I mean, in most applications, you don't have thousands of queries.
You only have like 10, 50, 100.
Yeah.
So they get cached pretty quickly and then you don't even run Python anymore.
From that point on, it's just C.
Oh, interesting.
Yeah.
You don't need to incredibly optimize the understanding of the query because like you said, it's not ad hoc stuff happening that happens at scale.
Exactly.
I mean, it's great when your compiler is exceptionally fast, but for a database and especially if it's smart around extracting constants, let's say you send a select one and then your next query is select two.
Essentially it's the same query.
Substitute the same query, just different constants.
So if you extract it and you cache the file query as if this wasn't the constant, but the argument the query, then yeah, you don't need to compile it for the second time.
So yeah.
Yeah.
I don't know Postgres super, super well, but I know some databases, they at their level, when they see a query, they're like, oh, I've seen this query before.
They can cache the query plan and those types of, so that's like another level of performance and speed up as well.
Right.
We do that as well.
Um, I mean, we did it even in async Pg, for example, async Pg automatically prepare statements for you to enjoy this optimization.
So that Postgres doesn't have to reparse or SQL query can just execute the precast plan.
We do the same in HDB and many other things.
This is why HDB is kind of, it's based on Postgres, but it fully envelops Postgres because we want to be in like full control on the underlying Postgres instance.
Right.
So in some sense, this is a brand new database that's got some really cool features that I'm going to ask you about.
very soon.
Absolutely.
But in the other sense, it's got a lot of stability because it's kind of a database level API rethinking of a well known core that people already trust.
This is an interesting thing.
Actually, a lot of people are not 100% satisfied with relational databases for a variety of reasons.
Somebody.
Yeah.
Somebody is not satisfied with scaling.
Some are not satisfied with SQL and some not satisfied with migrations and how rigid the schema is and how inconvenient it is to deal with the relational database.
And so it's a huge problem.
You have a part of it, which is just language design and by standard library and type system, how that part works.
The second is workflows around your database.
The third is the engine of your database, like how it actually works.
EdgeDB wants to challenge everything, but we also not dumb enough to challenge everything.
At the same time, we understand that just writing this whole thing from scratch is impossible.
No company in the world would be able to pull it off.
Well, maybe some companies would be able to, but they're definitely not a startup.
But they have many, many employees.
Exactly.
And they're probably public.
Giant tech companies.
Exactly.
So for us, the only viable strategy was to pick a database that is already trusted, that is already fast and universally loved, which is Postgres.
And it's also incredibly capable and just build on top of it.
And it's not actually a new approach in databases.
Like lots of databases actually are built on like primitive key value databases, like level DB or something like that.
It's a popular approach.
We're just taking it further.
We are saying that, hey, using a key value storage won't buy us much.
We are like high level programming language requires a lot of code to be written to properly be executed in good time.
But SQL looks like this nice compile target.
So this is why we use Postgres.
Yeah.
Very cool.
Kind of the TypeScript to JavaScript equivalent of the database query language in a sense.
Yeah, pretty much.
I mean, sometimes I explain HDB as LLVM.
Like imagine LLVM, it compiles your high level code to low level code and then it, et cetera.
And the same about HDB.
We compile your, like high level schema to like a proper normalized table layout.
We compile our HQL, high level query language down to SQL.
SQL and that SQL can actually be jittered by Postgres.
So essentially, ultimately your HQL might be executing with like at native code speed, not now, but in the future.
So what's the elevator pitch for people who are out there?
They're slightly, you know, not super thrilled about the database they're necessarily using, whatever that is.
And they're kind of exploring.
I picked up a few things that I think make it unique, but I want to ask you, it's your baby.
All right.
I guess I'll give two pitches.
One is super high level and one is slightly more low level.
A super high level pitch is that imagine you have a tool and when it's a great tool, it becomes an extension of your hand.
Essentially, you just don't notice it.
You just do things, right?
Current databases are not like that.
They require lots and lots of mental overhead to work with them.
Like what one library do you use in this language?
Right.
Is there lazy loading and N+1 stuff I got to consider or is it not and all those kinds of things?
Exactly.
And then you have to learn their API and then you have to learn SQL and understand how those things interact with each other.
And then you have to care about deployment and migrations.
It's just so much headache.
This alone explains why MongoDB was so popular and is so popular because a lot of people just decided, okay, to hell with that.
I don't want to deal with this.
I believe in the relational space altogether.
Yeah, exactly.
Just abandoning this train.
Yeah, and we want to fix all of that in HDB.
We want to give you a tool that you just don't notice.
We want to give you a data model that just feels native to Python or TypeScript or Go or any other language.
You don't have to think in tables anymore.
I want to give you a query language that is super easy to use and learn and compose and build query builders around.
And essentially we want to essentially kill the entire concept of ORM.
We don't need it anymore.
We are almost sorry that ORMs have to exist in a way.
I was going to ask you about that.
There are so many incredibly difficult problems.
This problem is called object impedance mismatch there.
Yeah.
And tables to like objects.
It's a super hard problem.
I feel sorry that they have to go through this.
But we just looked at this problem and decided, hey, can we actually just solve this object impedance problem in a different way?
Can we just avoid solving it entirely?
Can we just give you a database with the proper high level data model that doesn't have this problem at all?
Sure.
And then suddenly you don't need ORMs.
Let's talk real quick about the actual way you define what would be the equivalent, I guess, of a DDL table create script or somewhat related to that maybe closer is like an ORM class.
Like it's kind of the...
Okay.
Can I start a little from afar?
Yeah, yeah.
Let's start back.
Okay.
Now it's going to be the second pitch, which is slightly more detailed.
So we say that HDB is a new kind of database.
It's not just relational.
We call it a graph relational database.
Essentially, we are saying that we created an extension to the relational model.
So what actually constitutes the graph relational model?
It's first of all, in all of your like rows, all of your tuples in your relational algebra, they essentially have a globally unique key.
Now, this is a requirement.
So data independent is just UID essentially.
Every row in your database will have it.
This is the first requirement, first modification.
The second extension is links.
The idea that links between data is like a first class citizen of the model.
You don't need join, you don't need foreign key.
You just know that, hey, if this type links to another type, it's just going to be like a relationship between the unique IDs.
This is what unique IDs gives you.
And the second thing is the third thing is that everything is a set.
This, like if you have an object that is connected to multiple other objects, this is a set of objects.
If you have an object that has a bunch of properties, then a set of properties.
Even a single thing is a set as well.
And this later enables HQL to be super composable.
But these are just like three simple kind of axioms that are in the core of the model.
So if you, if we talk about like this schema snippet where we have an object type, a block post with required property content, which is text and required link author, which is another type called user.
It's going to be compiled to a table in SQL with a column called content with a column ID, which is going to be a unique UUID for every blog post that will have it automatically.
It's immutable.
It's read only.
You don't have to create them manually.
And a user will also be a table and also have IDs.
And then we'll have a separate column, which is going to be called author, which you will have IDs of users.
So ultimately, ultimately like deep beneath what you see in edge DB is like this high level schema.
It's all compiled properly for the relational model.
It's all normalized there.
We are still relational.
We still like exhibit like the same, the same characteristics as just, we're hiding a lot of this like low level things.
that you had to bother with with this high level model, just abstracting away the low level stuff.
Is there a way to directly connect to that relational view?
You mean Postgres, the underlying Postgres other ways?
Yeah.
Like the underlying.
I'm not sure even that's necessarily a good idea, but you know, like in SQLAlchemy, there's a way to go like, I just need to get out of here and send raw SQL for a moment.
Right?
Like that feels like that's kind of the same.
I just need to go to the guts for a minute.
Yeah.
So with edge DB, the goal is for you to never actually need that.
There is just one exception to this.
Just one exception.
Ideally.
Yeah.
Okay.
But basically our goal with edge QL, like we knew that first of all, we have to elevate the data and make it more high level.
And second of all, we knew that, Hey, order for a relational database to be successful, it just has to have query language.
Right.
And because our data was different.
We have to come up with our own.
This is how which kill was born.
Yeah.
And we spent years designing edge QL.
And the reason why is because we wanted it to be actually more powerful than SQL in many ways.
Basically, if you have something that is expressible in SQL, but isn't expressible in SQL, we treat it as a bug immediately.
If something is easier to do in SQL, it's a bug.
And this is why we spent so many years kind of refining this thing to make it to be capable of thing.
So basically you never need to use SQL.
You don't need to know about SQL or know about its existence.
And this is a powerful thing because when you use a norm library, you have to know about SQL.
With SGP, no, you just learn one language.
You're good to go for the rest of your life.
Essentially.
There's just one use case when you might need SQL.
It's when, let's say you're a big company and you're using some BI tools like Tableau or something like that.
Graph analysts that already know SQL.
And we're going to do something about it.
We're going to open like a special adapter.
Adapter.
Exactly.
We'll allow you to just run SQL against the database in read-only mode.
That makes a lot of sense.
Because there are these tools, these big BI tools.
And you're like, if your data is here, do you really want to like have some job to move it to another Postgres just to run an analysis on it?
Yeah.
Exactly.
I mean, just like with us not attacking this problem all at once and implementing the engine and the language and everything.
else here, we also understand that we are not going to replace all the business intelligence infrastructure overnight.
Yeah.
And yeah, we have to make it be compatible.
It's not there yet.
We'll be a part of a future release.
Eventually.
You'll have a nice roadmap, which we'll cover in a minute.
But like, I really love that.
Oh my God.
Don't do it.
I can just say it out loud.
Like the ideas that we have.
But let me, like just for people who want to see if they go there, just visually, the way that you've laid this out of like where you are and where you're going.
Like so many libraries and products should model this because so often, you know, you'll reach out to the companies.
Hey, it'd be great if you could do this.
Oh yeah.
It's on our roadmap.
Like, oh yeah.
Well, what is that?
Like some, where do you even have this?
Anyway, I think your roadmap is great, but give us the update.
It is, it is beautiful and I encourage everybody to go and check it out.
It's hdp.com/roadmap.
It's, it is slightly outdated.
Well, lots of things that are in progress were already done.
Yeah.
This formula car here, this is a 2021 series.
They just redid the Formula One cars for 2022.
So yeah, that's probably not what you're talking about.
Yeah.
All right.
So tell us what's coming for this.
What's coming.
It took us years for building HDB 1.0.
And during this time, we were almost encouraging people not to use HDB because it's a relational database.
If you build a business on an alpha version of relational database and goes down, your business will go down with it most likely.
And people should know you just released 1.0, right?
Yes.
That's a huge, huge thing.
Congratulations.
We launched 1.0 a week ago.
It was on Hacker News, number one for like 13, maybe 14 hours.
Wow.
It was a pretty, pretty interesting event.
We also had a live stream, us launching it, talking about architecture of HDB, of the query language, comparing it to SQL.
It's a great event and I encourage you to check it out if you have a live stream.
If you're interested, it's YouTube/HDB.
Check it out.
You'll find it there.
But yeah.
So it took us years to do 1.0 just right.
To make sure that SQL is right, that its design is sound and that the schema is right and the workflows and CLI and the cloud APIs.
Everything is just right and that we are confident that, hey, we're not going to be changing it.
We're not going to be retroactively fixing things.
Took us a long year, many years, but now it's out.
And now we don't want to spend many years on HDB 2.0.
We actually want to make it way quicker.
We have the solid foundation.
We can iterate much faster now.
And this is what we're going to do.
So our current target, internal target, is to release 2.0 sometime in May 2022.
So relatively soon.
2.0 will have a few features.
One is almost implemented.
It's a group by statement.
As I said, the idea of HQL is to actually surpass SQL in capabilities.
And right now with HQL, it's already incredibly powerful.
You can fetch that data hierarchies.
You can compute things.
You can use aggregate functions.
You have sub queries.
You have JSON.
Like it's an incredibly powerful language right now, but a proper group by statements will give it like proper analytical flavor.
Now you will be able to actually create reports and we have a great group by design.
By the way, we try to make HQL design process as open as possible.
We have RFCs.
It's a GitHub slash HDB slash RFCs.
So if you're interested to look at how our group by is different from SQL group by and why it's better than SQL group by, you can just go ahead and read an RFC about our group by.
So group by is going to be one thing.
The second thing is going to be a proper explain for your queries.
Like why is my query slow?
We have some ideas on how to make it less critic than the default explain output that you get most databases.
Then there is an exciting thing.
And I hope that we'll have enough time to implement it, which is access control.
So HDB is this like vertically integrated thing.
So you define your schema and in your schema you can define aliases, which is basically a view in your relational database.
You can define fields or object types that are computed dynamically with that scale.
So schema depends on SQL and SQL depends on schema in HDB.
They are intertwined.
So we have this idea.
It's not that it's like super new, but in HDB it's going to be super powerful.
Is that you'll be able to specify different policies on your schema type.
Like allow reading something or allow mutating something or disallow, etc.
Right.
And we don't want to hard code that.
So essentially we are introducing this concept of context in a database.
You'll be able to define sort of like global variables, like context variables in your schema, say a user ID in 64 and something else.
And then when you just get your connection in your Python code, you say with context plus user ID that is automatically passed to the database.
In your schema, you can implement arbitrarily access logic on your schema type.
And this logic will be automatically enforced in order of queries.
So fantastic.
Yeah, that's really cool.
Fetching data for the home page is filtered.
You are fetching data for report and it only includes the data that your business logic allow it to be there.
So basically with HDB, you will have schema and that schema not only will define just the data layout of your application, but also the access patterns and many other things in the future.
Yeah.
I really want to ask you about the query syntax.
Yeah.
I find it super interesting, especially also how it relates to like ORMs and so on.
But Michael out in the audience has a pretty neat question that sort of follows on to the roadmap first.
So since HDB is fundamentally Python, it'd be great to have a way to run user defined functions in Python, I guess, still like stored procedures, but Python.
Yeah.
Not SQL.
Yeah.
It's an interesting question.
I mean, user defined functions.
Well, first of all, there are like a couple of different planes, I would say, of user defined functions in the context of HDB because HDB has this notion of extensions.
The API isn't public yet, but HDB, for example, supports GraphQL natively.
You can just run HDB, let's say on port 555.
This is the localhost:555/db/mydb/graphql.
We want you to be able to also define potentially, eventually, like user defined API handlers there so that with HDB, you would not need a backup at all if your business logic is relatively simple and you don't need like a full blown application.
Oh, interesting.
So if I've got like something on Netlify where it's pure static code, I just write a little JavaScript, some view or whatever, and it could theoretically do read only stuff maybe to an HDB.
To an HDB instance or something like that.
Or even write only.
Yeah, absolutely.
We just want to kind of push this idea of backendless development as far as we can.
And because HDB has this incredibly powerful schema and will soon have access control, that already allows you to eliminate a lot of code, right?
If only you could define some simple server side, database side functions.
A little bit of Python in there.
I'm starting to come around.
Yeah.
A little bit of Python or JavaScript or maybe a Rust or something.
that you can just make that request to Stripe API, do something and then glue things together.
Yeah.
Then maybe you don't need the backend at all.
So this is our vision eventually to allow things like this.
And second plane is user defined functions within the database.
And because there is in Postgres, those functions are going to be running like inside Postgres.
You will be able to call them from the query language.
Like, hey, use NumPy to crunch this data for me.
Like write in SQL.
This is also possible.
There are extensions for Postgres that allow you to do that.
It's possible to define user defined functions in Postgres.
Multiple different extensions for that are there.
So yeah, it's an interesting thing for us to think about.
And we are thinking about it, but probably not for 2.0.
Yeah.
Okay.
Very cool.
So let's take this statement here for a minute.
Yeah.
This query syntax highlights a lot of probably what makes EdgeDB unique and some of your motives
here.
So this, if you wanted to go and get say a movie, which has a relationship to an actor's
table and you want to do some sort of filter type thing, you would say select movie curly
brace, look at that title.
That's the select projection.
So a movie.title basically.
And then actors, curly brace, name and email.
So is that, is this part right here, this, the sub actors, is that traversing the relationship,
that graph relationship?
Exactly.
You're basically traversing the graph.
And then inside the select statement, you say order by.name and you have this cool convention
of dot, which if you're in one of these scopes, like curly bracket actors, then you can say
dot and it means dot name applies back to actors that, right?
Actors.
Yes.
And basically this is just syntax sugar.
Nothing prevents you from spelling it out completely.
Like you say, you can say order by movie.actors.name.
Yeah.
But because you're already in inside the actors, essentially, we're just like giving you this.
Yeah.
Fantastic.
Then another thing that stands out for the query syntax is you can define inline variables
using the walrus operator, by the way.
Yeah.
So you can say average review equals math mean dot reviews of the movie, then dot rating.
And is this also traversing?
Exactly.
What is this?
Yeah.
a movie type has a multi-linked reviews.
So multiple reviews can be attached to movies and every review has, let's say five star rating,
an integer one to five.
And this is how you quickly can say, hey, just calculate the mean number of all linked reviews
and all their ratings.
So somebody on Hacker News years ago aptly called HGL as a child of SQL and GraphQL.
And I mean, it's funny, but there is truth to it because GraphQL made it extremely obvious
to people that working with object hierarchies this way, when you can just have a query that
just select something deep, right, is extremely important.
People suddenly realize this is cool.
Some companies have been trying to make GraphQL work for relational databases such as Hasura.
And they have an amazing product.
The only problem is that GraphQL isn't actually, it wasn't, it wasn't designed for creating databases.
It's an API language, it's a REST replacement.
So while it works for some things, good luck computing something in GraphQL.
You just can't, you can fetch things, but you cannot compute like your average review is,
is not possible to do in GraphQL.
SQL on the other hand is, is very stubborn when you have to select anything nested, like
things in tables, you have to think in tables, you either like select super wide tables,
and then you have to write some Python code to kind of combine it back to your shape or use
a norm, or if you use an advanced database, you can things like, you can use things like
a Reag, but SQL isn't, isn't, it doesn't shine for things like this.
So with, HQL, we're kind of marrying those both worlds.
You have this, deep fetch syntax and, you have an ability to drop computation in any,
at any point of your query.
Now a couple of other like super important things about HQL.
If you want, I can go into them.
Yeah.
We're getting short on time, but yeah, go ahead.
Sure.
As I said before, sometimes the pitch HDB is like this LVM thing, like,
compiler.
When we compile HQL query to a SQL, we have one important thing.
Every HQL query, no matter how complex it is, it's always compiled to just one SQL query.
And this is very important in the context of relational databases, because when you have
just one single query, it's atomic.
So you don't need like an explicit transaction.
You're already like working.
You always work with the same snapshot of the essentially.
Interesting.
So you're not in this case, like going, doing a query for the movies and then doing a query
for the actors and then doing a query for the reviews as three steps.
You're just, it's basically a three way join.
And then you're getting the data back out.
Something like that.
It's slightly more complicated than three way join.
Yeah, sure it is.
But yeah, basically, basically, yeah, that's, that's the idea.
We wouldn't, for one HQL query, it's always one SQL query.
It's very important.
We use lots of interesting tricks to make it happen.
And if you're interested about those tricks, YouTube slash HDBs and watch our live event,
we explain this all actually.
But it's an important thing.
And then HQL is actually, it's very composable.
So you can pack multiple different queries into one query.
So you can have a query that reads data, insert data, mutates data, and introspects the schema.
All in one huge thing.
And it will execute quickly for you and return your data like in proper way, ready for you to be consumed.
So HQL is extremely powerful in that regard.
This is what separates it from ORPs because your OR, be it SQLAlchemy or Pre-Ur,
or Prisma or something like that.
They might have a high level API for some operations, but they also don't really restrict themselves
on how many queries it will take to implement that API.
Right.
And sometimes N plus one.
Yeah.
Right.
And if you benchmark it on localhost, for example, databases on your laptop and your code
executes on laptop, it appears to be fast.
So you have three queries instead of one.
So what?
Like there is zero latency between your database and your code.
And probably not full production levels of data.
Sure.
But when you move it to the dot data center, you will have latency between your code and
the database.
And even if you have like one millisecond latency between your queries, suddenly you just start
losing performance a lot because your Python that uses or JavaScript that uses a norm operation,
you can actually fire like 10 queries.
This is easy.
Like 10 queries is fine.
And imagine it just spend 10 milliseconds on just doing that.
Yeah.
Just latency.
Nothing else.
Yeah.
Just losing performance.
So with SGP, it's not a thing.
All right.
So final question here.
When I run this, what do I get back in Python?
Obviously there's a nice async and synchronous Python API to talk to this.
Yeah.
But when I run this query in Python, what do I get?
It depends on how you run it.
Yeah.
We offer you two modes, essentially two output modes.
Any HQ query can be compiled as JSON.
In our Python client, you just say query JSON.
And it will return your JSON data, like ready to be pumped to your front end.
Or you can just say query.
And when you say query, it will return you rich Python objects.
So you'll have movie Python object, which with a title, a string attribute with an actors list,
which will have factors, objects within it, et cetera.
It's also very compact, like on the IO level.
So we are not sending like super fat tables or anything.
The data is neatly serialized.
So no need for any duplication.
Yeah, that matters.
Anything.
It's just like you have your native object data model in the database.
You query it and you get objects out of it.
So you never have to think about like any tables or anything.
It's always high level.
Nice.
All right.
Final question.
Then we really do have to wrap it up.
One of the things that's really nice about ORMs is I can say my thing dot, and I get a list
in my editor of what I should be getting back from the database.
Can I do that with this?
I know like the movie is basically defined in the GraphQL schema definition.
Is there a way to do like a type shed type thing?
Yeah.
EdgeDB.
Sorry.
I don't know.
Maybe it's not a DB schema language, but is there a way to do like a type shed thing to say,
well, that thing you get back looks like this.
Yes.
Unfortunately not in Python yet.
In TypeScript, we just released our query builder and it's insane because the API of the
query builder super closely replicates the layout of the SQL query.
It's basically like one to one correspondence.
It's like almost like same thing.
And in TypeScript, we just focused on TypeScript first, then Python is next.
But for TypeScript, yes, you reflect your schema with just one command line command.
And in VS Code, you now have full autocomplete.
You can express your queries in TypeScript no matter how nested they are, no matter what
kind of computation you do.
It's still the same idea.
Whatever query you build in your TypeScript is going to be just single SQL query, just single
SQL query.
It's going to be fast.
And you have full autocompletion and more.
You actually have full return type inference.
So you don't have to type anything.
You have a query, your VS Code and TypeScript, they will know the type of the data that's going
to be returned.
Interesting.
Okay.
It works like magic.
We're going to see if we can replicate this experience with Python and mypy.
This is going to be our goal to make something like this happen.
Right now, we just have this low level, well, relatively low level client API for Python.
You can run any SQL query.
You can get data for it.
You can do it in async or sync.
Entirely up to you.
But the typing integration specifically isn't there.
And second part of this question is that we are looking in future implementing a language
server protocol for EdgeDB.
So installs it locally and then VS Code would just connect to it.
And then you would have your autocomplete for EdgeQL queries, for schema files.
This is going to be great, but I'm just not sure like what kind of ETA we can put in it.
Probably not for 2.0.
Right.
Okay.
Yeah.
Looking forward to it.
Very neat work on EdgeDB and obviously all the building blocks that we talked about
at the beginning.
Congratulations.
Thank you, Michael.
Yeah.
You bet.
All right.
I'll list my Pi as well.
My Pi is a great thing.
Use my Pi.
Cool.
Right on.
All right.
Final call to action.
People are interested in any of your projects.
Probably primarily EdgeDB.
What do you say?
How to get started?
Yeah, absolutely.
It's ready for you.
It's a 1.0.
It's a stable.
Follow us on Twitter.
It's Twitter edge database without any underscores or dashes.
Just edge database.
Follow us on Twitter.
You will find the discord link right in the Twitter description.
So join our discord.
We try to grow community.
And yeah, build something amazing.
EdgeDB.
I can't really do it.
You can't really do it.
I can't really do it.
If you want to do it.
If you want to do it, you can't really do it.
And then you can't really do it.
If you want to do it, you can't really do it.
You can't really do it.
If you want to do it.
You can't really do it.
So if you want to do it, you can't really do it.
If you want to do it, you can't really do it.
If you want to do it.
If you want to do it, you can't really do it.
You can't really do it.
If you want to do it.
Find the discord link right in the Twitter description.
So join our discord.
We try to grow community and yeah, build something amazing.
EdgeDB.
I can say it like with full confidence.
EdgeDB is the most amazing things that thing that ever happened to relational databases.
So take a look at it.
This is the beginning of hopefully a big movement.
Yeah, fantastic.
Let me put in one final postscript question.
Sorry.
I really wanted to ask you this and I think it matters for people considering adopting it.
But do keep it super quick.
What's the business model?
Like when you guys released this thing, is it how do people get it?
Will there be a free version?
What's the story?
So EdgeDB is fully open source.
It's Apache two licenses.
It's extremely permissive.
No strings attached.
We'll make money by running EdgeDB for you.
Essentially, we will have a hosted version of EdgeDB.
EdgeDB as a service.
Yeah, absolutely.
And this is how most other these companies make money these days.
It's not anymore about enterprise version of your database so much.
It is about, hey, can you run this?
It's a database for us in the private cloud.
Right.
This is what businesses want.
Back it up, scale it.
Give us all that kind of back.
Exactly.
Okay.
We're actively working on that.
Although you can run EdgeDB right now on top of Aurora Postgres, RDS Postgres, Google Cloud.
We have guides for that.
So if you need to deploy your HDB application, we have your back.
But we will have this native, proper cloud version of HDB with which you will be able to just, with one terminal command, you will be able to bootstrap a cloud database for yourself.
It's going to be amazing.
All right.
Fantastic.
Thanks, Gary.
Thank you.
Yeah.
Bye.
to check out what they're offering. It really helps support the show. Take some stress out of
your life. Get notified immediately about errors and performance issues in your web or mobile
applications with Sentry. Just visit talkpython.fm/sentry and get started for free. And be sure
to use the promo code talkpython, all one word. Add high performance, multi-party video calls to
any app or website with SignalWire. Visit talkpython.fm/SignalWire and mention
that you came from Talk Python to me to get started and grab those free credits.
Want to level up your Python? We have one of the largest catalogs of Python video courses over at
Talk Python. Our content ranges from true beginners to deeply advanced topics like memory and async.
And best of all, there's not a subscription in sight. Check it out for yourself at
training.talkpython.fm. Be sure to subscribe to the show, open your favorite podcast app,
and search for Python. We should be right at the top. You can also find the iTunes feed at
/itunes, the Google Play feed at /play, and the direct RSS feed at /rss on talkpython.fm.
We're live streaming most of our recordings these days. If you want to be part of the show and have
your comments featured on the air, be sure to subscribe to our YouTube channel at talkpython.fm
slash YouTube. This is your host, Michael Kennedy. Thanks so much for listening. I really appreciate it.
Now get out there and write some Python code.
Bye.
Thank you.