EdgeDB v2 (Sagittarius)
EdgeDB 2.0 was released on July 28th, 2022. Read the announcement blog post here.
We would like to thank our community for reporting issues and contributing fixes. You are awesome! ❤️
To play with the new features, install the CLI and initialize a new project. For an interesting schema with test data, check out the MCU Sandbox repo.
$
edgedb project init
Upgrading
Local instances
To upgrade a local project, run the following command inside the project directory.
$
edgedb project upgrade --to-latest
Alternatively, specify an instance name if you aren’t using a project.
$
edgedb project upgrade --to-latest -I my_instance
Hosted instances
To upgrade a remote (hosted) instance, we recommend the following dump-and-restore process.
1. Spin up an empty 2.0 instance by following one of our deployment guides. These guides have been updated to 2.0. Keep the DSN of the newly created instance handy.
- Take your application offline, then dump your v1.x database with the CLI
```
$
```
```
edgedb dump --dsn <old dsn> --all my_database.dump/
```
This will dump the schema and contents of your current database to a file on your local disk called `my_database.dump`. The file name isn’t important.
- Restore the empty v2.x instance from the dump
```
$
```
```
edgedb restore --all my_database.dump/ --dsn <new dsn>
```
Once the restore is complete, update your application to connect to the new instance.
This process will involve some downtime, specifically during steps 2 and 3. We are working on an in-place upgrade workflow that will reduce the amount of downtime involved and avoid the need to spin up a new instance. We’ll publish that soon; join the Discord for updates. Though for most applications the dump-and-restore workflow will be simpler and less error-prone.
Client libraries
We’ve released new versions of our JavaScript and Python client libraries that support all 2.0 features and implement the updated protocol. These versions are backwards compatible with v1.x instances, so we encourage all users to upgrade.
| |
| |
| |
| |
.NET (community-maintained) |
|
Elixir (community-maintained) |
|
New features
Integrated admin UI
All v2 instances ship with a built-in rich admin GUI. Access it by running edgedb ui
inside any EdgeDB project, or specify a local instance name with edgedb ui -I my_inst
. The command opens the instance’s admin UI using the default system browser.
The current iteration of the GUI has
a data browser and editor
a REPL for writing and executing EdgeQL queries
a schema introspection tool with text-based and graphical visualizations of the instance’s current schema
The new GROUP expression can be used to partition and aggregate data. The output of GROUP
are free objects representing each group, including the grouping, the grouping key, and the set of elements.
db>
group Movie { title } by .release_year;
{
{
key: {release_year: 2017},
grouping: {'release_year'},
elements: {
default::Movie {title: 'Guardians of the Galaxy Vol. 2'},
default::Movie {title: 'Spider-Man: Homecoming'},
default::Movie {title: 'Thor: Ragnarok'},
},
},
{
key: {release_year: 2013},
grouping: {'release_year'},
elements: {
default::Movie {title: 'Iron Man 3'},
default::Movie {title: 'Thor: The Dark World'},
},
},
...
}
Browse the docs for more details and examples, or refer to the original RFC 1009.
Global variables
Your schema can now contain global variables. These are contextual variables that are provided by the client and can be referenced in your queries and schema.
global current_user -> uuid;
select User filter .id = global current_user;
Client libraries have been updated to provide method for attaching global variables to a Client
instance; these values are sent along with all queries originating from that Client
.
TypeScript
Python
Go
import {createClient} from 'edgedb';
const client = createClient().withGlobals({
current_user: '2141a5b4-5634-4ccc-b835-437863534c51',
});
await client.query(`select global current_user;`);
from edgedb import create_client
client = create_client().with_globals({
'current_user': '580cc652-8ab8-4a20-8db9-4c79a4b1fd81'
})
result = client.query("""
select global current_user;
""")
package main
import (
"context"
"fmt"
"log"
"github.com/edgedb/edgedb-go"
)
func main() {
ctx := context.Background()
client, err := edgedb.CreateClient(ctx, edgedb.Options{})
if err != nil {
log.Fatal(err)
}
defer client.Close()
id, err := edgedb.ParseUUID("2141a5b4-5634-4ccc-b835-437863534c51")
if err != nil {
log.Fatal(err)
}
var result edgedb.UUID
err = client.
WithGlobals(map[string]interface{}{"current_user": id}).
QuerySingle(ctx, "SELECT global current_user;", &result)
if err != nil {
log.Fatal(err)
}
fmt.Println(result)
}
Globals are primarily intended as an enabling mechanism for object-level security.
Object-level security
Object types can now be augmented with object-level access policies. When combined with global variables, access policies can be used to push authorization logic into the database.
global current_user -> uuid;
type User {
required property email -> str { constraint exclusive; };
}
type BlogPost {
required property title -> str;
link author -> User;
access policy own_posts allow all using (
.author.id ?= global current_user
)
}
Refer to the docs or RFC 1011 for full details.
Range types
EdgeDB now supports range types representing intervals of values.
db>
select range(1, 10);
{range(1, 10, inc_lower := true, inc_upper := false)}
db>
select range_unpack(range(1, 10))
{1, 2, 3, 4, 5, 6, 7, 8, 9}
This release also introduces a new datatype cal::date_duration to represent a span of months/days. It is nearly equivalent to the existing cal::relative_duration but cannot represent sub-day durations.
This type is primarily intended to simplify cal::local_date logic.
db> select <cal::local_date>'2022-06-25' +
... <cal::date_duration>'5 days';
{<cal::local_date>'2022-06-30'}
db> select <cal::local_date>'2022-06-30' -
... <cal::local_date>'2022-06-25';
{<cal::date_duration>'P5D'}
Source deletion policies
Add deletion cascade functionality with on source delete
.
type BlogPost {
property title -> str;
}
type Person {
multi link posts -> BlogPost {
on source delete delete target;
}
}
Under this policy, deleting a User
will unconditionally delete its posts
as well.
To avoid deleting a Post
that is linked to by other schema entities, append if orphan
.
type Person {
multi link posts -> BlogPost {
on source delete delete target;
on source delete delete target if orphan;
}
}
Additional changes
EdgeQL
Support additional operations on local date and time types, including duration_get(), cal::duration_normalize_hours(), and cal::duration_normalize_days(). Per RFC 1013.
Support user-provided values for the
id
property when inserting objects (#3895). This can be useful when migrating data from an existing database.insert User {
id := <uuid>"5abf67cc-9f9f-4bbc-b009-d117d463a12e",
email := "jayz@example.com"
}
Add the new json_set() function (#4118).
Server
Support socket activation to reduce memory footprint on developer machines (#3899).
Introduce edgedb+http, a which tunnels the binary protocol over HTTP using JWT for authentication (#3979).
Support using JWT to authenticate to local instances (#3991).
Bug fixes
Generate unique
id
fields for each free shape object, and don’t use an actual in-database object to represent it, and make multiplicity inference understand free shapes better (#3631, #3633, #3634).Fail if local Postgres cluster fails to start.
Add
cfg::memory
to base types descriptor IDs table (#3882).Fix a cross-type exclusive constraint bug that could allow exclusive constraints to be violated in some complex type hierarchies (#3887).
Fix issue where server might attempt to acquire one more connection than it is configured to permit (#3901).
Fix use of
assert_exists
on properties that are being directly output (#3911).Fix a scope leakage that could cause a link referenced inside a computable to improperly correlate with something outside the computable (#3912).
Fix a number of issues with the floordiv (
//
) and modulus (%
) operators where we could return incorrect values or produce spurious errors, especially on very large values (#3909).Allow adding annotations to
abstract annotation
definitions (#3929).Expose
body
andlanguage
fields onschema::Function
(#3944).Make indexes extend from
schema::InheritingObject
(#3942).Fix some mis-compilations of nested shapes inside calls to functions like
assert_single
(#3927).Fix
SET TYPE
on properties with default values (#3954).Fix
describe
/populate
/describe
sequence (#3959).Upgrade many casts and functions from “Stable” to “Immutable” (#3975).
Fix link properties in type filtered shape links (#3987).
Allow DML statements in free shapes (#4002).
Allow customizing assertion messages in
assert_exists
and friends (#4019).
Protocol overhaul
A new version of the protocol—version 1.0—has been introduced. It eliminates all server state associated with connections that do not use transactions.
Support passing parameters to and returning values from multi-statement scripts.
2.1
Fix global defaults with nontrivial computation (#4182)
Fix migration that removes policy using clause (#4183)
Support ELSE-less UNLESS CONFLICT on explicit id INSERT (#4185)
Don’t create constraints on derived views when adding a pointer to a type (#4187)
Fix a bunch of missing source contexts in declarative (#4188)
Fix an ISE when a computed link is directly a property reference (#4193)
Fix an ISE when using an empty shape in some contexts (#4194)
Fix a number of error messages involving collection types in schemas (#4195)
Avoid doing semi-joins after a sequence of single links (#4196)
Make range() properly strict in its non-optional arguments (#4207)
Allow multiple FDs per socket in activation (#4189)
Add SCRAM authentication over HTTP (#4197)
Always arm auto-shutdown timer when it’s greater than zero (#4214)
Fix json -> array<json> cast of ‘[]’ (#4217)