| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | package core | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"database/sql/driver" | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2024-11-24 18:41:57 +08:00
										 |  |  | 	"slices" | 
					
						
							| 
									
										
										
										
											2024-11-04 16:51:32 +08:00
										 |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewFieldsList creates a new FieldsList instance with the provided fields.
 | 
					
						
							|  |  |  | func NewFieldsList(fields ...Field) FieldsList { | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | 	l := make(FieldsList, 0, len(fields)) | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for _, f := range fields { | 
					
						
							| 
									
										
										
										
											2024-11-24 18:41:57 +08:00
										 |  |  | 		l.add(-1, f) | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | 	return l | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // FieldsList defines a Collection slice of fields.
 | 
					
						
							|  |  |  | type FieldsList []Field | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Clone creates a deep clone of the current list.
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | func (l FieldsList) Clone() (FieldsList, error) { | 
					
						
							|  |  |  | 	copyRaw, err := json.Marshal(l) | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	result := FieldsList{} | 
					
						
							|  |  |  | 	if err := json.Unmarshal(copyRaw, &result); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return result, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // FieldNames returns a slice with the name of all list fields.
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | func (l FieldsList) FieldNames() []string { | 
					
						
							|  |  |  | 	result := make([]string, len(l)) | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | 	for i, field := range l { | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		result[i] = field.GetName() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return result | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // AsMap returns a map with all registered list field.
 | 
					
						
							|  |  |  | // The returned map is indexed with each field name.
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | func (l FieldsList) AsMap() map[string]Field { | 
					
						
							|  |  |  | 	result := make(map[string]Field, len(l)) | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | 	for _, field := range l { | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		result[field.GetName()] = field | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return result | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GetById returns a single field by its id.
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | func (l FieldsList) GetById(fieldId string) Field { | 
					
						
							|  |  |  | 	for _, field := range l { | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		if field.GetId() == fieldId { | 
					
						
							|  |  |  | 			return field | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GetByName returns a single field by its name.
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | func (l FieldsList) GetByName(fieldName string) Field { | 
					
						
							|  |  |  | 	for _, field := range l { | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		if field.GetName() == fieldName { | 
					
						
							|  |  |  | 			return field | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RemoveById removes a single field by its id.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This method does nothing if field with the specified id doesn't exist.
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | func (l *FieldsList) RemoveById(fieldId string) { | 
					
						
							|  |  |  | 	fields := *l | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	for i, field := range fields { | 
					
						
							|  |  |  | 		if field.GetId() == fieldId { | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | 			*l = append(fields[:i], fields[i+1:]...) | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RemoveByName removes a single field by its name.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This method does nothing if field with the specified name doesn't exist.
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | func (l *FieldsList) RemoveByName(fieldName string) { | 
					
						
							|  |  |  | 	fields := *l | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	for i, field := range fields { | 
					
						
							|  |  |  | 		if field.GetName() == fieldName { | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | 			*l = append(fields[:i], fields[i+1:]...) | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Add adds one or more fields to the current list.
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2024-10-30 02:08:16 +08:00
										 |  |  | // By default this method will try to REPLACE existing fields with
 | 
					
						
							|  |  |  | // the new ones by their id or by their name if the new field doesn't have an explicit id.
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2024-10-30 02:08:16 +08:00
										 |  |  | // If no matching existing field is found, it will APPEND the field to the end of the list.
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2024-10-30 02:08:16 +08:00
										 |  |  | // In all cases, if any of the new fields don't have an explicit id it will auto generate a default one for them
 | 
					
						
							|  |  |  | // (the id value doesn't really matter and it is mostly used as a stable identifier in case of a field rename).
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | func (l *FieldsList) Add(fields ...Field) { | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	for _, f := range fields { | 
					
						
							| 
									
										
										
										
											2024-11-24 18:41:57 +08:00
										 |  |  | 		l.add(-1, f) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // AddAt is the same as Add but insert/move the fields at the specific position.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // If pos < 0, then this method acts the same as calling Add.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // If pos > FieldsList total items, then the specified fields are inserted/moved at the end of the list.
 | 
					
						
							|  |  |  | func (l *FieldsList) AddAt(pos int, fields ...Field) { | 
					
						
							|  |  |  | 	total := len(*l) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, f := range fields { | 
					
						
							|  |  |  | 		if pos < 0 { | 
					
						
							|  |  |  | 			l.add(-1, f) | 
					
						
							|  |  |  | 		} else if pos > total { | 
					
						
							|  |  |  | 			l.add(total+i, f) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			l.add(pos+i, f) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | // AddMarshaledJSON parses the provided raw json data and adds the
 | 
					
						
							|  |  |  | // found fields into the current list (following the same rule as the Add method).
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2024-10-30 02:08:16 +08:00
										 |  |  | // The rawJSON argument could be one of:
 | 
					
						
							|  |  |  | //   - serialized array of field objects
 | 
					
						
							|  |  |  | //   - single field object.
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | //
 | 
					
						
							|  |  |  | // Example:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //	l.AddMarshaledJSON([]byte{`{"type":"text", name: "test"}`})
 | 
					
						
							|  |  |  | //	l.AddMarshaledJSON([]byte{`[{"type":"text", name: "test1"}, {"type":"text", name: "test2"}]`})
 | 
					
						
							|  |  |  | func (l *FieldsList) AddMarshaledJSON(rawJSON []byte) error { | 
					
						
							| 
									
										
										
										
											2024-11-24 18:41:57 +08:00
										 |  |  | 	extractedFields, err := marshaledJSONtoFieldsList(rawJSON) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	l.Add(extractedFields...) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // AddMarshaledJSONAt is the same as AddMarshaledJSON but insert/move the fields at the specific position.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // If pos < 0, then this method acts the same as calling AddMarshaledJSON.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // If pos > FieldsList total items, then the specified fields are inserted/moved at the end of the list.
 | 
					
						
							|  |  |  | func (l *FieldsList) AddMarshaledJSONAt(pos int, rawJSON []byte) error { | 
					
						
							|  |  |  | 	extractedFields, err := marshaledJSONtoFieldsList(rawJSON) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	l.AddAt(pos, extractedFields...) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func marshaledJSONtoFieldsList(rawJSON []byte) (FieldsList, error) { | 
					
						
							|  |  |  | 	extractedFields := FieldsList{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// nothing to add
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | 	if len(rawJSON) == 0 { | 
					
						
							| 
									
										
										
										
											2024-11-24 18:41:57 +08:00
										 |  |  | 		return extractedFields, nil | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// try to unmarshal first into a new fieds list
 | 
					
						
							|  |  |  | 	// (assuming that rawJSON is array of objects)
 | 
					
						
							|  |  |  | 	err := json.Unmarshal(rawJSON, &extractedFields) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		// try again but wrap the rawJSON in []
 | 
					
						
							|  |  |  | 		// (assuming that rawJSON is a single object)
 | 
					
						
							|  |  |  | 		wrapped := make([]byte, 0, len(rawJSON)+2) | 
					
						
							|  |  |  | 		wrapped = append(wrapped, '[') | 
					
						
							|  |  |  | 		wrapped = append(wrapped, rawJSON...) | 
					
						
							|  |  |  | 		wrapped = append(wrapped, ']') | 
					
						
							|  |  |  | 		err = json.Unmarshal(wrapped, &extractedFields) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2024-11-24 18:41:57 +08:00
										 |  |  | 			return nil, fmt.Errorf("failed to unmarshal the provided JSON - expects array of objects or just single object: %w", err) | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-24 18:41:57 +08:00
										 |  |  | 	return extractedFields, nil | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-24 18:41:57 +08:00
										 |  |  | func (l *FieldsList) add(pos int, newField Field) { | 
					
						
							| 
									
										
										
										
											2024-10-30 02:08:16 +08:00
										 |  |  | 	fields := *l | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var replaceByName bool | 
					
						
							| 
									
										
										
										
											2024-11-24 18:41:57 +08:00
										 |  |  | 	var replaceInPlace bool | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if pos < 0 { | 
					
						
							|  |  |  | 		replaceInPlace = true | 
					
						
							|  |  |  | 		pos = len(fields) | 
					
						
							|  |  |  | 	} else if pos > len(fields) { | 
					
						
							|  |  |  | 		pos = len(fields) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-10-30 02:08:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	newFieldId := newField.GetId() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// set default id
 | 
					
						
							|  |  |  | 	if newFieldId == "" { | 
					
						
							| 
									
										
										
										
											2024-10-30 02:08:16 +08:00
										 |  |  | 		replaceByName = true | 
					
						
							| 
									
										
										
										
											2024-11-04 16:51:32 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		baseId := newField.Type() + crc32Checksum(newField.GetName()) | 
					
						
							|  |  |  | 		newFieldId = baseId | 
					
						
							|  |  |  | 		for i := 2; i < 1000; i++ { | 
					
						
							|  |  |  | 			if l.GetById(newFieldId) == nil { | 
					
						
							|  |  |  | 				break // already unique
 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			newFieldId = baseId + strconv.Itoa(i) | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-11-04 16:51:32 +08:00
										 |  |  | 		newField.SetId(newFieldId) | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-24 18:41:57 +08:00
										 |  |  | 	// try to replace existing
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	for i, field := range fields { | 
					
						
							| 
									
										
										
										
											2024-10-30 02:08:16 +08:00
										 |  |  | 		if replaceByName { | 
					
						
							|  |  |  | 			if name := newField.GetName(); name != "" && field.GetName() == name { | 
					
						
							| 
									
										
										
										
											2024-11-24 18:41:57 +08:00
										 |  |  | 				// reuse the original id
 | 
					
						
							| 
									
										
										
										
											2024-10-30 02:08:16 +08:00
										 |  |  | 				newField.SetId(field.GetId()) | 
					
						
							| 
									
										
										
										
											2024-11-24 18:41:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				if replaceInPlace { | 
					
						
							|  |  |  | 					(*l)[i] = newField | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					// remove the current field and insert it later at the specific position
 | 
					
						
							|  |  |  | 					*l = slices.Delete(*l, i, i+1) | 
					
						
							|  |  |  | 					if total := len(*l); pos > total { | 
					
						
							|  |  |  | 						pos = total | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					break | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2024-10-30 02:08:16 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			if field.GetId() == newFieldId { | 
					
						
							| 
									
										
										
										
											2024-11-24 18:41:57 +08:00
										 |  |  | 				if replaceInPlace { | 
					
						
							|  |  |  | 					(*l)[i] = newField | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					// remove the current field and insert it later at the specific position
 | 
					
						
							|  |  |  | 					*l = slices.Delete(*l, i, i+1) | 
					
						
							|  |  |  | 					if total := len(*l); pos > total { | 
					
						
							|  |  |  | 						pos = total | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					break | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2024-10-30 02:08:16 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-24 18:41:57 +08:00
										 |  |  | 	// insert the new field
 | 
					
						
							|  |  |  | 	*l = slices.Insert(*l, pos, newField) | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // String returns the string representation of the current list.
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | func (l FieldsList) String() string { | 
					
						
							|  |  |  | 	v, _ := json.Marshal(l) | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	return string(v) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type onlyFieldType struct { | 
					
						
							|  |  |  | 	Type string `json:"type"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type fieldWithType struct { | 
					
						
							|  |  |  | 	Field | 
					
						
							|  |  |  | 	Type string `json:"type"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (fwt *fieldWithType) UnmarshalJSON(data []byte) error { | 
					
						
							|  |  |  | 	// extract the field type to init a blank factory
 | 
					
						
							|  |  |  | 	t := &onlyFieldType{} | 
					
						
							|  |  |  | 	if err := json.Unmarshal(data, t); err != nil { | 
					
						
							|  |  |  | 		return fmt.Errorf("failed to unmarshal field type: %w", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	factory, ok := Fields[t.Type] | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		return fmt.Errorf("missing or unknown field type in %s", data) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fwt.Type = t.Type | 
					
						
							|  |  |  | 	fwt.Field = factory() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// unmarshal the rest of the data into the created field
 | 
					
						
							|  |  |  | 	if err := json.Unmarshal(data, fwt.Field); err != nil { | 
					
						
							|  |  |  | 		return fmt.Errorf("failed to unmarshal field: %w", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // UnmarshalJSON implements [json.Unmarshaler] and
 | 
					
						
							|  |  |  | // loads the provided json data into the current FieldsList.
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | func (l *FieldsList) UnmarshalJSON(data []byte) error { | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	fwts := []fieldWithType{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := json.Unmarshal(data, &fwts); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | 	*l = []Field{} // reset
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for _, fwt := range fwts { | 
					
						
							| 
									
										
										
										
											2024-11-24 18:41:57 +08:00
										 |  |  | 		l.add(-1, fwt.Field) | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MarshalJSON implements the [json.Marshaler] interface.
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | func (l FieldsList) MarshalJSON() ([]byte, error) { | 
					
						
							|  |  |  | 	if l == nil { | 
					
						
							|  |  |  | 		l = []Field{} // always init to ensure that it is serialized as empty array
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | 	wrapper := make([]map[string]any, 0, len(l)) | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | 	for _, f := range l { | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		// precompute the json into a map so that we can append the type to a flatten object
 | 
					
						
							|  |  |  | 		raw, err := json.Marshal(f) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		data := map[string]any{} | 
					
						
							|  |  |  | 		if err := json.Unmarshal(raw, &data); err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		data["type"] = f.Type() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		wrapper = append(wrapper, data) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return json.Marshal(wrapper) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Value implements the [driver.Valuer] interface.
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | func (l FieldsList) Value() (driver.Value, error) { | 
					
						
							|  |  |  | 	data, err := json.Marshal(l) | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return string(data), err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Scan implements [sql.Scanner] interface to scan the provided value
 | 
					
						
							|  |  |  | // into the current FieldsList instance.
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | func (l *FieldsList) Scan(value any) error { | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	var data []byte | 
					
						
							|  |  |  | 	switch v := value.(type) { | 
					
						
							|  |  |  | 	case nil: | 
					
						
							|  |  |  | 		// no cast needed
 | 
					
						
							|  |  |  | 	case []byte: | 
					
						
							|  |  |  | 		data = v | 
					
						
							|  |  |  | 	case string: | 
					
						
							|  |  |  | 		data = []byte(v) | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return fmt.Errorf("failed to unmarshal FieldsList value %q", value) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(data) == 0 { | 
					
						
							|  |  |  | 		data = []byte("[]") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-09 22:11:14 +08:00
										 |  |  | 	return l.UnmarshalJSON(data) | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | } |