forgejo/modules/optional/option.go
Mathieu Fenniak 29eddd311b chore: upgrade to https://code.forgejo.org/xorm/xorm v1.4.0 (#12639)
Upgrade Forgejo to our forked [xorm v1.4.0](https://code.forgejo.org/xorm/xorm/compare/v1.3.9-forgejo.12...v1.4.0), which is now named `code.forgejo.org/xorm/xorm` to reflect the current expectation that it is a permanent fork.  A small number of API changes were made recently in https://code.forgejo.org/xorm/xorm/issues/120 which are accounted for in this PR, in addition to the module rename.

## Checklist

The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. All work and communication must conform to Forgejo's [AI Agreement](https://codeberg.org/forgejo/governance/src/branch/main/AIAgreement.md). There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org).

### Documentation

- [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change.
- [x] I did not document these changes and I do not expect someone else to do it.

### Release notes

- [ ] This change will be noticed by a Forgejo user or admin (feature, bug fix, performance, etc.). I suggest to include a release note for this change.
- [x] This change is not visible to a Forgejo user or admin (refactor, dependency upgrade, etc.). I think there is no need to add a release note for this change.

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/12639
Reviewed-by: Otto <otto@codeberg.org>
2026-05-20 20:20:08 +02:00

113 lines
2.5 KiB
Go

// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package optional
import (
"database/sql"
"database/sql/driver"
"reflect"
"strconv"
"code.forgejo.org/xorm/xorm/schemas"
)
type Option[T any] []T
func None[T any]() Option[T] {
return nil
}
func Some[T any](v T) Option[T] {
return Option[T]{v}
}
func FromPtr[T any](v *T) Option[T] {
if v == nil {
return None[T]()
}
return Some(*v)
}
func FromNonDefault[T comparable](v T) Option[T] {
var zero T
if v == zero {
return None[T]()
}
return Some(v)
}
func (o Option[T]) Has() bool {
return o != nil
}
func (o Option[T]) Get() (has bool, value T) {
if o != nil {
has = true
value = o[0]
}
return has, value
}
func (o Option[T]) ValueOrZeroValue() T {
var zeroValue T
return o.ValueOrDefault(zeroValue)
}
func (o Option[T]) ValueOrDefault(v T) T {
if o.Has() {
return o[0]
}
return v
}
// ParseBool get the corresponding optional.Option[bool] of a string using strconv.ParseBool
func ParseBool(s string) Option[bool] {
v, e := strconv.ParseBool(s)
if e != nil {
return None[bool]()
}
return Some(v)
}
// Option[T] can be used in an xorm bean as a field type for a nullable column. Multiple interfaces must be implemented
// for this to work correctly and won't be checked at compile-time of the bean struct, so they're asserted here in case
// the interface definitions change:
var (
_ sql.Scanner = (*Option[bool])(nil) // read data from DB
_ driver.Valuer = None[bool]() // write data to DB
_ schemas.SQLTypeDelegator = None[bool]() // represent column field type correctly
)
// Convert database data into an Option[T]. sql.Null[T] has all the necessary logic to perform Value(), so it is used as
// an implementation.
func (o *Option[T]) Scan(value any) error {
var n sql.Null[T]
if err := n.Scan(value); err != nil {
return err
}
if n.Valid {
*o = Some(n.V)
} else {
*o = None[T]()
}
return nil
}
// Convert Option[T] into the necessary database data to represent it. sql.Null[T] has all the necessary logic to
// perform Value(), so it is used as an implementation.
func (o Option[T]) Value() (driver.Value, error) {
var n sql.Null[T]
if o.Has() {
n.V = o[0]
n.Valid = true
} else {
n.Valid = false
}
return n.Value()
}
// Make xorm use whatever SQLType is appropriate for T to represent Option[T] in the database table
func (o Option[T]) DelegateSQLType() reflect.Type {
return reflect.TypeFor[T]()
}