151 lines
4.0 KiB
Go
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
|
|
}
|
|
}
|