package wmo import ( "context" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "gogs.mikescher.com/BlackForestBytes/goext/langext" "gogs.mikescher.com/BlackForestBytes/goext/rfctime" "gogs.mikescher.com/BlackForestBytes/goext/timeext" "gogs.mikescher.com/BlackForestBytes/goext/tst" "reflect" "testing" "time" ) func TestReflectionGetFieldType(t *testing.T) { type IDType string type TestData struct { ID IDType `bson:"_id"` CDate time.Time `bson:"cdate"` Sub struct { A string `bson:"a"` } `bson:"sub"` SubPtr *struct { A string `bson:"a"` } `bson:"subPtr"` Str string `bson:"str"` Ptr *int `bson:"ptr"` MDate rfctime.RFC3339NanoTime `bson:"mdate"` } coll := W[TestData](&mongo.Collection{}) coll.init() t0 := time.Now() t1 := rfctime.NewRFC3339Nano(t0) d := TestData{ ID: "1", CDate: t0, Sub: struct { A string `bson:"a"` }{ A: "2", }, SubPtr: &struct { A string `bson:"a"` }{ A: "4", }, Str: "3", Ptr: langext.Ptr(4), MDate: t1, } gft := func(k string) fullTypeRef { v, err := coll.getFieldType(k) if err != nil { t.Errorf("%s: %v", "failed to getFieldType", err) } return v } gfv := func(k string) any { v, err := coll.getFieldValue(d, k) if err != nil { t.Errorf("%s: %v", "failed to getFieldType", err) } return v } tst.AssertEqual(t, gft("_id").Kind.String(), "string") tst.AssertEqual(t, gft("_id").Type.String(), "wmo.IDType") tst.AssertEqual(t, gft("_id").Name, "ID") tst.AssertEqual(t, gft("_id").IsPointer, false) tst.AssertEqual(t, gfv("_id").(IDType), "1") tst.AssertEqual(t, gft("cdate").Kind.String(), "struct") tst.AssertEqual(t, gft("cdate").Type.String(), "time.Time") tst.AssertEqual(t, gft("cdate").Name, "CDate") tst.AssertEqual(t, gft("cdate").IsPointer, false) tst.AssertEqual(t, gfv("cdate").(time.Time), t0) tst.AssertEqual(t, gft("sub.a").Kind.String(), "string") tst.AssertEqual(t, gft("sub.a").Type.String(), "string") tst.AssertEqual(t, gft("sub.a").Name, "A") tst.AssertEqual(t, gft("sub.a").IsPointer, false) tst.AssertEqual(t, gfv("sub.a").(string), "2") tst.AssertEqual(t, gft("subPtr.a").Kind.String(), "string") tst.AssertEqual(t, gft("subPtr.a").Type.String(), "string") tst.AssertEqual(t, gft("subPtr.a").Name, "A") tst.AssertEqual(t, gft("subPtr.a").IsPointer, false) tst.AssertEqual(t, gfv("subPtr.a").(string), "4") tst.AssertEqual(t, gft("str").Kind.String(), "string") tst.AssertEqual(t, gft("str").Type.String(), "string") tst.AssertEqual(t, gft("str").Name, "Str") tst.AssertEqual(t, gft("str").IsPointer, false) tst.AssertEqual(t, gfv("str").(string), "3") tst.AssertEqual(t, gft("ptr").Kind.String(), "int") tst.AssertEqual(t, gft("ptr").Type.String(), "int") tst.AssertEqual(t, gft("ptr").Name, "Ptr") tst.AssertEqual(t, gft("ptr").IsPointer, true) tst.AssertEqual(t, *gfv("ptr").(*int), 4) } func TestReflectionGetTokenValueAsMongoType(t *testing.T) { type IDType string type TestData struct { ID IDType `bson:"_id"` CDate time.Time `bson:"cdate"` Sub struct { A string `bson:"a"` } `bson:"sub"` SubPtr struct { A string `bson:"a"` } `bson:"subPtr"` Str string `bson:"str"` Ptr *int `bson:"ptr"` Num int `bson:"num"` MDate rfctime.RFC3339NanoTime `bson:"mdate"` } coll := W[TestData](&mongo.Collection{}) coll.init() gtvasmt := func(value string, fieldName string) any { v, err := coll.getTokenValueAsMongoType(value, fieldName) if err != nil { t.Errorf("%s", "failed to getTokenValueAsMongoType") t.Errorf("%v+", err) } return v } tx, err := time.Parse(time.RFC3339Nano, "2009-11-10T23:00:00Z") if err != nil { t.Errorf("%v", err) } tst.AssertEqual(t, gtvasmt("hello", "str").(string), "hello") tst.AssertEqual(t, gtvasmt("hello", "sub.a").(string), "hello") tst.AssertEqual(t, gtvasmt("hello", "subPtr.a").(string), "hello") tst.AssertEqual(t, gtvasmt("4", "num").(int), 4) tst.AssertEqual(t, gtvasmt("asdf", "_id").(IDType), "asdf") tst.AssertEqual(t, gtvasmt("", "ptr").(*int), nil) tst.AssertEqual(t, *(gtvasmt("123", "ptr").(*int)), 123) tst.AssertEqual(t, gtvasmt("2009-11-10T23:00:00Z", "cdate").(time.Time), tx) tst.AssertEqual(t, gtvasmt("2009-11-10T23:00:00Z", "mdate").(rfctime.RFC3339NanoTime), rfctime.NewRFC3339Nano(tx)) } func TestReflectionGetFieldValueAsTokenString(t *testing.T) { type IDType string type TestData struct { ID IDType `bson:"_id"` CDate time.Time `bson:"cdate"` Sub struct { A string `bson:"a"` } `bson:"sub"` Str string `bson:"str"` Ptr *int `bson:"ptr"` Num int `bson:"num"` Ptr2 *int `bson:"ptr2"` FFF float64 `bson:"fff"` MDate rfctime.RFC3339NanoTime `bson:"mdate"` } coll := W[TestData](&mongo.Collection{}) coll.init() t0 := time.Date(2000, 1, 1, 12, 0, 0, 0, timeext.TimezoneBerlin) t1 := rfctime.NewRFC3339Nano(t0) d := TestData{ ID: "1", CDate: t0, MDate: t1, Sub: struct { A string `bson:"a"` }{ A: "2", }, Str: "3", Ptr: langext.Ptr(4), Num: 22, FFF: 22.5, Ptr2: nil, } gfvats := func(value TestData, fieldName string) string { v, err := coll.getFieldValueAsTokenString(value, fieldName) if err != nil { t.Errorf("%s: %v", "failed to getTokenValueAsMongoType", err) } return v } tst.AssertEqual(t, gfvats(d, "str"), "3") tst.AssertEqual(t, gfvats(d, "num"), "22") tst.AssertEqual(t, gfvats(d, "_id"), "1") tst.AssertEqual(t, gfvats(d, "ptr"), "4") tst.AssertEqual(t, gfvats(d, "ptr2"), "") tst.AssertEqual(t, gfvats(d, "fff"), "22.5") tst.AssertEqual(t, gfvats(d, "cdate"), t0.Format(time.RFC3339Nano)) tst.AssertEqual(t, gfvats(d, "mdate"), t0.Format(time.RFC3339Nano)) } func TestReflectionWithInterface(t *testing.T) { type TestData struct { ID primitive.ObjectID `bson:"_id"` CDate time.Time `bson:"cdate"` } type TestInterface interface { } coll1 := W[TestInterface](&mongo.Collection{}) tst.AssertTrue(t, coll1.coll != nil) tst.AssertEqual(t, 0, len(coll1.implDataTypeMap)) df := func(ctx context.Context, dec Decodable) (TestInterface, error) { return TestData{}, nil } coll2 := W[TestInterface](&mongo.Collection{}).WithDecodeFunc(df, TestData{}) tst.AssertTrue(t, coll2.coll != nil) tst.AssertEqual(t, 1, len(coll2.implDataTypeMap)) tst.AssertEqual(t, "ID", coll2.implDataTypeMap[reflect.TypeOf(TestData{})]["_id"].Name) tst.AssertEqual(t, "CDate", coll2.implDataTypeMap[reflect.TypeOf(TestData{})]["cdate"].Name) }