replaced indirect expand field.Unique with unique index constraint check
This commit is contained in:
		
							parent
							
								
									2a682a10b2
								
							
						
					
					
						commit
						226352f884
					
				|  | @ -9,6 +9,7 @@ import ( | ||||||
| 	"github.com/pocketbase/dbx" | 	"github.com/pocketbase/dbx" | ||||||
| 	"github.com/pocketbase/pocketbase/models" | 	"github.com/pocketbase/pocketbase/models" | ||||||
| 	"github.com/pocketbase/pocketbase/models/schema" | 	"github.com/pocketbase/pocketbase/models/schema" | ||||||
|  | 	"github.com/pocketbase/pocketbase/tools/dbutils" | ||||||
| 	"github.com/pocketbase/pocketbase/tools/inflector" | 	"github.com/pocketbase/pocketbase/tools/inflector" | ||||||
| 	"github.com/pocketbase/pocketbase/tools/list" | 	"github.com/pocketbase/pocketbase/tools/list" | ||||||
| 	"github.com/pocketbase/pocketbase/tools/security" | 	"github.com/pocketbase/pocketbase/tools/security" | ||||||
|  | @ -86,7 +87,7 @@ func (dao *Dao) expandRecords(records []*models.Record, expandPath string, fetch | ||||||
| 		if indirectRelFieldOptions == nil || indirectRelFieldOptions.CollectionId != mainCollection.Id { | 		if indirectRelFieldOptions == nil || indirectRelFieldOptions.CollectionId != mainCollection.Id { | ||||||
| 			return fmt.Errorf("Invalid indirect relation field path %q.", parts[0]) | 			return fmt.Errorf("Invalid indirect relation field path %q.", parts[0]) | ||||||
| 		} | 		} | ||||||
| 		if indirectRelFieldOptions.MaxSelect != nil && *indirectRelFieldOptions.MaxSelect != 1 { | 		if indirectRelFieldOptions.IsMultiple() { | ||||||
| 			// for now don't allow multi-relation indirect fields expand
 | 			// for now don't allow multi-relation indirect fields expand
 | ||||||
| 			// due to eventual poor query performance with large data sets.
 | 			// due to eventual poor query performance with large data sets.
 | ||||||
| 			return fmt.Errorf("Multi-relation fields cannot be indirectly expanded in %q.", parts[0]) | 			return fmt.Errorf("Multi-relation fields cannot be indirectly expanded in %q.", parts[0]) | ||||||
|  | @ -126,7 +127,7 @@ func (dao *Dao) expandRecords(records []*models.Record, expandPath string, fetch | ||||||
| 			MaxSelect:    nil, | 			MaxSelect:    nil, | ||||||
| 			CollectionId: indirectRel.Id, | 			CollectionId: indirectRel.Id, | ||||||
| 		} | 		} | ||||||
| 		if indirectRelField.Unique { | 		if isRelFieldUnique(indirectRel, indirectRelField.Name) { | ||||||
| 			relFieldOptions.MaxSelect = types.Pointer(1) | 			relFieldOptions.MaxSelect = types.Pointer(1) | ||||||
| 		} | 		} | ||||||
| 		// indirect relation
 | 		// indirect relation
 | ||||||
|  | @ -269,3 +270,14 @@ func normalizeExpands(paths []string) []string { | ||||||
| 
 | 
 | ||||||
| 	return list.ToUniqueStringSlice(result) | 	return list.ToUniqueStringSlice(result) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func isRelFieldUnique(collection *models.Collection, fieldName string) bool { | ||||||
|  | 	for _, idx := range collection.Indexes { | ||||||
|  | 		parsed := dbutils.ParseIndex(idx.(string)) | ||||||
|  | 		if parsed.Unique && len(parsed.Columns) == 1 && strings.EqualFold(parsed.Columns[0].Name, fieldName) { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -362,3 +362,57 @@ func TestExpandRecord(t *testing.T) { | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func TestIndirectExpandSingeVsArrayResult(t *testing.T) { | ||||||
|  | 	app, _ := tests.NewTestApp() | ||||||
|  | 	defer app.Cleanup() | ||||||
|  | 
 | ||||||
|  | 	record, err := app.Dao().FindRecordById("demo3", "7nwo8tuiatetxdm") | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// non-unique indirect expand
 | ||||||
|  | 	{ | ||||||
|  | 		errs := app.Dao().ExpandRecord(record, []string{"demo4(rel_one_cascade)"}, func(c *models.Collection, ids []string) ([]*models.Record, error) { | ||||||
|  | 			return app.Dao().FindRecordsByIds(c.Id, ids, nil) | ||||||
|  | 		}) | ||||||
|  | 		if len(errs) > 0 { | ||||||
|  | 			t.Fatal(errs) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		result, ok := record.Expand()["demo4(rel_one_cascade)"].([]*models.Record) | ||||||
|  | 		if !ok { | ||||||
|  | 			t.Fatalf("Expected the expanded result to be a slice, got %v", result) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// mock a unique constraint for the rel_one_cascade field
 | ||||||
|  | 	{ | ||||||
|  | 		demo4, err := app.Dao().FindCollectionByNameOrId("demo4") | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Fatal(err) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		demo4.Indexes = append(demo4.Indexes, "create unique index idx_unique_expand on demo4 (rel_one_cascade)") | ||||||
|  | 
 | ||||||
|  | 		if err := app.Dao().SaveCollection(demo4); err != nil { | ||||||
|  | 			t.Fatalf("Failed to mock unique constraint: %v", err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// non-unique indirect expand
 | ||||||
|  | 	{ | ||||||
|  | 		errs := app.Dao().ExpandRecord(record, []string{"demo4(rel_one_cascade)"}, func(c *models.Collection, ids []string) ([]*models.Record, error) { | ||||||
|  | 			return app.Dao().FindRecordsByIds(c.Id, ids, nil) | ||||||
|  | 		}) | ||||||
|  | 		if len(errs) > 0 { | ||||||
|  | 			t.Fatal(errs) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		result, ok := record.Expand()["demo4(rel_one_cascade)"].(*models.Record) | ||||||
|  | 		if !ok { | ||||||
|  | 			t.Fatalf("Expected the expanded result to be a single model, got %v", result) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
										
											Binary file not shown.
										
									
								
							
		Loading…
	
		Reference in New Issue