[#943] exposed apis.EnrichRecord and apis.EnrichRecords

This commit is contained in:
Gani Georgiev
2022-11-17 14:17:10 +02:00
parent 6e9cf986c5
commit 39408f135b
16 changed files with 297 additions and 212 deletions
+30 -19
View File
@@ -52,10 +52,11 @@ type RecordFieldResolver struct {
baseCollection *models.Collection
allowHiddenFields bool
allowedFields []string
requestData map[string]any
loadedCollections []*models.Collection
joins []join // we cannot use a map because the insertion order is not preserved
exprs []dbx.Expression
requestData *models.FilterRequestData
staticRequestData map[string]any
}
// NewRecordFieldResolver creates and initializes a new `RecordFieldResolver`.
@@ -66,10 +67,10 @@ type RecordFieldResolver struct {
func NewRecordFieldResolver(
dao *daos.Dao,
baseCollection *models.Collection,
requestData map[string]any,
requestData *models.FilterRequestData,
allowHiddenFields bool,
) *RecordFieldResolver {
return &RecordFieldResolver{
r := &RecordFieldResolver{
dao: dao,
baseCollection: baseCollection,
requestData: requestData,
@@ -86,6 +87,22 @@ func NewRecordFieldResolver(
`^\@collection\.\w+\.\w+[\w\.]*$`,
},
}
// @todo remove after IN operator and multi-match filter enhancements
r.staticRequestData = map[string]any{}
if r.requestData != nil {
r.staticRequestData["method"] = r.requestData.Method
r.staticRequestData["query"] = r.requestData.Query
r.staticRequestData["data"] = r.requestData.Data
r.staticRequestData["auth"] = nil
if r.requestData.AuthRecord != nil {
r.requestData.AuthRecord.IgnoreEmailVisibility(true)
r.staticRequestData["auth"] = r.requestData.AuthRecord.PublicExport()
r.requestData.AuthRecord.IgnoreEmailVisibility(false)
}
}
return r
}
// UpdateQuery implements `search.FieldResolver` interface.
@@ -159,6 +176,10 @@ func (r *RecordFieldResolver) Resolve(fieldName string) (resultName string, plac
return "", nil, fmt.Errorf("Invalid @request data field path in %q.", fieldName)
}
if r.requestData == nil {
return "NULL", nil, nil
}
// plain @request.* field
if !strings.HasPrefix(fieldName, "@request.auth.") || list.ExistInSlice(fieldName, plainRequestAuthFields) {
return r.resolveStaticRequestField(props[1:]...)
@@ -173,28 +194,18 @@ func (r *RecordFieldResolver) Resolve(fieldName string) (resultName string, plac
// resolve the auth collection fields
// ---
rawAuthRecordId, _ := extractNestedMapVal(r.requestData, "auth", "id")
authRecordId := cast.ToString(rawAuthRecordId)
if authRecordId == "" {
if r.requestData == nil || r.requestData.AuthRecord == nil || r.requestData.AuthRecord.Collection() == nil {
return "NULL", nil, nil
}
rawAuthCollectionId, _ := extractNestedMapVal(r.requestData, "auth", schema.FieldNameCollectionId)
authCollectionId := cast.ToString(rawAuthCollectionId)
if authCollectionId == "" {
return "NULL", nil, nil
}
collection, err := r.loadCollection(authCollectionId)
if err != nil {
return "", nil, fmt.Errorf("Failed to load collection %q from field path %q.", currentCollectionName, fieldName)
}
collection := r.requestData.AuthRecord.Collection()
r.loadedCollections = append(r.loadedCollections, collection)
currentCollectionName = collection.Name
currentTableAlias = "__auth_" + inflector.Columnify(currentCollectionName)
authIdParamKey := "auth" + security.PseudorandomString(5)
authIdParams := dbx.Params{authIdParamKey: authRecordId}
authIdParams := dbx.Params{authIdParamKey: r.requestData.AuthRecord.Id}
// ---
// join the auth collection
@@ -331,7 +342,7 @@ func (r *RecordFieldResolver) Resolve(fieldName string) (resultName string, plac
func (r *RecordFieldResolver) resolveStaticRequestField(path ...string) (resultName string, placeholderParams dbx.Params, err error) {
// ignore error because requestData is dynamic and some of the
// lookup keys may not be defined for the request
resultVal, _ := extractNestedMapVal(r.requestData, path...)
resultVal, _ := extractNestedMapVal(r.staticRequestData, path...)
switch v := resultVal.(type) {
case nil:
@@ -387,7 +398,7 @@ func extractNestedMapVal(m map[string]any, keys ...string) (result any, err erro
func (r *RecordFieldResolver) loadCollection(collectionNameOrId string) (*models.Collection, error) {
// return already loaded
for _, collection := range r.loadedCollections {
if collection.Name == collectionNameOrId || collection.Id == collectionNameOrId {
if collection.Id == collectionNameOrId || strings.EqualFold(collection.Name, collectionNameOrId) {
return collection, nil
}
}
+18 -13
View File
@@ -5,6 +5,7 @@ import (
"regexp"
"testing"
"github.com/pocketbase/pocketbase/models"
"github.com/pocketbase/pocketbase/resolvers"
"github.com/pocketbase/pocketbase/tests"
"github.com/pocketbase/pocketbase/tools/list"
@@ -19,8 +20,8 @@ func TestRecordFieldResolverUpdateQuery(t *testing.T) {
t.Fatal(err)
}
requestData := map[string]any{
"auth": authRecord.PublicExport(),
requestData := &models.FilterRequestData{
AuthRecord: authRecord,
}
scenarios := []struct {
@@ -181,8 +182,8 @@ func TestRecordFieldResolverResolveSchemaFields(t *testing.T) {
t.Fatal(err)
}
requestData := map[string]any{
"auth": authRecord.PublicExport(),
requestData := &models.FilterRequestData{
AuthRecord: authRecord,
}
r := resolvers.NewRecordFieldResolver(app.Dao(), collection, requestData, true)
@@ -262,16 +263,16 @@ func TestRecordFieldResolverResolveStaticRequestDataFields(t *testing.T) {
t.Fatal(err)
}
requestData := map[string]any{
"method": "get",
"query": map[string]any{
requestData := &models.FilterRequestData{
Method: "get",
Query: map[string]any{
"a": 123,
},
"data": map[string]any{
Data: map[string]any{
"b": 456,
"c": map[string]int{"sub": 1},
},
"user": authRecord.PublicExport(),
AuthRecord: authRecord,
}
r := resolvers.NewRecordFieldResolver(app.Dao(), collection, requestData, true)
@@ -295,7 +296,11 @@ func TestRecordFieldResolverResolveStaticRequestDataFields(t *testing.T) {
{"@request.data.c", false, `"{\"sub\":1}"`},
{"@request.auth", true, ""},
{"@request.auth.id", false, `"4q1xlclmfloku33"`},
{"@request.auth.file", false, `"[]"`},
{"@request.auth.email", false, `"test@example.com"`},
{"@request.auth.username", false, `"users75657"`},
{"@request.auth.verified", false, `false`},
{"@request.auth.emailVisibility", false, `false`},
{"@request.auth.missing", false, `NULL`},
}
for i, s := range scenarios {
@@ -315,7 +320,7 @@ func TestRecordFieldResolverResolveStaticRequestDataFields(t *testing.T) {
// ---
if len(params) == 0 {
if name != "NULL" {
t.Errorf("(%d) Expected 0 placeholder parameters, got %v", i, params)
t.Errorf("(%d) Expected 0 placeholder parameters for %v, got %v", i, name, params)
}
continue
}
@@ -323,7 +328,7 @@ func TestRecordFieldResolverResolveStaticRequestDataFields(t *testing.T) {
// existing key
// ---
if len(params) != 1 {
t.Errorf("(%d) Expected 1 placeholder parameter, got %v", i, params)
t.Errorf("(%d) Expected 1 placeholder parameter for %v, got %v", i, name, params)
continue
}
@@ -340,7 +345,7 @@ func TestRecordFieldResolverResolveStaticRequestDataFields(t *testing.T) {
encodedParamValue, _ := json.Marshal(paramValue)
if string(encodedParamValue) != s.expectParamValue {
t.Errorf("(%d) Expected params %v, got %v", i, s.expectParamValue, string(encodedParamValue))
t.Errorf("(%d) Expected params %v for %v, got %v", i, s.expectParamValue, name, string(encodedParamValue))
}
}
}