Skip to content

Commit

Permalink
Merge pull request #11 from manicar2093/feat/work-with-custom-types
Browse files Browse the repository at this point in the history
feat: add new way to assign values on sql scan
  • Loading branch information
manicar2093 authored May 24, 2024
2 parents 9a6b98d + cb75b99 commit 2e91cfd
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 18 deletions.
17 changes: 9 additions & 8 deletions goption.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ func Empty[T any]() Optional[T] {

// Of returns an Optional with the specified present value. It does not matters if value is nil
func Of[T any](value T) Optional[T] {
return Optional[T]{value: value, isValidValue: isValidData(value)}
_, isValid := isValidData(value)
return Optional[T]{value: value, isValidValue: isValid}
}

// Get when a value is present returns the value, otherwise throws ErrNoSuchElement.
Expand Down Expand Up @@ -62,20 +63,20 @@ func (c Optional[T]) MustGet() T {
return val
}

func isValidData[T any](value T) bool {
func isValidData[T any](value T) (reflect.Value, bool) {
typeOfValue := reflect.TypeOf(value)
if typeOfValue == nil {
return false
return reflect.Value{}, false
}
kind := typeOfValue.Kind()

val := reflect.ValueOf(value)

switch kind {
switch typeOfValue.Kind() {
case reflect.Pointer:
return !val.IsNil()
return val, !val.IsNil()
case reflect.Slice:
return val.Len() != 0
return val, val.Len() != 0
default:
return !val.IsZero()
return val, !val.IsZero()
}
}
30 changes: 20 additions & 10 deletions sql.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
package goption

import "database/sql/driver"
import (
"database/sql/driver"
"fmt"
"reflect"
)

// Scan assigns a value from a database driver.
//
// The src value will be of one of the following types:
//
// int64
// float64
// bool
// []byte
// string
// time.Time
// nil - for NULL values
// int64
// float64
// bool
// []byte
// string
// time.Time
// nil - for NULL values
//
// An error should be returned if the value cannot be stored
// without loss of information.
Expand All @@ -21,10 +25,16 @@ import "database/sql/driver"
// and should not be retained. Their underlying memory is owned by the driver.
// If retention is necessary, copy their values before the next call to Scan.
func (c *Optional[T]) Scan(src any) error {
isSrcValid := isValidData(src)
srcValue, isSrcValid := isValidData(src)
c.isValidValue = isSrcValid
if isSrcValid {
c.value = src.(T)
destType := reflect.TypeOf(c.value)
if !srcValue.Type().ConvertibleTo(destType) {
return fmt.Errorf("interface conversion: interface {} is %s, not %s", srcValue.Type(), destType)
}

c.value = srcValue.Convert(destType).Interface().(T)
return nil
}
return nil
}
Expand Down
11 changes: 11 additions & 0 deletions sql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,17 @@ var _ = Describe("Sql", func() {
Expect(opt.IsPresent()).To(BeFalse())
})
})

When("has a custom type", func() {
It("assign it by its type", func() {
type Money int

opt := goption.Empty[Money]()

Expect(opt.Scan(400)).To(Succeed())
Expect(opt.IsPresent()).To(BeTrue())
})
})
})

Describe("Value", func() {
Expand Down

0 comments on commit 2e91cfd

Please sign in to comment.