2023-03-17 11:32:31 +00:00
mod parse ;
use parse ::Parse ;
2023-08-30 18:01:30 +00:00
mod helpers ;
use helpers ::new_ds ;
2024-08-21 12:34:16 +00:00
use surrealdb_core ::dbs ::Session ;
use surrealdb_core ::err ::Error ;
use surrealdb_core ::iam ::Role ;
use surrealdb_core ::sql ::Value ;
2023-03-17 11:32:31 +00:00
#[ tokio::test ]
async fn select_field_value ( ) -> Result < ( ) , Error > {
let sql = "
CREATE person :tobie SET name = ' Tobie ' ;
CREATE person :jaime SET name = ' Jaime ' ;
SELECT VALUE name FROM person ;
SELECT name FROM person ;
" ;
2023-08-30 18:01:30 +00:00
let dbs = new_ds ( ) . await ? ;
2023-07-29 18:47:25 +00:00
let ses = Session ::owner ( ) . with_ns ( " test " ) . with_db ( " test " ) ;
2023-07-05 21:26:13 +00:00
let res = & mut dbs . execute ( sql , & ses , None ) . await ? ;
2023-03-17 11:32:31 +00:00
assert_eq! ( res . len ( ) , 4 ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
id : person :tobie ,
name : ' Tobie '
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
id : person :jaime ,
name : ' Jaime '
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
' Jaime ' ,
' Tobie ' ,
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
name : ' Jaime '
} ,
{
name : ' Tobie '
}
] " ,
) ;
2023-08-27 18:00:11 +00:00
assert_eq! ( tmp , val ) ;
//
Ok ( ( ) )
}
#[ tokio::test ]
async fn select_field_and_omit ( ) -> Result < ( ) , Error > {
let sql = "
CREATE person :tobie SET name = ' Tobie ' , password = ' 123456 ' , opts . security = ' secure ' ;
CREATE person :jaime SET name = ' Jaime ' , password = ' asdfgh ' , opts . security = ' secure ' ;
SELECT * OMIT password , opts . security FROM person ;
SELECT * FROM person ;
" ;
2023-08-30 18:01:30 +00:00
let dbs = new_ds ( ) . await ? ;
2023-08-27 18:00:11 +00:00
let ses = Session ::owner ( ) . with_ns ( " test " ) . with_db ( " test " ) ;
let res = & mut dbs . execute ( sql , & ses , None ) . await ? ;
assert_eq! ( res . len ( ) , 4 ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
id : person :tobie ,
name : ' Tobie ' ,
password : ' 123456 ' ,
opts : {
security : ' secure ' ,
} ,
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
id : person :jaime ,
name : ' Jaime ' ,
password : ' asdfgh ' ,
opts : {
security : ' secure ' ,
} ,
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
id : person :jaime ,
name : ' Jaime ' ,
opts : { } ,
} ,
{
id : person :tobie ,
name : ' Tobie ' ,
opts : { } ,
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
id : person :jaime ,
name : ' Jaime ' ,
password : ' asdfgh ' ,
opts : {
security : ' secure ' ,
} ,
} ,
{
id : person :tobie ,
name : ' Tobie ' ,
password : ' 123456 ' ,
opts : {
security : ' secure ' ,
} ,
}
] " ,
) ;
2023-03-17 11:32:31 +00:00
assert_eq! ( tmp , val ) ;
//
Ok ( ( ) )
}
2023-05-09 22:17:29 +00:00
2023-06-20 23:31:23 +00:00
#[ tokio::test ]
async fn select_expression_value ( ) -> Result < ( ) , Error > {
let sql = "
CREATE thing :a SET number = 5 , boolean = true ;
CREATE thing :b SET number = - 5 , boolean = false ;
SELECT VALUE - number FROM thing ;
SELECT VALUE ! boolean FROM thing ;
2023-07-14 12:22:37 +00:00
SELECT VALUE ! boolean FROM thing EXPLAIN FULL ;
2023-06-20 23:31:23 +00:00
" ;
2023-08-30 18:01:30 +00:00
let dbs = new_ds ( ) . await ? ;
2023-07-29 18:47:25 +00:00
let ses = Session ::owner ( ) . with_ns ( " test " ) . with_db ( " test " ) ;
let res = & mut dbs . execute ( sql , & ses , None ) . await ? ;
2023-07-14 12:22:37 +00:00
assert_eq! ( res . len ( ) , 5 ) ;
2023-06-20 23:31:23 +00:00
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
boolean : true ,
id : thing :a ,
number : 5
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
boolean : false ,
id : thing :b ,
number : - 5
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
- 5 ,
5 ,
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
false ,
true
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
2023-07-14 12:22:37 +00:00
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
detail : {
table : ' thing ' ,
} ,
operation : ' Iterate Table '
} ,
2024-03-12 10:48:53 +00:00
{
detail : {
2024-03-28 16:29:55 +00:00
type : ' Memory '
2024-03-12 10:48:53 +00:00
} ,
operation : ' Collector '
} ,
2023-07-14 12:22:37 +00:00
{
detail : {
count : 2 ,
} ,
operation : ' Fetch '
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
2023-06-20 23:31:23 +00:00
Ok ( ( ) )
}
2023-07-15 07:08:26 +00:00
#[ tokio::test ]
async fn select_dynamic_array_keys_and_object_keys ( ) -> Result < ( ) , Error > {
let sql = "
LET $lang = ' en ' ;
2024-06-12 09:15:09 +00:00
UPSERT documentation :test CONTENT {
2023-07-15 07:08:26 +00:00
primarylang : ' en ' ,
languages : {
' en ' : ' this is english ' ,
' es ' : ' esto es español ' ,
' de ' : ' das ist Englisch ' ,
} ,
tags : [
{ type : ' library ' , value : ' client - side ' } ,
{ type : ' library ' , value : ' server - side ' } ,
{ type : ' environment ' , value : ' frontend ' } ,
]
} ;
- - An array filter , followed by an array index operation
SELECT tags [ WHERE type = ' library ' ] [ 0 ] . value FROM documentation :test ;
- - Selecting an object value or array index using a string as a key
SELECT languages [ ' en ' ] AS content FROM documentation :test ;
- - Updating an object value or array index using a string as a key
2024-06-12 09:15:09 +00:00
UPSERT documentation :test SET languages [ ' en ' ] = ' my primary text ' ;
2023-07-15 07:08:26 +00:00
- - Selecting an object value or array index using a parameter as a key
SELECT languages [ $lang ] AS content FROM documentation :test ;
- - Updating an object value or array index using a parameter as a key
2024-06-12 09:15:09 +00:00
UPSERT documentation :test SET languages [ $lang ] = ' my secondary text ' ;
2023-07-15 07:08:26 +00:00
- - Selecting an object or array index value using the value of another document field as a key
SELECT languages [ primarylang ] AS content FROM documentation ;
" ;
2023-08-30 18:01:30 +00:00
let dbs = new_ds ( ) . await ? ;
2023-07-29 18:47:25 +00:00
let ses = Session ::owner ( ) . with_ns ( " test " ) . with_db ( " test " ) ;
2023-07-15 07:08:26 +00:00
let res = & mut dbs . execute ( sql , & ses , None ) . await ? ;
assert_eq! ( res . len ( ) , 8 ) ;
//
let tmp = res . remove ( 0 ) . result ;
assert! ( tmp . is_ok ( ) ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
id : documentation :test ,
languages : {
de : ' das ist Englisch ' ,
en : ' this is english ' ,
es : ' esto es español ' ,
} ,
primarylang : ' en ' ,
tags : [
{
type : ' library ' ,
value : ' client - side ' ,
} ,
{
type : ' library ' ,
value : ' server - side ' ,
} ,
{
type : ' environment ' ,
value : ' frontend ' ,
}
]
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
tags : {
value : ' client - side '
}
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
content : ' this is english '
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ;
assert! ( tmp . is_ok ( ) ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
content : ' my primary text '
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ;
assert! ( tmp . is_ok ( ) ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
content : ' my secondary text '
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
Ok ( ( ) )
}
2023-05-09 22:17:29 +00:00
#[ tokio::test ]
async fn select_writeable_subqueries ( ) -> Result < ( ) , Error > {
let sql = "
2024-06-12 09:15:09 +00:00
LET $id = ( UPSERT tester :test ) ;
2023-05-09 22:17:29 +00:00
RETURN $id ;
2024-06-12 09:15:09 +00:00
LET $id = ( UPSERT tester :test ) . id ;
2023-05-09 22:17:29 +00:00
RETURN $id ;
2024-06-12 09:15:09 +00:00
LET $id = ( SELECT VALUE id FROM ( UPSERT tester :test ) ) [ 0 ] ;
2023-05-09 22:17:29 +00:00
RETURN $id ;
" ;
2023-08-30 18:01:30 +00:00
let dbs = new_ds ( ) . await ? ;
2023-07-29 18:47:25 +00:00
let ses = Session ::owner ( ) . with_ns ( " test " ) . with_db ( " test " ) ;
2023-07-05 21:26:13 +00:00
let res = & mut dbs . execute ( sql , & ses , None ) . await ? ;
2023-05-09 22:17:29 +00:00
assert_eq! ( res . len ( ) , 6 ) ;
//
let tmp = res . remove ( 0 ) . result ;
assert! ( tmp . is_ok ( ) ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
2023-09-05 15:22:13 +00:00
" [
{
id : tester :test
}
] " ,
2023-05-09 22:17:29 +00:00
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ;
assert! ( tmp . is_ok ( ) ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
2023-09-05 15:22:13 +00:00
let val = Value ::parse ( " [tester:test] " ) ;
2023-05-09 22:17:29 +00:00
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ;
assert! ( tmp . is_ok ( ) ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse ( " tester:test " ) ;
assert_eq! ( tmp , val ) ;
//
Ok ( ( ) )
}
2023-06-13 18:00:16 +00:00
#[ tokio::test ]
async fn select_where_field_is_bool ( ) -> Result < ( ) , Error > {
let sql = "
CREATE test :1 SET active = false ;
CREATE test :2 SET active = false ;
CREATE test :3 SET active = true ;
SELECT * FROM test WHERE active = false ;
SELECT * FROM test WHERE active ! = true ;
SELECT * FROM test WHERE active = true ;
" ;
2023-08-30 18:01:30 +00:00
let dbs = new_ds ( ) . await ? ;
2023-07-29 18:47:25 +00:00
let ses = Session ::owner ( ) . with_ns ( " test " ) . with_db ( " test " ) ;
2023-07-05 21:26:13 +00:00
let res = & mut dbs . execute ( sql , & ses , None ) . await ? ;
2023-06-13 18:00:16 +00:00
assert_eq! ( res . len ( ) , 6 ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
id : test :1 ,
active : false
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
id : test :2 ,
active : false
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
id : test :3 ,
active : true
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
id : test :1 ,
active : false
} ,
{
id : test :2 ,
active : false
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
id : test :1 ,
active : false
} ,
{
id : test :2 ,
active : false
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
id : test :3 ,
active : true
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
Ok ( ( ) )
}
2023-07-10 08:19:37 +00:00
#[ tokio::test ]
async fn select_where_field_is_thing_and_with_index ( ) -> Result < ( ) , Error > {
let sql = "
2023-07-15 07:08:26 +00:00
CREATE person :tobie SET name = ' Tobie ' ;
2023-07-10 08:19:37 +00:00
DEFINE INDEX author ON TABLE post COLUMNS author ;
CREATE post :1 SET author = person :tobie ;
CREATE post :2 SET author = person :tobie ;
2023-07-13 10:12:34 +00:00
SELECT * FROM post WHERE author = person :tobie EXPLAIN ;
2023-07-14 12:22:37 +00:00
SELECT * FROM post WHERE author = person :tobie EXPLAIN FULL ;
2023-07-13 10:12:34 +00:00
SELECT * FROM post WHERE author = person :tobie ; " ;
2023-08-30 18:01:30 +00:00
let dbs = new_ds ( ) . await ? ;
2023-07-29 18:47:25 +00:00
let ses = Session ::owner ( ) . with_ns ( " test " ) . with_db ( " test " ) ;
2023-07-10 08:19:37 +00:00
let res = & mut dbs . execute ( sql , & ses , None ) . await ? ;
2023-07-14 12:22:37 +00:00
assert_eq! ( res . len ( ) , 7 ) ;
2023-07-10 08:19:37 +00:00
//
let _ = res . remove ( 0 ) . result ? ;
let _ = res . remove ( 0 ) . result ? ;
let _ = res . remove ( 0 ) . result ? ;
let _ = res . remove ( 0 ) . result ? ;
//
let tmp = res . remove ( 0 ) . result ? ;
2023-07-13 10:12:34 +00:00
let val = Value ::parse (
" [
{
detail : {
plan : {
index : ' author ' ,
operator : ' = ' ,
value : person :tobie
} ,
table : ' post ' ,
} ,
operation : ' Iterate Index '
2024-03-12 10:48:53 +00:00
} ,
{
detail : {
2024-03-28 16:29:55 +00:00
type : ' Memory '
2024-03-12 10:48:53 +00:00
} ,
operation : ' Collector '
2023-07-13 10:12:34 +00:00
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
2023-07-14 12:22:37 +00:00
let val = Value ::parse (
" [
{
detail : {
plan : {
index : ' author ' ,
operator : ' = ' ,
value : person :tobie
} ,
table : ' post ' ,
} ,
operation : ' Iterate Index '
} ,
2024-03-12 10:48:53 +00:00
{
detail : {
2024-03-28 16:29:55 +00:00
type : ' Memory '
2024-03-12 10:48:53 +00:00
} ,
operation : ' Collector '
} ,
2023-07-14 12:22:37 +00:00
{
detail : {
count : 2 ,
} ,
operation : ' Fetch '
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
2023-07-10 08:19:37 +00:00
let val = Value ::parse (
" [
{
author : person :tobie ,
id : post :1
} ,
{
author : person :tobie ,
id : post :2
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
Ok ( ( ) )
}
2023-06-19 18:41:13 +00:00
#[ tokio::test ]
async fn select_where_and_with_index ( ) -> Result < ( ) , Error > {
let sql = "
CREATE person :tobie SET name = ' Tobie ' , genre = 'm' ;
CREATE person :jaime SET name = ' Jaime ' , genre = 'm' ;
DEFINE INDEX person_name ON TABLE person COLUMNS name ;
2023-07-13 10:12:34 +00:00
SELECT name FROM person WHERE name = ' Tobie ' AND genre = 'm' EXPLAIN ;
SELECT name FROM person WHERE name = ' Tobie ' AND genre = 'm' ; " ;
2023-08-30 18:01:30 +00:00
let dbs = new_ds ( ) . await ? ;
2023-07-29 18:47:25 +00:00
let ses = Session ::owner ( ) . with_ns ( " test " ) . with_db ( " test " ) ;
2023-07-05 21:26:13 +00:00
let res = & mut dbs . execute ( sql , & ses , None ) . await ? ;
2023-07-13 10:12:34 +00:00
assert_eq! ( res . len ( ) , 5 ) ;
2023-06-19 18:41:13 +00:00
//
let _ = res . remove ( 0 ) . result ? ;
let _ = res . remove ( 0 ) . result ? ;
let _ = res . remove ( 0 ) . result ? ;
//
let tmp = res . remove ( 0 ) . result ? ;
2023-07-13 10:12:34 +00:00
let val = Value ::parse (
" [
{
detail : {
plan : {
index : ' person_name ' ,
operator : ' = ' ,
value : ' Tobie '
} ,
table : ' person ' ,
} ,
operation : ' Iterate Index '
2024-03-12 10:48:53 +00:00
} ,
{
detail : {
2024-03-28 16:29:55 +00:00
type : ' Memory '
2024-03-12 10:48:53 +00:00
} ,
operation : ' Collector '
2023-07-13 10:12:34 +00:00
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
2023-06-19 18:41:13 +00:00
let val = Value ::parse (
" [
{
name : ' Tobie '
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
Ok ( ( ) )
}
#[ tokio::test ]
async fn select_where_and_with_unique_index ( ) -> Result < ( ) , Error > {
let sql = "
CREATE person :tobie SET name = ' Tobie ' , genre = 'm' ;
CREATE person :jaime SET name = ' Jaime ' , genre = 'm' ;
DEFINE INDEX person_name ON TABLE person COLUMNS name UNIQUE ;
2023-07-13 10:12:34 +00:00
SELECT name FROM person WHERE name = ' Jaime ' AND genre = 'm' EXPLAIN ;
SELECT name FROM person WHERE name = ' Jaime ' AND genre = 'm' ; " ;
2023-08-30 18:01:30 +00:00
let dbs = new_ds ( ) . await ? ;
2023-07-29 18:47:25 +00:00
let ses = Session ::owner ( ) . with_ns ( " test " ) . with_db ( " test " ) ;
2023-07-05 21:26:13 +00:00
let res = & mut dbs . execute ( sql , & ses , None ) . await ? ;
2023-07-13 10:12:34 +00:00
assert_eq! ( res . len ( ) , 5 ) ;
2023-06-19 18:41:13 +00:00
//
let _ = res . remove ( 0 ) . result ? ;
let _ = res . remove ( 0 ) . result ? ;
let _ = res . remove ( 0 ) . result ? ;
//
let tmp = res . remove ( 0 ) . result ? ;
2023-07-13 10:12:34 +00:00
let val = Value ::parse (
" [
{
detail : {
plan : {
index : ' person_name ' ,
operator : ' = ' ,
value : ' Jaime '
} ,
table : ' person ' ,
} ,
operation : ' Iterate Index '
2024-03-12 10:48:53 +00:00
} ,
{
detail : {
2024-03-28 16:29:55 +00:00
type : ' Memory '
2024-03-12 10:48:53 +00:00
} ,
operation : ' Collector '
2023-07-13 10:12:34 +00:00
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
2023-06-19 18:41:13 +00:00
let val = Value ::parse (
" [
{
name : ' Jaime '
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
Ok ( ( ) )
}
#[ tokio::test ]
async fn select_where_and_with_fulltext_index ( ) -> Result < ( ) , Error > {
let sql = "
CREATE person :tobie SET name = ' Tobie ' , genre = 'm' ;
CREATE person :jaime SET name = ' Jaime ' , genre = 'm' ;
DEFINE ANALYZER simple TOKENIZERS blank , class FILTERS lowercase ;
DEFINE INDEX ft_name ON TABLE person COLUMNS name SEARCH ANALYZER simple BM25 ( 1.2 , 0.75 ) ;
2023-07-13 10:12:34 +00:00
SELECT name FROM person WHERE name @ @ ' Jaime ' AND genre = 'm' EXPLAIN ;
SELECT name FROM person WHERE name @ @ ' Jaime ' AND genre = 'm' ; " ;
2023-08-30 18:01:30 +00:00
let dbs = new_ds ( ) . await ? ;
2023-07-29 18:47:25 +00:00
let ses = Session ::owner ( ) . with_ns ( " test " ) . with_db ( " test " ) ;
2023-07-05 21:26:13 +00:00
let res = & mut dbs . execute ( sql , & ses , None ) . await ? ;
2023-07-13 10:12:34 +00:00
assert_eq! ( res . len ( ) , 6 ) ;
2023-06-19 18:41:13 +00:00
//
let _ = res . remove ( 0 ) . result ? ;
let _ = res . remove ( 0 ) . result ? ;
let _ = res . remove ( 0 ) . result ? ;
let _ = res . remove ( 0 ) . result ? ;
//
let tmp = res . remove ( 0 ) . result ? ;
2023-07-13 10:12:34 +00:00
let val = Value ::parse (
" [
{
detail : {
plan : {
index : ' ft_name ' ,
operator : ' @ @ ' ,
value : ' Jaime '
} ,
table : ' person ' ,
} ,
operation : ' Iterate Index '
2024-03-12 10:48:53 +00:00
} ,
{
detail : {
2024-03-28 16:29:55 +00:00
type : ' Memory '
2024-03-12 10:48:53 +00:00
} ,
operation : ' Collector '
2023-07-13 10:12:34 +00:00
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
2023-06-19 18:41:13 +00:00
let val = Value ::parse (
" [
{
name : ' Jaime '
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
Ok ( ( ) )
}
2023-07-14 12:22:37 +00:00
#[ tokio::test ]
async fn select_where_explain ( ) -> Result < ( ) , Error > {
let sql = "
CREATE person :tobie SET name = ' Tobie ' ;
CREATE person :jaime SET name = ' Jaime ' ;
CREATE software :surreal SET name = ' SurrealDB ' ;
SELECT * FROM person , software EXPLAIN ;
SELECT * FROM person , software EXPLAIN FULL ; " ;
2023-08-30 18:01:30 +00:00
let dbs = new_ds ( ) . await ? ;
2023-07-29 18:47:25 +00:00
let ses = Session ::owner ( ) . with_ns ( " test " ) . with_db ( " test " ) ;
2023-07-14 12:22:37 +00:00
let res = & mut dbs . execute ( sql , & ses , None ) . await ? ;
assert_eq! ( res . len ( ) , 5 ) ;
//
let _ = res . remove ( 0 ) . result ? ;
let _ = res . remove ( 0 ) . result ? ;
let _ = res . remove ( 0 ) . result ? ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
detail : {
table : ' person ' ,
} ,
operation : ' Iterate Table '
} ,
{
detail : {
table : ' software ' ,
} ,
operation : ' Iterate Table '
2024-03-12 10:48:53 +00:00
} ,
{
detail : {
2024-03-28 16:29:55 +00:00
type : ' Memory '
2024-03-12 10:48:53 +00:00
} ,
operation : ' Collector '
} ,
2023-07-14 12:22:37 +00:00
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
detail : {
table : ' person ' ,
} ,
operation : ' Iterate Table '
} ,
{
detail : {
table : ' software ' ,
} ,
operation : ' Iterate Table '
} ,
2024-03-12 10:48:53 +00:00
{
detail : {
2024-03-28 16:29:55 +00:00
type : ' Memory '
2024-03-12 10:48:53 +00:00
} ,
operation : ' Collector '
} ,
2023-07-14 12:22:37 +00:00
{
detail : {
count : 3 ,
} ,
operation : ' Fetch '
} ,
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
Ok ( ( ) )
}
2023-07-29 18:47:25 +00:00
2023-09-12 10:14:09 +00:00
#[ tokio::test ]
async fn select_with_function_field ( ) -> Result < ( ) , Error > {
let sql = " SELECT *, function() { return this.a } AS b FROM [{ a: 1 }]; " ;
let dbs = new_ds ( ) . await ? ;
let ses = Session ::owner ( ) . with_ns ( " test " ) . with_db ( " test " ) ;
let res = & mut dbs . execute ( sql , & ses , None ) . await ? ;
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse ( " [{ a: 1, b: 1 }] " ) ;
assert_eq! ( tmp , val ) ;
Ok ( ( ) )
}
2023-07-29 18:47:25 +00:00
//
// Permissions
//
async fn common_permissions_checks ( auth_enabled : bool ) {
let tests = vec! [
// Root level
( ( ( ) . into ( ) , Role ::Owner ) , ( " NS " , " DB " ) , true , " owner at root level should be able to select " ) ,
( ( ( ) . into ( ) , Role ::Editor ) , ( " NS " , " DB " ) , true , " editor at root level should be able to select " ) ,
( ( ( ) . into ( ) , Role ::Viewer ) , ( " NS " , " DB " ) , true , " viewer at root level should not be able to select " ) ,
// Namespace level
( ( ( " NS " , ) . into ( ) , Role ::Owner ) , ( " NS " , " DB " ) , true , " owner at namespace level should be able to select on its namespace " ) ,
( ( ( " NS " , ) . into ( ) , Role ::Owner ) , ( " OTHER_NS " , " DB " ) , false , " owner at namespace level should not be able to select on another namespace " ) ,
( ( ( " NS " , ) . into ( ) , Role ::Editor ) , ( " NS " , " DB " ) , true , " editor at namespace level should be able to select on its namespace " ) ,
( ( ( " NS " , ) . into ( ) , Role ::Editor ) , ( " OTHER_NS " , " DB " ) , false , " editor at namespace level should not be able to select on another namespace " ) ,
( ( ( " NS " , ) . into ( ) , Role ::Viewer ) , ( " NS " , " DB " ) , true , " viewer at namespace level should not be able to select on its namespace " ) ,
( ( ( " NS " , ) . into ( ) , Role ::Viewer ) , ( " OTHER_NS " , " DB " ) , false , " viewer at namespace level should not be able to select on another namespace " ) ,
// Database level
( ( ( " NS " , " DB " ) . into ( ) , Role ::Owner ) , ( " NS " , " DB " ) , true , " owner at database level should be able to select on its database " ) ,
( ( ( " NS " , " DB " ) . into ( ) , Role ::Owner ) , ( " NS " , " OTHER_DB " ) , false , " owner at database level should not be able to select on another database " ) ,
( ( ( " NS " , " DB " ) . into ( ) , Role ::Owner ) , ( " OTHER_NS " , " DB " ) , false , " owner at database level should not be able to select on another namespace even if the database name matches " ) ,
( ( ( " NS " , " DB " ) . into ( ) , Role ::Editor ) , ( " NS " , " DB " ) , true , " editor at database level should be able to select on its database " ) ,
( ( ( " NS " , " DB " ) . into ( ) , Role ::Editor ) , ( " NS " , " OTHER_DB " ) , false , " editor at database level should not be able to select on another database " ) ,
( ( ( " NS " , " DB " ) . into ( ) , Role ::Editor ) , ( " OTHER_NS " , " DB " ) , false , " editor at database level should not be able to select on another namespace even if the database name matches " ) ,
( ( ( " NS " , " DB " ) . into ( ) , Role ::Viewer ) , ( " NS " , " DB " ) , true , " viewer at database level should not be able to select on its database " ) ,
( ( ( " NS " , " DB " ) . into ( ) , Role ::Viewer ) , ( " NS " , " OTHER_DB " ) , false , " viewer at database level should not be able to select on another database " ) ,
( ( ( " NS " , " DB " ) . into ( ) , Role ::Viewer ) , ( " OTHER_NS " , " DB " ) , false , " viewer at database level should not be able to select on another namespace even if the database name matches " ) ,
] ;
let statement = " SELECT * FROM person " ;
2024-08-21 12:34:16 +00:00
let empty_array = Value ::parse ( " [] " ) ;
2023-07-29 18:47:25 +00:00
for ( ( level , role ) , ( ns , db ) , should_succeed , msg ) in tests . into_iter ( ) {
let sess = Session ::for_level ( level , role ) . with_ns ( ns ) . with_db ( db ) ;
{
2023-08-30 18:01:30 +00:00
let ds = new_ds ( ) . await . unwrap ( ) . with_auth_enabled ( auth_enabled ) ;
2023-07-29 18:47:25 +00:00
// Prepare datastore
let mut resp = ds
. execute ( " CREATE person " , & Session ::owner ( ) . with_ns ( " NS " ) . with_db ( " DB " ) , None )
. await
. unwrap ( ) ;
let res = resp . remove ( 0 ) . output ( ) ;
assert! (
2024-08-21 12:34:16 +00:00
res . is_ok ( ) & & res . unwrap ( ) ! = empty_array ,
2023-07-29 18:47:25 +00:00
" unexpected error creating person record "
) ;
let mut resp = ds
. execute ( " CREATE person " , & Session ::owner ( ) . with_ns ( " OTHER_NS " ) . with_db ( " DB " ) , None )
. await
. unwrap ( ) ;
let res = resp . remove ( 0 ) . output ( ) ;
assert! (
2024-08-21 12:34:16 +00:00
res . is_ok ( ) & & res . unwrap ( ) ! = empty_array ,
2023-07-29 18:47:25 +00:00
" unexpected error creating person record "
) ;
let mut resp = ds
. execute ( " CREATE person " , & Session ::owner ( ) . with_ns ( " NS " ) . with_db ( " OTHER_DB " ) , None )
. await
. unwrap ( ) ;
let res = resp . remove ( 0 ) . output ( ) ;
assert! (
2024-08-21 12:34:16 +00:00
res . is_ok ( ) & & res . unwrap ( ) ! = empty_array ,
2023-07-29 18:47:25 +00:00
" unexpected error creating person record "
) ;
// Run the test
let mut resp = ds . execute ( statement , & sess , None ) . await . unwrap ( ) ;
let res = resp . remove ( 0 ) . output ( ) ;
// Select always succeeds, but the result may be empty
assert! ( res . is_ok ( ) ) ;
if should_succeed {
2024-08-21 12:34:16 +00:00
assert! ( res . unwrap ( ) ! = empty_array , " {} " , msg ) ;
2023-07-29 18:47:25 +00:00
} else {
2024-08-21 12:34:16 +00:00
assert! ( res . unwrap ( ) = = empty_array , " {} " , msg ) ;
2023-07-29 18:47:25 +00:00
}
}
}
}
#[ tokio::test ]
async fn check_permissions_auth_enabled ( ) {
let auth_enabled = true ;
//
// Test common scenarios
//
common_permissions_checks ( auth_enabled ) . await ;
//
// Test Anonymous user
//
// When the table grants no permissions
{
2023-08-30 18:01:30 +00:00
let ds = new_ds ( ) . await . unwrap ( ) . with_auth_enabled ( auth_enabled ) ;
2023-07-29 18:47:25 +00:00
let mut resp = ds
. execute (
" DEFINE TABLE person PERMISSIONS NONE; CREATE person; " ,
& Session ::owner ( ) . with_ns ( " NS " ) . with_db ( " DB " ) ,
None ,
)
. await
. unwrap ( ) ;
let res = resp . remove ( 0 ) . output ( ) ;
assert! ( res . is_ok ( ) , " failed to create table: {:?} " , res ) ;
let mut resp = ds
. execute ( " SELECT * FROM person " , & Session ::default ( ) . with_ns ( " NS " ) . with_db ( " DB " ) , None )
. await
. unwrap ( ) ;
let res = resp . remove ( 0 ) . output ( ) ;
assert! (
res . unwrap ( ) = = Value ::parse ( " [] " ) ,
" {} " ,
" anonymous user should not be able to select if the table has no permissions "
) ;
}
// When the table exists and grants full permissions
{
2023-08-30 18:01:30 +00:00
let ds = new_ds ( ) . await . unwrap ( ) . with_auth_enabled ( auth_enabled ) ;
2023-07-29 18:47:25 +00:00
let mut resp = ds
. execute (
" DEFINE TABLE person PERMISSIONS FULL; CREATE person; " ,
& Session ::owner ( ) . with_ns ( " NS " ) . with_db ( " DB " ) ,
None ,
)
. await
. unwrap ( ) ;
let res = resp . remove ( 0 ) . output ( ) ;
assert! ( res . is_ok ( ) , " failed to create table: {:?} " , res ) ;
let mut resp = ds
. execute ( " SELECT * FROM person " , & Session ::default ( ) . with_ns ( " NS " ) . with_db ( " DB " ) , None )
. await
. unwrap ( ) ;
let res = resp . remove ( 0 ) . output ( ) ;
assert! (
res . unwrap ( ) ! = Value ::parse ( " [] " ) ,
" {} " ,
" anonymous user should be able to select if the table has full permissions "
) ;
}
}
#[ tokio::test ]
async fn check_permissions_auth_disabled ( ) {
let auth_enabled = false ;
//
// Test common scenarios
//
common_permissions_checks ( auth_enabled ) . await ;
//
// Test Anonymous user
//
// When the table grants no permissions
{
2023-08-30 18:01:30 +00:00
let ds = new_ds ( ) . await . unwrap ( ) . with_auth_enabled ( auth_enabled ) ;
2023-07-29 18:47:25 +00:00
let mut resp = ds
. execute (
" DEFINE TABLE person PERMISSIONS NONE; CREATE person; " ,
& Session ::owner ( ) . with_ns ( " NS " ) . with_db ( " DB " ) ,
None ,
)
. await
. unwrap ( ) ;
let res = resp . remove ( 0 ) . output ( ) ;
assert! ( res . is_ok ( ) , " failed to create table: {:?} " , res ) ;
let mut resp = ds
. execute ( " SELECT * FROM person " , & Session ::default ( ) . with_ns ( " NS " ) . with_db ( " DB " ) , None )
. await
. unwrap ( ) ;
let res = resp . remove ( 0 ) . output ( ) ;
assert! (
res . unwrap ( ) ! = Value ::parse ( " [] " ) ,
" {} " ,
" anonymous user should be able to select if the table has no permissions "
) ;
}
// When the table exists and grants full permissions
{
2023-08-30 18:01:30 +00:00
let ds = new_ds ( ) . await . unwrap ( ) . with_auth_enabled ( auth_enabled ) ;
2023-07-29 18:47:25 +00:00
let mut resp = ds
. execute (
" DEFINE TABLE person PERMISSIONS FULL; CREATE person; " ,
& Session ::owner ( ) . with_ns ( " NS " ) . with_db ( " DB " ) ,
None ,
)
. await
. unwrap ( ) ;
let res = resp . remove ( 0 ) . output ( ) ;
assert! ( res . is_ok ( ) , " failed to create table: {:?} " , res ) ;
let mut resp = ds
. execute ( " SELECT * FROM person " , & Session ::default ( ) . with_ns ( " NS " ) . with_db ( " DB " ) , None )
. await
. unwrap ( ) ;
let res = resp . remove ( 0 ) . output ( ) ;
assert! (
res . unwrap ( ) ! = Value ::parse ( " [] " ) ,
" {} " ,
" anonymous user should be able to select if the table has full permissions "
) ;
}
}
2023-11-26 20:11:41 +00:00
#[ tokio::test ]
async fn select_only ( ) -> Result < ( ) , Error > {
let sql : & str = "
SELECT * FROM ONLY 1 ;
SELECT * FROM ONLY NONE ;
SELECT * FROM ONLY [ ] ;
SELECT * FROM ONLY [ 1 ] ;
SELECT * FROM ONLY [ 1 , 2 ] ;
SELECT * FROM ONLY [ ] LIMIT 1 ;
SELECT * FROM ONLY [ 1 ] LIMIT 1 ;
SELECT * FROM ONLY [ 1 , 2 ] LIMIT 1 ;
SELECT * FROM ONLY 1 , 2 ;
SELECT * FROM ONLY 1 , 2 LIMIT 1 ;
" ;
let dbs = new_ds ( ) . await ? ;
let ses = Session ::owner ( ) . with_ns ( " test " ) . with_db ( " test " ) ;
let res = & mut dbs . execute ( sql , & ses , None ) . await ? ;
assert_eq! ( res . len ( ) , 10 ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse ( " 1 " ) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse ( " NONE " ) ;
assert_eq! ( tmp , val ) ;
//
match res . remove ( 0 ) . result {
Err ( surrealdb ::error ::Db ::SingleOnlyOutput ) = > ( ) ,
_ = > panic! ( " Query should have failed with error: Expected a single result output when using the ONLY keyword " )
}
//
match res . remove ( 0 ) . result {
Err ( surrealdb ::error ::Db ::SingleOnlyOutput ) = > ( ) ,
_ = > panic! ( " Query should have failed with error: Expected a single result output when using the ONLY keyword " )
}
//
match res . remove ( 0 ) . result {
Err ( surrealdb ::error ::Db ::SingleOnlyOutput ) = > ( ) ,
_ = > panic! ( " Query should have failed with error: Expected a single result output when using the ONLY keyword " )
}
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse ( " NONE " ) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse ( " 1 " ) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse ( " 1 " ) ;
assert_eq! ( tmp , val ) ;
//
match res . remove ( 0 ) . result {
Err ( surrealdb ::error ::Db ::SingleOnlyOutput ) = > ( ) ,
_ = > panic! ( " Query should have failed with error: Expected a single result output when using the ONLY keyword " )
}
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse ( " 1 " ) ;
assert_eq! ( tmp , val ) ;
//
Ok ( ( ) )
}
2024-02-15 11:32:20 +00:00
#[ tokio::test ]
async fn select_issue_3510 ( ) -> Result < ( ) , Error > {
let sql : & str = "
CREATE a :1 ;
CREATE b :1 SET link = a :1 , num = 1 ;
SELECT link . * FROM b ;
SELECT link . * FROM b WHERE num = 1 ;
" ;
let dbs = new_ds ( ) . await ? ;
let ses = Session ::owner ( ) . with_ns ( " test " ) . with_db ( " test " ) ;
let res = & mut dbs . execute ( sql , & ses , None ) . await ? ;
assert_eq! ( res . len ( ) , 4 ) ;
//
let _ = res . remove ( 0 ) . result ? ;
let _ = res . remove ( 0 ) . result ? ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
link : {
id : a :1
}
}
] " ,
) ;
assert_eq! ( format! ( " {:#} " , tmp ) , format! ( " {:#} " , val ) ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
assert_eq! ( format! ( " {:#} " , tmp ) , format! ( " {:#} " , val ) ) ;
Ok ( ( ) )
}
2024-07-31 15:20:19 +00:00
#[ tokio::test ]
async fn select_destructure ( ) -> Result < ( ) , Error > {
let sql = "
CREATE person :1 SET name = ' John ' , age = 21 , obj = { a : 1 , b : 2 , c : { d : 3 , e : 4 , f : 5 } } ;
SELECT obj . { a , c . { e , f } } FROM person ;
SELECT * OMIT obj . c . { d , f } FROM person ;
" ;
let dbs = new_ds ( ) . await ? ;
let ses = Session ::owner ( ) . with_ns ( " test " ) . with_db ( " test " ) ;
let res = & mut dbs . execute ( sql , & ses , None ) . await ? ;
assert_eq! ( res . len ( ) , 3 ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
id : person :1 ,
name : ' John ' ,
age : 21 ,
obj : {
a : 1 ,
b : 2 ,
c : {
d : 3 ,
e : 4 ,
f : 5
}
}
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
obj : {
a : 1 ,
c : {
e : 4 ,
f : 5
}
}
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
id : person :1 ,
name : ' John ' ,
age : 21 ,
obj : {
a : 1 ,
b : 2 ,
c : { e : 4 }
}
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
Ok ( ( ) )
}
2024-08-05 17:06:54 +00:00
#[ tokio::test ]
async fn select_field_from_graph_no_flattening ( ) -> Result < ( ) , Error > {
let sql = "
CREATE a :1 , a :2 ;
RELATE a :1 ->b :1 ->a :2 SET list = [ 1 , 2 , 3 ] ;
RELATE a :1 ->b :2 ->a :2 SET list = [ 4 , 5 , 6 ] ;
SELECT VALUE ->b . list FROM a :1 ;
" ;
let dbs = new_ds ( ) . await ? ;
let ses = Session ::owner ( ) . with_ns ( " test " ) . with_db ( " test " ) ;
let res = & mut dbs . execute ( sql , & ses , None ) . await ? ;
assert_eq! ( res . len ( ) , 4 ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{ id : a :1 } ,
{ id : a :2 }
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
id : b :1 ,
in : a :1 ,
out : a :2 ,
list : [ 1 , 2 , 3 ]
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
{
id : b :2 ,
in : a :1 ,
out : a :2 ,
list : [ 4 , 5 , 6 ]
}
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
let tmp = res . remove ( 0 ) . result ? ;
let val = Value ::parse (
" [
[
[
1 ,
2 ,
3
] ,
[
4 ,
5 ,
6
]
]
] " ,
) ;
assert_eq! ( tmp , val ) ;
//
Ok ( ( ) )
}