Skip to content

Commit 74796b4

Browse files
author
Miguel Molina
authored
Merge pull request #113 from erizocosmico/hotfix/ulid-scan
base: fix ULID Scan method
2 parents 5ad9c11 + 543ff45 commit 74796b4

File tree

2 files changed

+83
-1
lines changed

2 files changed

+83
-1
lines changed

model.go

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package kallax
22

33
import (
4+
"bytes"
45
"database/sql"
56
"database/sql/driver"
7+
"encoding/hex"
68
"fmt"
79
"math/rand"
810
"sync"
@@ -212,7 +214,85 @@ func NewULID() ULID {
212214

213215
// Scan implements the Scanner interface.
214216
func (id *ULID) Scan(src interface{}) error {
215-
return (*uuid.UUID)(id).Scan(src)
217+
switch src := src.(type) {
218+
case []byte:
219+
if len(src) != 16 {
220+
return id.UnmarshalText(src)
221+
}
222+
223+
var ulid ulid.ULID
224+
if err := ulid.UnmarshalBinary(src); err != nil {
225+
return err
226+
}
227+
*id = ULID(ulid)
228+
return nil
229+
case string:
230+
return id.Scan([]byte(src))
231+
default:
232+
return fmt.Errorf("kallax: cannot scan %T into ULID", src)
233+
}
234+
}
235+
236+
var (
237+
urnPrefix = []byte("urn:uuid:")
238+
byteGroups = []int{8, 4, 4, 4, 12}
239+
)
240+
241+
// UnmarshalText implements the encoding.TextUnmarshaler interface.
242+
// Following formats are supported:
243+
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
244+
// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
245+
// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
246+
// Implements the exact same code as the UUID UnmarshalText removing the
247+
// version check.
248+
func (u *ULID) UnmarshalText(text []byte) (err error) {
249+
if len(text) < 32 {
250+
err = fmt.Errorf("uuid: UUID string too short: %s", text)
251+
return
252+
}
253+
254+
t := text[:]
255+
braced := false
256+
257+
if bytes.Equal(t[:9], urnPrefix) {
258+
t = t[9:]
259+
} else if t[0] == '{' {
260+
braced = true
261+
t = t[1:]
262+
}
263+
264+
b := u[:]
265+
266+
for i, byteGroup := range byteGroups {
267+
if i > 0 && t[0] == '-' {
268+
t = t[1:]
269+
} else if i > 0 && t[0] != '-' {
270+
err = fmt.Errorf("kallax: invalid ulid string format")
271+
return
272+
}
273+
274+
if len(t) < byteGroup {
275+
err = fmt.Errorf("kallax: ulid string too short: %s", text)
276+
return
277+
}
278+
279+
if i == 4 && len(t) > byteGroup &&
280+
((braced && t[byteGroup] != '}') || len(t[byteGroup:]) > 1 || !braced) {
281+
err = fmt.Errorf("kallax: ulid string too long: %s", t)
282+
return
283+
}
284+
285+
_, err = hex.Decode(b[:byteGroup/2], t[:byteGroup])
286+
287+
if err != nil {
288+
return
289+
}
290+
291+
t = t[byteGroup:]
292+
b = b[byteGroup/2:]
293+
}
294+
295+
return
216296
}
217297

218298
// Value implements the Valuer interface.

model_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ func TestULID_ScanValue(t *testing.T) {
4747

4848
r.Equal(expected, id)
4949
r.Equal(expected.String(), id.String())
50+
51+
r.NoError(id.Scan([]byte("015af13d-2271-fb69-2dcd-fb24a1fd7dcc")))
5052
}
5153

5254
func TestVirtualColumn(t *testing.T) {

0 commit comments

Comments
 (0)