Documentation
¶
Overview ¶
Package client is a standard-library-only HTTP client for a running jsondbd server. It mirrors the jsondb library's Collection API so a program can switch between embedding jsondb directly and talking to a remote server with only the construction line changing.
The Document and Filter types here are deliberate mirrors of the library's types: they serialize identically but are defined separately so importing this package never drags in the storage library or modernc.org/sqlite. They must stay in sync with the jsondb package.
Package jsondb is the Go driver for jsondb, a MongoDB-lite JSON document store built on SQLite.
It talks HTTP to a running jsondb server and is shaped after the MongoDB Go driver, so code written against one reads the same against the other:
c, err := jsondb.Connect(ctx, "jsondb://localhost:8080")
if err != nil {
return err
}
users := c.Collection("users")
res, err := users.InsertOne(ctx, jsondb.Document{"name": "Ada", "tier": "plat"})
gold, err := users.Find(ctx, jsondb.M{"tier": "gold"}, jsondb.WithLimit(10))
_, err = users.UpdateMany(ctx, jsondb.M{"tier": "gold"},
jsondb.Document{"$inc": jsondb.M{"logins": 1}})
Dependencies ¶
The standard library only. Adding a third-party import breaks the package's contract: a program embedding the storage engine and a program talking to a server should be able to swap between them by changing the construction line, and nothing else.
Semantics worth knowing ¶
The full contract is in the server repository's docs/wire-protocol.md. The parts that most often surprise people:
- Filters traverse arrays. {"tags": "x"} matches both {"tags": "x"} and {"tags": ["x","y"]}. $ne and $nin mean *no* value matches. Objects are not arrays and are never traversed.
- UpdateResult.MatchedCount and ModifiedCount differ. Writing a document's existing values reports one matched and none modified.
- Update operators read the document as it was, so order never matters, and a type conflict ($inc on a string) is an error that writes nothing.
- Unique indexes are sparse by default: documents missing the path never collide.
- UpdateOne, ReplaceOne and DeleteOne act on the match with the lowest _id, so repeated calls are deterministic.
- Find returns a complete slice, not a cursor. Skip-based paging is O(skip).
Versioning ¶
The driver speaks API version 1 and verifies it on Connect, failing with both numbers named rather than letting a mismatch surface later as a 404. Unknown fields in server responses are ignored, so a newer server that has added fields still works.
Index ¶
- Constants
- Variables
- type APIError
- type Client
- type Collection
- func (c *Collection) CountDocuments(ctx context.Context, filter Filter) (int64, error)
- func (c *Collection) CreateIndex(ctx context.Context, spec IndexSpec) error
- func (c *Collection) DeleteByID(ctx context.Context, id string) error
- func (c *Collection) DeleteMany(ctx context.Context, filter Filter) (*DeleteResult, error)
- func (c *Collection) DeleteOne(ctx context.Context, filter Filter) (*DeleteResult, error)
- func (c *Collection) Drop(ctx context.Context) error
- func (c *Collection) DropIndex(ctx context.Context, name string) error
- func (c *Collection) Explain(ctx context.Context, filter Filter, opts ...FindOption) (*Plan, error)
- func (c *Collection) Find(ctx context.Context, filter Filter, opts ...FindOption) ([]Document, error)
- func (c *Collection) FindOne(ctx context.Context, filter Filter, opts ...FindOption) (Document, error)
- func (c *Collection) GetByID(ctx context.Context, id string) (Document, error)
- func (c *Collection) InsertMany(ctx context.Context, docs []Document) (*InsertManyResult, error)
- func (c *Collection) InsertOne(ctx context.Context, doc Document) (*InsertOneResult, error)
- func (c *Collection) ListIndexes(ctx context.Context) ([]IndexInfo, error)
- func (c *Collection) PatchByID(ctx context.Context, id string, fields Document) error
- func (c *Collection) Rename(ctx context.Context, newName string) error
- func (c *Collection) ReplaceByID(ctx context.Context, id string, doc Document) error
- func (c *Collection) ReplaceOne(ctx context.Context, filter Filter, replacement Document, opts ...UpdateOption) (*UpdateResult, error)
- func (c *Collection) Stats(ctx context.Context) (*CollectionStats, error)
- func (c *Collection) UpdateMany(ctx context.Context, filter Filter, update Document, opts ...UpdateOption) (*UpdateResult, error)
- func (c *Collection) UpdateOne(ctx context.Context, filter Filter, update Document, opts ...UpdateOption) (*UpdateResult, error)
- type CollectionInfo
- type CollectionStats
- type DeleteResult
- type Document
- type Filter
- type FindOption
- type IndexInfo
- type IndexSpec
- type InsertManyResult
- type InsertOneResult
- type M
- type Option
- type Plan
- type PlanStep
- type UpdateOption
- type UpdateResult
- type VersionInfo
Constants ¶
const APIPrefix = "/api/v1"
APIPrefix is the versioned path every data endpoint sits under. It must match the server's; Connect and Ping verify that at runtime rather than leaving a mismatch to surface as a puzzling 404.
const APIVersion = 1
APIVersion is the contract version this client is written against.
Variables ¶
var ( ErrNotFound = errors.New("jsondb: document not found") ErrInvalidFilter = errors.New("jsondb: invalid filter") ErrInvalidJSON = errors.New("jsondb: invalid JSON") ErrInvalidName = errors.New("jsondb: invalid collection name") ErrDuplicateKey = errors.New("jsondb: duplicate key") ErrInvalidUpdate = errors.New("jsondb: invalid update") )
Sentinel errors mirror the library's so errors.Is works for consumers.
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client talks to a jsondbd base URL.
func Connect ¶
Connect builds a Client from a connection URI and verifies that the server speaks a contract this client understands.
Accepted schemes are jsondb:// (plain HTTP), jsondbs:// (HTTPS), and http:// or https:// directly. A mismatched API version fails here, with both numbers named, rather than surfacing later as a 404 on a path that moved.
func New ¶
New returns a client bound to a jsondbd base URL, e.g. "http://localhost:8080".
func (*Client) Collection ¶
func (c *Client) Collection(name string) *Collection
Collection returns a handle for the named collection.
func (*Client) ListCollections ¶
func (c *Client) ListCollections(ctx context.Context) ([]CollectionInfo, error)
Collections lists collection names and counts.
type Collection ¶
type Collection struct {
// contains filtered or unexported fields
}
Collection is a handle to a named collection on the remote server.
func (*Collection) CountDocuments ¶
CountDocuments returns the number of documents matching the filter.
func (*Collection) CreateIndex ¶
func (c *Collection) CreateIndex(ctx context.Context, spec IndexSpec) error
CreateIndex creates an expression index over one or more JSON paths.
func (*Collection) DeleteByID ¶
func (c *Collection) DeleteByID(ctx context.Context, id string) error
DeleteByID removes the document with the given id.
func (*Collection) DeleteMany ¶
func (c *Collection) DeleteMany(ctx context.Context, filter Filter) (*DeleteResult, error)
DeleteMany removes every matching document.
func (*Collection) DeleteOne ¶
func (c *Collection) DeleteOne(ctx context.Context, filter Filter) (*DeleteResult, error)
DeleteOne removes at most one matching document.
func (*Collection) Drop ¶
func (c *Collection) Drop(ctx context.Context) error
Drop deletes every document in the collection, along with its indexes.
func (*Collection) DropIndex ¶
func (c *Collection) DropIndex(ctx context.Context, name string) error
DropIndex removes an index by name; ErrNotFound if it is not there.
func (*Collection) Explain ¶
func (c *Collection) Explain(ctx context.Context, filter Filter, opts ...FindOption) (*Plan, error)
Explain returns the plan the server would use for the equivalent Find, without running it.
func (*Collection) Find ¶
func (c *Collection) Find(ctx context.Context, filter Filter, opts ...FindOption) ([]Document, error)
Find returns documents matching the filter.
func (*Collection) FindOne ¶
func (c *Collection) FindOne(ctx context.Context, filter Filter, opts ...FindOption) (Document, error)
FindOne returns the first matching document, or ErrNotFound.
func (*Collection) InsertMany ¶
func (c *Collection) InsertMany(ctx context.Context, docs []Document) (*InsertManyResult, error)
InsertMany stores multiple documents in one request and returns their ids.
func (*Collection) InsertOne ¶
func (c *Collection) InsertOne(ctx context.Context, doc Document) (*InsertOneResult, error)
InsertOne stores a document and returns its new id.
func (*Collection) ListIndexes ¶
func (c *Collection) ListIndexes(ctx context.Context) ([]IndexInfo, error)
ListIndexes lists the indexes on this collection.
func (*Collection) Rename ¶
func (c *Collection) Rename(ctx context.Context, newName string) error
Rename moves the collection's documents and indexes under a new name.
func (*Collection) ReplaceByID ¶
ReplaceByID fully replaces the document with the given id.
func (*Collection) ReplaceOne ¶
func (c *Collection) ReplaceOne(ctx context.Context, filter Filter, replacement Document, opts ...UpdateOption) (*UpdateResult, error)
ReplaceOne swaps the whole body of at most one matching document.
func (*Collection) Stats ¶
func (c *Collection) Stats(ctx context.Context) (*CollectionStats, error)
Stats reports document count and stored size for the collection.
func (*Collection) UpdateMany ¶
func (c *Collection) UpdateMany(ctx context.Context, filter Filter, update Document, opts ...UpdateOption) (*UpdateResult, error)
UpdateMany applies an update document to every matching document.
func (*Collection) UpdateOne ¶
func (c *Collection) UpdateOne(ctx context.Context, filter Filter, update Document, opts ...UpdateOption) (*UpdateResult, error)
UpdateOne applies an update document to at most one matching document.
type CollectionInfo ¶
CollectionInfo is a collection name and its document count.
type CollectionStats ¶
type CollectionStats struct {
Name string `json:"name"`
Count int64 `json:"count"`
Size int64 `json:"size"`
AvgObjSize int64 `json:"avgObjSize"`
NumIndexes int `json:"numIndexes"`
}
CollectionStats mirrors jsondb.CollectionStats.
type DeleteResult ¶
type DeleteResult struct {
DeletedCount int64 `json:"deletedCount"`
}
DeleteResult mirrors jsondb.DeleteResult.
type FindOption ¶
type FindOption func(*findOptions)
FindOption configures Find/FindOne/Count (mirrors jsondb's options).
func WithSort ¶
func WithSort(path string, asc bool) FindOption
WithSort orders results by a JSON path, ascending or descending.
type IndexInfo ¶
type IndexInfo struct {
Name string `json:"name"`
Coll string `json:"collection"`
Paths []string `json:"paths"`
Unique bool `json:"unique"`
}
IndexInfo mirrors jsondb.IndexInfo.
type IndexSpec ¶
type IndexSpec struct {
Paths []string `json:"paths"`
Unique bool `json:"unique"`
Name string `json:"name,omitempty"`
}
IndexSpec mirrors jsondb.IndexSpec.
type InsertManyResult ¶
type InsertManyResult struct {
InsertedIDs []string `json:"insertedIds"`
}
InsertManyResult mirrors jsondb.InsertManyResult.
type InsertOneResult ¶
type InsertOneResult struct {
InsertedID string `json:"insertedId"`
}
InsertOneResult mirrors jsondb.InsertOneResult.
type Option ¶
type Option func(*Client)
Option configures a Client.
func WithHTTPClient ¶
WithHTTPClient sets a custom *http.Client (timeouts, transport).
func WithHeader ¶
WithHeader adds a header sent on every request (e.g. an auth header).
type Plan ¶
type Plan struct {
Steps []PlanStep `json:"steps"`
// SeeksIndex reports that the plan narrows the search rather than
// examining every document in the collection.
SeeksIndex bool `json:"seeksIndex"`
// SortsInMemory reports that results are collected and sorted rather than
// read in index order. An index covering the sort path removes it.
SortsInMemory bool `json:"sortsInMemory"`
}
Plan is a server-reported query plan: the steps SQLite would take, plus the reading of them.
SeeksIndex and SortsInMemory arrive as fields rather than being derived here, because the markers that produce them depend on how the storage engine answers a query — which is the server's business, and has already changed once. A client deriving them itself would silently go wrong.
type PlanStep ¶
type PlanStep struct {
ID int `json:"id"`
Parent int `json:"parent"`
Detail string `json:"detail"`
}
PlanStep is one row of the server's query plan.
type UpdateOption ¶
type UpdateOption func(*updateOptions)
UpdateOption mirrors jsondb.UpdateOption.
func WithUpsert ¶
func WithUpsert() UpdateOption
WithUpsert inserts a document when the filter matches nothing.
type UpdateResult ¶
type UpdateResult struct {
MatchedCount int64 `json:"matchedCount"`
ModifiedCount int64 `json:"modifiedCount"`
UpsertedID string `json:"upsertedId,omitempty"`
}
UpdateResult mirrors jsondb.UpdateResult.