vendor: update buildkit to v0.29.0-rc1

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
Tonis Tiigi
2026-03-25 15:47:08 -07:00
parent a7d3578248
commit eba72a35e4
518 changed files with 29223 additions and 24305 deletions
+9
View File
@@ -0,0 +1,9 @@
codecov:
notify:
after_n_builds: 2
coverage:
status:
patch:
default:
target: 80%
+6 -2
View File
@@ -1,2 +1,6 @@
secrets.yml
coverage.out
*.out
*.cov
.idea
.env
.mcp.json
.claude/
+11 -18
View File
@@ -2,25 +2,11 @@ version: "2"
linters:
default: all
disable:
- cyclop
- depguard
- errchkjson
- errorlint
- exhaustruct
- forcetypeassert
- funlen
- gochecknoglobals
- gochecknoinits
- gocognit
- godot
- gomoddirectives
- godox
- gosmopolitan
- inamedparam
- intrange
- ireturn
- lll
- musttag
- nestif
- exhaustruct
- nlreturn
- nonamedreturns
- noinlineerr
@@ -29,7 +15,6 @@ linters:
- testpackage
- thelper
- tparallel
- unparam
- varnamelen
- whitespace
- wrapcheck
@@ -41,8 +26,15 @@ linters:
goconst:
min-len: 2
min-occurrences: 3
cyclop:
max-complexity: 20
gocyclo:
min-complexity: 45
min-complexity: 20
exhaustive:
default-signifies-exhaustive: true
default-case-required: true
lll:
line-length: 180
exclusions:
generated: lax
presets:
@@ -58,6 +50,7 @@ formatters:
enable:
- gofmt
- goimports
- gofumpt
exclusions:
generated: lax
paths:
+4 -2
View File
@@ -23,7 +23,9 @@ include:
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
@@ -55,7 +57,7 @@ further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at ivan+abuse@flanders.co.nz. All
reported by contacting the project team at <ivan+abuse@flanders.co.nz>. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
@@ -68,7 +70,7 @@ members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
available at [<http://contributor-covenant.org/version/1/4>][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
+52
View File
@@ -0,0 +1,52 @@
# Contributors
- Repository: ['go-openapi/strfmt']
| Total Contributors | Total Contributions |
| --- | --- |
| 40 | 225 |
| Username | All Time Contribution Count | All Commits |
| --- | --- | --- |
| @casualjim | 88 | <https://github.com/go-openapi/strfmt/commits?author=casualjim> |
| @fredbi | 57 | <https://github.com/go-openapi/strfmt/commits?author=fredbi> |
| @youyuanwu | 13 | <https://github.com/go-openapi/strfmt/commits?author=youyuanwu> |
| @jlambatl | 9 | <https://github.com/go-openapi/strfmt/commits?author=jlambatl> |
| @GlenDC | 5 | <https://github.com/go-openapi/strfmt/commits?author=GlenDC> |
| @padamstx | 4 | <https://github.com/go-openapi/strfmt/commits?author=padamstx> |
| @dimovnike | 3 | <https://github.com/go-openapi/strfmt/commits?author=dimovnike> |
| @carlv-stripe | 3 | <https://github.com/go-openapi/strfmt/commits?author=carlv-stripe> |
| @Copilot | 3 | <https://github.com/go-openapi/strfmt/commits?author=Copilot> |
| @keramix | 3 | <https://github.com/go-openapi/strfmt/commits?author=keramix> |
| @gregmarr | 2 | <https://github.com/go-openapi/strfmt/commits?author=gregmarr> |
| @vadorovsky | 2 | <https://github.com/go-openapi/strfmt/commits?author=vadorovsky> |
| @Ompluscator | 2 | <https://github.com/go-openapi/strfmt/commits?author=Ompluscator> |
| @johnnyg | 2 | <https://github.com/go-openapi/strfmt/commits?author=johnnyg> |
| @chakrit | 2 | <https://github.com/go-openapi/strfmt/commits?author=chakrit> |
| @bg451 | 2 | <https://github.com/go-openapi/strfmt/commits?author=bg451> |
| @aleksandr-vin | 2 | <https://github.com/go-openapi/strfmt/commits?author=aleksandr-vin> |
| @ujjwalsh | 1 | <https://github.com/go-openapi/strfmt/commits?author=ujjwalsh> |
| @kenjones-cisco | 1 | <https://github.com/go-openapi/strfmt/commits?author=kenjones-cisco> |
| @jwalter1-quest | 1 | <https://github.com/go-openapi/strfmt/commits?author=jwalter1-quest> |
| @ccoVeille | 1 | <https://github.com/go-openapi/strfmt/commits?author=ccoVeille> |
| @tylerb | 1 | <https://github.com/go-openapi/strfmt/commits?author=tylerb> |
| @tzneal | 1 | <https://github.com/go-openapi/strfmt/commits?author=tzneal> |
| @tklauser | 1 | <https://github.com/go-openapi/strfmt/commits?author=tklauser> |
| @SuperQ | 1 | <https://github.com/go-openapi/strfmt/commits?author=SuperQ> |
| @srizzling | 1 | <https://github.com/go-openapi/strfmt/commits?author=srizzling> |
| @shawnps | 1 | <https://github.com/go-openapi/strfmt/commits?author=shawnps> |
| @prashantv | 1 | <https://github.com/go-openapi/strfmt/commits?author=prashantv> |
| @krnkl | 1 | <https://github.com/go-openapi/strfmt/commits?author=krnkl> |
| @mstoykov | 1 | <https://github.com/go-openapi/strfmt/commits?author=mstoykov> |
| @maxatome | 1 | <https://github.com/go-openapi/strfmt/commits?author=maxatome> |
| @jerome-laforge | 1 | <https://github.com/go-openapi/strfmt/commits?author=jerome-laforge> |
| @justincormack | 1 | <https://github.com/go-openapi/strfmt/commits?author=justincormack> |
| @elipavlov | 1 | <https://github.com/go-openapi/strfmt/commits?author=elipavlov> |
| @gbjk | 1 | <https://github.com/go-openapi/strfmt/commits?author=gbjk> |
| @enesanbar | 1 | <https://github.com/go-openapi/strfmt/commits?author=enesanbar> |
| @CodeLingoBot | 1 | <https://github.com/go-openapi/strfmt/commits?author=CodeLingoBot> |
| @Kunde21 | 1 | <https://github.com/go-openapi/strfmt/commits?author=Kunde21> |
| @bvwells | 1 | <https://github.com/go-openapi/strfmt/commits?author=bvwells> |
| @ligustah | 1 | <https://github.com/go-openapi/strfmt/commits?author=ligustah> |
_this file was generated by the [Contributors GitHub Action](https://github.com/github-community-projects/contributors)_
+150 -12
View File
@@ -1,15 +1,61 @@
# Strfmt [![Build Status](https://github.com/go-openapi/strfmt/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/strfmt/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/strfmt/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/strfmt)
[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/strfmt/master/LICENSE)
[![GoDoc](https://godoc.org/github.com/go-openapi/strfmt?status.svg)](http://godoc.org/github.com/go-openapi/strfmt)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/strfmt)](https://goreportcard.com/report/github.com/go-openapi/strfmt)
# strfmt
<!-- Badges: status -->
[![Tests][test-badge]][test-url] [![Coverage][cov-badge]][cov-url] [![CI vuln scan][vuln-scan-badge]][vuln-scan-url] [![CodeQL][codeql-badge]][codeql-url]
<!-- Badges: release & docker images -->
<!-- Badges: code quality -->
<!-- Badges: license & compliance -->
[![Release][release-badge]][release-url] [![Go Report Card][gocard-badge]][gocard-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url]
<!-- Badges: documentation & support -->
<!-- Badges: others & stats -->
[![GoDoc][godoc-badge]][godoc-url] [![Discord Channel][discord-badge]][discord-url] [![go version][goversion-badge]][goversion-url] ![Top language][top-badge] ![Commits since latest release][commits-badge]
---
Golang support for string formats defined by JSON Schema and OpenAPI.
## Announcements
* **2025-12-19** : new community chat on discord
* a new discord community channel is available to be notified of changes and support users
* our venerable Slack channel remains open, and will be eventually discontinued on **2026-03-31**
You may join the discord community by clicking the invite link on the discord badge (also above). [![Discord Channel][discord-badge]][discord-url]
Or join our Slack channel: [![Slack Channel][slack-logo]![slack-badge]][slack-url]
* **2026-03-07** : v0.26.0 **dropped dependency to the mongodb driver**
* mongodb users can still use this package without any change
* however, we have frozen the back-compatible support for mongodb driver at v2.5.0
* users who want to keep-up with future evolutions (possibly incompatible) of this driver
can do so by adding a blank import in their program: `import _ "github.com/go-openapi/strfmt/enable/mongodb"`.
This will switch the behavior to the actual driver, which remains regularly updated as an independent module.
## Status
API is stable.
## Import this library in your project
```cmd
go get github.com/go-openapi/strfmt
```
## Contents
This package exposes a registry of data types to support string formats in the go-openapi toolkit.
strfmt represents a well known string format such as credit card or email. The go toolkit for OpenAPI specifications knows how to deal with those.
`strfmt` represents a well known string format such as hostname or email.
## Supported data formats
go-openapi/strfmt follows the swagger 2.0 specification with the following formats
This package provides a few extra formats such as credit card (US), color, etc.
Format types can serialize and deserialize JSON or from a SQL database.
BSON is also supported (MongoDB).
### Supported formats
`go-openapi/strfmt` follows the swagger 2.0 specification with the following formats
defined [here](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types).
It also provides convenient extensions to go-openapi users.
@@ -43,7 +89,7 @@ It also provides convenient extensions to go-openapi users.
> It does not provide validation for numerical values with swagger format extension for JSON types "number" or
> "integer" (e.g. float, double, int32...).
## Type conversion
### Type conversion
All types defined here are stringers and may be converted to strings with `.String()`.
Note that most types defined by this package may be converted directly to string like `string(Email{})`.
@@ -51,13 +97,14 @@ Note that most types defined by this package may be converted directly to string
`Date` and `DateTime` may be converted directly to `time.Time` like `time.Time(Time{})`.
Similarly, you can convert `Duration` to `time.Duration` as in `time.Duration(Duration{})`
## Using pointers
### Using pointers
The `conv` subpackage provides helpers to convert the types to and from pointers, just like `go-openapi/swag` does
with primitive types.
## Format types
Types defined in strfmt expose marshaling and validation capabilities.
### Format types
Types defined in `strfmt` expose marshaling and validation capabilities.
List of defined types:
- Base64
@@ -87,6 +134,97 @@ List of defined types:
- [UUID7](https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7)
- [ULID](https://github.com/ulid/spec)
### Database support
All format types implement the `database/sql` interfaces `sql.Scanner` and `driver.Valuer`,
so they work out of the box with Go's standard `database/sql` package and any SQL driver.
All format types also implement BSON marshaling/unmarshaling for use with MongoDB.
By default, a built-in minimal codec is used (compatible with mongo-driver v2.5.0).
For full driver support, add `import _ "github.com/go-openapi/strfmt/enable/mongodb"`.
> **MySQL / MariaDB caveat for `DateTime`:**
> The `go-sql-driver/mysql` driver has hard-coded handling for `time.Time` but does not
> intercept type redefinitions like `strfmt.DateTime`. As a result, `DateTime.Value()` sends
> an RFC 3339 string (e.g. `"2024-06-15T12:30:45.123Z"`) that MySQL/MariaDB rejects for
> `DATETIME` columns.
>
> Workaround: set `strfmt.MarshalFormat` to a MySQL-compatible format such as
> `strfmt.ISO8601LocalTime` and normalize to UTC before marshaling:
>
> ```go
> strfmt.MarshalFormat = strfmt.ISO8601LocalTime
> strfmt.NormalizeTimeForMarshal = func(t time.Time) time.Time { return t.UTC() }
> ```
>
> See [#174](https://github.com/go-openapi/strfmt/issues/174) for details.
Integration tests for MongoDB, MariaDB, and PostgreSQL run in CI to verify database roundtrip
compatibility for all format types. See [`internal/testintegration/`](internal/testintegration/).
## Change log
See <https://github.com/go-openapi/strfmt/releases>
## References
<https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md>
## Licensing
This library ships under the [SPDX-License-Identifier: Apache-2.0](./LICENSE).
## Other documentation
* [All-time contributors](./CONTRIBUTORS.md)
* [Contributing guidelines](.github/CONTRIBUTING.md)
* [Maintainers documentation](docs/MAINTAINERS.md)
* [Code style](docs/STYLE.md)
## Cutting a new release
Maintainers can cut a new release by either:
* running [this workflow](https://github.com/go-openapi/strfmt/actions/workflows/bump-release.yml)
* or pushing a semver tag
* signed tags are preferred
* The tag message is prepended to release notes
<!-- Badges: status -->
[test-badge]: https://github.com/go-openapi/strfmt/actions/workflows/go-test.yml/badge.svg
[test-url]: https://github.com/go-openapi/strfmt/actions/workflows/go-test.yml
[cov-badge]: https://codecov.io/gh/go-openapi/strfmt/branch/master/graph/badge.svg
[cov-url]: https://codecov.io/gh/go-openapi/strfmt
[vuln-scan-badge]: https://github.com/go-openapi/strfmt/actions/workflows/scanner.yml/badge.svg
[vuln-scan-url]: https://github.com/go-openapi/strfmt/actions/workflows/scanner.yml
[codeql-badge]: https://github.com/go-openapi/strfmt/actions/workflows/codeql.yml/badge.svg
[codeql-url]: https://github.com/go-openapi/strfmt/actions/workflows/codeql.yml
<!-- Badges: release & docker images -->
[release-badge]: https://badge.fury.io/gh/go-openapi%2Fstrfmt.svg
[release-url]: https://badge.fury.io/gh/go-openapi%2Fstrfmt
[gomod-badge]: https://badge.fury.io/go/github.com%2Fgo-openapi%2Fstrfmt.svg
[gomod-url]: https://badge.fury.io/go/github.com%2Fgo-openapi%2Fstrfmt
<!-- Badges: code quality -->
[gocard-badge]: https://goreportcard.com/badge/github.com/go-openapi/strfmt
[gocard-url]: https://goreportcard.com/report/github.com/go-openapi/strfmt
[codefactor-badge]: https://img.shields.io/codefactor/grade/github/go-openapi/strfmt
[codefactor-url]: https://www.codefactor.io/repository/github/go-openapi/strfmt
<!-- Badges: documentation & support -->
[doc-badge]: https://img.shields.io/badge/doc-site-blue?link=https%3A%2F%2Fgoswagger.io%2Fgo-openapi%2F
[doc-url]: https://goswagger.io/go-openapi
[godoc-badge]: https://pkg.go.dev/badge/github.com/go-openapi/strfmt
[godoc-url]: http://pkg.go.dev/github.com/go-openapi/strfmt
[slack-logo]: https://a.slack-edge.com/e6a93c1/img/icons/favicon-32.png
[slack-badge]: https://img.shields.io/badge/slack-blue?link=https%3A%2F%2Fgoswagger.slack.com%2Farchives%2FC04R30YM
[slack-url]: https://goswagger.slack.com/archives/C04R30YMU
[discord-badge]: https://img.shields.io/discord/1446918742398341256?logo=discord&label=discord&color=blue
[discord-url]: https://discord.gg/FfnFYaC3k5
<!-- Badges: license & compliance -->
[license-badge]: http://img.shields.io/badge/license-Apache%20v2-orange.svg
[license-url]: https://github.com/go-openapi/strfmt/?tab=Apache-2.0-1-ov-file#readme
<!-- Badges: others & stats -->
[goversion-badge]: https://img.shields.io/github/go-mod/go-version/go-openapi/strfmt
[goversion-url]: https://github.com/go-openapi/strfmt/blob/master/go.mod
[top-badge]: https://img.shields.io/github/languages/top/go-openapi/strfmt
[commits-badge]: https://img.shields.io/github/commits-since/go-openapi/strfmt/latest
+37
View File
@@ -0,0 +1,37 @@
# Security Policy
This policy outlines the commitment and practices of the go-openapi maintainers regarding security.
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 0.x | :white_check_mark: |
## Vulnerability checks in place
This repository uses automated vulnerability scans, at every merged commit and at least once a week.
We use:
* [`GitHub CodeQL`][codeql-url]
* [`trivy`][trivy-url]
* [`govulncheck`][govulncheck-url]
Reports are centralized in github security reports and visible only to the maintainers.
## Reporting a vulnerability
If you become aware of a security vulnerability that affects the current repository,
**please report it privately to the maintainers**
rather than opening a publicly visible GitHub issue.
Please follow the instructions provided by github to [Privately report a security vulnerability][github-guidance-url].
> [!NOTE]
> On Github, navigate to the project's "Security" tab then click on "Report a vulnerability".
[codeql-url]: https://github.com/github/codeql
[trivy-url]: https://trivy.dev/docs/latest/getting-started
[govulncheck-url]: https://go.dev/blog/govulncheck
[github-guidance-url]: https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability
+56 -32
View File
@@ -5,62 +5,62 @@ package strfmt
import (
"database/sql/driver"
"encoding/hex"
"encoding/json"
"fmt"
bsonprim "go.mongodb.org/mongo-driver/bson/primitive"
)
func init() {
func init() { //nolint:gochecknoinits // registers bsonobjectid format in the default registry
var id ObjectId
// register this format in the default registry
Default.Add("bsonobjectid", &id, IsBSONObjectID)
}
// IsBSONObjectID returns true when the string is a valid BSON.ObjectId
// IsBSONObjectID returns true when the string is a valid BSON [ObjectId].
func IsBSONObjectID(str string) bool {
_, err := bsonprim.ObjectIDFromHex(str)
_, err := objectIDFromHex(str)
return err == nil
}
// ObjectId represents a BSON object ID (alias to go.mongodb.org/mongo-driver/bson/primitive.ObjectID)
// ObjectId represents a BSON object ID (a 12-byte unique identifier).
//
// swagger:strfmt bsonobjectid
type ObjectId bsonprim.ObjectID //nolint:revive
// swagger:strfmt bsonobjectid.
type ObjectId [12]byte //nolint:revive
// NewObjectId creates a ObjectId from a Hex String
// nilObjectID is the zero-value ObjectId.
var nilObjectID ObjectId //nolint:gochecknoglobals // package-level sentinel
// NewObjectId creates a [ObjectId] from a hexadecimal String.
func NewObjectId(hex string) ObjectId { //nolint:revive
oid, err := bsonprim.ObjectIDFromHex(hex)
oid, err := objectIDFromHex(hex)
if err != nil {
panic(err)
}
return ObjectId(oid)
return oid
}
// MarshalText turns this instance into text
// MarshalText turns this instance into text.
func (id ObjectId) MarshalText() ([]byte, error) {
oid := bsonprim.ObjectID(id)
if oid == bsonprim.NilObjectID {
if id == nilObjectID {
return nil, nil
}
return []byte(oid.Hex()), nil
return []byte(id.Hex()), nil
}
// UnmarshalText hydrates this instance from text
// UnmarshalText hydrates this instance from text.
func (id *ObjectId) UnmarshalText(data []byte) error { // validation is performed later on
if len(data) == 0 {
*id = ObjectId(bsonprim.NilObjectID)
*id = nilObjectID
return nil
}
oidstr := string(data)
oid, err := bsonprim.ObjectIDFromHex(oidstr)
oid, err := objectIDFromHex(string(data))
if err != nil {
return err
}
*id = ObjectId(oid)
*id = oid
return nil
}
// Scan read a value from a database driver
// Scan read a value from a database driver.
func (id *ObjectId) Scan(raw any) error {
var data []byte
switch v := raw.(type) {
@@ -75,27 +75,36 @@ func (id *ObjectId) Scan(raw any) error {
return id.UnmarshalText(data)
}
// Value converts a value to a database driver value
// Value converts a value to a database driver value.
func (id ObjectId) Value() (driver.Value, error) {
return driver.Value(bsonprim.ObjectID(id).Hex()), nil
return driver.Value(id.Hex()), nil
}
// Hex returns the hex string representation of the [ObjectId].
func (id ObjectId) Hex() string {
return hex.EncodeToString(id[:])
}
func (id ObjectId) String() string {
return bsonprim.ObjectID(id).Hex()
return id.Hex()
}
// MarshalJSON returns the ObjectId as JSON
// MarshalJSON returns the [ObjectId] as JSON.
func (id ObjectId) MarshalJSON() ([]byte, error) {
return bsonprim.ObjectID(id).MarshalJSON()
return json.Marshal(id.Hex())
}
// UnmarshalJSON sets the ObjectId from JSON
// UnmarshalJSON sets the [ObjectId] from JSON.
func (id *ObjectId) UnmarshalJSON(data []byte) error {
var obj bsonprim.ObjectID
if err := obj.UnmarshalJSON(data); err != nil {
var hexStr string
if err := json.Unmarshal(data, &hexStr); err != nil {
return err
}
*id = ObjectId(obj)
oid, err := objectIDFromHex(hexStr)
if err != nil {
return err
}
*id = oid
return nil
}
@@ -104,7 +113,7 @@ func (id *ObjectId) DeepCopyInto(out *ObjectId) {
*out = *id
}
// DeepCopy copies the receiver into a new ObjectId.
// DeepCopy copies the receiver into a new [ObjectId].
func (id *ObjectId) DeepCopy() *ObjectId {
if id == nil {
return nil
@@ -113,3 +122,18 @@ func (id *ObjectId) DeepCopy() *ObjectId {
id.DeepCopyInto(out)
return out
}
// objectIDFromHex parses a 24-character hex string into an [ObjectId].
func objectIDFromHex(s string) (ObjectId, error) {
const objectIDHexLen = 24
if len(s) != objectIDHexLen {
return nilObjectID, fmt.Errorf("the provided hex string %q is not a valid ObjectID: %w", s, ErrFormat)
}
b, err := hex.DecodeString(s)
if err != nil {
return nilObjectID, fmt.Errorf("the provided hex string %q is not a valid ObjectID: %w", s, err)
}
var oid ObjectId
copy(oid[:], b)
return oid, nil
}
+13 -14
View File
@@ -10,35 +10,34 @@ import (
"time"
)
func init() {
func init() { //nolint:gochecknoinits // registers date format in the default registry
d := Date{}
// register this format in the default registry
Default.Add("date", &d, IsDate)
}
// IsDate returns true when the string is a valid date
// IsDate returns true when the string is a valid date.
func IsDate(str string) bool {
_, err := time.Parse(RFC3339FullDate, str)
return err == nil
}
const (
// RFC3339FullDate represents a full-date as specified by RFC3339
// RFC3339FullDate represents a full-date as specified by RFC3339.
// See: http://goo.gl/xXOvVd
RFC3339FullDate = "2006-01-02"
)
// Date represents a date from the API
// Date represents a date from the API.
//
// swagger:strfmt date
// swagger:strfmt date.
type Date time.Time
// String converts this date into a string
// String converts this date into a string.
func (d Date) String() string {
return time.Time(d).Format(RFC3339FullDate)
}
// UnmarshalText parses a text representation into a date type
// UnmarshalText parses a text representation into a date type.
func (d *Date) UnmarshalText(text []byte) error {
if len(text) == 0 {
return nil
@@ -51,7 +50,7 @@ func (d *Date) UnmarshalText(text []byte) error {
return nil
}
// MarshalText serializes this date type to string
// MarshalText serializes this date type to string.
func (d Date) MarshalText() ([]byte, error) {
return []byte(d.String()), nil
}
@@ -79,12 +78,12 @@ func (d Date) Value() (driver.Value, error) {
return driver.Value(d.String()), nil
}
// MarshalJSON returns the Date as JSON
// MarshalJSON returns the Date as JSON.
func (d Date) MarshalJSON() ([]byte, error) {
return json.Marshal(time.Time(d).Format(RFC3339FullDate))
}
// UnmarshalJSON sets the Date from JSON
// UnmarshalJSON sets the Date from JSON.
func (d *Date) UnmarshalJSON(data []byte) error {
if string(data) == jsonNull {
return nil
@@ -126,12 +125,12 @@ func (d *Date) GobDecode(data []byte) error {
return d.UnmarshalBinary(data)
}
// MarshalBinary implements the encoding.BinaryMarshaler interface.
// MarshalBinary implements the encoding.[encoding.BinaryMarshaler] interface.
func (d Date) MarshalBinary() ([]byte, error) {
return time.Time(d).MarshalBinary()
}
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
// UnmarshalBinary implements the encoding.[encoding.BinaryUnmarshaler] interface.
func (d *Date) UnmarshalBinary(data []byte) error {
var original time.Time
@@ -145,7 +144,7 @@ func (d *Date) UnmarshalBinary(data []byte) error {
return nil
}
// Equal checks if two Date instances are equal
// Equal checks if two Date instances are equal.
func (d Date) Equal(d2 Date) bool {
return time.Time(d).Equal(time.Time(d2))
}
+221 -213
View File
File diff suppressed because it is too large Load Diff
+1 -3
View File
@@ -1,7 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0
// Package strfmt contains custom string formats
//
// TODO: add info on how to define and register a custom format
// Package strfmt contains custom string formats.
package strfmt
+12 -12
View File
@@ -14,9 +14,8 @@ import (
"time"
)
func init() {
func init() { //nolint:gochecknoinits // registers duration format in the default registry
d := Duration(0)
// register this format in the default registry
Default.Add("duration", &d, IsDuration)
}
@@ -25,6 +24,7 @@ const (
daysInWeek = 7
)
//nolint:gochecknoglobals // package-level lookup tables for duration parsing
var (
timeUnits = [][]string{
{"ns", "nano"},
@@ -51,7 +51,7 @@ var (
durationMatcher = regexp.MustCompile(`^(((?:-\s?)?\d+)(\.\d+)?\s*([A-Za-zµ]+))`)
)
// IsDuration returns true if the provided string is a valid duration
// IsDuration returns true if the provided string is a valid duration.
func IsDuration(str string) bool {
_, err := ParseDuration(str)
return err == nil
@@ -60,17 +60,17 @@ func IsDuration(str string) bool {
// Duration represents a duration
//
// Duration stores a period of time as a nanosecond count, with the largest
// repesentable duration being approximately 290 years.
// representable duration being approximately 290 years.
//
// swagger:strfmt duration
// swagger:strfmt duration.
type Duration time.Duration
// MarshalText turns this instance into text
// MarshalText turns this instance into text.
func (d Duration) MarshalText() ([]byte, error) {
return []byte(time.Duration(d).String()), nil
}
// UnmarshalText hydrates this instance from text
// UnmarshalText hydrates this instance from text.
func (d *Duration) UnmarshalText(data []byte) error { // validation is performed later on
dd, err := ParseDuration(string(data))
if err != nil {
@@ -80,7 +80,7 @@ func (d *Duration) UnmarshalText(data []byte) error { // validation is performed
return nil
}
// ParseDuration parses a duration from a string, compatible with scala duration syntax
// ParseDuration parses a duration from a string, compatible with scala duration syntax.
func ParseDuration(cand string) (time.Duration, error) {
if dur, err := time.ParseDuration(cand); err == nil {
return dur, nil
@@ -143,7 +143,7 @@ func ParseDuration(cand string) (time.Duration, error) {
// Scan reads a Duration value from database driver type.
func (d *Duration) Scan(raw any) error {
switch v := raw.(type) {
// TODO: case []byte: // ?
// Proposal for enhancement: case []byte: // ?
case int64:
*d = Duration(v)
case float64:
@@ -162,17 +162,17 @@ func (d Duration) Value() (driver.Value, error) {
return driver.Value(int64(d)), nil
}
// String converts this duration to a string
// String converts this duration to a string.
func (d Duration) String() string {
return time.Duration(d).String()
}
// MarshalJSON returns the Duration as JSON
// MarshalJSON returns the Duration as JSON.
func (d Duration) MarshalJSON() ([]byte, error) {
return json.Marshal(time.Duration(d).String())
}
// UnmarshalJSON sets the Duration from JSON
// UnmarshalJSON sets the Duration from JSON.
func (d *Duration) UnmarshalJSON(data []byte) error {
if string(data) == jsonNull {
return nil
+1 -1
View File
@@ -5,7 +5,7 @@ package strfmt
type strfmtError string
// ErrFormat is an error raised by the strfmt package
// ErrFormat is an error raised by the [strfmt] package.
const ErrFormat strfmtError = "format error"
func (e strfmtError) Error() string {
+89 -85
View File
@@ -16,20 +16,20 @@ import (
"github.com/go-viper/mapstructure/v2"
)
// Default is the default formats registry
var Default = NewSeededFormats(nil, nil)
// Default is the default formats registry.
var Default = NewSeededFormats(nil, nil) //nolint:gochecknoglobals // package-level default registry, by design
// Validator represents a validator for a string format.
type Validator func(string) bool
// NewFormats creates a new formats registry seeded with the values from the default
func NewFormats() Registry {
// NewFormats creates a new formats registry seeded with the values from the default.
func NewFormats() Registry { //nolint:ireturn // factory function returns the Registry interface by design
//nolint:forcetypeassert
return NewSeededFormats(Default.(*defaultFormats).data, nil)
}
// NewSeededFormats creates a new formats registry
func NewSeededFormats(seeds []knownFormat, normalizer NameNormalizer) Registry {
// NewSeededFormats creates a new formats registry.
func NewSeededFormats(seeds []knownFormat, normalizer NameNormalizer) Registry { //nolint:ireturn // factory function returns the Registry interface by design
if normalizer == nil {
normalizer = DefaultNameNormalizer
}
@@ -50,7 +50,7 @@ type knownFormat struct {
// NameNormalizer is a function that normalizes a format name.
type NameNormalizer func(string) string
// DefaultNameNormalizer removes all dashes
// DefaultNameNormalizer removes all dashes.
func DefaultNameNormalizer(name string) string {
return strings.ReplaceAll(name, "-", "")
}
@@ -62,8 +62,8 @@ type defaultFormats struct {
normalizeName NameNormalizer
}
// MapStructureHookFunc is a decode hook function for mapstructure
func (f *defaultFormats) MapStructureHookFunc() mapstructure.DecodeHookFunc {
// MapStructureHookFunc is a decode hook function for mapstructure.
func (f *defaultFormats) MapStructureHookFunc() mapstructure.DecodeHookFunc { //nolint:ireturn // returns interface required by mapstructure
return func(from reflect.Type, to reflect.Type, obj any) (any, error) {
if from.Kind() != reflect.String {
return obj, nil
@@ -76,83 +76,87 @@ func (f *defaultFormats) MapStructureHookFunc() mapstructure.DecodeHookFunc {
for _, v := range f.data {
tpe, _ := f.GetType(v.Name)
if to == tpe {
switch v.Name {
case "date":
d, err := time.ParseInLocation(RFC3339FullDate, data, DefaultTimeLocation)
if err != nil {
return nil, err
}
return Date(d), nil
case "datetime":
input := data
if len(input) == 0 {
return nil, fmt.Errorf("empty string is an invalid datetime format: %w", ErrFormat)
}
return ParseDateTime(input)
case "duration":
dur, err := ParseDuration(data)
if err != nil {
return nil, err
}
return Duration(dur), nil
case "uri":
return URI(data), nil
case "email":
return Email(data), nil
case "uuid":
return UUID(data), nil
case "uuid3":
return UUID3(data), nil
case "uuid4":
return UUID4(data), nil
case "uuid5":
return UUID5(data), nil
case "uuid7":
return UUID7(data), nil
case "hostname":
return Hostname(data), nil
case "ipv4":
return IPv4(data), nil
case "ipv6":
return IPv6(data), nil
case "cidr":
return CIDR(data), nil
case "mac":
return MAC(data), nil
case "isbn":
return ISBN(data), nil
case "isbn10":
return ISBN10(data), nil
case "isbn13":
return ISBN13(data), nil
case "creditcard":
return CreditCard(data), nil
case "ssn":
return SSN(data), nil
case "hexcolor":
return HexColor(data), nil
case "rgbcolor":
return RGBColor(data), nil
case "byte":
return Base64(data), nil
case "password":
return Password(data), nil
case "ulid":
ulid, err := ParseULID(data)
if err != nil {
return nil, err
}
return ulid, nil
default:
return nil, errors.InvalidTypeName(v.Name)
}
return decodeFormatFromString(v.Name, data)
}
}
return data, nil
}
}
// Add adds a new format, return true if this was a new item instead of a replacement
// decodeFormatFromString decodes a string into the appropriate format type by name.
func decodeFormatFromString(name, data string) (any, error) { //nolint:gocyclo,cyclop // flat switch over format names, no real complexity
switch name {
case "date":
d, err := time.ParseInLocation(RFC3339FullDate, data, DefaultTimeLocation)
if err != nil {
return nil, err
}
return Date(d), nil
case "datetime":
if len(data) == 0 {
return nil, fmt.Errorf("empty string is an invalid datetime format: %w", ErrFormat)
}
return ParseDateTime(data)
case "duration":
dur, err := ParseDuration(data)
if err != nil {
return nil, err
}
return Duration(dur), nil
case "uri":
return URI(data), nil
case "email":
return Email(data), nil
case "uuid":
return UUID(data), nil
case "uuid3":
return UUID3(data), nil
case "uuid4":
return UUID4(data), nil
case "uuid5":
return UUID5(data), nil
case "uuid7":
return UUID7(data), nil
case "hostname":
return Hostname(data), nil
case "ipv4":
return IPv4(data), nil
case "ipv6":
return IPv6(data), nil
case "cidr":
return CIDR(data), nil
case "mac":
return MAC(data), nil
case "isbn":
return ISBN(data), nil
case "isbn10":
return ISBN10(data), nil
case "isbn13":
return ISBN13(data), nil
case "creditcard":
return CreditCard(data), nil
case "ssn":
return SSN(data), nil
case "hexcolor":
return HexColor(data), nil
case "rgbcolor":
return RGBColor(data), nil
case "byte":
return Base64(data), nil
case "password":
return Password(data), nil
case "ulid":
ulid, err := ParseULID(data)
if err != nil {
return nil, err
}
return ulid, nil
default:
return nil, errors.InvalidTypeName(name)
}
}
// Add adds a new format, return true if this was a new item instead of a replacement.
func (f *defaultFormats) Add(name string, strfmt Format, validator Validator) bool {
f.Lock()
defer f.Unlock()
@@ -178,7 +182,7 @@ func (f *defaultFormats) Add(name string, strfmt Format, validator Validator) bo
return true
}
// GetType gets the type for the specified name
// GetType gets the type for the specified name.
func (f *defaultFormats) GetType(name string) (reflect.Type, bool) {
f.Lock()
defer f.Unlock()
@@ -191,7 +195,7 @@ func (f *defaultFormats) GetType(name string) (reflect.Type, bool) {
return nil, false
}
// DelByName removes the format by the specified name, returns true when an item was actually removed
// DelByName removes the format by the specified name, returns true when an item was actually removed.
func (f *defaultFormats) DelByName(name string) bool {
f.Lock()
defer f.Unlock()
@@ -208,7 +212,7 @@ func (f *defaultFormats) DelByName(name string) bool {
return false
}
// DelByFormat removes the specified format, returns true when an item was actually removed
// DelByFormat removes the specified format, returns true when an item was actually removed.
func (f *defaultFormats) DelByFormat(strfmt Format) bool {
f.Lock()
defer f.Unlock()
@@ -228,7 +232,7 @@ func (f *defaultFormats) DelByFormat(strfmt Format) bool {
return false
}
// ContainsName returns true if this registry contains the specified name
// ContainsName returns true if this registry contains the specified name.
func (f *defaultFormats) ContainsName(name string) bool {
f.Lock()
defer f.Unlock()
@@ -241,7 +245,7 @@ func (f *defaultFormats) ContainsName(name string) bool {
return false
}
// ContainsFormat returns true if this registry contains the specified format
// ContainsFormat returns true if this registry contains the specified format.
func (f *defaultFormats) ContainsFormat(strfmt Format) bool {
f.Lock()
defer f.Unlock()
+7
View File
@@ -0,0 +1,7 @@
use (
.
./enable/mongodb
./internal/testintegration
)
go 1.24.0
+16
View File
@@ -0,0 +1,16 @@
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30 h1:BHT1/DKsYDGkUgQ2jmMaozVcdk+sVfz0+1ZJq4zkWgw=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+7 -7
View File
@@ -13,7 +13,7 @@ import (
// Format represents a string format.
//
// All implementations of Format provide a string representation and text
// marshaling/unmarshaling interface to be used by encoders (e.g. encoding/json).
// marshaling/unmarshaling interface to be used by encoders (e.g. encoding/[json]).
type Format interface {
String() string
encoding.TextMarshaler
@@ -22,11 +22,11 @@ type Format interface {
// Registry is a registry of string formats, with a validation method.
type Registry interface {
Add(string, Format, Validator) bool
DelByName(string) bool
GetType(string) (reflect.Type, bool)
ContainsName(string) bool
Validates(string, string) bool
Parse(string, string) (any, error)
Add(name string, strfmt Format, validator Validator) bool
DelByName(name string) bool
GetType(name string) (reflect.Type, bool)
ContainsName(name string) bool
Validates(name, data string) bool
Parse(name, data string) (any, error)
MapStructureHookFunc() mapstructure.DecodeHookFunc
}
+71
View File
@@ -0,0 +1,71 @@
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0
// Package bsonlite provides a minimal BSON codec for strfmt types.
//
// This codec produces BSON output compatible with go.mongodb.org/mongo-driver/v2
// (v2.5.0). It handles only the exact BSON patterns used by strfmt:
// single-key {"data": value} documents with string, DateTime, or ObjectID values.
//
// This package is intended to provide a backward-compatible API to users of
// go-openapi/strfmt. It is not intended to be maintained or to follow the
// evolutions of the official MongoDB drivers. For up-to-date MongoDB support,
// import "github.com/go-openapi/strfmt/enable/mongodb" to replace this codec
// with one backed by the real driver.
package bsonlite
import "time"
// Codec provides BSON document marshal/unmarshal for strfmt types.
//
// MarshalDoc encodes a single-key BSON document {"data": value}.
// The value must be one of: string, time.Time, or [12]byte (ObjectID).
//
// UnmarshalDoc decodes a BSON document and returns the "data" field's value.
// Returns one of: string, time.Time, or [12]byte depending on the BSON type.
type Codec interface {
MarshalDoc(value any) ([]byte, error)
UnmarshalDoc(data []byte) (any, error)
}
// C is the active BSON codec.
//
//nolint:gochecknoglobals // replaceable codec, by design
var C Codec = liteCodec{}
// Replace swaps the active BSON codec with the provided implementation.
// This is intended to be called from enable/mongodb's init().
//
// Since [Replace] affects the global state of the package, it is not intended for concurrent use.
func Replace(c Codec) {
C = c
}
// BSON type tags (from the BSON specification).
const (
TypeString byte = 0x02
TypeObjectID byte = 0x07
TypeDateTime byte = 0x09
TypeNull byte = 0x0A
)
// ObjectIDSize is the size of a BSON ObjectID in bytes.
const ObjectIDSize = 12
// DateTimeToMillis converts a time.Time to BSON DateTime milliseconds.
func DateTimeToMillis(t time.Time) int64 {
const (
millisec = 1000
microsec = 1_000_000
)
return t.Unix()*millisec + int64(t.Nanosecond())/microsec
}
// MillisToTime converts BSON DateTime milliseconds to time.Time.
func MillisToTime(millis int64) time.Time {
const (
millisec = 1000
nanosPerMs = 1_000_000
)
return time.Unix(millis/millisec, millis%millisec*nanosPerMs)
}
+213
View File
@@ -0,0 +1,213 @@
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0
package bsonlite
import (
"encoding/binary"
"errors"
"fmt"
"time"
)
// liteCodec is a minimal BSON codec that handles only the patterns used by strfmt:
// single-key documents of the form {"data": <value>} where value is a string,
// BSON DateTime (time.Time), or BSON ObjectID ([12]byte).
type liteCodec struct{}
var _ Codec = liteCodec{}
func (liteCodec) MarshalDoc(value any) ([]byte, error) {
switch v := value.(type) {
case string:
return marshalStringDoc(v), nil
case time.Time:
return marshalDateTimeDoc(v), nil
case [ObjectIDSize]byte:
return marshalObjectIDDoc(v), nil
default:
return nil, fmt.Errorf("bsonlite: unsupported value type %T: %w", value, errUnsupportedType)
}
}
func (liteCodec) UnmarshalDoc(data []byte) (any, error) {
return unmarshalDoc(data)
}
// BSON wire format helpers.
//
// Document: int32(size) + elements + 0x00
// Element: byte(type) + cstring(key) + value
// String: int32(len+1) + bytes + 0x00
// DateTime: int64 (LE, millis since epoch)
// ObjectID: [12]byte
const dataKey = "data\x00"
func marshalStringDoc(s string) []byte {
sBytes := []byte(s)
// doc_size(4) + type(1) + key("data\0"=5) + strlen(4) + string + \0(1) + doc_term(1)
docSize := 4 + 1 + len(dataKey) + 4 + len(sBytes) + 1 + 1
buf := make([]byte, docSize)
pos := 0
binary.LittleEndian.PutUint32(buf[pos:], uint32(docSize)) //nolint:gosec // size is computed from input, cannot overflow
pos += 4
buf[pos] = TypeString
pos++
pos += copy(buf[pos:], dataKey)
binary.LittleEndian.PutUint32(buf[pos:], uint32(len(sBytes)+1)) //nolint:gosec // string length cannot overflow uint32
pos += 4
pos += copy(buf[pos:], sBytes)
buf[pos] = 0 // string null terminator
pos++
buf[pos] = 0 // document terminator
return buf
}
func marshalDateTimeDoc(t time.Time) []byte {
// doc_size(4) + type(1) + key("data\0"=5) + int64(8) + doc_term(1)
const docSize = 4 + 1 + 5 + 8 + 1
buf := make([]byte, docSize)
pos := 0
binary.LittleEndian.PutUint32(buf[pos:], docSize)
pos += 4
buf[pos] = TypeDateTime
pos++
pos += copy(buf[pos:], dataKey)
millis := DateTimeToMillis(t)
binary.LittleEndian.PutUint64(buf[pos:], uint64(millis)) //nolint:gosec // negative datetime millis are valid
// pos += 8
buf[docSize-1] = 0 // document terminator
return buf
}
func marshalObjectIDDoc(oid [ObjectIDSize]byte) []byte {
// doc_size(4) + type(1) + key("data\0"=5) + objectid(12) + doc_term(1)
const docSize = 4 + 1 + 5 + ObjectIDSize + 1
buf := make([]byte, docSize)
pos := 0
binary.LittleEndian.PutUint32(buf[pos:], docSize)
pos += 4
buf[pos] = TypeObjectID
pos++
pos += copy(buf[pos:], dataKey)
copy(buf[pos:], oid[:])
// pos += ObjectIDSize
buf[docSize-1] = 0 // document terminator
return buf
}
var (
errUnsupportedType = errors.New("bsonlite: unsupported type")
errDocTooShort = errors.New("bsonlite: document too short")
errDocSize = errors.New("bsonlite: document size mismatch")
errNoTerminator = errors.New("bsonlite: missing key terminator")
errTruncated = errors.New("bsonlite: truncated value")
errDataNotFound = errors.New("bsonlite: \"data\" field not found")
)
func unmarshalDoc(raw []byte) (any, error) {
const minDocSize = 5 // int32(size) + terminator
if len(raw) < minDocSize {
return nil, errDocTooShort
}
docSize := int(binary.LittleEndian.Uint32(raw[:4]))
if docSize != len(raw) {
return nil, errDocSize
}
pos := 4
for pos < docSize-1 {
if pos >= len(raw) {
return nil, errTruncated
}
typeByte := raw[pos]
pos++
// Read key (cstring: bytes until 0x00).
keyStart := pos
for pos < len(raw) && raw[pos] != 0 {
pos++
}
if pos >= len(raw) {
return nil, errNoTerminator
}
key := string(raw[keyStart:pos])
pos++ // skip null terminator
val, newPos, err := readValue(typeByte, raw, pos)
if err != nil {
return nil, err
}
pos = newPos
if key == "data" {
return val, nil
}
}
return nil, errDataNotFound
}
func readValue(typeByte byte, raw []byte, pos int) (any, int, error) {
switch typeByte {
case TypeString:
if pos+4 > len(raw) {
return nil, 0, errTruncated
}
strLen := int(binary.LittleEndian.Uint32(raw[pos:]))
pos += 4
if pos+strLen > len(raw) || strLen < 1 {
return nil, 0, errTruncated
}
s := string(raw[pos : pos+strLen-1]) // exclude null terminator
return s, pos + strLen, nil
case TypeObjectID:
if pos+ObjectIDSize > len(raw) {
return nil, 0, errTruncated
}
var oid [ObjectIDSize]byte
copy(oid[:], raw[pos:pos+ObjectIDSize])
return oid, pos + ObjectIDSize, nil
case TypeDateTime:
const dateTimeSize = 8
if pos+dateTimeSize > len(raw) {
return nil, 0, errTruncated
}
millis := int64(binary.LittleEndian.Uint64(raw[pos:])) //nolint:gosec // negative datetime millis are valid
return MillisToTime(millis), pos + dateTimeSize, nil
case TypeNull:
return nil, pos, nil
default:
return nil, 0, fmt.Errorf("bsonlite: unsupported BSON type 0x%02x: %w", typeByte, errUnsupportedType)
}
}
+521 -566
View File
File diff suppressed because it is too large Load Diff
+45 -37
View File
@@ -12,14 +12,12 @@ import (
"time"
)
var (
// UnixZero sets the zero unix UTC timestamp we want to compare against.
//
// Unix 0 for an EST timezone is not equivalent to a UTC timezone.
UnixZero = time.Unix(0, 0).UTC()
)
// UnixZero sets the zero unix UTC timestamp we want to compare against.
//
// Unix 0 for an EST timezone is not equivalent to a UTC timezone.
var UnixZero = time.Unix(0, 0).UTC() //nolint:gochecknoglobals // package-level sentinel value for unix epoch
func init() {
func init() { //nolint:gochecknoinits // registers datetime format in the default registry
dt := DateTime{}
Default.Add("datetime", &dt, IsDateTime)
}
@@ -50,38 +48,48 @@ func IsDateTime(str string) bool {
}
const (
// RFC3339Millis represents a ISO8601 format to millis instead of to nanos
// RFC3339Millis represents a ISO8601 format to millis instead of to nanos.
RFC3339Millis = "2006-01-02T15:04:05.000Z07:00"
// RFC3339MillisNoColon represents a ISO8601 format to millis instead of to nanos
// RFC3339MillisNoColon represents a ISO8601 format to millis instead of to nanos.
RFC3339MillisNoColon = "2006-01-02T15:04:05.000Z0700"
// RFC3339Micro represents a ISO8601 format to micro instead of to nano
// RFC3339Micro represents a ISO8601 format to micro instead of to nano.
RFC3339Micro = "2006-01-02T15:04:05.000000Z07:00"
// RFC3339MicroNoColon represents a ISO8601 format to micro instead of to nano
// RFC3339MicroNoColon represents a ISO8601 format to micro instead of to nano.
RFC3339MicroNoColon = "2006-01-02T15:04:05.000000Z0700"
// ISO8601LocalTime represents a ISO8601 format to ISO8601 in local time (no timezone)
// ISO8601LocalTime represents a ISO8601 format to ISO8601 in local time (no timezone).
ISO8601LocalTime = "2006-01-02T15:04:05"
// ISO8601TimeWithReducedPrecision represents a ISO8601 format with reduced precision (dropped secs)
// ISO8601TimeWithReducedPrecision represents a ISO8601 format with reduced precision (dropped secs).
ISO8601TimeWithReducedPrecision = "2006-01-02T15:04Z"
// ISO8601TimeWithReducedPrecisionLocaltime represents a ISO8601 format with reduced precision and no timezone (dropped seconds + no timezone)
// ISO8601TimeWithReducedPrecisionLocaltime represents a ISO8601 format with reduced precision and no timezone (dropped seconds + no timezone).
ISO8601TimeWithReducedPrecisionLocaltime = "2006-01-02T15:04"
// ISO8601TimeUniversalSortableDateTimePattern represents a ISO8601 universal sortable date time pattern.
ISO8601TimeUniversalSortableDateTimePattern = "2006-01-02 15:04:05"
// ISO8601TimeUniversalSortableDateTimePatternShortForm is the short form of ISO8601TimeUniversalSortableDateTimePattern
// ISO8601TimeUniversalSortableDateTimePatternShortForm is the short form of [ISO8601TimeUniversalSortableDateTimePattern].
ISO8601TimeUniversalSortableDateTimePatternShortForm = "2006-01-02"
// DateTimePattern pattern to match for the date-time format from http://tools.ietf.org/html/rfc3339#section-5.6
DateTimePattern = `^([0-9]{2}):([0-9]{2}):([0-9]{2})(.[0-9]+)?(z|([+-][0-9]{2}:[0-9]{2}))$`
)
//nolint:gochecknoglobals // package-level configuration for datetime parsing and marshaling
var (
rxDateTime = regexp.MustCompile(DateTimePattern)
// DateTimeFormats is the collection of formats used by ParseDateTime()
DateTimeFormats = []string{RFC3339Micro, RFC3339MicroNoColon, RFC3339Millis, RFC3339MillisNoColon, time.RFC3339, time.RFC3339Nano, ISO8601LocalTime, ISO8601TimeWithReducedPrecision, ISO8601TimeWithReducedPrecisionLocaltime, ISO8601TimeUniversalSortableDateTimePattern, ISO8601TimeUniversalSortableDateTimePatternShortForm}
// DateTimeFormats is the collection of formats used by [ParseDateTime]().
DateTimeFormats = []string{
RFC3339Micro, RFC3339MicroNoColon,
RFC3339Millis, RFC3339MillisNoColon,
time.RFC3339, time.RFC3339Nano,
ISO8601LocalTime,
ISO8601TimeWithReducedPrecision,
ISO8601TimeWithReducedPrecisionLocaltime,
ISO8601TimeUniversalSortableDateTimePattern,
ISO8601TimeUniversalSortableDateTimePatternShortForm,
}
// MarshalFormat sets the time resolution format used for marshaling time (set to milliseconds)
// MarshalFormat sets the time resolution format used for marshaling time (set to milliseconds).
MarshalFormat = RFC3339Millis
// NormalizeTimeForMarshal provides a normalization function on time before marshalling (e.g. time.UTC).
// NormalizeTimeForMarshal provides a normalization function on time before marshaling (e.g. [time.UTC]).
// By default, the time value is not changed.
NormalizeTimeForMarshal = func(t time.Time) time.Time { return t }
@@ -89,7 +97,7 @@ var (
DefaultTimeLocation = time.UTC
)
// ParseDateTime parses a string that represents an ISO8601 time or a unix epoch
// ParseDateTime parses a string that represents an ISO8601 time or a unix epoch.
func ParseDateTime(data string) (DateTime, error) {
if data == "" {
return NewDateTime(), nil
@@ -112,46 +120,46 @@ func ParseDateTime(data string) (DateTime, error) {
// Most APIs we encounter want either millisecond or second precision times.
// This just tries to make it worry-free.
//
// swagger:strfmt date-time
// swagger:strfmt date-time.
type DateTime time.Time
// NewDateTime is a representation of the UNIX epoch (January 1, 1970 00:00:00 UTC) for the [DateTime] type.
//
// Notice that this is not the zero value of the [DateTime] type.
//
// You may use [DateTime.IsUNIXZero] to check against this value.
// You may use [DateTime.IsUnixZero] to check against this value.
func NewDateTime() DateTime {
return DateTime(time.Unix(0, 0).UTC())
}
// MakeDateTime is a representation of the zero value of the [DateTime] type (January 1, year 1, 00:00:00 UTC).
//
// You may use [Datetime.IsZero] to check against this value.
// You may use [DateTime.IsZero] to check against this value.
func MakeDateTime() DateTime {
return DateTime(time.Time{})
}
// String converts this time to a string
// String converts this time to a string.
func (t DateTime) String() string {
return NormalizeTimeForMarshal(time.Time(t)).Format(MarshalFormat)
}
// IsZero returns whether the date time is a zero value
// IsZero returns whether the date time is a zero value.
func (t DateTime) IsZero() bool {
return time.Time(t).IsZero()
}
// IsUnixZero returns whether the date time is equivalent to time.Unix(0, 0).UTC().
// IsUnixZero returns whether the date time is equivalent to [time.Unix](0, 0).UTC().
func (t DateTime) IsUnixZero() bool {
return time.Time(t).Equal(UnixZero)
}
// MarshalText implements the text marshaller interface
// MarshalText implements the text marshaler interface.
func (t DateTime) MarshalText() ([]byte, error) {
return []byte(t.String()), nil
}
// UnmarshalText implements the text unmarshaller interface
// UnmarshalText implements the text unmarshaler interface.
func (t *DateTime) UnmarshalText(text []byte) error {
tt, err := ParseDateTime(string(text))
if err != nil {
@@ -161,9 +169,9 @@ func (t *DateTime) UnmarshalText(text []byte) error {
return nil
}
// Scan scans a DateTime value from database driver type.
// Scan scans a [DateTime] value from database driver type.
func (t *DateTime) Scan(raw any) error {
// TODO: case int64: and case float64: ?
// Proposal for enhancement: case int64: and case float64: ?
switch v := raw.(type) {
case []byte:
return t.UnmarshalText(v)
@@ -180,17 +188,17 @@ func (t *DateTime) Scan(raw any) error {
return nil
}
// Value converts DateTime to a primitive value ready to written to a database.
// Value converts [DateTime] to a primitive value ready to written to a database.
func (t DateTime) Value() (driver.Value, error) {
return driver.Value(t.String()), nil
}
// MarshalJSON returns the DateTime as JSON
// MarshalJSON returns the [DateTime] as JSON.
func (t DateTime) MarshalJSON() ([]byte, error) {
return json.Marshal(NormalizeTimeForMarshal(time.Time(t)).Format(MarshalFormat))
}
// UnmarshalJSON sets the DateTime from JSON
// UnmarshalJSON sets the [DateTime] from JSON.
func (t *DateTime) UnmarshalJSON(data []byte) error {
if string(data) == jsonNull {
return nil
@@ -213,7 +221,7 @@ func (t *DateTime) DeepCopyInto(out *DateTime) {
*out = *t
}
// DeepCopy copies the receiver into a new DateTime.
// DeepCopy copies the receiver into a new [DateTime].
func (t *DateTime) DeepCopy() *DateTime {
if t == nil {
return nil
@@ -233,12 +241,12 @@ func (t *DateTime) GobDecode(data []byte) error {
return t.UnmarshalBinary(data)
}
// MarshalBinary implements the encoding.BinaryMarshaler interface.
// MarshalBinary implements the encoding.[encoding.BinaryMarshaler] interface.
func (t DateTime) MarshalBinary() ([]byte, error) {
return NormalizeTimeForMarshal(time.Time(t)).MarshalBinary()
}
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
// UnmarshalBinary implements the encoding.[encoding.BinaryUnmarshaler] interface.
func (t *DateTime) UnmarshalBinary(data []byte) error {
var original time.Time
@@ -252,7 +260,7 @@ func (t *DateTime) UnmarshalBinary(data []byte) error {
return nil
}
// Equal checks if two DateTime instances are equal using time.Time's Equal method
// Equal checks if two [DateTime] instances are equal using [time.Time]'s Equal method.
func (t DateTime) Equal(t2 DateTime) bool {
return time.Time(t).Equal(time.Time(t2))
}
+29 -27
View File
@@ -11,23 +11,25 @@ import (
"io"
"sync"
"github.com/oklog/ulid"
"github.com/oklog/ulid/v2"
)
// ULID represents a ulid string format
// ref:
// ULID represents a [ulid] string format.
//
// # Reference
//
// https://github.com/ulid/spec
//
// impl:
// # Implementation
//
// https://github.com/oklog/ulid
//
// swagger:strfmt ulid
// swagger:strfmt ulid.
type ULID struct {
ulid.ULID
}
//nolint:gochecknoglobals // package-level ULID configuration and overridable scan/value functions
var (
ulidEntropyPool = sync.Pool{
New: func() any {
@@ -35,6 +37,7 @@ var (
},
}
// ULIDScanDefaultFunc is the default implementation for scanning a [ULID] from a database driver value.
ULIDScanDefaultFunc = func(raw any) (ULID, error) {
u := NewULIDZero()
switch x := raw.(type) {
@@ -54,45 +57,44 @@ var (
return u, fmt.Errorf("cannot sql.Scan() strfmt.ULID from: %#v: %w", raw, ulid.ErrScanValue)
}
// ULIDScanOverrideFunc allows you to override the Scan method of the ULID type
// ULIDScanOverrideFunc allows you to override the Scan method of the [ULID] type.
ULIDScanOverrideFunc = ULIDScanDefaultFunc
// ULIDValueDefaultFunc is the default implementation for converting a [ULID] to a database driver value.
ULIDValueDefaultFunc = func(u ULID) (driver.Value, error) {
return driver.Value(u.String()), nil
}
// ULIDValueOverrideFunc allows you to override the Value method of the ULID type
// ULIDValueOverrideFunc allows you to override the Value method of the [ULID] type.
ULIDValueOverrideFunc = ULIDValueDefaultFunc
)
func init() {
// register formats in the default registry:
// - ulid
func init() { //nolint:gochecknoinits // registers ulid format in the default registry
ulid := ULID{}
Default.Add("ulid", &ulid, IsULID)
}
// IsULID checks if provided string is ULID format
// Be noticed that this function considers overflowed ULID as non-ulid.
// For more details see https://github.com/ulid/spec
// IsULID checks if provided string is [ULID] format
// Be noticed that this function considers overflowed [ULID] as non-[ulid].
// For more details see https://github.com/[ulid]/spec
func IsULID(str string) bool {
_, err := ulid.ParseStrict(str)
return err == nil
}
// ParseULID parses a string that represents an valid ULID
// ParseULID parses a string that represents an valid [ULID].
func ParseULID(str string) (ULID, error) {
var u ULID
return u, u.UnmarshalText([]byte(str))
}
// NewULIDZero returns a zero valued ULID type
// NewULIDZero returns a zero valued [ULID] type.
func NewULIDZero() ULID {
return ULID{}
}
// NewULID generates new unique ULID value and a error if any
// NewULID generates new unique [ULID] value and a error if any.
func NewULID() (ULID, error) {
var u ULID
@@ -112,22 +114,22 @@ func NewULID() (ULID, error) {
return u, nil
}
// GetULID returns underlying instance of ULID
// GetULID returns underlying instance of [ULID].
func (u *ULID) GetULID() any {
return u.ULID
}
// MarshalText returns this instance into text
// MarshalText returns this instance into text.
func (u ULID) MarshalText() ([]byte, error) {
return u.ULID.MarshalText()
}
// UnmarshalText hydrates this instance from text
// UnmarshalText hydrates this instance from text.
func (u *ULID) UnmarshalText(data []byte) error { // validation is performed later on
return u.ULID.UnmarshalText(data)
}
// Scan reads a value from a database driver
// Scan reads a value from a database driver.
func (u *ULID) Scan(raw any) error {
ul, err := ULIDScanOverrideFunc(raw)
if err == nil {
@@ -136,7 +138,7 @@ func (u *ULID) Scan(raw any) error {
return err
}
// Value converts a value to a database driver value
// Value converts a value to a database driver value.
func (u ULID) Value() (driver.Value, error) {
return ULIDValueOverrideFunc(u)
}
@@ -145,12 +147,12 @@ func (u ULID) String() string {
return u.ULID.String()
}
// MarshalJSON returns the ULID as JSON
// MarshalJSON returns the [ULID] as JSON.
func (u ULID) MarshalJSON() ([]byte, error) {
return json.Marshal(u.String())
}
// UnmarshalJSON sets the ULID from JSON
// UnmarshalJSON sets the [ULID] from JSON.
func (u *ULID) UnmarshalJSON(data []byte) error {
if string(data) == jsonNull {
return nil
@@ -172,7 +174,7 @@ func (u *ULID) DeepCopyInto(out *ULID) {
*out = *u
}
// DeepCopy copies the receiver into a new ULID.
// DeepCopy copies the receiver into a new [ULID].
func (u *ULID) DeepCopy() *ULID {
if u == nil {
return nil
@@ -192,17 +194,17 @@ func (u *ULID) GobDecode(data []byte) error {
return u.ULID.UnmarshalBinary(data)
}
// MarshalBinary implements the encoding.BinaryMarshaler interface.
// MarshalBinary implements the encoding.[encoding.BinaryMarshaler] interface.
func (u ULID) MarshalBinary() ([]byte, error) {
return u.ULID.MarshalBinary()
}
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
// UnmarshalBinary implements the encoding.[encoding.BinaryUnmarshaler] interface.
func (u *ULID) UnmarshalBinary(data []byte) error {
return u.ULID.UnmarshalBinary(data)
}
// Equal checks if two ULID instances are equal by their underlying type
// Equal checks if two [ULID] instances are equal by their underlying type.
func (u ULID) Equal(other ULID) bool {
return u.ULID == other.ULID
}