From 80d65a198bfa1cf83cb5e9c6d2207565667d8ab4 Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Tue, 23 Jan 2024 20:22:51 +0200 Subject: [PATCH] optimized multiple records cascade delete query --- daos/record.go | 14 +++++++------- daos/record_test.go | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/daos/record.go b/daos/record.go index f16fe03f..1f79a004 100644 --- a/daos/record.go +++ b/daos/record.go @@ -659,8 +659,6 @@ func (dao *Dao) DeleteRecord(record *models.Record) error { // // NB! This method is expected to be called inside a transaction. func (dao *Dao) cascadeRecordDelete(mainRecord *models.Record, refs map[*models.Collection][]*schema.SchemaField) error { - uniqueJsonEachAlias := "__je__" + security.PseudorandomString(4) - // @todo consider changing refs to a slice // // Sort the refs keys to ensure that the cascade events firing order is always the same. @@ -684,15 +682,17 @@ func (dao *Dao) cascadeRecordDelete(mainRecord *models.Record, refs map[*models. recordTableName := inflector.Columnify(refCollection.Name) prefixedFieldName := recordTableName + "." + inflector.Columnify(field.Name) - query := dao.RecordQuery(refCollection).Distinct(true) + query := dao.RecordQuery(refCollection) if opt, ok := field.Options.(schema.MultiValuer); !ok || !opt.IsMultiple() { query.AndWhere(dbx.HashExp{prefixedFieldName: mainRecord.Id}) } else { - query.InnerJoin(fmt.Sprintf( - `json_each(CASE WHEN json_valid([[%s]]) THEN [[%s]] ELSE json_array([[%s]]) END) as {{%s}}`, - prefixedFieldName, prefixedFieldName, prefixedFieldName, uniqueJsonEachAlias, - ), dbx.HashExp{uniqueJsonEachAlias + ".value": mainRecord.Id}) + query.AndWhere(dbx.Exists(dbx.NewExp(fmt.Sprintf( + `SELECT 1 FROM json_each(CASE WHEN json_valid([[%s]]) THEN [[%s]] ELSE json_array([[%s]]) END) {{__je__}} WHERE [[__je__.value]]={:jevalue}`, + prefixedFieldName, prefixedFieldName, prefixedFieldName, + ), dbx.Params{ + "jevalue": mainRecord.Id, + }))) } if refCollection.Id == mainRecord.Collection().Id { diff --git a/daos/record_test.go b/daos/record_test.go index ed3b9e2c..12797128 100644 --- a/daos/record_test.go +++ b/daos/record_test.go @@ -1205,11 +1205,11 @@ func TestDeleteRecord(t *testing.T) { } // ensure that the json rel fields were prefixed joinedQueries := strings.Join(calledQueries, " ") - expectedRelManyPart := "`demo1` INNER JOIN json_each(CASE WHEN json_valid([[demo1.rel_many]]) THEN [[demo1.rel_many]] ELSE json_array([[demo1.rel_many]]) END)" + expectedRelManyPart := "SELECT `demo1`.* FROM `demo1` WHERE EXISTS (SELECT 1 FROM json_each(CASE WHEN json_valid([[demo1.rel_many]]) THEN [[demo1.rel_many]] ELSE json_array([[demo1.rel_many]]) END) {{__je__}} WHERE [[__je__.value]]='" if !strings.Contains(joinedQueries, expectedRelManyPart) { t.Fatalf("(rec3) Expected the cascade delete to call the query \n%v, got \n%v", expectedRelManyPart, calledQueries) } - expectedRelOnePart := "SELECT DISTINCT `demo1`.* FROM `demo1` WHERE (`demo1`.`rel_one`=" + expectedRelOnePart := "SELECT `demo1`.* FROM `demo1` WHERE (`demo1`.`rel_one`='" if !strings.Contains(joinedQueries, expectedRelOnePart) { t.Fatalf("(rec3) Expected the cascade delete to call the query \n%v, got \n%v", expectedRelOnePart, calledQueries) }