v1.0.0

Wed, 13 Sep 2023 00:00:00 GMT

After numerous beta releases crammed into just months of development, we are releasing SurrealDB v1.0.0! 🎉 Here follow some of our 1.0.0 highlights #### Introducing new type validation methods in SurrealQL `v1.0.0` introduces new type validation methods. These new methods allow you to check which type any sort of value is on the go. ```surql LET $value = "I am a string"; RETURN [ type::is::string($value), type::is::record($value), type::is::number($value), ]; ``` #### Guaranteed single item results with the new ONLY keyword It was a previously difficult to select, create, update or delete just a single record, so we simplified it a bit. ```surql // Will return an object, as we can guarantee just a single record is requested SELECT * FROM ONLY person:tobie; // This will throw an error, as multiple records are being created and returned CREATE ONLY person:tobie, person:jaime; ``` #### Get realtime updates in your application with SurrealDB Live Queries `v1.0.0` introduces Live Queries. This powerful technology allows you to write applications where you can serve realtime updates to your frontend. ```surql // You can initiate the live query in your application LET $lq = LIVE SELECT * FROM person WHERE age > 18; // And you can dispose the live query once it is no longer needed KILL $lq; ``` ```js // SurrealDB SDKs allow you to easily initiate live queries, and to process the received messages. const lq = await db.live('person', function ({ action, result }) { if (action == 'CREATE') { renderPersonInFrontend(result); } }); // Once you no longer need the live feed of updates, you can dispose the live query await db.kill(lq); ``` #### Efficiently index and search your data with SurrealDB Full Text Search With Full Text Search, you can efficiently store and index data, and search through it. ```surql // We can define an analyzer on our database, // Then, define an index to dictate which content we want to index (yep, that easy) DEFINE ANALYZER simple TOKENIZERS blank,class FILTERS snowball(english); DEFINE INDEX content ON article FIELDS content SEARCH ANALYZER simple BM25 HIGHLIGHTS; // We can then create some content CREATE article SET content = "Join us at SurrealDB World, as we unveil our version 1.0.0 to the world!"; CREATE article SET content = "We will absolutely be at Surreal World!"; // And lastly, select some data from the article table. // We use the special "@num@" operator, where we define a reference. // We can then reference back in the search::* functions. SELECT *, search::score(1) AS score, search::offsets(1) AS offsets, search::highlight('', '', 1) AS highlighted FROM article WHERE content @1@ 'world' ORDER BY score DESC; ``` #### Allow or deny capabilities when starting your SurrealDB instance All capabilities are disabled by default. This means that by default, you are not able to use any methods, embedded scripting functions, make outbound network calls, or access the database anonymously. Down below follows a set of examples to showcase how one can configure capabilities. Capabilities are further documented in the Capabilities documentation. ```shell # Allow all capabilities user@localhost % surreal start --allow-all # Allow all functions, except for custom functions user@localhost % surreal start --allow-funcs --deny-funcs fn # Allow all capabilities, but deny guest/anonymous access to the database user@localhost % surreal start --allow-all --deny-guests ``` #### Revamped root users It is now possible to define multiple root users in SurrealDB. This change did require some changes in the way that you start your database however. With this change, you will now only initially have to provide the `--user` and `--pass` flags to create the initial root user, but once the first root user exists, they will no longer by utilized. For more information, check out the Authentication guide, and the surreal start and `DEFINE USER` documentation. ```shell # When you initially start the database, you can create the first root user. user@localhost % surreal start --auth --user root --pass root file:database.db # In the future, you don't need to specify the --user and --pass flags anymore user@localhost % surreal start --auth file:database.db ``` ```surql // Afterwards, you are able to create multiple root users. DEFINE USER tobie ON ROOT PASSWORD "SecurePassword!" ROLES OWNER; DEFINE USER jaime ON ROOT PASSWORD "SecurePassword!" ROLES EDITOR; DEFINE USER john ON ROOT PASSWORD "SecurePassword!" ROLES VIEWER; ``` #### Strict typing in SurrealQL `v1.0.0` introduces a more strict and powerful typing system. It makes things more simple to understand, and it goes a long way in preventing all kinds of weird bugs in your schemas! ```surql // Where you previously had to manually assert that a field does not contain NONE or NULL DEFINE FIELD age ON person TYPE number ASSERT $value != NONE AND $value != NULL; // You can now simply set the type and be ensured that only a number will be stored in that field. DEFINE FIELD age ON person TYPE number; // To make types optional, you can use the newly introduced "option" type. // This guarantees the field to be either empty (NONE), or a number. DEFINE FIELD age ON person TYPE option; // We also introduces some new types! DEFINE FIELD ratings ON movie TYPE array; DEFINE FIELD best_ratings ON movie TYPE array; DEFINE FIELD unique_ratings ON movie TYPE set; // And we made sure that the record type is also in-line with this new format DEFINE FIELD author ON book TYPE record; // Lastly, it is now possible to set a union type. DEFINE FIELD title ON article TYPE string | number; // They can also be used in "nested" types DEFINE FIELD description ON article TYPE option; DEFINE FIELD author ON article TYPE record; ``` #### Set a `DEFAULT` value on field definitions ```surql // You previously needed to involve logic with the "VALUE" clause to set a default value. DEFINE FIELD enabled ON user TYPE bool VALUE $value OR $before OR true; // You can now simply use the DEFAULT clause for this. DEFINE FIELD enabled ON user TYPE bool DEFAULT true; // As an added bonus, when you only define a VALUE clause with a simple value, // then that will also act as the default value. DEFINE FIELD constant ON demo VALUE 123; // This will act the same as the following DEFINE FIELD constant ON demo VALUE 123 DEFAULT 123; ``` #### `PERMISSIONS` on global parameters and custom functions Scope and anonymous users previously had access to every defined global parameter and function. You can now define these resources with a `PERMISSIONS` clause to protect them. ```surql DEFINE PARAM $perms_none VALUE 'Nobody can see me' PERMISSIONS NONE; DEFINE PARAM $perms_full VALUE 'Everybody can see me' PERMISSIONS FULL; DEFINE PARAM $perms_scope VALUE 'Only admins can see me' PERMISSIONS WHERE $scope = 'admin'; DEFINE FUNCTION fn::perms::none() { RETURN 'Nobody can invoke me'; } PERMISSIONS NONE; DEFINE FUNCTION fn::perms::full() { RETURN 'Everybody can invoke me'; } PERMISSIONS FULL; DEFINE FUNCTION fn::perms::scope() { RETURN 'Only admins can invoke me'; } PERMISSIONS WHERE $scope = 'admin'; ``` #### `FOR`, `BREAK` and `CONTINUE` statements ```surql // Here, we loop through an array with three numbers. // For any number under two, we skip the iteration // For any number above two, we break the loop // The result is that only when the number is two, we will create the "person:two" record. FOR $num IN [1, 2, 3] { IF $num < 2 { CONTINUE; }; IF $num > 2 { BREAK; }; CREATE person:two; }; // Here, we select the id for every person in the database, and we gift them a ticket to SurrealDB World. FOR $person IN (SELECT VALUE id FROM person) { CREATE gift CONTENT { recipient: $person, type: "ticket", event: "SurrealDB World" }; }; ``` #### `THROW` statement Did something unexpected happen, and do you want to throw an error to the client? Now you can! ```surql LET $message = "Some error message"; THROW "Failed to perform action: " + $message; ``` #### `COMMENT` away on resource definitions! ```surql // Give extra context about a certain resource DEFINE TABLE user COMMENT "This table will store users!"; ``` #### Less bulky `IF ELSE` statements We found the `IF ELSE` statement to be a bit bulky at times. Now, when you use a block (`{}`) as the body of the statement, you can skip out on the `THEN` and `END` keywords! ```surql // Previously IF something = true THEN { RETURN 123; } END; // Now IF something = true { RETURN 123; }; ``` #### More features for our embedded scripting functions With `fetch()`, `query()`, `value()` and basically every SurrealQL function now being available within the embedded scripting functions, they are a very powerful extension to SurrealQL, and can be used to solve complex problems otherwise impossible! Read more about them in the [Embedded scripting functions](https://surrealdb.com/docs/surrealql/functions/script) documentation. ```surql function() { const page = await fetch('https://google.com'); const people = await surrealdb.query('SELECT * FROM person'); const auth = await surrealdb.value('auth'); const uuid = surrealdb.functions.rand.uuid.v4(); } ``` #### Support for `FLEXIBLE` fields on `SCHEMAFULL` tables `SCHEMAFULL` and `SCHEMALESS` functionality can now be used together, suitable for capturing schema-free log data. ```surql // We want to define a SCHEMAFULL table DEFINE TABLE person SCHEMAFULL; // But we want one field to allow any content DEFINE FIELD settings on person TYPE object FLEXIBLE; // We can then set the field value without a schema CREATE person:test CONTENT { settings: { nested: { object: { thing: 'test' } } } }; ``` #### Support code blocks and advanced expressions It is now possible to run blocks of code, with support for an arbitrary number of statements, including `LET` and `RETURN` statements. This allows for writing advanced custom logic, and allowing for more complicated handling of data operations. ```surql DEFINE FIELD average_sales ON metrics VALUE { LET $sales = (SELECT VALUE quantity FROM sales); LET $total = math::sum($sales); LET $count = count($sales); RETURN ($total / $count); }; ``` #### Define custom functions with DEFINE FUNCTION statements SurrealDB now supports the ability to define global database-wide custom functions, which allow for complicated or repeated user-defined code, to be run seamlessly within any query across the database. Custom functions support typed arguments, and multiple nested queries with custom logic. ```surql -- Define a global function which can be used in any query DEFINE FUNCTION fn::get_person($first: string, $last: string, $birthday: string) { LET $person = SELECT * FROM person WHERE [first, last, birthday] = [$first, $last, $birthday]; RETURN IF $person[0].id THEN $person[0] ELSE CREATE person SET first = $first, last = $last, birthday = $birthday END; }; -- Call the global custom function, receiving the returned result LET $person = fn::get_person('Tobie', 'Morgan Hitchcock', '2022-09-21'); ```