Exemple #1
0
// Returns a session that's not backed by a database
func createFakeSession() *dbr.Session {
	cxn, err := dbr.NewConnection()
	if err != nil {
		panic(err)
	}
	return cxn.NewSession()
}
Exemple #2
0
func TestEntityTypeSliceGetByCode(t *testing.T) {
	db := csdb.MustConnectTest()
	defer db.Close()
	dbrSess := dbr.NewConnection(db, nil).NewSession(nil)

	s, err := eav.TableCollection.Structure(eav.TableIndexEntityType)
	if err != nil {
		t.Error(err)
	}

	var entityTypeCollection eav.TableEntityTypeSlice
	_, err = dbrSess.
		Select(s.Columns...).
		From(s.Name).
		LoadStructs(&entityTypeCollection)
	if err != nil {
		t.Error(err)
	}

	etc, err := entityTypeCollection.GetByCode("catalog_categories")
	assert.Nil(t, etc)
	assert.Error(t, err)

	etc, err = entityTypeCollection.GetByCode("catalog_category")
	assert.NotNil(t, etc)
	assert.NoError(t, err)
}
Exemple #3
0
func TestTableStructure(t *testing.T) {
	db := csdb.MustConnectTest()
	defer db.Close()

	sValid, err := tableMap.Structure(table1)
	assert.NotNil(t, sValid)
	assert.NoError(t, err)

	assert.Equal(t, "catalog_category_anc_categs_index_tmp", tableMap.Name(table2))
	assert.Equal(t, "", tableMap.Name(table4))

	sInvalid, err := tableMap.Structure(table4)
	assert.Nil(t, sInvalid)
	assert.Error(t, err)

	dbrSess := dbr.NewConnection(db, nil).NewSession(nil)
	selectBuilder, err := sValid.Select(dbrSess)
	assert.NoError(t, err)
	selectString, _ := selectBuilder.ToSql()
	assert.Equal(t, "SELECT `main_table`.`category_id`, `main_table`.`path` FROM `catalog_category_anc_categs_index_idx` AS `main_table`", selectString)

	selectBuilder, err = sInvalid.Select(dbrSess)
	assert.Error(t, err)
	assert.Nil(t, selectBuilder)
}
Exemple #4
0
func TestSaveToDb(t *testing.T) {
	//for hacking testing added :-)
	db := csdb.MustConnectTest()
	defer db.Close()
	dbrSess := dbr.NewConnection(db, nil).NewSession(nil)

	//		var peds = TableProductEntityDecimalSlice{
	//			&TableProductEntityDecimal{ValueID: 1, AttributeID: 73, StoreID: 0, EntityID: 1, Value: money.New(money.Precision(4)).Set(9990000)},
	//			&TableProductEntityDecimal{ValueID: 2, AttributeID: 78, StoreID: 0, EntityID: 1, Value: money.New(money.Precision(4))}, // null values
	//			&TableProductEntityDecimal{ValueID: 3, AttributeID: 74, StoreID: 0, EntityID: 1, Value: money.New(money.Precision(4))}, // null values
	//			&TableProductEntityDecimal{ValueID: 4, AttributeID: 77, StoreID: 0, EntityID: 1, Value: money.New(money.Precision(4))}, // null values
	//			&TableProductEntityDecimal{ValueID: 5, AttributeID: 73, StoreID: 1, EntityID: 1, Value: money.New(money.Precision(4)).Set(7059933)},
	//			&TableProductEntityDecimal{ValueID: 6, AttributeID: 73, StoreID: 4, EntityID: 1, Value: money.New(money.Precision(4)).Set(7059933)},
	//			&TableProductEntityDecimal{ValueID: 7, AttributeID: 73, StoreID: 2, EntityID: 1, Value: money.New(money.Precision(4)).Set(7059933)},
	//			&TableProductEntityDecimal{ValueID: 8, AttributeID: 73, StoreID: 3, EntityID: 1, Value: money.New(money.Precision(4)).Set(7059933)},
	//		}

	tuple := &TableProductEntityDecimal{ValueID: 0, AttributeID: 73, StoreID: 3, EntityID: 231, Value: money.New(money.Precision(4)).Set(7779933)}
	tuple2 := &TableProductEntityDecimal{ValueID: 0, AttributeID: 74, StoreID: 2, EntityID: 231, Value: money.New(money.Precision(4)).Set(8889933)}
	ib := dbrSess.InsertInto("catalog_product_entity_decimal")
	ib.Columns("attribute_id", "store_id", "entity_id", "value")

	ib.Values(tuple.AttributeID, tuple.StoreID, tuple.EntityID, &tuple.Value)
	ib.Values(tuple2.AttributeID, tuple2.StoreID, tuple2.EntityID, &tuple2.Value)
	//	t.Error(ib.ToSql())
	res, err := ib.Exec()
	t.Log(err)
	t.Logf("%#v", res)
	t.Log(res.LastInsertId())
	t.Log(res.RowsAffected())

}
Exemple #5
0
// Connect creates a new database connection from a DSN stored in an
// environment variable.
func Connect(opts ...dbr.ConnectionOption) (*dbr.Connection, error) {
	dsn, err := GetDSN()
	if err != nil {
		return nil, errgo.Mask(err)
	}
	c, err := dbr.NewConnection(dbr.SetDSN(dsn))
	return c.ApplyOpts(opts...), err
}
Exemple #6
0
func TestApplyCoreConfigData(t *testing.T) {
	db := csdb.MustConnectTest()
	defer db.Close()
	sess := dbr.NewConnection(db, nil).NewSession(nil)

	m := config.NewManager()
	if err := m.ApplyCoreConfigData(sess); err != nil {
		t.Error(err)
	}
}
Exemple #7
0
func TestTableStoreSliceLoad(t *testing.T) {
	db := csdb.MustConnectTest()
	defer db.Close()
	dbrSess := dbr.NewConnection(db, nil).NewSession(nil)
	var stores store.TableStoreSlice
	stores.Load(dbrSess)
	assert.True(t, stores.Len() > 2)
	for _, s := range stores {
		assert.True(t, len(s.Code.String) > 1)
	}
}
Exemple #8
0
func TestTableGroupSliceLoad(t *testing.T) {
	db := csdb.MustConnectTest()
	defer db.Close()
	dbrSess := dbr.NewConnection(db, nil).NewSession(nil)
	var groups store.TableGroupSlice
	groups.Load(dbrSess)
	assert.True(t, groups.Len() > 2)
	for _, s := range groups {
		assert.True(t, len(s.Name) > 1)
	}
}
Exemple #9
0
func TestGetAttributeSelectSql(t *testing.T) {
	db := csdb.MustConnectTest()
	defer db.Close()

	dbrSess := dbr.NewConnection(db, nil).NewSession(nil)
	dbrSelect, err := eav.GetAttributeSelectSql(dbrSess, NewAddAttrTables(db, "customer"), 1, 4)
	if err != nil {
		t.Error(err)
	}
	sql, _ := dbrSelect.ToSql()
	assert.Equal(t, "SELECT `main_table`.`attribute_id`, `main_table`.`entity_type_id`, `main_table`.`attribute_code`, `main_table`.`backend_model`, `main_table`.`backend_type`, `main_table`.`backend_table`, `main_table`.`frontend_model`, `main_table`.`frontend_input`, `main_table`.`frontend_label`, `main_table`.`frontend_class`, `main_table`.`source_model`, `main_table`.`is_user_defined`, `main_table`.`is_unique`, `main_table`.`note`, `additional_table`.`input_filter`, `additional_table`.`validate_rules`, `additional_table`.`is_system`, `additional_table`.`sort_order`, `additional_table`.`data_model`, `additional_table`.`is_used_for_customer_segment`, IFNULL(`scope_table`.`is_visible`, `additional_table`.`is_visible`) AS `is_visible`, IFNULL(`scope_table`.`is_required`, `main_table`.`is_required`) AS `is_required`, IFNULL(`scope_table`.`default_value`, `main_table`.`default_value`) AS `default_value`, IFNULL(`scope_table`.`multiline_count`, `additional_table`.`multiline_count`) AS `multiline_count` FROM `eav_attribute` AS `main_table` INNER JOIN `customer_eav_attribute` AS `additional_table` ON (`additional_table`.`attribute_id` = `main_table`.`attribute_id`) AND (`main_table`.`entity_type_id` = ?) LEFT JOIN `customer_eav_attribute_website` AS `scope_table` ON (`scope_table`.`attribute_id` = `main_table`.`attribute_id`) AND (`scope_table`.`website_id` = ?)", sql)
}
Exemple #10
0
func Connect() (*sql.DB, *dbr.Connection, error) {
	dsn, err := GetDSN()
	if err != nil {
		return nil, nil, errgo.Mask(err)
	}
	db, err := sql.Open("mysql", dsn)
	if err != nil {
		return nil, nil, errgo.Mask(err)
	}
	dbrConn := dbr.NewConnection(db, nil)
	return db, dbrConn, nil
}
Exemple #11
0
// depends on generated code
func TestSQLQueryToColumnsToStruct(t *testing.T) {
	db := csdb.MustConnectTest()
	defer db.Close()

	dbrSess := dbr.NewConnection(db, nil).NewSession(nil)
	dbrSelect, err := eav.GetAttributeSelectSql(dbrSess, NewAddAttrTables(db, "catalog_product"), 4, 0)
	if err != nil {
		t.Error(err)
	}

	colSliceDbr, err := SQLQueryToColumns(db, dbrSelect)
	if err != nil {
		t.Error(err)
	}

	assert.Len(t, colSliceDbr, 35)

	for _, col := range colSliceDbr {
		assert.True(t, col.Field.Valid, fmt.Sprintf("%#v", col))
		assert.True(t, col.Type.Valid, fmt.Sprintf("%#v", col))
	}

	columns2, err2 := SQLQueryToColumns(db, nil, "SELECT * FROM `catalog_product_option`", " ORDER BY option_id DESC")
	if err2 != nil {
		t.Error(err2)
	}
	assert.Len(t, columns2, 10)
	for _, col := range columns2 {
		assert.True(t, col.Field.Valid, fmt.Sprintf("%#v", col))
		assert.True(t, col.Type.Valid, fmt.Sprintf("%#v", col))
	}

	colSliceDbr.MapSQLToGoDBRType()
	code, err := ColumnsToStructCode(nil, "testStruct", colSliceDbr)
	if err != nil {
		t.Error(err, "\n", string(code))
	}

	checkContains := [][]byte{
		[]byte(`TeststructSlice`),
		[]byte(`dbr.NullString`),
		[]byte("`db:\"is_visible_in_advanced_search\"`"),
	}
	for _, s := range checkContains {
		if false == bytes.Contains(code, s) {
			t.Errorf("%s\ndoes not contain %s", code, s)
		}
	}
}
Exemple #12
0
func TestNewManagerReInit(t *testing.T) {
	numCPU := runtime.NumCPU()
	prevCPU := runtime.GOMAXPROCS(numCPU)
	t.Logf("GOMAXPROCS was: %d now: %d", prevCPU, numCPU)
	defer runtime.GOMAXPROCS(prevCPU)

	// quick implement, use mock of dbr.SessionRunner and remove connection
	db := csdb.MustConnectTest()
	defer db.Close()
	dbrSess := dbr.NewConnection(db, nil).NewSession(nil)

	storeManager := store.NewManager(store.NewStorageOption(nil /* trick it*/))
	if err := storeManager.ReInit(dbrSess); err != nil {
		t.Fatal(err)
	}

	tests := []struct {
		have    config.ScopeIDer
		wantErr error
	}{
		{config.ScopeCode("de"), nil},
		{config.ScopeCode("cz"), store.ErrStoreNotFound},
		{config.ScopeCode("de"), nil},
		{config.ScopeID(1), nil},
		{config.ScopeID(100), store.ErrStoreNotFound},
		{mockIDCode{1, "de"}, nil},
		{mockIDCode{2, "cz"}, store.ErrStoreNotFound},
		{mockIDCode{2, ""}, nil},
		{nil, store.ErrAppStoreNotSet}, // if set returns default store
	}

	for _, test := range tests {
		s, err := storeManager.Store(test.have)
		if test.wantErr == nil {
			assert.NoError(t, err, "For test: %#v", test)
			assert.NotNil(t, s)
			//			assert.NotEmpty(t, s.Data().Code.String, "%#v", s.Data())
		} else {
			assert.Error(t, err, "For test: %#v", test)
			assert.EqualError(t, test.wantErr, err.Error(), "For test: %#v", test)
			assert.Nil(t, s)
		}
	}
	assert.False(t, storeManager.IsCacheEmpty())
	storeManager.ClearCache()
	assert.True(t, storeManager.IsCacheEmpty())
}
Exemple #13
0
func off_TestLoadFromDb(t *testing.T) {
	//for hacking testing added :-)
	db := csdb.MustConnectTest()
	defer db.Close()
	dbrSess := dbr.NewConnection(db, nil).NewSession(nil)

	sel := dbrSess.SelectBySql("SELECT * FROM `catalog_product_entity_decimal`")
	var peds TableProductEntityDecimalSlice

	if rows, err := sel.LoadStructs(&peds); err != nil {
		t.Error(err)
	} else if rows == 0 {
		t.Error("0 rows loaded")
	}

	for _, ped := range peds {
		fmt.Printf("%#v\n", ped)
	}
}
Exemple #14
0
func TestEntityType(t *testing.T) {
	db := csdb.MustConnectTest()
	defer db.Close()
	dbrSess := dbr.NewConnection(db, nil).NewSession(nil)
	var et eav.TableEntityType
	et.LoadByCode(
		dbrSess,
		"catalog_product",
		func(sb *dbr.SelectBuilder) *dbr.SelectBuilder {
			sb.OrderBy("entity_type_id")
			return sb
		},
	)

	assert.NotEmpty(t, et.EntityModel)
	assert.NotEmpty(t, et.AttributeModel.String)
	assert.True(t, et.EntityTypeID > 0, "EntityTypeID should be greater 0 but is: %#v\n", et)
	assert.True(t, et.IsRealEav())
}
Exemple #15
0
func TestGetEavValueTables(t *testing.T) {
	db := csdb.MustConnectTest()
	defer db.Close()
	dbrConn := dbr.NewConnection(db, nil)

	tests := []struct {
		haveETC   []string // have entity type codes
		wantErr   bool
		wantCVMap TypeCodeValueTable
	}{
		{
			haveETC:   []string{"catalog_category", "catalog_product"},
			wantErr:   false,
			wantCVMap: TypeCodeValueTable{"catalog_category": map[string]string{"catalog_category_entity_datetime": "datetime", "catalog_category_entity_decimal": "decimal", "catalog_category_entity_int": "int", "catalog_category_entity_text": "text", "catalog_category_entity_varchar": "varchar"}, "catalog_product": map[string]string{"catalog_product_entity_datetime": "datetime", "catalog_product_entity_decimal": "decimal", "catalog_product_entity_int": "int", "catalog_product_entity_text": "text", "catalog_product_entity_varchar": "varchar"}},
		},
		{
			haveETC:   []string{"customer_address", "customer"},
			wantErr:   false,
			wantCVMap: TypeCodeValueTable{"customer_address": map[string]string{"customer_address_entity_text": "text", "customer_address_entity_varchar": "varchar", "customer_address_entity_datetime": "datetime", "customer_address_entity_decimal": "decimal", "customer_address_entity_int": "int"}, "customer": map[string]string{"csCustomer_value_decimal": "decimal", "csCustomer_value_int": "int", "csCustomer_value_text": "text", "csCustomer_value_varchar": "varchar", "csCustomer_value_datetime": "datetime"}},
		},
		{
			haveETC:   []string{"catalog_address"},
			wantErr:   false,
			wantCVMap: TypeCodeValueTable{"catalog_address": map[string]string{}},
		},
	}

	for _, test := range tests {
		tcMap, err := GetEavValueTables(dbrConn, test.haveETC)
		if test.wantErr {
			assert.Error(t, err)
		}
		if !test.wantErr && err != nil {
			t.Error(err)
		}

		assert.EqualValues(t, test.wantCVMap, tcMap)
		assert.Len(t, tcMap, len(test.wantCVMap))
	}
}
Exemple #16
0
func TestStorageReInit(t *testing.T) {
	numCPU := runtime.NumCPU()
	prevCPU := runtime.GOMAXPROCS(numCPU)
	t.Logf("GOMAXPROCS was: %d now: %d", prevCPU, numCPU)
	defer runtime.GOMAXPROCS(prevCPU)

	// quick implement, use mock of dbr.SessionRunner and remove connection
	db := csdb.MustConnectTest()
	defer db.Close()
	dbrConn := dbr.NewConnection(db, nil)

	nsg := store.NewStorage(nil, nil, nil)
	if err := nsg.ReInit(dbrConn.NewSession(nil)); err != nil {
		t.Error(err)
	}

	stores, err := nsg.Stores()
	assert.NoError(t, err)
	assert.True(t, stores.Len() > 0, "Expecting at least one store loaded from DB")
	for _, s := range stores {
		assert.NotEmpty(t, s.Data().Code.String, "Store: %#v", s.Data())
	}

	groups, err := nsg.Groups()
	assert.True(t, groups.Len() > 0, "Expecting at least one group loaded from DB")
	assert.NoError(t, err)
	for _, g := range groups {
		assert.NotEmpty(t, g.Data().Name, "Group: %#v", g.Data())
	}

	websites, err := nsg.Websites()
	assert.True(t, websites.Len() > 0, "Expecting at least one website loaded from DB")
	assert.NoError(t, err)
	for _, w := range websites {
		assert.NotEmpty(t, w.Data().Code.String, "Website: %#v", w.Data())
	}
}
Exemple #17
0
func TestGetAttributeSelect(t *testing.T) {
	db := csdb.MustConnectTest()
	defer db.Close()
	dbrSess := dbr.NewConnection(db, nil).NewSession(nil)
	et, err := eav.GetEntityTypeCollection().GetByCode("catalog_product")
	if err != nil {
		t.Error(err)
	}
	websiteID := int64(1)
	dbrSelect, err := eav.GetAttributeSelectSql(dbrSess, et.AdditionalAttributeTable, et.EntityTypeID, websiteID)
	if err != nil {
		t.Error(err)
	}
	sql, _ := dbrSelect.ToSql()

	assert.Equal(
		t,
		"SELECT `main_table`.`attribute_id`, `main_table`.`entity_type_id`, `main_table`.`attribute_code`, `main_table`.`backend_model`, `main_table`.`backend_type`, `main_table`.`backend_table`, `main_table`.`frontend_model`, `main_table`.`frontend_input`, `main_table`.`frontend_label`, `main_table`.`frontend_class`, `main_table`.`source_model`, `main_table`.`is_required`, `main_table`.`is_user_defined`, `main_table`.`default_value`, `main_table`.`is_unique`, `main_table`.`note`, `additional_table`.`frontend_input_renderer`, `additional_table`.`is_global`, `additional_table`.`is_visible`, `additional_table`.`is_searchable`, `additional_table`.`is_filterable`, `additional_table`.`is_comparable`, `additional_table`.`is_visible_on_front`, `additional_table`.`is_html_allowed_on_front`, `additional_table`.`is_used_for_price_rules`, `additional_table`.`is_filterable_in_search`, `additional_table`.`used_in_product_listing`, `additional_table`.`used_for_sort_by`, `additional_table`.`is_configurable`, `additional_table`.`apply_to`, `additional_table`.`is_visible_in_advanced_search`, `additional_table`.`position`, `additional_table`.`is_wysiwyg_enabled`, `additional_table`.`is_used_for_promo_rules`, `additional_table`.`search_weight` FROM `eav_attribute` AS `main_table` INNER JOIN `catalog_eav_attribute` AS `additional_table` ON (`additional_table`.`attribute_id` = `main_table`.`attribute_id`) AND (`main_table`.`entity_type_id` = ?)",
		sql,
	)

	et, err = eav.GetEntityTypeCollection().GetByCode("customer")
	if err != nil {
		t.Error(err)
	}
	dbrSelect, err = eav.GetAttributeSelectSql(dbrSess, et.AdditionalAttributeTable, et.EntityTypeID, websiteID)
	if err != nil {
		t.Error(err)
	}
	sql, _ = dbrSelect.ToSql()
	assert.Equal(
		t,
		"SELECT `main_table`.`attribute_id`, `main_table`.`entity_type_id`, `main_table`.`attribute_code`, `main_table`.`backend_model`, `main_table`.`backend_type`, `main_table`.`backend_table`, `main_table`.`frontend_model`, `main_table`.`frontend_input`, `main_table`.`frontend_label`, `main_table`.`frontend_class`, `main_table`.`source_model`, `main_table`.`is_required`, `main_table`.`is_user_defined`, `main_table`.`default_value`, `main_table`.`is_unique`, `main_table`.`note`, `additional_table`.`is_visible`, `additional_table`.`input_filter`, `additional_table`.`multiline_count`, `additional_table`.`validate_rules`, `additional_table`.`is_system`, `additional_table`.`sort_order`, `additional_table`.`data_model`, `additional_table`.`is_used_for_customer_segment`, `scope_table`.`is_visible` AS `scope_is_visible`, `scope_table`.`is_required` AS `scope_is_required`, `scope_table`.`default_value` AS `scope_default_value`, `scope_table`.`multiline_count` AS `scope_multiline_count` FROM `eav_attribute` AS `main_table` INNER JOIN `customer_eav_attribute` AS `additional_table` ON (`additional_table`.`attribute_id` = `main_table`.`attribute_id`) AND (`main_table`.`entity_type_id` = ?) LEFT JOIN `customer_eav_attribute_website` AS `scope_table` ON (`scope_table`.`attribute_id` = `main_table`.`attribute_id`) AND (`scope_table`.`website_id` = ?)",
		sql,
	)
}
Exemple #18
0
func TestGetSQLPrepareForTemplate(t *testing.T) {
	db := csdb.MustConnectTest()
	defer db.Close()

	resultSlice2, err := LoadStringEntities(db, nil, "SELECT * FROM `cataloginventory_stock` ", "ORDER BY stock_id")
	if err != nil {
		t.Error(err)
	}
	assert.Len(t, resultSlice2, 1) // 1 row
	for _, row := range resultSlice2 {
		assert.True(t, len(row["stock_id"]) > 0, "Incorrect length of stock_id", fmt.Sprintf("%#v", row))
	}

	// advanced test

	dbrSess := dbr.NewConnection(db, nil).NewSession(nil)
	dbrSelect, err := eav.GetAttributeSelectSql(dbrSess, NewAddAttrTables(db, "catalog_product"), 4, 0)
	if err != nil {
		t.Error(err)
	}

	attributeResultSlice, err := LoadStringEntities(db, dbrSelect)
	if err != nil {
		t.Error(err)
	}
	assert.Len(t, attributeResultSlice, 110) // 110 rows
	for _, row := range attributeResultSlice {
		assert.True(t, len(row["attribute_id"]) > 0, "Incorrect length of attribute_id", fmt.Sprintf("%#v", row))
	}

	colSliceDbr, err := SQLQueryToColumns(db, dbrSelect)
	if err != nil {
		t.Error(err)
	}

	for _, col := range colSliceDbr {
		assert.Empty(t, col.GoType)
		assert.Empty(t, col.GoName)
	}

	var unchanged = make(map[string]string)
	for _, s := range attributeResultSlice {
		assert.True(t, len(s["is_wysiwyg_enabled"]) == 1, "Should contain 0 or 1 as string: %s", s["is_wysiwyg_enabled"])
		assert.True(t, len(s["used_in_product_listing"]) == 1, "Should contain 0 or 1 as string: %s", s["used_in_product_listing"])
		assert.False(t, strings.ContainsRune(s["attribute_code"], '"'), "Should not contain double quotes for escaping: %s", s["attribute_code"])
		unchanged[s["attribute_id"]] = s["entity_type_id"]
	}

	importPaths1 := PrepareForTemplate(colSliceDbr, attributeResultSlice, ConfigAttributeModel, "catalog")
	assert.True(t, len(importPaths1) > 1, "Should output multiple import paths: %#v", importPaths1)

	for _, s := range attributeResultSlice {
		assert.True(t, len(s["is_wysiwyg_enabled"]) >= 4, "Should contain false or true as string: %s", s["is_wysiwyg_enabled"])
		assert.True(t, len(s["used_in_product_listing"]) >= 4, "Should contain false or true as string: %s", s["used_in_product_listing"])
		assert.True(t, strings.ContainsRune(s["attribute_code"], '"'), "Should contain double quotes for escaping: %s", s["attribute_code"])
		assert.Equal(t, unchanged[s["attribute_id"]], s["entity_type_id"], "Columns: %#v", s)
		assert.True(t, len(s["frontend_model"]) >= 3, "Should contain nil or a Go func: %s", s["frontend_model"])
		assert.True(t, len(s["backend_model"]) >= 3, "Should contain nil or a Go func: %s", s["backend_model"])
		assert.True(t, len(s["source_model"]) >= 3, "Should contain nil or a Go func: %s", s["source_model"])
	}
}