newDynamicModel creates a new dynamic struct with fields based on the specified "shape". The "shape" values are used as defaults and could be of type: - int64 (ex.: 0) - *int64 (ex.: nullInt()) - float64 (ex.: -0) - *float64 (ex.: nullFloat()) - string (ex.: "") - *string (ex.
(shape map[string]any)
| 1192 | // "total": 0, |
| 1193 | // }) |
| 1194 | func newDynamicModel(shape map[string]any) any { |
| 1195 | info := make([]*shapeFieldInfo, 0, len(shape)) |
| 1196 | |
| 1197 | var hash strings.Builder |
| 1198 | |
| 1199 | sortedKeys := make([]string, 0, len(shape)) |
| 1200 | for k := range shape { |
| 1201 | sortedKeys = append(sortedKeys, k) |
| 1202 | } |
| 1203 | sort.Strings(sortedKeys) |
| 1204 | |
| 1205 | for _, k := range sortedKeys { |
| 1206 | v := shape[k] |
| 1207 | vt := reflect.TypeOf(v) |
| 1208 | |
| 1209 | switch vt.Kind() { |
| 1210 | case reflect.Map: |
| 1211 | raw, _ := json.Marshal(v) |
| 1212 | newV := types.JSONMap[any]{} |
| 1213 | newV.Scan(raw) |
| 1214 | v = newV |
| 1215 | vt = reflect.TypeOf(v) |
| 1216 | case reflect.Slice, reflect.Array: |
| 1217 | raw, _ := json.Marshal(v) |
| 1218 | newV := types.JSONArray[any]{} |
| 1219 | newV.Scan(raw) |
| 1220 | v = newV |
| 1221 | vt = reflect.TypeOf(newV) |
| 1222 | case reflect.Pointer: |
| 1223 | // for pointers always fallback to nil as their default value |
| 1224 | v = nil |
| 1225 | } |
| 1226 | |
| 1227 | hash.WriteString(k) |
| 1228 | hash.WriteString(":") |
| 1229 | hash.WriteString(vt.String()) // it doesn't guarantee to be unique across all types but it should be fine with the primitive types DynamicModel is used |
| 1230 | hash.WriteString("|") |
| 1231 | |
| 1232 | info = append(info, &shapeFieldInfo{key: k, value: v, valueType: vt}) |
| 1233 | } |
| 1234 | |
| 1235 | st := cachedDynamicModelStructs.GetOrSet(hash.String(), func() reflect.Type { |
| 1236 | structFields := make([]reflect.StructField, len(info)) |
| 1237 | |
| 1238 | for i, item := range info { |
| 1239 | structFields[i] = reflect.StructField{ |
| 1240 | Name: inflector.UcFirst(item.key), // ensures that the field is exportable |
| 1241 | Type: item.valueType, |
| 1242 | Tag: reflect.StructTag(`db:"` + item.key + `" json:"` + item.key + `" form:"` + item.key + `"`), |
| 1243 | } |
| 1244 | } |
| 1245 | |
| 1246 | return reflect.StructOf(structFields) |
| 1247 | }) |
| 1248 | |
| 1249 | elem := reflect.New(st).Elem() |
| 1250 | |
| 1251 | // load default values into the new model |