2022-07-07 00:19:05 +03:00
package resolvers_test
import (
"encoding/json"
2022-07-20 22:33:24 +03:00
"regexp"
2022-07-07 00:19:05 +03:00
"testing"
"github.com/pocketbase/pocketbase/resolvers"
"github.com/pocketbase/pocketbase/tests"
2022-07-20 22:33:24 +03:00
"github.com/pocketbase/pocketbase/tools/list"
2022-07-07 00:19:05 +03:00
)
func TestRecordFieldResolverUpdateQuery ( t * testing . T ) {
app , _ := tests . NewTestApp ( )
defer app . Cleanup ( )
collection , err := app . Dao ( ) . FindCollectionByNameOrId ( "demo4" )
if err != nil {
t . Fatal ( err )
}
2022-07-20 22:33:24 +03:00
requestData := map [ string ] any {
"user" : map [ string ] any {
"id" : "4d0197cc-2b4a-3f83-a26b-d77bc8423d3c" ,
"profile" : map [ string ] any {
"id" : "d13f60a4-5765-48c7-9e1d-3e782340f833" ,
"name" : "test" ,
} ,
} ,
}
2022-07-07 00:19:05 +03:00
scenarios := [ ] struct {
2022-07-20 22:33:24 +03:00
name string
fields [ ] string
expectQuery string
2022-07-07 00:19:05 +03:00
} {
2022-07-20 22:33:24 +03:00
{
"missing field" ,
[ ] string { "" } ,
"SELECT `demo4`.* FROM `demo4`" ,
} ,
{
"non relation field" ,
[ ] string { "title" } ,
2022-07-07 00:19:05 +03:00
"SELECT `demo4`.* FROM `demo4`" ,
2022-07-20 22:33:24 +03:00
} ,
{
"incomplete rel" ,
[ ] string { "onerel" } ,
2022-07-07 00:19:05 +03:00
"SELECT `demo4`.* FROM `demo4`" ,
2022-07-20 22:33:24 +03:00
} ,
{
"single rel" ,
[ ] string { "onerel.title" } ,
"SELECT DISTINCT `demo4`.* FROM `demo4` LEFT JOIN `demo4` `demo4_onerel` ON [[demo4.onerel]] LIKE ('%' || [[demo4_onerel.id]] || '%')" ,
} ,
{
"non-relation field + single rel" ,
[ ] string { "title" , "onerel.title" } ,
"SELECT DISTINCT `demo4`.* FROM `demo4` LEFT JOIN `demo4` `demo4_onerel` ON [[demo4.onerel]] LIKE ('%' || [[demo4_onerel.id]] || '%')" ,
} ,
{
"nested incomplete rels" ,
[ ] string { "manyrels.onerel" } ,
"SELECT DISTINCT `demo4`.* FROM `demo4` LEFT JOIN `demo4` `demo4_manyrels` ON [[demo4.manyrels]] LIKE ('%' || [[demo4_manyrels.id]] || '%')" ,
} ,
{
"nested complete rels" ,
[ ] string { "manyrels.onerel.title" } ,
"SELECT DISTINCT `demo4`.* FROM `demo4` LEFT JOIN `demo4` `demo4_manyrels` ON [[demo4.manyrels]] LIKE ('%' || [[demo4_manyrels.id]] || '%') LEFT JOIN `demo4` `demo4_manyrels_onerel` ON [[demo4_manyrels.onerel]] LIKE ('%' || [[demo4_manyrels_onerel.id]] || '%')" ,
} ,
{
"repeated nested rels" ,
[ ] string { "manyrels.onerel.manyrels.onerel.title" } ,
"SELECT DISTINCT `demo4`.* FROM `demo4` LEFT JOIN `demo4` `demo4_manyrels` ON [[demo4.manyrels]] LIKE ('%' || [[demo4_manyrels.id]] || '%') LEFT JOIN `demo4` `demo4_manyrels_onerel` ON [[demo4_manyrels.onerel]] LIKE ('%' || [[demo4_manyrels_onerel.id]] || '%') LEFT JOIN `demo4` `demo4_manyrels_onerel_manyrels` ON [[demo4_manyrels_onerel.manyrels]] LIKE ('%' || [[demo4_manyrels_onerel_manyrels.id]] || '%') LEFT JOIN `demo4` `demo4_manyrels_onerel_manyrels_onerel` ON [[demo4_manyrels_onerel_manyrels.onerel]] LIKE ('%' || [[demo4_manyrels_onerel_manyrels_onerel.id]] || '%')" ,
} ,
{
"multiple rels" ,
[ ] string { "manyrels.title" , "onerel.onefile" } ,
"SELECT DISTINCT `demo4`.* FROM `demo4` LEFT JOIN `demo4` `demo4_manyrels` ON [[demo4.manyrels]] LIKE ('%' || [[demo4_manyrels.id]] || '%') LEFT JOIN `demo4` `demo4_onerel` ON [[demo4.onerel]] LIKE ('%' || [[demo4_onerel.id]] || '%')" ,
} ,
{
"@collection join" ,
[ ] string { "@collection.demo.title" , "@collection.demo2.text" , "@collection.demo.file" } ,
"SELECT DISTINCT `demo4`.* FROM `demo4` LEFT JOIN `demo` `__collection_demo` LEFT JOIN `demo2` `__collection_demo2`" ,
} ,
{
"static @request.user.profile fields" ,
[ ] string { "@request.user.id" , "@request.user.profile.id" , "@request.data.demo" } ,
2022-07-07 00:19:05 +03:00
"SELECT `demo4`.* FROM `demo4`" ,
2022-07-20 22:33:24 +03:00
} ,
{
"relational @request.user.profile fields" ,
[ ] string { "@request.user.profile.rel.id" , "@request.user.profile.rel.name" } ,
"^" +
regexp . QuoteMeta ( "SELECT DISTINCT `demo4`.* FROM `demo4` LEFT JOIN `profiles` `__user_profiles` ON [[__user_profiles.id]] =" ) +
" {:.*} " +
regexp . QuoteMeta ( "LEFT JOIN `profiles` `__user_profiles_rel` ON [[__user_profiles.rel]] LIKE ('%' || [[__user_profiles_rel.id]] || '%')" ) +
"$" ,
} ,
2022-07-07 00:19:05 +03:00
}
for i , s := range scenarios {
query := app . Dao ( ) . RecordQuery ( collection )
2022-07-20 22:33:24 +03:00
r := resolvers . NewRecordFieldResolver ( app . Dao ( ) , collection , requestData )
for _ , field := range s . fields {
r . Resolve ( field )
}
2022-07-07 00:19:05 +03:00
if err := r . UpdateQuery ( query ) ; err != nil {
t . Errorf ( "(%d) UpdateQuery failed with error %v" , i , err )
continue
}
rawQuery := query . Build ( ) . SQL ( )
2022-07-20 22:33:24 +03:00
if ! list . ExistInSliceWithRegex ( rawQuery , [ ] string { s . expectQuery } ) {
t . Errorf ( "(%d) Expected query\n %v \ngot:\n %v" , i , s . expectQuery , rawQuery )
2022-07-07 00:19:05 +03:00
}
}
}
func TestRecordFieldResolverResolveSchemaFields ( t * testing . T ) {
app , _ := tests . NewTestApp ( )
defer app . Cleanup ( )
collection , err := app . Dao ( ) . FindCollectionByNameOrId ( "demo4" )
if err != nil {
t . Fatal ( err )
}
2022-07-20 22:33:24 +03:00
requestData := map [ string ] any {
"user" : map [ string ] any {
"id" : "4d0197cc-2b4a-3f83-a26b-d77bc8423d3c" ,
"profile" : map [ string ] any {
"id" : "d13f60a4-5765-48c7-9e1d-3e782340f833" ,
} ,
} ,
}
r := resolvers . NewRecordFieldResolver ( app . Dao ( ) , collection , requestData )
2022-07-07 00:19:05 +03:00
scenarios := [ ] struct {
fieldName string
expectError bool
expectName string
} {
{ "" , true , "" } ,
{ " " , true , "" } ,
{ "unknown" , true , "" } ,
{ "invalid format" , true , "" } ,
{ "id" , false , "[[demo4.id]]" } ,
{ "created" , false , "[[demo4.created]]" } ,
{ "updated" , false , "[[demo4.updated]]" } ,
{ "title" , false , "[[demo4.title]]" } ,
{ "title.test" , true , "" } ,
{ "manyrels" , false , "[[demo4.manyrels]]" } ,
{ "manyrels." , true , "" } ,
{ "manyrels.unknown" , true , "" } ,
{ "manyrels.title" , false , "[[demo4_manyrels.title]]" } ,
{ "manyrels.onerel.manyrels.onefile" , false , "[[demo4_manyrels_onerel_manyrels.onefile]]" } ,
2022-07-20 22:33:24 +03:00
// @request.user.profile relation join:
{ "@request.user.profile.rel.name" , false , "[[__user_profiles_rel.name]]" } ,
// @collection fieds:
2022-07-07 00:19:05 +03:00
{ "@collect" , true , "" } ,
{ "collection.demo4.title" , true , "" } ,
{ "@collection" , true , "" } ,
{ "@collection.unknown" , true , "" } ,
{ "@collection.demo" , true , "" } ,
{ "@collection.demo." , true , "" } ,
2022-07-20 22:33:24 +03:00
{ "@collection.demo.title" , false , "[[__collection_demo.title]]" } ,
{ "@collection.demo4.title" , false , "[[__collection_demo4.title]]" } ,
{ "@collection.demo4.id" , false , "[[__collection_demo4.id]]" } ,
{ "@collection.demo4.created" , false , "[[__collection_demo4.created]]" } ,
{ "@collection.demo4.updated" , false , "[[__collection_demo4.updated]]" } ,
2022-07-07 00:19:05 +03:00
{ "@collection.demo4.manyrels.missing" , true , "" } ,
2022-07-20 22:33:24 +03:00
{ "@collection.demo4.manyrels.onerel.manyrels.onerel.onefile" , false , "[[__collection_demo4_manyrels_onerel_manyrels_onerel.onefile]]" } ,
2022-07-07 00:19:05 +03:00
}
2022-07-20 22:33:24 +03:00
for _ , s := range scenarios {
2022-07-07 00:19:05 +03:00
name , params , err := r . Resolve ( s . fieldName )
hasErr := err != nil
if hasErr != s . expectError {
2022-07-20 22:33:24 +03:00
t . Errorf ( "(%q) Expected hasErr %v, got %v (%v)" , s . fieldName , s . expectError , hasErr , err )
2022-07-07 00:19:05 +03:00
continue
}
if name != s . expectName {
2022-07-20 22:33:24 +03:00
t . Errorf ( "(%q) Expected name %q, got %q" , s . fieldName , s . expectName , name )
2022-07-07 00:19:05 +03:00
}
// params should be empty for non @request fields
if len ( params ) != 0 {
2022-07-20 22:33:24 +03:00
t . Errorf ( "(%q) Expected 0 params, got %v" , s . fieldName , params )
2022-07-07 00:19:05 +03:00
}
}
}
2022-07-20 22:33:24 +03:00
func TestRecordFieldResolverResolveStaticRequestDataFields ( t * testing . T ) {
2022-07-07 00:19:05 +03:00
app , _ := tests . NewTestApp ( )
defer app . Cleanup ( )
collection , err := app . Dao ( ) . FindCollectionByNameOrId ( "demo4" )
if err != nil {
t . Fatal ( err )
}
requestData := map [ string ] any {
"method" : "get" ,
"query" : map [ string ] any {
"a" : 123 ,
} ,
"data" : map [ string ] any {
"b" : 456 ,
"c" : map [ string ] int { "sub" : 1 } ,
} ,
2022-07-20 22:33:24 +03:00
"user" : map [ string ] any {
"id" : "4d0197cc-2b4a-3f83-a26b-d77bc8423d3c" ,
"profile" : map [ string ] any {
"id" : "d13f60a4-5765-48c7-9e1d-3e782340f833" ,
"name" : "test" ,
} ,
} ,
2022-07-07 00:19:05 +03:00
}
r := resolvers . NewRecordFieldResolver ( app . Dao ( ) , collection , requestData )
scenarios := [ ] struct {
fieldName string
expectError bool
expectParamValue string // encoded json
} {
{ "@request" , true , "" } ,
{ "@request.invalid format" , true , "" } ,
{ "@request.invalid_format2!" , true , "" } ,
{ "@request.missing" , true , "" } ,
{ "@request.method" , false , ` "get" ` } ,
{ "@request.query" , true , ` ` } ,
{ "@request.query.a" , false , ` 123 ` } ,
{ "@request.query.a.missing" , false , ` ` } ,
{ "@request.data" , true , ` ` } ,
{ "@request.data.b" , false , ` 456 ` } ,
{ "@request.data.b.missing" , false , ` ` } ,
{ "@request.data.c" , false , ` " { \"sub\":1}" ` } ,
{ "@request.user" , true , "" } ,
2022-07-20 22:33:24 +03:00
{ "@request.user.id" , false , ` "4d0197cc-2b4a-3f83-a26b-d77bc8423d3c" ` } ,
{ "@request.user.profile" , false , ` " { \"id\":\"d13f60a4-5765-48c7-9e1d-3e782340f833\",\"name\":\"test\"}" ` } ,
{ "@request.user.profile.name" , false , ` "test" ` } ,
2022-07-07 00:19:05 +03:00
}
for i , s := range scenarios {
name , params , err := r . Resolve ( s . fieldName )
hasErr := err != nil
if hasErr != s . expectError {
t . Errorf ( "(%d) Expected hasErr %v, got %v (%v)" , i , s . expectError , hasErr , err )
continue
}
if hasErr {
continue
}
// missing key
// ---
if len ( params ) == 0 {
if name != "NULL" {
t . Errorf ( "(%d) Expected 0 placeholder parameters, got %v" , i , params )
}
continue
}
// existing key
// ---
if len ( params ) != 1 {
t . Errorf ( "(%d) Expected 1 placeholder parameter, got %v" , i , params )
continue
}
var paramName string
var paramValue any
for k , v := range params {
paramName = k
paramValue = v
}
if name != ( "{:" + paramName + "}" ) {
t . Errorf ( "(%d) Expected parameter name %q, got %q" , i , paramName , name )
}
encodedParamValue , _ := json . Marshal ( paramValue )
if string ( encodedParamValue ) != s . expectParamValue {
t . Errorf ( "(%d) Expected params %v, got %v" , i , s . expectParamValue , string ( encodedParamValue ) )
}
}
}