Skip to content

Commit

Permalink
deduplicate code and add comments
Browse files Browse the repository at this point in the history
  • Loading branch information
felix-roehrich committed Jan 22, 2025
1 parent 8bea07d commit 75289ac
Showing 1 changed file with 16 additions and 30 deletions.
46 changes: 16 additions & 30 deletions pgtype/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,37 +71,12 @@ func (c *JSONCodec) PlanEncode(m *Map, oid uint32, format int16, value any) Enco
}
}

// JSON needs its on scan plan for pointers to handle 'null'::json(b).
// Consider making pointerPointerScanPlan more flexible in the future.
type jsonPointerScanPlan struct {
next ScanPlan
}

func (p jsonPointerScanPlan) planNext(c *JSONCodec, m *Map, oid uint32, formatCode int16, target any, depth int) ScanPlan {
if depth > 8 {
return &scanPlanFail{m: m, oid: oid, formatCode: formatCode}
}

switch target.(type) {
case *string:
p.next = &scanPlanAnyToString{}
case *[]byte:
p.next = &scanPlanJSONToByteSlice{}
case BytesScanner:
p.next = &scanPlanBinaryBytesToBytesScanner{}
case sql.Scanner:
p.next = &scanPlanSQLScanner{formatCode: formatCode}
default:
rv := reflect.ValueOf(target)
if rv.Kind() == reflect.Pointer && rv.Elem().Kind() == reflect.Pointer {
var plan jsonPointerScanPlan
p.next = plan.planNext(c, m, oid, formatCode, rv.Elem().Interface(), depth+1)
} else {
p.next = &scanPlanJSONToJSONUnmarshal{unmarshal: c.Unmarshal}
}
}

return p
}

func (p jsonPointerScanPlan) Scan(src []byte, dst any) error {
el := reflect.ValueOf(dst).Elem()
if src == nil || string(src) == "null" {
Expand Down Expand Up @@ -163,7 +138,17 @@ func (e *encodePlanJSONCodecEitherFormatMarshal) Encode(value any, buf []byte) (
return buf, nil
}

func (c *JSONCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
func (c *JSONCodec) PlanScan(m *Map, oid uint32, formatCode int16, target any) ScanPlan {
return c.planScan(m, oid, formatCode, target, 0)
}

// JSON cannot fallback to pointerPointerScanPlan because of 'null'::json(b),
// so we need to duplicate the logic here.
func (c *JSONCodec) planScan(m *Map, oid uint32, formatCode int16, target any, depth int) ScanPlan {
if depth > 8 {
return &scanPlanFail{m: m, oid: oid, formatCode: formatCode}
}

switch target.(type) {
case *string:
return &scanPlanAnyToString{}
Expand All @@ -172,13 +157,14 @@ func (c *JSONCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanP
case BytesScanner:
return &scanPlanBinaryBytesToBytesScanner{}
case sql.Scanner:
return &scanPlanSQLScanner{formatCode: format}
return &scanPlanSQLScanner{formatCode: formatCode}
}

rv := reflect.ValueOf(target)
if rv.Kind() == reflect.Pointer && rv.Elem().Kind() == reflect.Pointer {
var plan jsonPointerScanPlan
return plan.planNext(c, m, oid, format, rv.Elem().Interface(), 0)
plan.next = c.planScan(m, oid, formatCode, rv.Elem().Interface(), depth+1)
return plan
} else {
return &scanPlanJSONToJSONUnmarshal{unmarshal: c.Unmarshal}
}
Expand Down

0 comments on commit 75289ac

Please sign in to comment.