mirror of
https://github.com/pocketbase/pocketbase.git
synced 2024-12-01 11:01:04 +02:00
474 lines
12 KiB
Go
474 lines
12 KiB
Go
package daos_test
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/pocketbase/dbx"
|
|
"github.com/pocketbase/pocketbase/models"
|
|
"github.com/pocketbase/pocketbase/models/schema"
|
|
"github.com/pocketbase/pocketbase/tests"
|
|
"github.com/pocketbase/pocketbase/tools/list"
|
|
)
|
|
|
|
func TestRecordQuery(t *testing.T) {
|
|
app, _ := tests.NewTestApp()
|
|
defer app.Cleanup()
|
|
|
|
collection, _ := app.Dao().FindCollectionByNameOrId("demo")
|
|
|
|
expected := fmt.Sprintf("SELECT `%s`.* FROM `%s`", collection.Name, collection.Name)
|
|
|
|
sql := app.Dao().RecordQuery(collection).Build().SQL()
|
|
if sql != expected {
|
|
t.Errorf("Expected sql %s, got %s", expected, sql)
|
|
}
|
|
}
|
|
|
|
func TestFindRecordById(t *testing.T) {
|
|
app, _ := tests.NewTestApp()
|
|
defer app.Cleanup()
|
|
|
|
collection, _ := app.Dao().FindCollectionByNameOrId("demo")
|
|
|
|
scenarios := []struct {
|
|
id string
|
|
filter func(q *dbx.SelectQuery) error
|
|
expectError bool
|
|
}{
|
|
{"00000000-bafd-48f7-b8b7-090638afe209", nil, true},
|
|
{"b5c2ffc2-bafd-48f7-b8b7-090638afe209", nil, false},
|
|
{"b5c2ffc2-bafd-48f7-b8b7-090638afe209", func(q *dbx.SelectQuery) error {
|
|
q.AndWhere(dbx.HashExp{"title": "missing"})
|
|
return nil
|
|
}, true},
|
|
{"b5c2ffc2-bafd-48f7-b8b7-090638afe209", func(q *dbx.SelectQuery) error {
|
|
return errors.New("test error")
|
|
}, true},
|
|
{"b5c2ffc2-bafd-48f7-b8b7-090638afe209", func(q *dbx.SelectQuery) error {
|
|
q.AndWhere(dbx.HashExp{"title": "lorem"})
|
|
return nil
|
|
}, false},
|
|
}
|
|
|
|
for i, scenario := range scenarios {
|
|
record, err := app.Dao().FindRecordById(collection, scenario.id, scenario.filter)
|
|
|
|
hasErr := err != nil
|
|
if hasErr != scenario.expectError {
|
|
t.Errorf("(%d) Expected hasErr to be %v, got %v (%v)", i, scenario.expectError, hasErr, err)
|
|
}
|
|
|
|
if record != nil && record.Id != scenario.id {
|
|
t.Errorf("(%d) Expected record with id %s, got %s", i, scenario.id, record.Id)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFindRecordsByIds(t *testing.T) {
|
|
app, _ := tests.NewTestApp()
|
|
defer app.Cleanup()
|
|
|
|
collection, _ := app.Dao().FindCollectionByNameOrId("demo")
|
|
|
|
scenarios := []struct {
|
|
ids []string
|
|
filter func(q *dbx.SelectQuery) error
|
|
expectTotal int
|
|
expectError bool
|
|
}{
|
|
{[]string{}, nil, 0, false},
|
|
{[]string{"00000000-bafd-48f7-b8b7-090638afe209"}, nil, 0, false},
|
|
{[]string{"b5c2ffc2-bafd-48f7-b8b7-090638afe209"}, nil, 1, false},
|
|
{
|
|
[]string{"b5c2ffc2-bafd-48f7-b8b7-090638afe209", "848a1dea-5ddd-42d6-a00d-030547bffcfe"},
|
|
nil,
|
|
2,
|
|
false,
|
|
},
|
|
{
|
|
[]string{"b5c2ffc2-bafd-48f7-b8b7-090638afe209", "848a1dea-5ddd-42d6-a00d-030547bffcfe"},
|
|
func(q *dbx.SelectQuery) error {
|
|
return errors.New("test error")
|
|
},
|
|
0,
|
|
true,
|
|
},
|
|
{
|
|
[]string{"b5c2ffc2-bafd-48f7-b8b7-090638afe209", "848a1dea-5ddd-42d6-a00d-030547bffcfe"},
|
|
func(q *dbx.SelectQuery) error {
|
|
q.AndWhere(dbx.Like("title", "test").Match(true, true))
|
|
return nil
|
|
},
|
|
1,
|
|
false,
|
|
},
|
|
}
|
|
|
|
for i, scenario := range scenarios {
|
|
records, err := app.Dao().FindRecordsByIds(collection, scenario.ids, scenario.filter)
|
|
|
|
hasErr := err != nil
|
|
if hasErr != scenario.expectError {
|
|
t.Errorf("(%d) Expected hasErr to be %v, got %v (%v)", i, scenario.expectError, hasErr, err)
|
|
}
|
|
|
|
if len(records) != scenario.expectTotal {
|
|
t.Errorf("(%d) Expected %d records, got %d", i, scenario.expectTotal, len(records))
|
|
continue
|
|
}
|
|
|
|
for _, r := range records {
|
|
if !list.ExistInSlice(r.Id, scenario.ids) {
|
|
t.Errorf("(%d) Couldn't find id %s in %v", i, r.Id, scenario.ids)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFindRecordsByExpr(t *testing.T) {
|
|
app, _ := tests.NewTestApp()
|
|
defer app.Cleanup()
|
|
|
|
collection, _ := app.Dao().FindCollectionByNameOrId("demo")
|
|
|
|
scenarios := []struct {
|
|
expression dbx.Expression
|
|
expectIds []string
|
|
expectError bool
|
|
}{
|
|
{
|
|
nil,
|
|
[]string{},
|
|
true,
|
|
},
|
|
{
|
|
dbx.HashExp{"id": 123},
|
|
[]string{},
|
|
false,
|
|
},
|
|
{
|
|
dbx.Like("title", "test").Match(true, true),
|
|
[]string{
|
|
"848a1dea-5ddd-42d6-a00d-030547bffcfe",
|
|
"577bd676-aacb-4072-b7da-99d00ee210a4",
|
|
},
|
|
false,
|
|
},
|
|
}
|
|
|
|
for i, scenario := range scenarios {
|
|
records, err := app.Dao().FindRecordsByExpr(collection, scenario.expression)
|
|
|
|
hasErr := err != nil
|
|
if hasErr != scenario.expectError {
|
|
t.Errorf("(%d) Expected hasErr to be %v, got %v (%v)", i, scenario.expectError, hasErr, err)
|
|
}
|
|
|
|
if len(records) != len(scenario.expectIds) {
|
|
t.Errorf("(%d) Expected %d records, got %d", i, len(scenario.expectIds), len(records))
|
|
continue
|
|
}
|
|
|
|
for _, r := range records {
|
|
if !list.ExistInSlice(r.Id, scenario.expectIds) {
|
|
t.Errorf("(%d) Couldn't find id %s in %v", i, r.Id, scenario.expectIds)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFindFirstRecordByData(t *testing.T) {
|
|
app, _ := tests.NewTestApp()
|
|
defer app.Cleanup()
|
|
|
|
collection, _ := app.Dao().FindCollectionByNameOrId("demo")
|
|
|
|
scenarios := []struct {
|
|
key string
|
|
value any
|
|
expectId string
|
|
expectError bool
|
|
}{
|
|
{
|
|
"",
|
|
"848a1dea-5ddd-42d6-a00d-030547bffcfe",
|
|
"",
|
|
true,
|
|
},
|
|
{
|
|
"id",
|
|
"invalid",
|
|
"",
|
|
true,
|
|
},
|
|
{
|
|
"id",
|
|
"848a1dea-5ddd-42d6-a00d-030547bffcfe",
|
|
"848a1dea-5ddd-42d6-a00d-030547bffcfe",
|
|
false,
|
|
},
|
|
{
|
|
"title",
|
|
"lorem",
|
|
"b5c2ffc2-bafd-48f7-b8b7-090638afe209",
|
|
false,
|
|
},
|
|
}
|
|
|
|
for i, scenario := range scenarios {
|
|
record, err := app.Dao().FindFirstRecordByData(collection, scenario.key, scenario.value)
|
|
|
|
hasErr := err != nil
|
|
if hasErr != scenario.expectError {
|
|
t.Errorf("(%d) Expected hasErr to be %v, got %v (%v)", i, scenario.expectError, hasErr, err)
|
|
continue
|
|
}
|
|
|
|
if !scenario.expectError && record.Id != scenario.expectId {
|
|
t.Errorf("(%d) Expected record with id %s, got %v", i, scenario.expectId, record.Id)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIsRecordValueUnique(t *testing.T) {
|
|
app, _ := tests.NewTestApp()
|
|
defer app.Cleanup()
|
|
|
|
collection, _ := app.Dao().FindCollectionByNameOrId("demo4")
|
|
|
|
testManyRelsId1 := "df55c8ff-45ef-4c82-8aed-6e2183fe1125"
|
|
testManyRelsId2 := "b84cd893-7119-43c9-8505-3c4e22da28a9"
|
|
|
|
scenarios := []struct {
|
|
key string
|
|
value any
|
|
excludeId string
|
|
expected bool
|
|
}{
|
|
{"", "", "", false},
|
|
{"missing", "unique", "", false},
|
|
{"title", "unique", "", true},
|
|
{"title", "demo1", "", false},
|
|
{"title", "demo1", "054f9f24-0a0a-4e09-87b1-bc7ff2b336a2", true},
|
|
{"manyrels", []string{testManyRelsId2}, "", false},
|
|
{"manyrels", []any{testManyRelsId2}, "", false},
|
|
// with exclude
|
|
{"manyrels", []string{testManyRelsId1, testManyRelsId2}, "b8ba58f9-e2d7-42a0-b0e7-a11efd98236b", true},
|
|
// reverse order
|
|
{"manyrels", []string{testManyRelsId2, testManyRelsId1}, "", true},
|
|
}
|
|
|
|
for i, scenario := range scenarios {
|
|
result := app.Dao().IsRecordValueUnique(collection, scenario.key, scenario.value, scenario.excludeId)
|
|
|
|
if result != scenario.expected {
|
|
t.Errorf("(%d) Expected %v, got %v", i, scenario.expected, result)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFindUserRelatedRecords(t *testing.T) {
|
|
app, _ := tests.NewTestApp()
|
|
defer app.Cleanup()
|
|
|
|
u0 := &models.User{}
|
|
u1, _ := app.Dao().FindUserByEmail("test3@example.com")
|
|
u2, _ := app.Dao().FindUserByEmail("test2@example.com")
|
|
|
|
scenarios := []struct {
|
|
user *models.User
|
|
expectedIds []string
|
|
}{
|
|
{u0, []string{}},
|
|
{u1, []string{
|
|
"94568ca2-0bee-49d7-b749-06cb97956fd9", // demo2
|
|
"fc69274d-ca5c-416a-b9ef-561b101cfbb1", // profile
|
|
}},
|
|
{u2, []string{
|
|
"b2d5e39d-f569-4cc1-b593-3f074ad026bf", // profile
|
|
}},
|
|
}
|
|
|
|
for i, scenario := range scenarios {
|
|
records, err := app.Dao().FindUserRelatedRecords(scenario.user)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(records) != len(scenario.expectedIds) {
|
|
t.Errorf("(%d) Expected %d records, got %d (%v)", i, len(scenario.expectedIds), len(records), records)
|
|
continue
|
|
}
|
|
|
|
for _, r := range records {
|
|
if !list.ExistInSlice(r.Id, scenario.expectedIds) {
|
|
t.Errorf("(%d) Couldn't find %s in %v", i, r.Id, scenario.expectedIds)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSaveRecord(t *testing.T) {
|
|
app, _ := tests.NewTestApp()
|
|
defer app.Cleanup()
|
|
|
|
collection, _ := app.Dao().FindCollectionByNameOrId("demo")
|
|
|
|
// create
|
|
// ---
|
|
r1 := models.NewRecord(collection)
|
|
r1.SetDataValue("title", "test_new")
|
|
err1 := app.Dao().SaveRecord(r1)
|
|
if err1 != nil {
|
|
t.Fatal(err1)
|
|
}
|
|
newR1, _ := app.Dao().FindFirstRecordByData(collection, "title", "test_new")
|
|
if newR1 == nil || newR1.Id != r1.Id || newR1.GetStringDataValue("title") != r1.GetStringDataValue("title") {
|
|
t.Errorf("Expected to find record %v, got %v", r1, newR1)
|
|
}
|
|
|
|
// update
|
|
// ---
|
|
r2, _ := app.Dao().FindFirstRecordByData(collection, "id", "b5c2ffc2-bafd-48f7-b8b7-090638afe209")
|
|
r2.SetDataValue("title", "test_update")
|
|
err2 := app.Dao().SaveRecord(r2)
|
|
if err2 != nil {
|
|
t.Fatal(err2)
|
|
}
|
|
newR2, _ := app.Dao().FindFirstRecordByData(collection, "title", "test_update")
|
|
if newR2 == nil || newR2.Id != r2.Id || newR2.GetStringDataValue("title") != r2.GetStringDataValue("title") {
|
|
t.Errorf("Expected to find record %v, got %v", r2, newR2)
|
|
}
|
|
}
|
|
|
|
func TestDeleteRecord(t *testing.T) {
|
|
app, _ := tests.NewTestApp()
|
|
defer app.Cleanup()
|
|
|
|
demo, _ := app.Dao().FindCollectionByNameOrId("demo")
|
|
demo2, _ := app.Dao().FindCollectionByNameOrId("demo2")
|
|
|
|
// delete unsaved record
|
|
// ---
|
|
rec1 := models.NewRecord(demo)
|
|
err1 := app.Dao().DeleteRecord(rec1)
|
|
if err1 == nil {
|
|
t.Fatal("(rec1) Didn't expect to succeed deleting new record")
|
|
}
|
|
|
|
// delete existing record while being part of a non-cascade required relation
|
|
// ---
|
|
rec2, _ := app.Dao().FindFirstRecordByData(demo, "id", "848a1dea-5ddd-42d6-a00d-030547bffcfe")
|
|
err2 := app.Dao().DeleteRecord(rec2)
|
|
if err2 == nil {
|
|
t.Fatalf("(rec2) Expected error, got nil")
|
|
}
|
|
|
|
// delete existing record
|
|
// ---
|
|
rec3, _ := app.Dao().FindFirstRecordByData(demo, "id", "577bd676-aacb-4072-b7da-99d00ee210a4")
|
|
err3 := app.Dao().DeleteRecord(rec3)
|
|
if err3 != nil {
|
|
t.Fatalf("(rec3) Expected nil, got error %v", err3)
|
|
}
|
|
|
|
// check if it was really deleted
|
|
rec3, _ = app.Dao().FindRecordById(demo, rec3.Id, nil)
|
|
if rec3 != nil {
|
|
t.Fatalf("(rec3) Expected record to be deleted, got %v", rec3)
|
|
}
|
|
|
|
// check if the operation cascaded
|
|
rel, _ := app.Dao().FindFirstRecordByData(demo2, "id", "63c2ab80-84ab-4057-a592-4604a731f78f")
|
|
if rel != nil {
|
|
t.Fatalf("(rec3) Expected the delete to cascade, found relation %v", rel)
|
|
}
|
|
}
|
|
|
|
func TestSyncRecordTableSchema(t *testing.T) {
|
|
app, _ := tests.NewTestApp()
|
|
defer app.Cleanup()
|
|
|
|
oldCollection, err := app.Dao().FindCollectionByNameOrId("demo")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
updatedCollection, err := app.Dao().FindCollectionByNameOrId("demo")
|
|
updatedCollection.Name = "demo_renamed"
|
|
updatedCollection.Schema.RemoveField(updatedCollection.Schema.GetFieldByName("file").Id)
|
|
updatedCollection.Schema.AddField(
|
|
&schema.SchemaField{
|
|
Name: "new_field",
|
|
Type: schema.FieldTypeEmail,
|
|
},
|
|
)
|
|
updatedCollection.Schema.AddField(
|
|
&schema.SchemaField{
|
|
Id: updatedCollection.Schema.GetFieldByName("title").Id,
|
|
Name: "title_renamed",
|
|
Type: schema.FieldTypeEmail,
|
|
},
|
|
)
|
|
|
|
scenarios := []struct {
|
|
newCollection *models.Collection
|
|
oldCollection *models.Collection
|
|
expectedTableName string
|
|
expectedColumns []string
|
|
}{
|
|
{
|
|
&models.Collection{
|
|
Name: "new_table",
|
|
Schema: schema.NewSchema(
|
|
&schema.SchemaField{
|
|
Name: "test",
|
|
Type: schema.FieldTypeText,
|
|
},
|
|
),
|
|
},
|
|
nil,
|
|
"new_table",
|
|
[]string{"id", "created", "updated", "test"},
|
|
},
|
|
// no changes
|
|
{
|
|
oldCollection,
|
|
oldCollection,
|
|
"demo",
|
|
[]string{"id", "created", "updated", "title", "file"},
|
|
},
|
|
// renamed table, deleted column, renamed columnd and new column
|
|
{
|
|
updatedCollection,
|
|
oldCollection,
|
|
"demo_renamed",
|
|
[]string{"id", "created", "updated", "title_renamed", "new_field"},
|
|
},
|
|
}
|
|
|
|
for i, scenario := range scenarios {
|
|
err := app.Dao().SyncRecordTableSchema(scenario.newCollection, scenario.oldCollection)
|
|
if err != nil {
|
|
t.Errorf("(%d) %v", i, err)
|
|
continue
|
|
}
|
|
|
|
if !app.Dao().HasTable(scenario.newCollection.Name) {
|
|
t.Errorf("(%d) Expected table %s to exist", i, scenario.newCollection.Name)
|
|
}
|
|
|
|
cols, _ := app.Dao().GetTableColumns(scenario.newCollection.Name)
|
|
if len(cols) != len(scenario.expectedColumns) {
|
|
t.Errorf("(%d) Expected columns %v, got %v", i, scenario.expectedColumns, cols)
|
|
}
|
|
|
|
for _, c := range cols {
|
|
if !list.ExistInSlice(c, scenario.expectedColumns) {
|
|
t.Errorf("(%d) Couldn't find column %s in %v", i, c, scenario.expectedColumns)
|
|
}
|
|
}
|
|
}
|
|
}
|