Documentation
¶
Overview ¶
Package batch renders many codes from one request.
The unit of work is an Item: either raw Data, or a builder Type with a Payload, plus per-item option overrides in the same dot notation the request layer uses everywhere else. Items arrive either as a JSON array or as a CSV document, which is what a warehouse or an events team actually has.
batch does not know how to render anything. The caller supplies a RenderFunc and batch supplies ordering, concurrency, failure isolation and packaging. That inversion is deliberate: it keeps the HTTP layer out of this package's imports, so the interesting behaviour — ordering under concurrency, one bad item not sinking the run, zip entry naming — is testable against a stub in microseconds instead of against a real encoder.
Index ¶
Constants ¶
const ( // OutputZIP packages one file per successful item plus a manifest. OutputZIP = "zip" // OutputJSON returns the results inline, bodies base64-encoded. OutputJSON = "json" // OutputPDF is not produced here; see Run for why. OutputPDF = "pdf" )
The output formats Run can produce.
Variables ¶
var ( // ErrEmptyBatch means the request carried no items at all. ErrEmptyBatch = errors.New("batch is empty") // ErrTooManyItems means the request exceeded the configured item cap. ErrTooManyItems = errors.New("too many items") // ErrBadCSV means the CSV document could not be turned into items. ErrBadCSV = errors.New("invalid csv") // ErrUnsupportedOutput means the requested output format is not one batch // can produce. ErrUnsupportedOutput = errors.New("unsupported batch output") // ErrNoRenderer means Run was called without a RenderFunc, which is a // wiring mistake in the caller rather than anything a request can cause. ErrNoRenderer = errors.New("no render function supplied") )
Sentinel errors for the batch package.
Every one of these is a structural fault: the request could not be started or could not be finished. A single item failing to render is never an error here — it is a Result with OK false.
Functions ¶
This section is empty.
Types ¶
type Item ¶
type Item struct {
// ID names the item. It is echoed in the results and used as the file
// stem in a zip, after sanitising. Empty means "use the position".
ID string `json:"id,omitempty"`
// Data is the raw string to encode, when no Type is given.
Data string `json:"data,omitempty"`
// Type names a builder; Payload is that builder's input.
Type string `json:"type,omitempty"`
// Payload holds the builder's fields.
Payload map[string]any `json:"payload,omitempty"`
// Options are dot-notation overrides for this item alone. They sit on top
// of the batch's Defaults.
Options map[string]any `json:"options,omitempty"`
}
Item is one code to render in a batch.
func ParseCSV ¶
ParseCSV turns a CSV document into items.
The first row is a header. `id`, `data` and `type` map onto the item's own fields; every `style.*`, `encode.*` and `output.*` column becomes a per-item option, and every `payload.*` column becomes a builder field. A `data` column is required unless the header carries `type` together with at least one `payload.*` column, which is the shape of a batch built from structured data rather than from ready-made strings.
Cell values stay strings. The request layer already parses text into every field's type — that is how the query string works — so converting here would only be a second, divergent parser.
Errors name the row. A CSV of nine hundred lines that fails on one of them is useless without that number, and the row reported is the line in the document the caller uploaded, counting the header as row 1, so it matches what their editor shows.
type Output ¶
type Output struct {
// Body is the packaged bytes: a zip archive or a JSON document.
Body []byte
// MIME is Body's media type.
MIME string
// Filename is a suggested download name.
Filename string
// Results is the per-item outcome, in input order, for a caller that wants
// to reshape the response itself.
Results []Result
}
Output is the packaged result of a run.
func Run ¶
func Run(ctx context.Context, req Request, render RenderFunc, o RunOptions) (*Output, error)
Run renders every item and packages the results.
Items render concurrently, bounded by RunOptions.Concurrency, but Results is always in input order: each worker writes into its own slot, so ordering costs nothing and cannot drift with scheduling.
One item failing does not fail the batch. Its Result carries OK false and the reason, the rest continue, and the archive simply does not contain that file. Run returns an error only for a structural fault: an empty or oversized batch, an unparseable CSV, an output format it cannot produce, or a cancelled context.
Output "pdf" is deliberately not implemented here. A batch is a bag of independent codes with no page geometry; laying codes out on a sheet is a different job with a different request shape, and it lives at /v1/sheet. Asking for it here returns ErrUnsupportedOutput.
type RenderFunc ¶
RenderFunc is how batch renders one item.
The HTTP layer supplies it, so batch never imports httpapi. It is called from several goroutines at once and must be safe for concurrent use. defaults are the batch-wide options; merging them with the item's own overrides is the caller's job, because only the caller knows the precedence rules of the request layer.
type Rendered ¶
type Rendered struct {
// Body is the encoded file.
Body []byte
// MIME is its media type, used to choose zip compression and to fill the
// manifest.
MIME string
// Extension is the file extension without the dot.
Extension string
// Data is the string that was ultimately encoded, which for a built
// payload is not what the caller sent and is worth echoing back.
Data string
}
Rendered is what a RenderFunc produces for one item.
type Request ¶
type Request struct {
// Items lists the codes to render.
Items []Item `json:"items,omitempty"`
// CSV is an alternative to Items: a header row plus one row per code.
// Setting both is rejected rather than guessed at.
CSV string `json:"csv,omitempty"`
// Defaults are dot-notation options applied to every item.
Defaults map[string]any `json:"defaults,omitempty"`
// Output selects the packaging: zip, json, or pdf. Empty means zip.
Output string `json:"output"`
}
Request is a whole batch.
type Result ¶
type Result struct {
// ID is the item's ID, or its position when it had none.
ID string `json:"id"`
// OK reports whether the item rendered.
OK bool `json:"ok"`
// Data is the string that was encoded.
Data string `json:"data,omitempty"`
// Error is the failure reason when OK is false.
Error string `json:"error,omitempty"`
// Bytes is the size of the rendered file.
Bytes int `json:"bytes,omitempty"`
// Filename is the name this item takes inside a zip.
Filename string `json:"filename,omitempty"`
// MIME is the rendered file's media type.
MIME string `json:"mime,omitempty"`
// Body is the base64-encoded file, present only in the json output where
// there is no envelope to carry the bytes separately.
Body string `json:"body,omitempty"`
}
Result is the outcome for one item, in input order.
type RunOptions ¶
type RunOptions struct {
// MaxItems caps the batch size. Zero or negative means no cap, which is
// only appropriate for a trusted caller.
MaxItems int
// Concurrency bounds how many items render at once. Zero picks a default
// from the core count.
Concurrency int
}
RunOptions bounds a run.