438 karma · joined September 20, 2012
Previously co-founder and CTO of Gel Data [1].
[1] https://geldata.com
[ my public key: https://keybase.io/elprans; my proof: https://keybase.io/elprans/sigs/p0bjVrvsPB2J-0pE_ZgpeT-gli6jsZ45wHgeBaMKNNY ]
That said, the functional variant is a likely way to represent EdgeQL in programming languages.
In a classic relational model everything is a tuple containing scalar values. Graph-relational extends the relational data model in three ways:
- every relation always has a global immutable key independent of data (explicit autoincrement keys aren't needed)
- this enables us to add a "reference type", which is essentially a pointer to some other record (i.e. a foreign key)
- attributes can be set-valued, so you can have nested collections in queries and in your data model.
This is what lets us do `Movie.actors.name` instead of a bunch of `JOINs`, because `actors` is declared as a set-valued reference type in the `Movie` relation.
Yes, this is fundamental, and it is what enables us to drive the innovation in the query language. PostgreSQL's query engine is awesome and very powerful, but it is hopelessly obscured by SQL and its data model, and then further by the ORMs. EdgeDB and EdgeQL liberate that power and present it in a modernized way. EdgeQL wouldn't be possible or practical today without Postgres.
Thank you!
> also that we get to have beer at a conference sometime to share war stories and trade-offs
Looking forward!
Thanks!
> any plans to implement a full stored procedure language?
There are plans, and they have the word "Wasm" in them :-) You can also do a lot with pure-EdgeQL functions already.
> how well does it integrate with calls to postgres functions?
In theory all you need to do is write a function declaration with `USING SQL FUNCTION` [2], however we are currently limiting this functionality to the standard library, until we grow a well-defined user extension mechanism (a-la `CREATE EXTENSION` in Postgres).
[1] https://github.com/edgedb/edgedb/blob/6f87f44fbc9854ba060994...
> The schema you have designed helps a lot on the server-side. If this schema can be extensible (that is, people can make extensions by allowing extra information in the schema that the DBMS ignores, similar to comments) and available to an authorized user, people can create great tools for the client-side as well.
EdgeDB supports arbitrary JSON annotations on all schema objects, for example:
type User {
property name -> str {
annotation render_as := '"textbox"';
constraint expression on (len(.name) < 10) {
annotation comment := '"needed for external reasons"';
}
}
annotation data_for_app := "some-json-data"
}
> I'm throwing away Prisma integration of my company's project because they did not provide enough extension points, hooks and all the other ways to use the full power of the database. So as soon as you need something they don't support, you have to bypass the whole abstraction layer.This is why we are investing so hard into EdgeQL. If you can't express something with EdgeQL that you can with SQL -- it's a bug. If whatever you do seems _harder_ (or slower) with EdgeQL than with SQL, it's also a bug. Same applies to generated database clients (we'll be releasing a JavaScript/TypeScript client generator / query builder alongside EdgeDB 1.0).
We definitely need more collective effort put into "Better SQL", so PRQL is a welcome sight!
[1] https://github.com/edgedb/rfcs/blob/21e581a188715c6ff82944b6...
(disclaimer: I work on EdgeDB)
[1] https://www.edgedb.com/ [2] https://www.edgedb.com/docs/guides/migrations/index [3] https://www.edgedb.com/docs/guides/introspection/index [4] https://www.edgedb.com/docs/graphql/graphql
[1] https://github.com/edgedb/edgedb-docker#official-dockerfile-...
Loading arbitrary JSON by introspecting the data, and auto-generating the schema and the necessary DML statements is fairly straightforward too. I have a rough Python proof-of-concept, will need to find time to finish and publish it.
type Tree {
property value -> str
link parent -> Tree
}
you'd traverse the link as usual: SELECT Tree {
value,
parent: {
value
}
}
FILTER .parent.parent.parent.value = 'foo'
If there's a need to self-join on an arbitrary property, then you could use a `WITH` clause to explicitly bind the two sets: WITH
T1 := Tree,
T2 := Tree
SELECT
T1 {
similarly_valued := (SELECT T2 FILTER T1.value = T2.value)
} SELECT Department {
name,
employees := (
SELECT Employee { name, salary }
FILTER Employee.department_name = Department.name
)
}
Links in EdgeQL are merely an abstraction over the fact that most joins in a well-normalized schema are done over primary keys.1. Elimination of duplicates from every projection is prohibitively expensive.
2. Sometimes you actually _want_ duplicates to show up without injecting a synthetic key into every projection.
3. There's DISTINCT.
Absolutely!
WITH
april := <datetime>'2020-04-01T00:00+00',
NewCustomers := (
SELECT Customer
FILTER
NOT EXISTS (
SELECT .orders
FILTER .date < april
)
),
AprilCustomers := (
SELECT Customer
FILTER
datetime_truncate(.orders.date, 'months') = april
),
NewAprilCustomers := (
SELECT AprilCustomers
FILTER AprilCustomers IN NewCustomers
)
SELECT
(count(NewAprilCustomers) / count(AprilCustomers)) * 100;
This assumes the following schema: type Order_ {
property date -> datetime;
}
type Customer {
multi link orders -> Order_;
} SELECT 'one' IF value = 1 ELSE 'not one'
If value is an empty set, then the result is _always_ an empty set, unlike SQL that pretends NULL values are actually boolean for the purposes of the condition. EdgeQL expressions are, essentially, set comprehensions, the above is equivalent to this Python expression: {'one' if v = 1 else 'not one' for v in value}It's not. Just because data can be fetched as a set of "tree-like" things does not make the model hierarchical in any way. But it makes lots of practical use cases easier.
> The fundamental idea that you have a highly structured data tree is what the relational model threw away.
And then ORMs came and reinstated the status quo. Truth is, many applications actually benefit from a highly structured data graph. That said, you don't have to use the "highly structured" bits of EdgeDB, it's perfectly fine if all your types are simple tuples.
> We compose things into other things, subtype things, and otherwise deal in things. And this turns out to be a disaster when lots of people need to extend and reuse hunks of the same database.
I would be very interested in reading about this. Do you have any references? Most cases of "disaster" in my experience had to do with extremely poorly defined and documented schemas that had barely any relation to the actual business model.
> Why not just use an Option/Maybe type?
We are considering adding algebraic types and a syntax to match them, but it ultimately boils down to taste and use case:
SELECT value ?? "fallback in case of empty"
is not fundamentally different from (hypothetical): SELECT
MATCH value
CASE Some(non_empty_val) THEN non_empty_val
CASE Empty THEN "fallback in case of empty"
END;This is because we define infix OR as
{a OR b | ∀ (a, b) ∈ (A x B)}
Same goes for the cast function.
You may argue that this is confusing, but if you think about everything as a set comprehension, it is way more consistent. For example the `CASE WHEN` example from the post would always return `{}` for empty input, making it obvious.
> but it's explicitly advertised as a feature of EdgeQL that it can return trees (json-like structures)
The tree-like return is not an aspect of a language system, it's a matter of output representation. For example:
SELECT User { favorites: {name} }
still returns a flat set of User objects. The shape selector `{ ... }` is an annotation that defines how an object is serialized in the output.> I would ultimately hope for something that can be expressed as a number of function calls and commonly used data structures
This is exactly where we are going. Orthogonality in the underlying language makes it much easier to achieve this.
> and is it as good as PosgreSQL, or MariaDB, or sqlite?
EdgeDB is based on Postgres, we actually transpile EdgeQL to SQL. EXPLAIN and query performance analysis are being worked on.
> in the real world I have to worry more about how performant and robust a thing is under load, than I can worry about programming convenience.
We have posted some benchmarks [1], and more are coming.