@@ -28,12 +28,12 @@ The CSVW spec defines the following steps to parse a string value in a csv cell:
2828package datatype
2929
3030import (
31+ "fmt"
3132 "gocldf/internal/jsonutil"
32- "strconv"
3333)
3434
3535/*
36- BaseType ties together functions related to converting between string and Go representations of CSVW datatypes.
36+ baseType ties together functions related to converting between string and Go representations of CSVW datatypes.
3737
3838GetDerivedDescription is called when instantiating a Datatype object.
3939The result is stored as DerivedDescription member of the Datatype and can be
@@ -49,25 +49,41 @@ SqlType specifies the best matching SQLite data type.
4949ToSql implements the conversion of the Go object to a suitable object for insertion
5050into a SQLite database.
5151*/
52- type BaseType struct {
52+ type baseType struct {
5353 GetDerivedDescription func (map [string ]any ) (map [string ]any , error )
54+ SetValueConstraints func (map [string ]stringAndAny ) error
5455 ToGo func (* Datatype , string , bool ) (any , error )
5556 ToString func (* Datatype , any ) (string , error )
5657 SqlType string
5758 ToSql func (* Datatype , any ) (any , error )
5859}
5960
60- // BaseTypes provides a mapping of CSVW data type base names to BaseType instances.
61- var BaseTypes = map [string ]BaseType {
62- "boolean" : Boolean ,
63- "string" : String ,
64- "anyURI" : AnyURI ,
65- "integer" : Integer ,
66- "decimal" : Decimal ,
67- "float" : Decimal ,
68- "number" : Decimal ,
69- "double" : Decimal ,
70- "json" : Json ,
61+ func zeroGetDerivedDescription (m map [string ]any ) (map [string ]any , error ) {
62+ if len (m ) < 0 {
63+ return nil , fmt .Errorf ("zeroGetDerivedDescription called with %d values" , len (m ))
64+ }
65+ return map [string ]any {}, nil
66+ }
67+
68+ func zeroSetValueConstraints (m map [string ]stringAndAny ) error {
69+ if len (m ) != 4 {
70+ return fmt .Errorf ("zeroGetDerivedDescription called with %d values" , len (m ))
71+ }
72+ return nil
73+ }
74+
75+ // BaseTypes provides a mapping of CSVW data type base names to baseType instances.
76+ var BaseTypes = map [string ]baseType {
77+ "boolean" : Boolean ,
78+ "string" : String ,
79+ "anyURI" : AnyURI ,
80+ "integer" : Integer ,
81+ "decimal" : Decimal ,
82+ "float" : Decimal ,
83+ "number" : Decimal ,
84+ "double" : Decimal ,
85+ "json" : Json ,
86+ "datetime" : Datetime ,
7187}
7288
7389// Datatype holds the data related to a CSVW datatype description.
@@ -86,20 +102,17 @@ type Datatype struct {
86102 DerivedDescription map [string ]any
87103}
88104
105+ type stringAndAny struct {
106+ str string
107+ val any
108+ }
109+
89110// New is a factory function to create a Datatype as specified in a JSON description.
90111func New (jsonCol map [string ]interface {}) (* Datatype , error ) {
91112 var (
113+ s2a stringAndAny
92114 s string
93115 err error
94- //
95- minInclusiveS string
96- maxInclusiveS string
97- minExclusiveS string
98- maxExclusiveS string
99- minInclusive any = nil
100- maxInclusive any = nil
101- minExclusive any = nil
102- maxExclusive any = nil
103116 // We seed the three length constraints with a sentinel value.
104117 length = - 1
105118 minLength = - 1
@@ -108,6 +121,12 @@ func New(jsonCol map[string]interface{}) (*Datatype, error) {
108121 )
109122 dtProps := map [string ]any {}
110123
124+ valueConstraintNames := []string {"minInclusive" , "maxInclusive" , "minExclusive" , "maxExclusive" }
125+ valueConstraints := make (map [string ]stringAndAny , 4 )
126+ for _ , v := range valueConstraintNames {
127+ valueConstraints [v ] = stringAndAny {"" , nil }
128+ }
129+
111130 val , ok := jsonCol ["datatype" ]
112131 if ok {
113132 s , ok = val .(string )
@@ -129,64 +148,40 @@ func New(jsonCol map[string]interface{}) (*Datatype, error) {
129148 return nil , err
130149 }
131150 // For constraints which must match the base type we first get the string representation.
132- minInclusiveS , err = jsonutil .GetString (dtProps , "minimum" , "" )
133- if err != nil {
134- return nil , err
135- }
136- maxInclusiveS , err = jsonutil .GetString (dtProps , "maximum" , "" )
137- if err != nil {
138- return nil , err
151+ for _ , v := range valueConstraintNames {
152+ s2a = valueConstraints [v ]
153+ if s2a .str == "" {
154+ s2a .str , err = jsonutil .GetString (dtProps , v , "" )
155+ if err != nil {
156+ return nil , err
157+ }
158+ }
159+ valueConstraints [v ] = s2a
139160 }
140- if minInclusiveS == "" {
141- minInclusiveS , err = jsonutil .GetString (dtProps , "minInclusive" , "" )
161+ // minimum is just an alias for minInclusive.
162+ if valueConstraints ["minInclusive" ].str == "" {
163+ s2a = valueConstraints ["minInclusive" ]
164+ s2a .str , err = jsonutil .GetString (dtProps , "minimum" , "" )
142165 if err != nil {
143166 return nil , err
144167 }
168+ valueConstraints ["minInclusive" ] = s2a
145169 }
146- minExclusiveS , err = jsonutil .GetString (dtProps , "minExclusive" , "" )
147- if err != nil {
148- return nil , err
149- }
150- if maxInclusiveS == "" {
151- maxInclusiveS , err = jsonutil .GetString (dtProps , "maxInclusive" , "" )
170+ // and so is maximum
171+ if valueConstraints ["maxInclusive" ].str == "" {
172+ s2a = valueConstraints ["maxInclusive" ]
173+ s2a .str , err = jsonutil .GetString (dtProps , "maximum" , "" )
152174 if err != nil {
153175 return nil , err
154176 }
155- }
156- maxExclusiveS , err = jsonutil .GetString (dtProps , "maxExclusive" , "" )
157- if err != nil {
158- return nil , err
177+ valueConstraints ["maxInclusive" ] = s2a
159178 }
160179 }
161180 }
162181 // Now convert the constraints appropriately:
163- switch base {
164- case "integer" :
165- if minInclusiveS != "" {
166- minInclusive , err = strconv .Atoi (minInclusiveS )
167- }
168- if minExclusiveS != "" {
169- minExclusive , err = strconv .Atoi (minExclusiveS )
170- }
171- if maxInclusiveS != "" {
172- maxInclusive , err = strconv .Atoi (maxInclusiveS )
173- }
174- if maxExclusiveS != "" {
175- maxExclusive , err = strconv .Atoi (maxExclusiveS )
176- }
177- case "decimal" , "float" , "number" , "double" :
178- if minInclusiveS != "" {
179- minInclusive , err = strconv .ParseFloat (minInclusiveS , 64 )
180- }
181- if minExclusiveS != "" {
182- minExclusive , err = strconv .ParseFloat (minExclusiveS , 64 )
183- }
184- if maxInclusiveS != "" {
185- maxInclusive , err = strconv .ParseFloat (maxInclusiveS , 64 )
186- }
187- if maxExclusiveS != "" {
188- maxExclusive , err = strconv .ParseFloat (maxExclusiveS , 64 )
189- }
182+ err = BaseTypes [base ].SetValueConstraints (valueConstraints )
183+ if err != nil {
184+ return nil , err
190185 }
191186 // We compute the derived description map once at instantiation.
192187 dd , err := BaseTypes [base ].GetDerivedDescription (dtProps )
@@ -200,10 +195,10 @@ func New(jsonCol map[string]interface{}) (*Datatype, error) {
200195 Length : length ,
201196 MinLength : minLength ,
202197 MaxLength : maxLength ,
203- MinInclusive : minInclusive ,
204- MinExclusive : minExclusive ,
205- MaxInclusive : maxInclusive ,
206- MaxExclusive : maxExclusive ,
198+ MinInclusive : valueConstraints [ " minInclusive" ]. val ,
199+ MinExclusive : valueConstraints [ " minExclusive" ]. val ,
200+ MaxInclusive : valueConstraints [ " maxInclusive" ]. val ,
201+ MaxExclusive : valueConstraints [ " maxExclusive" ]. val ,
207202 }
208203 return res , nil
209204}
0 commit comments