package db import ( "fmt" "reflect" "strings" ) type DataTable[T any] struct { TableName string } func (base *DataTable[T]) GetSimilarFieldsQuery(ref T, fields []string) (string, error) { var structFields = base.getFieldsMap() var value = reflect.ValueOf(ref) var filterMap = make(map[string]any) for _, v := range fields { var fieldIndex, exists = structFields[v] if !exists { return "", fmt.Errorf("Failed to create a query for the object: there is no such field as %s in %s", v, reflect.TypeFor[T]().Name()) } filterMap[v] = value.Field(fieldIndex).Interface() } fmt.Println(filterMap) return base.formQueryWithFilters(filterMap), nil } // Filters are stored as KVP where the field is the key and the value is the filter func (base *DataTable[T]) formQueryWithFilters(filters map[string]any) string { if len(filters) == 0 { return base.formSelectAllQuery() } var sb = strings.Builder{} var baseQuery = base.formSelectAllQuery() sb.WriteString(strings.TrimRight(baseQuery, ";")) sb.WriteString(" WHERE (") var isFirst = true for k, v := range filters { if !isFirst { sb.WriteString(" AND ") } sb.WriteString(fmt.Sprintf("%s = ", k)) switch v.(type) { case string: sb.WriteString(fmt.Sprintf("'%s'", v)) case int, uint64: sb.WriteString(fmt.Sprintf("%d", v)) } isFirst = false } sb.WriteString(");") return sb.String() } // Forms a query to get all the fields from database func (base *DataTable[T]) formSelectAllQuery() string { var sb = strings.Builder{} sb.WriteString("SELECT (") var fields = base.getFields() for i, v := range fields { if i != 0 { sb.WriteString(", ") } sb.WriteString(v) } sb.WriteString(") FROM ") sb.WriteString(base.TableName) sb.WriteString(";") return sb.String() } func (base *DataTable[T]) getFields() []string { var zero T var outp = make([]string, 0) for _, f := range reflect.VisibleFields(reflect.TypeOf(zero)) { var tag, exists = f.Tag.Lookup("sql") if exists { outp = append(outp, tag) } else { outp = append(outp, f.Name) } } return outp } func (base *DataTable[T]) getFieldsMap() map[string]int { var zero T var outp = make(map[string]int) for i, f := range reflect.VisibleFields(reflect.TypeOf(zero)) { var tag, exists = f.Tag.Lookup("sql") if exists { outp[tag] = i } else { outp[f.Name] = i } } return outp }