go icon indicating copy to clipboard operation
go copied to clipboard

proposal: database/sql: Support for generics with NullTypes Interface

Open timdadd opened this issue 3 years ago • 1 comments

To support handling of generics, add an interface that includes all the null types type NullTypes interface { NullString | NullInt64 | NullTime | NullBool ... }

timdadd avatar Oct 26 '22 17:10 timdadd

what does the interface enable? why can't you define the interface in the code that's using it?

seankhliao avatar Oct 26 '22 17:10 seankhliao

This proposal has been added to the active column of the proposals project and will now be reviewed at the weekly proposal review meetings. — rsc for the proposal review group

rsc avatar Nov 09 '22 19:11 rsc

It's still unclear what this would enable us to do.

rsc avatar Nov 16 '22 18:11 rsc

The only reason for adding this is because the sql package defines all the null types. As it's generic code in the software using the SQL package, it would be better if the interface is defined in the SQL package because if the SQL package adds another type in the future then the generic will not work unless the interface defined in the software using the SQL package updates their interface.

So if someone doesn't want to support all the types in their generic code then they define their own interface. But if, as I have, the written code works with all types then it would be nice, if a future release of the sql package added the new type to a published interface instead of the current risk that something breaks.

timdadd avatar Nov 16 '22 21:11 timdadd

@timdadd I don't understand how you would use the interface. Do you have concrete code you can share that would make use of this interface?

rsc avatar Nov 30 '22 18:11 rsc

@rsc I have to unmarshall json messages that have an unknown structure but follow the sql.null format because they were marshalled from SQL structs. Being SQL null they are of the format xxx/valid. I want to save writing code for each SQL Null type, so instead I build the functions using a single generic function.

Here is my generic function that builds 3 real functions

// interfaceToType takes a json Interface and unmarshalls to the SQL type given
func interfaceToType[V sql.NullString | sql.NullInt64 | sql.NullTime](m interface{}, t V) (res V, err error) {
	var buf []byte
	if buf, err = json.Marshal(m); err != nil {
		return res, logErrF("couldn't marshall the map %w:%v", m, err)
	}
	logf("interfaceToType", string(buf))
	if err = json.Unmarshal(buf, &res); err != nil {
		return res, logErrF("couldn't unmarshall the map %s:%v", buf, err)
	}
	logf("interfaceToType", res)
	return
}

The calling code is like this:

	if an.DisplayName, err = interfaceToType(attrNameMap["display_name"], an.DisplayName); err != nil {
		return
	}

If an interface exists then I can use instead of [] and then if you add a new type then my code just needs recompilation.

Here's a bit of JSON I have to unmarshall, but I can't use a struct because the JSON structure is inconsistent:

			"attr_type": "T",
			"attr_type_format_id": {
				"Int64": 0,
				"Valid": false
			},
			"format_value": "",
			"import": false,
			"optional": false,
			"normalise": true,
			"display_name": {
				"String": "",
				"Valid": true
			},

Of course you might have a much better way of doing all this, if so then please let me know.

timdadd avatar Nov 30 '22 21:11 timdadd

I don't see anything in interfaceToType that is specific to SQL. It seems like a shorter function would be:

func unmarshal[T any](m interface{}) (res T, err error) {
	var buf []byte
	if buf, err = json.Marshal(m); err != nil {
		return res, logErrF("couldn't marshall the map %w:%v", m, err)
	}
	logf("interfaceToType", string(buf))
	if err = json.Unmarshal(buf, &res); err != nil {
		return res, logErrF("couldn't unmarshall the map %s:%v", buf, err)
	}
	logf("interfaceToType", res)
	return
}

and then used as

	if an.DisplayName, err = unmarshal[sql.NullString](attrNameMap["display_name"]); err != nil {
		return
	}

This wouldn't need the null interface constraint at all.

rsc avatar Dec 07 '22 18:12 rsc

Based on the discussion above, this proposal seems like a likely decline. — rsc for the proposal review group

rsc avatar Dec 14 '22 19:12 rsc

No change in consensus, so declined. — rsc for the proposal review group

rsc avatar Dec 21 '22 19:12 rsc