Files
go_vndb/model.go
2026-05-07 19:34:48 +08:00

151 lines
4.0 KiB
Go

package govndb
import "strings"
const (
// DefaultBaseURL is the production VNDB Kana API endpoint.
DefaultBaseURL = "https://api.vndb.org/kana"
)
// Endpoint identifies a POST Kana query endpoint.
type Endpoint string
const (
EndpointVN Endpoint = "vn"
EndpointRelease Endpoint = "release"
EndpointProducer Endpoint = "producer"
EndpointCharacter Endpoint = "character"
EndpointStaff Endpoint = "staff"
EndpointTag Endpoint = "tag"
EndpointTrait Endpoint = "trait"
EndpointQuote Endpoint = "quote"
EndpointUList Endpoint = "ulist"
)
type QueryRequest struct {
// Filters accepts the Kana filter expression in JSON-array or compact-string form.
Filters any `json:"filters,omitempty"`
// Fields is the explicit comma-separated field selection string required by Kana.
Fields string `json:"fields,omitempty"`
Sort string `json:"sort,omitempty"`
Reverse bool `json:"reverse,omitempty"`
Results int `json:"results,omitempty"`
Page int `json:"page,omitempty"`
User string `json:"user,omitempty"`
Count bool `json:"count,omitempty"`
CompactFilters bool `json:"compact_filters,omitempty"`
NormalizedFilters bool `json:"normalized_filters,omitempty"`
}
// QueryResponse is the standard response envelope returned by Kana query endpoints.
type QueryResponse[T any] struct {
Results []T `json:"results"`
More bool `json:"more"`
Count *int `json:"count,omitempty"`
CompactFilters string `json:"compact_filters,omitempty"`
NormalizedFilters any `json:"normalized_filters,omitempty"`
}
// Stats contains the aggregate counts returned by GET /stats.
type Stats struct {
Chars int `json:"chars"`
Producers int `json:"producers"`
Releases int `json:"releases"`
Staff int `json:"staff"`
Tags int `json:"tags"`
Traits int `json:"traits"`
VN int `json:"vn"`
}
// AuthInfo is returned by GET /authinfo for a token-authenticated request.
type AuthInfo struct {
ID string `json:"id"`
Username string `json:"username"`
Permissions []string `json:"permissions"`
}
// UserQuery represents a GET /user request.
type UserQuery struct {
Queries []string
Fields string
}
// UserResult maps each requested user lookup key to the resolved user object.
type UserResult map[string]*User
// ErrorResponse wraps non-2xx responses returned by the API.
type ErrorResponse struct {
StatusCode int
Body string
}
func (e *ErrorResponse) Error() string {
if e == nil {
return ""
}
if e.Body == "" {
return "vndb: request failed"
}
return "vndb: " + e.Body
}
// Field appends a Kana field selection fragment to a builder.
type Field interface {
AppendTo(*strings.Builder)
}
type fieldName string
func (f fieldName) AppendTo(builder *strings.Builder) {
builder.WriteString(string(f))
}
type fieldGroup struct {
name string
fields []Field
}
func (f fieldGroup) AppendTo(builder *strings.Builder) {
builder.WriteString(f.name)
builder.WriteByte('{')
appendFields(builder, f.fields)
builder.WriteByte('}')
}
// FieldName creates a single field selection entry.
func FieldName(name string) Field {
return fieldName(name)
}
// FieldGroup creates a nested field selection entry such as image{url,dims}.
func FieldGroup(name string, fields ...Field) Field {
return fieldGroup{name: name, fields: fields}
}
// Fields joins field fragments into the exact string format expected by Kana.
func Fields(fields ...Field) string {
var builder strings.Builder
appendFields(&builder, fields)
return builder.String()
}
// WithFields returns a copy of the request with Fields populated from helpers.
func (r QueryRequest) WithFields(fields ...Field) QueryRequest {
r.Fields = Fields(fields...)
return r
}
func appendFields(builder *strings.Builder, fields []Field) {
first := true
for _, field := range fields {
if field == nil {
continue
}
if !first {
builder.WriteByte(',')
}
field.AppendTo(builder)
first = false
}
}