sync with master
This commit is contained in:
		
						commit
						536707bfe7
					
				| 
						 | 
					@ -56,6 +56,12 @@
 | 
				
			||||||
  store.GetAll() map[string]T
 | 
					  store.GetAll() map[string]T
 | 
				
			||||||
  ```
 | 
					  ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## v0.11.4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Fixed cascade delete for rel records with the same id as the main record ([#1689](https://github.com/pocketbase/pocketbase/issues/1689)).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## v0.11.3
 | 
					## v0.11.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Fix realtime API panic on concurrent clients iteration ([#1628](https://github.com/pocketbase/pocketbase/issues/1628))
 | 
					- Fix realtime API panic on concurrent clients iteration ([#1628](https://github.com/pocketbase/pocketbase/issues/1628))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -98,6 +98,7 @@ func (dao *Dao) FindRecordsByIds(
 | 
				
			||||||
// Returns an empty slice if no records are found.
 | 
					// Returns an empty slice if no records are found.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// Example:
 | 
					// Example:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
//	expr1 := dbx.HashExp{"email": "test@example.com"}
 | 
					//	expr1 := dbx.HashExp{"email": "test@example.com"}
 | 
				
			||||||
//	expr2 := dbx.NewExp("LOWER(username) = {:username}", dbx.Params{"username": "test"})
 | 
					//	expr2 := dbx.NewExp("LOWER(username) = {:username}", dbx.Params{"username": "test"})
 | 
				
			||||||
//	dao.FindRecordsByExpr("example", expr1, expr2)
 | 
					//	dao.FindRecordsByExpr("example", expr1, expr2)
 | 
				
			||||||
| 
						 | 
					@ -402,13 +403,16 @@ func (dao *Dao) cascadeRecordDelete(mainRecord *models.Record, refs map[*models.
 | 
				
			||||||
			// @todo optimize single relation lookup in v0.12+
 | 
								// @todo optimize single relation lookup in v0.12+
 | 
				
			||||||
			query := dao.RecordQuery(refCollection).
 | 
								query := dao.RecordQuery(refCollection).
 | 
				
			||||||
				Distinct(true).
 | 
									Distinct(true).
 | 
				
			||||||
				AndWhere(dbx.Not(dbx.HashExp{recordTableName + ".id": mainRecord.Id})).
 | 
					 | 
				
			||||||
				InnerJoin(fmt.Sprintf(
 | 
									InnerJoin(fmt.Sprintf(
 | 
				
			||||||
					// note: the case is used to normalize the value access
 | 
										// note: the case is used to normalize the value access
 | 
				
			||||||
					`json_each(CASE WHEN json_valid([[%s]]) THEN [[%s]] ELSE json_array([[%s]]) END) as {{%s}}`,
 | 
										`json_each(CASE WHEN json_valid([[%s]]) THEN [[%s]] ELSE json_array([[%s]]) END) as {{%s}}`,
 | 
				
			||||||
					prefixedFieldName, prefixedFieldName, prefixedFieldName, uniqueJsonEachAlias,
 | 
										prefixedFieldName, prefixedFieldName, prefixedFieldName, uniqueJsonEachAlias,
 | 
				
			||||||
				), dbx.HashExp{uniqueJsonEachAlias + ".value": mainRecord.Id})
 | 
									), dbx.HashExp{uniqueJsonEachAlias + ".value": mainRecord.Id})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if refCollection.Id == mainRecord.Collection().Id {
 | 
				
			||||||
 | 
									query.AndWhere(dbx.Not(dbx.HashExp{recordTableName + ".id": mainRecord.Id}))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// trigger cascade for each batchSize rel items until there is none
 | 
								// trigger cascade for each batchSize rel items until there is none
 | 
				
			||||||
			batchSize := 4000
 | 
								batchSize := 4000
 | 
				
			||||||
			rows := make([]dbx.NullStringMap, 0, batchSize)
 | 
								rows := make([]dbx.NullStringMap, 0, batchSize)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -693,6 +693,12 @@ func TestDeleteRecordBatchProcessing(t *testing.T) {
 | 
				
			||||||
		t.Fatal("The main record wasn't deleted")
 | 
							t.Fatal("The main record wasn't deleted")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// check if the c1 b rel field were updated
 | 
				
			||||||
 | 
						c1RecordB, err := app.Dao().FindRecordById("c1", "b")
 | 
				
			||||||
 | 
						if err != nil || c1RecordB.GetString("rel") != "" {
 | 
				
			||||||
 | 
							t.Fatalf("Expected c1RecordB.rel to be nil, got %v", c1RecordB.GetString("rel"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// check if the c2 rel fields were updated
 | 
						// check if the c2 rel fields were updated
 | 
				
			||||||
	c2Records, err := app.Dao().FindRecordsByExpr("c2", nil)
 | 
						c2Records, err := app.Dao().FindRecordsByExpr("c2", nil)
 | 
				
			||||||
	if err != nil || len(c2Records) == 0 {
 | 
						if err != nil || len(c2Records) == 0 {
 | 
				
			||||||
| 
						 | 
					@ -725,6 +731,16 @@ func createMockBatchProcessingData(dao *daos.Dao) error {
 | 
				
			||||||
			Name: "text",
 | 
								Name: "text",
 | 
				
			||||||
			Type: schema.FieldTypeText,
 | 
								Type: schema.FieldTypeText,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							// self reference
 | 
				
			||||||
 | 
							&schema.SchemaField{
 | 
				
			||||||
 | 
								Name: "rel",
 | 
				
			||||||
 | 
								Type: schema.FieldTypeRelation,
 | 
				
			||||||
 | 
								Options: &schema.RelationOptions{
 | 
				
			||||||
 | 
									MaxSelect:     types.Pointer(1),
 | 
				
			||||||
 | 
									CollectionId:  "c1",
 | 
				
			||||||
 | 
									CascadeDelete: false, // should unset all rel fields
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	if err := dao.SaveCollection(c1); err != nil {
 | 
						if err := dao.SaveCollection(c1); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
| 
						 | 
					@ -771,15 +787,17 @@ func createMockBatchProcessingData(dao *daos.Dao) error {
 | 
				
			||||||
	// insert mock records
 | 
						// insert mock records
 | 
				
			||||||
	c1RecordA := models.NewRecord(c1)
 | 
						c1RecordA := models.NewRecord(c1)
 | 
				
			||||||
	c1RecordA.Id = "a"
 | 
						c1RecordA.Id = "a"
 | 
				
			||||||
 | 
						c1RecordA.Set("rel", c1RecordA.Id) // self reference
 | 
				
			||||||
	if err := dao.Save(c1RecordA); err != nil {
 | 
						if err := dao.Save(c1RecordA); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	c1RecordB := models.NewRecord(c1)
 | 
						c1RecordB := models.NewRecord(c1)
 | 
				
			||||||
	c1RecordB.Id = "b"
 | 
						c1RecordB.Id = "b"
 | 
				
			||||||
 | 
						c1RecordB.Set("rel", c1RecordA.Id) // rel to another record from the same collection
 | 
				
			||||||
	if err := dao.Save(c1RecordB); err != nil {
 | 
						if err := dao.Save(c1RecordB); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for i := 0; i < 2400; i++ {
 | 
						for i := 0; i < 4500; i++ {
 | 
				
			||||||
		c2Record := models.NewRecord(c2)
 | 
							c2Record := models.NewRecord(c2)
 | 
				
			||||||
		c2Record.Set("rel", []string{c1RecordA.Id, c1RecordB.Id})
 | 
							c2Record.Set("rel", []string{c1RecordA.Id, c1RecordB.Id})
 | 
				
			||||||
		if err := dao.Save(c2Record); err != nil {
 | 
							if err := dao.Save(c2Record); err != nil {
 | 
				
			||||||
| 
						 | 
					@ -793,5 +811,14 @@ func createMockBatchProcessingData(dao *daos.Dao) error {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// set the same id as the relation for at least 1 record
 | 
				
			||||||
 | 
						// to check whether the correct condition will be added
 | 
				
			||||||
 | 
						c3Record := models.NewRecord(c3)
 | 
				
			||||||
 | 
						c3Record.Set("rel", c1RecordA.Id)
 | 
				
			||||||
 | 
						c3Record.Id = c1RecordA.Id
 | 
				
			||||||
 | 
						if err := dao.Save(c3Record); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue