Documentation
¶
Overview ¶
Package io defines the I/O pipeline framework for Pulse: Reader/Writer interfaces, schema inference, and job types (ImportJob, ExportJob, ConvertJob).
Format-specific adapters live in sub-packages (csv, tsv).
Index ¶
- Constants
- func ApplyVectorKinds(decls []VectorDecl, kinds []string) error
- func CompareOverlayLayer(got, want *types.OverlayLayer) error
- func CompareOverlayLayers(got, want []*types.OverlayLayer) error
- func CompareOverlayPayload(got, want types.OverlayPayload) error
- func CompareOverlayRef(got, want types.OverlayRef) error
- func CompareOverlaySummary(got, want *types.OverlaySummary) error
- func DiscardWriter(w Writer) error
- func ErrStopIteration() error
- func IsNullCell(v any, explicit bool) bool
- func LoadSchemaFile(fs afero.Fs, path string) (*encoding.Schema, error)
- func MaxSetElements() int
- func ParseSchemaFieldType(field, name string) (encoding.FieldType, error)
- func ParseSchemaJSON(data []byte) (*encoding.Schema, error)
- func RegisteredFieldTypeNames() []string
- func ResolveFloatWidth(width string) (encoding.FieldType, error)
- func ResolveTransferLevel(level int) (int, error)
- func SchemaFromFields(defs []SchemaFileField) (*encoding.Schema, error)
- func SetTypeFor(elements int) (encoding.FieldType, bool)
- func ShardName(k int) string
- func VectorElementColumn(field string, labels []string, e int) string
- func WidestSetType() encoding.FieldType
- type CohortBuild
- type CohortBuildOptions
- type CohortBuildReport
- type CohortSource
- type CohortValidator
- type CohortWriter
- type ConvertJob
- type ConvertReport
- type ConvertSource
- type DSTPolicy
- type DedupJob
- type DedupReport
- type DiscardableWriter
- type ExportJob
- type ExportReport
- type GroupCandidate
- type GroupDecl
- type GroupDetection
- type GroupReport
- type ImportJob
- type ImportProjection
- type ImportReport
- type InferOptions
- type InferenceResult
- type InferenceWarning
- type LabelResolver
- type LabelWarning
- type LateKeyRefuser
- type ListAwareReader
- type ListAwareWriter
- type ListCell
- type ListColumn
- type NullAwareReader
- type NullAwareWriter
- type OverlayAwareWriter
- type OverlayWarningEmitter
- type PredictReport
- type Reader
- type ResetReader
- type RowError
- type SchemaAwareReader
- type SchemaAwareWriter
- type SchemaFileField
- type SidecarEmitter
- type SourceAwareWriter
- type SourceWarningEmitter
- type TargetWarningEmitter
- type TransferExportJob
- type TransferImportJob
- type TransferReport
- type VectorDecl
- type Writer
Constants ¶
const ( // CandidateVerdictUnmeasured: the candidate outgrew its share of // the detection memory budget before the pass ended; no figures. CandidateVerdictUnmeasured = "unmeasured" // CandidateReasonMemoryBound is the Reason on an unmeasured // candidate. CandidateReasonMemoryBound = "detection_memory_bound" )
Candidate verdicts beyond the gate's own (encoding.GroupVerdict*).
const ( FloatWidthF64 = "f64" FloatWidthF32 = "f32" )
Float-width knob values (InferOptions.FloatWidth, ImportJob.FloatWidth, CLI --float). The empty string is FloatWidthF64.
const ( MinTransferLevel = 1 MaxTransferLevel = 22 )
MinTransferLevel and MaxTransferLevel bound the accepted zstd levels. The encoder maps them onto its four speed classes (zstd.EncoderLevelFromZstd): 1-2 fastest, 3-5 default, 6-9 better, 10-22 best.
const ( TransferLayoutSingleFile = "single_file" TransferLayoutShardArchive = "shard_archive" )
Transfer layout names reported on TransferReport.Layout.
const DefaultSetDelimiter = iocore.DefaultSetDelimiter
DefaultSetDelimiter is iocore.DefaultSetDelimiter.
const DefaultTransferLevel = 3
DefaultTransferLevel is the zstd level used when a job leaves Level at zero. Level 3 is zstd's own default and was the level measured during planning.
const DetailOption = "option"
DetailOption marks a refusal of an import OPTION (rather than of the data): its details carry DetailOption = the option's name, so an adapter (the CLI) can tell a mistyped flag value from a bad source.
const EmptySetCell = iocore.EmptySetCell
EmptySetCell is iocore.EmptySetCell.
const MaxBuildShards = math.MaxUint16
MaxBuildShards is the most shards one sharded build may write: the archive trailer's shard count is a u16.
const TransferCodec = "zstd"
TransferCodec is the one codec the transfer artifact uses.
const TransferExtension = ".zst"
TransferExtension is the conventional suffix appended to a cohort's file name for its transfer artifact.
Variables ¶
This section is empty.
Functions ¶
func ApplyVectorKinds ¶
func ApplyVectorKinds(decls []VectorDecl, kinds []string) error
ApplyVectorKinds parses each CLI `--vector-kind NAME:KIND[:MIN:MAX]` value and sets Kind / ScaleMin / ScaleMax on the declaration it names. A value naming no declared vector (reason "kind_unknown_vector"), a vector given two kinds ("kind_duplicate"), a malformed value ("malformed"), an unknown kind ("kind_invalid") or a bad range ("scale_invalid") is PULSE_IMPORT_VECTOR_INVALID.
func CompareOverlayLayer ¶
func CompareOverlayLayer(got, want *types.OverlayLayer) error
CompareOverlayLayer returns nil when the two layers match across all renderer-facing slots (name, kind, scope, ref, payload, summary). Per-shape payload comparison dispatches through CompareOverlayPayload.
func CompareOverlayLayers ¶
func CompareOverlayLayers(got, want []*types.OverlayLayer) error
CompareOverlayLayers returns nil when `got` matches `want` slot-for- slot. Mismatch returns an error describing the first divergence — length, slot index, name / kind / scope, shape, or per-shape payload. Designed for use inside table-driven test bodies; callers wrap the error in t.Errorf for the failure message.
Exported so the per-format integration tests under internal/io/exportoverlay/ share one comparison surface across Arrow / Parquet / Excel / NDJSON round-trips.
func CompareOverlayPayload ¶
func CompareOverlayPayload(got, want types.OverlayPayload) error
CompareOverlayPayload dispatches by shape and compares the populated arm. Absent arms (the non-matching shape's sub-payload nil) are untouched — the OverlayPayload union always populates exactly one arm per the Shape discriminator.
func CompareOverlayRef ¶
func CompareOverlayRef(got, want types.OverlayRef) error
CompareOverlayRef returns nil when the two refs share the same discriminator state. The structural comparison covers the Margin / Population / Stage / Slot arms — extending this helper when new ref arms land follows the additive-only rule (new arms compare nil-vs- nil before recursing into the new fields).
func CompareOverlaySummary ¶
func CompareOverlaySummary(got, want *types.OverlaySummary) error
CompareOverlaySummary returns nil when both summaries match across every populated field. nil-vs-nil counts as match; nil-vs-non-nil is a mismatch.
func ErrStopIteration ¶
func ErrStopIteration() error
ErrStopIteration returns the stop iteration sentinel for use by readers.
func LoadSchemaFile ¶
LoadSchemaFile reads an explicit schema document from path on fs and decodes it with ParseSchemaJSON.
func ParseSchemaFieldType ¶
ParseSchemaFieldType resolves the type name an explicit schema file declares for field. The name must be a registered field type (encoding.ParseFieldType, exact spelling); anything else is PULSE_IMPORT_SCHEMA_TYPE_UNKNOWN naming the field, the type as written and the valid set. There is no fallback — an unknown name used to become f64 silently, so a typo stored the column in the wrong type.
func ParseSchemaJSON ¶
ParseSchemaJSON decodes an explicit schema document (a JSON array of SchemaFileField) into an encoding.Schema. It is the one schema-file decoder every surface shares (CLI import / import predict / convert --schema, and any library or MCP caller that holds the document inline), so they cannot lay the same document out differently.
Type names resolve through ParseSchemaFieldType (an unknown name is PULSE_IMPORT_SCHEMA_TYPE_UNKNOWN, never a silent fallback). The layout — ByteOffset and BitPosition — comes from the canonical encx.LayoutFields, so a document mixing bit-packed (u4, packed_bool) and byte-aligned fields yields exactly the schema inference builds for the same fields. CsvColumnIdx is the array position, a placeholder the by-name resolver overwrites before any row is read.
A document that is not a JSON array of field objects, or that lists no field, is PULSE_IMPORT_SCHEMA_INVALID (details: reason "malformed" / "empty").
func RegisteredFieldTypeNames ¶
func RegisteredFieldTypeNames() []string
RegisteredFieldTypeNames lists every registered field type's name in type-byte order, walked off the encoding registry (FieldType.IsKnown) so a new type joins the list without an edit here.
func ResolveFloatWidth ¶
ResolveFloatWidth maps a float-width knob value to the field type an all-float column infers as: "" and "f64" → f64, "f32" → f32. Any other value is PULSE_IMPORT_FLOAT_WIDTH_INVALID (details: value, valid).
func ResolveTransferLevel ¶
ResolveTransferLevel validates level and applies the default.
func SchemaFromFields ¶
func SchemaFromFields(defs []SchemaFileField) (*encoding.Schema, error)
SchemaFromFields builds the encoding.Schema an explicit schema document's decoded entries describe — the step ParseSchemaJSON runs after decoding, exposed for callers that already hold the entries (MCP pulse_import's `schema` argument), so every surface resolves type names and lays fields out through this one routine. An empty list is PULSE_IMPORT_SCHEMA_INVALID (details: reason "empty"): no cohort can be written from it, and "no schema" is spelled by passing none.
func SetTypeFor ¶
SetTypeFor is iocore.SetTypeFor.
func ShardName ¶
ShardName is the archive entry name of a sharded build's k-th shard (1-based): part-00001.pulse, part-00002.pulse, ...
func VectorElementColumn ¶
VectorElementColumn is the expanded column name of element e (0-based) of the vector field `field`: `<field>_<label>` when the vector carries labels, `<field>_<e+1>` otherwise.
Types ¶
type CohortBuild ¶
type CohortBuild struct {
// contains filtered or unexported fields
}
CohortBuild writes a single-file cohort from typed rows appended one at a time — ungrouped (format 0x01) unless a declared group survives the viability gate or constant elision forms a group (0x02). It is the row-at-a-time twin of an explicit-schema ImportJob and runs the same code for everything that decides bytes — schema description checks, dictionary assignment with the declared rung as a ceiling, decimal precision, set cells and the row layout (cell_encode.go) — so the cohort is byte-identical to an import of the same rows with the same schema.
Build model: every accepted row is encoded straight to a spool file beside the target on the build's afero filesystem (dictionaries precede records on the wire, so the preamble can only be written once the last row is in). The spool holds LOGICAL rows. With groups or elision, Close first runs import's full pass over it — the ConstantDetector (elision), then the GroupEncoder into a second, physical spool, then the gate's ratio assessment, all before anything is published. Close then writes the preamble plus the (logical or physical) spooled rows to a temp file beside the target, fsyncs it and renames it over the target; Abort, or any Close failure, removes the spool and the temp file and leaves the target untouched. With ShardMaxRecords the same layout is cut into shard files in a staging directory beside the target and published by ONE Archive call instead (publishArchive). A CohortBuild is not safe for concurrent use.
func NewCohortBuild ¶
func NewCohortBuild(ctx context.Context, fsys afero.Fs, target string, schema *encoding.Schema, opts CohortBuildOptions) (*CohortBuild, error)
NewCohortBuild validates target and schema and opens the spool.
An anchored target (`archive.pulse#name.pulse`) builds ONE shard and Close hands it to AppendShard: the archive must already exist and be a shard archive, name must be a new plain basename, and Overwrite, Groups, ElideConstants and ShardMaxRecords are refused (the archive's group layout wins; AddShard reconciles the shard to it). The spool and staging live beside the archive.
Refusals (SERVICE_VALIDATION unless noted): an empty target, a `.zst` transfer target, an existing target without Overwrite or a directory at the target; for an anchored target a missing archive (no implicit create), a file that is not a shard archive, a malformed shard name, an option the append refuses, a reserved shard name (PULSE_SHARD_RESERVED_NAME), a name already in the archive (PULSE_SHARD_NAME_COLLISION), an unreadable archive (its own code) and, through CheckAppend, a schema AddShard is certain to refuse (its own PULSE_SHARD_* code); a malformed schema (no fields, empty or duplicate names, an unknown type, a bad decimal precision/scale, a pre-seeded dictionary longer than its rung, parent groups in the schema); an over-long description (PULSE_IMPORT_DESCRIPTION_TOO_LONG); under Strict a low-quality description (PULSE_FIELD_DESCRIPTION_LOW_QUALITY); a bad group declaration (PULSE_GROUP_*, from the same encoder check import runs); and under Strict a too-narrow group (PULSE_GROUP_TOO_NARROW).
func (*CohortBuild) Abort ¶
func (b *CohortBuild) Abort() error
Abort discards the build: the spool is removed and the target is untouched. It is idempotent and a no-op after Close.
func (*CohortBuild) Append ¶
func (b *CohortBuild) Append(row []any) error
Append converts row — one typed value per schema field, in field order, using the CohortRow type mapping — and spools it. A row that does not convert is rejected with PULSE_IMPORT_ROW_ERROR (details: row, field, reason ∈ arity / type / null / overflow) and leaves NO trace: nothing is spooled and no dictionary entry it introduced is kept, so the build continues as if the call never happened. A spool write failure is sticky: every later Append and Close returns it.
func (*CohortBuild) Close ¶
func (b *CohortBuild) Close() (*CohortBuildReport, error)
Close writes the cohort: the preamble (schema with the final dictionaries) then the spooled rows into a temp file beside the target, fsynced and renamed over it. Whatever the outcome the spool is removed and the build is finished; on failure the temp file is removed too and the target is untouched. Without Overwrite a target that appeared since NewCohortBuild is refused.
func (*CohortBuild) Schema ¶
func (b *CohortBuild) Schema() *encoding.Schema
Schema returns the schema the build writes (layout recomputed, dictionaries as grown so far).
type CohortBuildOptions ¶
type CohortBuildOptions struct {
// Strict turns every PULSE_FIELD_DESCRIPTION_LOW_QUALITY finding
// into a fatal error raised by NewCohortBuild.
Strict bool
// Overwrite lets the build replace an existing target. Without it
// an existing target is refused (SERVICE_VALIDATION).
Overwrite bool
// Groups declares parent groups exactly as ImportJob.Groups does:
// the PULSE_GROUP_* declaration checks and the viability gate's
// width screen run in NewCohortBuild, the encode and the ratio
// assessment in Close. Strict is the gate's strictness too (as
// `--strict` is for import).
Groups []GroupDecl
// ElideConstants stores every field holding one value on every row
// once, as ImportJob.ElideConstants does — decided by a full pass
// over the spooled rows at Close.
ElideConstants bool
// RatioFloor is the viability gate's rows-per-tuple floor
// (ImportJob.DedupRatioFloor); 0 selects the default.
RatioFloor float64
// ShardMaxRecords > 0 makes Close publish a shard archive at the
// target instead of a single-file cohort: the spooled rows are cut
// into consecutive shards of ShardMaxRecords rows (the last one
// partial; one empty shard for an empty build), each a standalone
// cohort with the ONE layout the full pass decided — so the group
// gate and constant elision are decided once over all rows and every
// shard carries the same schema, dictionaries and group layout —
// staged as ShardName(k) in a directory beside the target and handed
// to Archive in one call. Negative is refused; 0 is a single file.
ShardMaxRecords int
// Archive publishes the staged shard files as an archive at target,
// atomically (the facade wires Pulse.CreateShardArchive), returning
// its non-fatal warnings. Required when ShardMaxRecords > 0.
Archive func(ctx context.Context, target string, shardPaths []string) ([]*errors.CodedError, error)
// AppendShard adds one staged shard file to an EXISTING archive,
// atomically (the facade wires Pulse.AddShard; the entry name is
// the file's basename), returning its non-fatal warnings. Required
// for an anchored target (`archive.pulse#name.pulse`): the build is
// then ONE shard appended to that archive — see NewCohortBuild.
AppendShard func(ctx context.Context, archivePath, shardPath string) ([]*errors.CodedError, error)
// CheckAppend, when set, is the up-front cohesion check an anchored
// build runs at NewCohortBuild against the archive's canonical
// schema, with the build's (layout-recomputed) schema: it refuses
// only what AddShard is certain to refuse, with AddShard's own code
// and message (the facade wires the service's
// PrecheckShardCohesion). AppendShard at Close stays the authority.
CheckAppend func(ctx context.Context, archivePath string, schema *encoding.Schema) error
}
CohortBuildOptions configures a CohortBuild.
type CohortBuildReport ¶
type CohortBuildReport struct {
// Target is the cohort path written.
Target string
// Records is the number of rows written.
Records int64
// FormatVersion is the header version byte written — a function of
// the schema's content, never a flag.
FormatVersion byte
// Schema is the schema written, dictionaries final.
Schema *encoding.Schema
// Warnings are the non-fatal findings: description quality, then
// the viability gate's (PULSE_GROUP_TOO_NARROW from the width
// screen, then PULSE_DEDUP_LOW_RATIO from the ratio assessment).
Warnings []*errors.CodedError
// Groups describes every declared group, in declaration order, as
// ImportReport.Groups does. Nil when none was declared.
Groups []GroupReport
// ElidedConstants names the fields ElideConstants stored once.
ElidedConstants []string
// Replaced reports that a cohort already existed at Target and was
// atomically replaced (Overwrite).
Replaced bool
// Shards names a sharded build's shard entries, in archive order,
// or the one entry an anchored (append) build added. Nil for a
// single-file build.
Shards []string
}
CohortBuildReport is what a successful CohortBuild.Close wrote.
type CohortSource ¶
type CohortSource = iocore.CohortSource
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type CohortValidator ¶
type CohortValidator = iocore.CohortValidator
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type CohortWriter ¶
type CohortWriter = iocore.CohortWriter
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type ConvertJob ¶
type ConvertJob struct {
Source Reader
Target Writer
// Schema is the caller-authored schema, matched to the source's
// columns by exact name exactly as ImportJob.Schema is.
Schema *encoding.Schema
KeepPulseAt string // optional: also write intermediate .pulse
SampleRows int
FS afero.Fs
// IgnoreExtra drops source columns (and late NDJSON / JSON-array
// keys) the explicit Schema does not name, instead of refusing; see
// ImportJob.IgnoreExtra.
IgnoreExtra bool
// FloatWidth is the width an inferred all-float column takes: "f64"
// (default; "") or "f32"; anything else is
// PULSE_IMPORT_FLOAT_WIDTH_INVALID. See ImportJob.FloatWidth. CLI
// `--float`.
FloatWidth string
// Includes restricts the export half to the named schema fields,
// in schema order. Nil / empty means write every field. The
// intermediate .pulse file (when KeepPulseAt is set) always
// carries the full schema — projection is an output-time overlay,
// not an on-disk schema change. See ExportJob.Includes.
Includes []string
// Labels apply to the export phase only — the import side reads
// raw source bytes and has no use for label translation. See
// ExportJob.Labels.
Labels []*types.LabelBinding
// LabelResolver carries the runtime resolver. See
// ExportJob.LabelResolver.
LabelResolver LabelResolver
// IncludeOverlays controls whether the export half embeds
// Response.Overlays in the format-native sidecar. Identical
// tri-state semantics to ExportJob.IncludeOverlays — nil defaults
// to emit, *true forces emit, *false drops overlays. The
// intermediate .pulse file (when KeepPulseAt is set) is byte-
// identical regardless of this flag because overlays are an
// export-side concern only; the .pulse byte format never carries
// overlay payloads. See ExportJob.IncludeOverlays for the per-
// format wire shape.
IncludeOverlays *bool
// Overlays carries the Response.Overlays layers the convert should
// embed in the target adapter. Identical semantics to
// ExportJob.Overlays — the export half of the convert dispatches the
// slice via SetOverlays on writers satisfying OverlayAwareWriter
// when IncludeOverlays does not explicitly opt out. The intermediate
// .pulse file (when KeepPulseAt is set) never carries overlay
// payloads.
Overlays []*types.OverlayLayer
// SourceTZ, ColumnSourceTZ and DSTPolicy read the source's naive
// datetime literals in a source zone, with ImportJob's exact
// semantics and refusals (see ImportJob.SourceTZ). Convert is a TEXT
// pass, so a zoned naive literal reaches the target as the canonical
// UTC literal of the instant it names (`2026-01-15T14:00:00Z`) — the
// value a source-zone import stores — while a literal with its own
// `Z` / offset, an unparseable cell and every non-zoned column pass
// through verbatim. The KeepPulseAt intermediate is imported in the
// same zone. Empty (the default) changes nothing.
SourceTZ string
ColumnSourceTZ map[string]string
DSTPolicy DSTPolicy
}
ConvertJob chains import and export with no intermediate file on disk (unless KeepPulseAt is set).
func NewConvertJob ¶
func NewConvertJob(source Reader, target Writer) *ConvertJob
NewConvertJob creates a ConvertJob with default settings.
func (*ConvertJob) Hash ¶
func (j *ConvertJob) Hash() string
Hash returns the canonical content hash of the ConvertJob. Same rules as ExportJob.Hash — IncludeOverlays participates so cache keys differ between overlay-bearing and overlay-stripped converts.
The hash is namespaced under "convert_job" to keep ConvertJob hashes disjoint from ExportJob hashes.
func (*ConvertJob) Predict ¶
func (j *ConvertJob) Predict(ctx context.Context) (*PredictReport, error)
Predict validates the conversion without writing.
func (*ConvertJob) Run ¶
func (j *ConvertJob) Run(ctx context.Context) (*ConvertReport, error)
Run executes the convert job, streaming from source to target. If KeepPulseAt is set, also writes an intermediate .pulse file.
Total failure is an ERROR, not a zero-row report, exactly as on ImportJob.Run and ExportJob.Run. If the pass reads at least one row and converts none of them, Run returns a nil report and a coded error — PULSE_EXPORT_ROW_ERROR, since every RowError convert can record comes from Target.WriteRow, or the first row error's own code when it carries one — with rows_read, rows_failed, first_row and first_error in details, and no KeepPulseAt intermediate is written. Partial conversion is unchanged: some rows out, some on ConvertReport.RowErrors, nil error. A source with no data rows converts to an empty target and is a success. See totalRowFailure.
A categorical dictionary that OVERFLOWS its rung is the other refusal — for a DECLARED schema (an explicit ConvertJob.Schema or a SchemaAwareReader source's). It is a capacity violation rather than a row condition — past the limit every further unseen category is lost for the rest of the file — so Run stops at the offending cell with PULSE_IMPORT_CATEGORICAL_OVERFLOW (row / column / type / max_entries / value in details), before any KeepPulseAt intermediate is written. ImportJob fails the same condition under the same code.
An INFERRED schema is promoted instead, by the import's own rule (convertOrWiden, import_widen.go): a categorical past its rung, an integer past its width and an f32 past its range move to the narrowest type that holds the value, ConvertReport.Schema carries the final types, ConvertReport.WidthWarnings one PULSE_IMPORT_WIDTH_PROMOTED per field, and a KeepPulseAt intermediate is imported at those types — the cohort a plain import of the source writes. Only a categorical past categorical_u32 still refuses. Convert passes cell TEXT through, so a promotion never changes what the target receives.
type ConvertReport ¶
type ConvertReport struct {
RowsConverted int
Schema *encoding.Schema
RowErrors []RowError
LabelWarnings []LabelWarning
OverlayWarnings []*errors.CodedError
// SourceWarnings carries the source Reader's non-fatal diagnostics
// — see ImportReport.SourceWarnings. Distinct from OverlayWarnings,
// which come from the TARGET Writer.
SourceWarnings []*errors.CodedError
// TargetWarnings carries the target Writer's non-fatal diagnostics
// — see ExportReport.TargetWarnings.
TargetWarnings []*errors.CodedError
// WidthWarnings carries one PULSE_IMPORT_WIDTH_PROMOTED warning per
// field of an INFERRED schema the row pass promoted past its
// sample-inferred width (see ImportReport.WidthWarnings); Schema
// carries the promoted types. Nil for a declared schema, and when
// nothing outgrew its width.
WidthWarnings []*errors.CodedError `json:"WidthWarnings,omitempty"`
// ZoneWarnings carries the one PULSE_IMPORT_DST_RESOLVED warning a
// ConvertJob.DSTPolicy of earlier / later raises when it resolved a
// source-zone local time (see ImportReport.ZoneWarnings).
ZoneWarnings []*errors.CodedError `json:"ZoneWarnings,omitempty"`
}
ConvertReport summarizes the result of a convert operation.
RowErrors is a PARTIAL-failure channel, exactly as on ImportReport and ExportReport: when a non-empty source yields zero converted rows, ConvertJob.Run returns a coded error and no report.
OverlayWarnings carries the warn-and-skip codes the target Writer surfaced through OverlayWarningEmitter — see ExportReport.OverlayWarnings.
type ConvertSource ¶
type ConvertSource = iocore.ConvertSource
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type DSTPolicy ¶
type DSTPolicy string
DSTPolicy decides a naive source-zone wall clock a DST transition makes ambiguous or nonexistent. See ImportJob.DSTPolicy.
const ( // DSTPolicyError refuses the import at the first such row (the // default; the empty string means it). DSTPolicyError DSTPolicy = "error" // DSTPolicyEarlier resolves with the pre-transition offset. DSTPolicyEarlier DSTPolicy = "earlier" // DSTPolicyLater resolves with the post-transition offset. DSTPolicyLater DSTPolicy = "later" )
type DedupJob ¶
type DedupJob struct {
// FS is the filesystem both Source and Target live on. Required.
FS afero.Fs
// Source is the cohort to convert. Any supported format version.
Source string
// Target is where the converted cohort is written. Empty (or equal
// to Source) rewrites Source IN PLACE. A different path must not
// exist yet: the job never overwrites a file it was not asked to
// convert.
Target string
// Groups declares the parent groups, exactly as ImportJob.Groups.
Groups []GroupDecl
// ElideConstants stores every field holding one value on every
// record once, as ImportJob.ElideConstants. Declared members are
// never elided.
ElideConstants bool
// DedupRatioFloor and StrictDedup are the viability gate's policy,
// as on ImportJob.
DedupRatioFloor float64
StrictDedup bool
// SuggestGroups runs candidate detection over the source (before any
// rewrite) and returns it on DedupReport.GroupCandidates. With no
// Groups and no ElideConstants the job is detection-only and writes
// nothing.
SuggestGroups bool
}
DedupJob converts an existing single-file cohort to a grouped cohort. Shard archives are not this job's input — the caller (pulse.Dedup) refuses them with a coded error before a byte is read.
type DedupReport ¶
type DedupReport struct {
// Source and Target are the paths read and written; InPlace is true
// when they are the same file.
Source string `json:"source"`
Target string `json:"target"`
InPlace bool `json:"in_place"`
// Rewritten is false when nothing was written: a detection-only run,
// or one whose every declared group was dropped by the width floor
// with no elision to apply. The target is then untouched.
Rewritten bool `json:"rewritten"`
// Records is the record count of the source (and of the rewrite).
Records int64 `json:"records"`
// FormatVersionBefore/After, BytesBefore/After and
// StrideBefore/After describe the source and the written cohort.
// Without a rewrite the After figures repeat the Before ones.
FormatVersionBefore int `json:"format_version_before"`
FormatVersionAfter int `json:"format_version_after"`
BytesBefore int64 `json:"bytes_before"`
BytesAfter int64 `json:"bytes_after"`
StrideBefore int `json:"stride_before"`
StrideAfter int `json:"stride_after"`
// ElidedConstants names the fields ElideConstants stored once.
ElidedConstants []string `json:"elided_constants,omitempty"`
// Groups reports every declaration's verdict and figures, in
// declaration order — the same GroupReport import produces.
Groups []GroupReport `json:"groups,omitempty"`
// GroupWarnings carries the viability gate's findings
// (PULSE_GROUP_TOO_NARROW, PULSE_DEDUP_LOW_RATIO).
GroupWarnings []*errors.CodedError `json:"group_warnings,omitempty"`
// GroupCandidates is the SuggestGroups detection report, measured
// over the source's records.
GroupCandidates *GroupDetection `json:"group_candidates,omitempty"`
}
DedupReport describes a retro-dedup run.
type DiscardableWriter ¶
type DiscardableWriter = iocore.DiscardableWriter
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type ExportJob ¶
type ExportJob struct {
Source string // input .pulse path
Target Writer
FS afero.Fs
// Includes restricts the export to the named source-schema fields,
// in source-schema order. Nil / empty means export every field
// (prior behaviour). Names must match Schema.Fields[i].Name
// exactly. Unknown names return PULSE_EXPORT_FIELD_UNKNOWN with
// the offending name + list of known fields. Label augment
// siblings ("<field>_label") are emitted only for included source
// fields; replace mode applies to included fields as before.
Includes []string
// Labels rewrites or augments categorical column values during
// export using embedder-registered label tables. Bindings name a
// categorical field plus a label table; mode=replace overwrites
// the column value, mode=augment emits a sibling "<field>_label"
// column. See types.LabelBinding for semantics. Nil/empty means
// the exporter writes raw resolved categorical values, matching
// pre-label behaviour.
Labels []*types.LabelBinding
// LabelResolver carries the runtime resolver built from Labels +
// the pulse Service's registered LabelTables. The pulse.Export
// facade builds the resolver and sets this field; callers using
// io.ExportJob directly without a Pulse instance must supply a
// satisfying implementation (typically wrapping
// processing.BuildLabelResolver). Nil means no label translation.
LabelResolver LabelResolver
// IncludeOverlays controls whether Response.Overlays land in the
// exported artefact for adapters that can carry them. The slot is
// a tri-state pointer:
//
// - nil ⇒ DEFAULT EMIT — when the host Response carries any
// overlay layers the adapter embeds them in the
// format-native sidecar (additive-by-default, per PRD
// §6 FR-L5). Output for an overlay-free Response is
// byte-identical to a pre-overlay ExportJob.
// - true ⇒ explicit emit — same behaviour as nil for downstream
// adapters, but the explicit toggle distinguishes the
// intent in canonical-hash composition so cache keys
// differ between "default" and "explicit yes".
// - false ⇒ opt out — overlays are dropped on export even when
// the host Response carries layers. Output is byte-
// identical to a pre-overlay ExportJob against the
// same host result.
//
// Per-format semantics (research/export-embedding-shape.md):
//
// - Arrow / Parquet — overlays ride as a top-level
// LIST<STRUCT> "overlays" field group emitted once in the
// first record-batch / row-group; the host record stream is
// byte-identical to the opt-out shape.
// - Excel — one sheet per layer named "__overlay_<layer_name>";
// the host workbook sheet is unchanged from the opt-out shape.
// - NDJSON — single trailing line {"_overlays": [...]} after the
// last host-record line; the host stream is byte-identical
// until the trailer.
// - CSV / TSV — warn-and-skip. The dispatcher emits one
// PULSE_OVERLAY_EXPORT_CSV_UNSUPPORTED warning and writes the
// host CSV verbatim; no overlay output lands. Setting
// IncludeOverlays=false suppresses the warning while keeping
// the same CSV body.
//
// The pointer shape mirrors the Includes-slot precedent (a nil
// slice means "default": include every field) — nil here means
// "default: emit overlays when present" rather than "explicit no"
// because Go bool zero is false. Marshalling via encoding/json
// honours `omitempty` so nil pointers do not appear in canonical
// JSON; explicit *true and *false both serialise as booleans and
// produce distinct canonical-hash keys via ExportJob.Hash().
IncludeOverlays *bool
// Overlays carries the Response.Overlays layers the export should
// embed in the target adapter's format-native sidecar (Arrow /
// Parquet column family, Excel sheets, NDJSON trailer) per
// research/export-embedding-shape.md. ExportJob.Run dispatches the
// slice to writers satisfying OverlayAwareWriter when IncludeOverlays
// does not explicitly opt out. The CSV / TSV warn-and-skip family
// also accepts the slice through SetOverlays but emits a
// PULSE_OVERLAY_EXPORT_CSV_UNSUPPORTED warning (surfaced on
// ExportReport.OverlayWarnings) instead of writing the layers into
// the CSV body. nil / empty leaves the export byte-identical to a
// pre-overlay job. The slot is intentionally NOT part of the
// canonical-hash composition — two jobs sharing IncludeOverlays /
// Source / Includes / Labels but differing in the overlay payload
// resolve through the SAME cache key because the cache identity is
// the export REQUEST, not the response.
Overlays []*types.OverlayLayer
// TimeZone renders every `datetime` cell on this IANA zone's wall
// clock with its numeric offset — 2026-03-29T08:00:00+05:30 under
// "Asia/Kolkata" — instead of the canonical UTC `…Z` literal. The
// literal names the same instant, so re-importing the export (the
// importer honours an explicit offset) round-trips every value
// exactly. `date` cells are calendar days and never move.
//
// Validated by temporal.LoadZone at Run / Predict time: IANA
// Area/Location names or "UTC" only, anything else is
// PULSE_TIMEZONE_UNKNOWN. Empty (the default), "UTC" and every
// UTC-equivalent zone ("Etc/UTC") leave the output byte-identical
// to a zone-free export.
//
// Every row-stream target (csv, tsv, ndjson, jsonarray, excel, and
// the UTF8 datetime columns of arrow / parquet) carries the local
// literal. The `.sav` writer encodes from raw storage, where a
// DATETIME is a naive wall-clock count with no offset slot, so it
// refuses a non-UTC zone with PULSE_SPSS_EXPORT_UNSUPPORTED rather
// than silently ignore or lossily apply it.
TimeZone string
}
ExportJob converts a .pulse file into tabular output.
func NewExportJob ¶
NewExportJob creates an ExportJob.
func (*ExportJob) Hash ¶
Hash returns the canonical content hash of the ExportJob. Two jobs with the same logical export shape produce the same hash; two jobs with different IncludeOverlays settings (nil / *true / *false) produce distinct hashes so consumers caching export artefacts by hash key do not return stale results when the overlay opt-out flips.
IncludeOverlays participates in the hash composition per research/export-embedding-shape.md §8: the slot is a request-side input to the adapter, so two jobs differing only in IncludeOverlays produce different export artefacts (overlays emitted in one, dropped in the other) and the cache key MUST distinguish.
The hash is namespaced under "export_job" to keep ExportJob and ConvertJob hashes disjoint even when their shapes overlap.
func (*ExportJob) Predict ¶
func (j *ExportJob) Predict(ctx context.Context) (*PredictReport, error)
Predict validates the export without writing.
It reads the source header and schema, estimates the record count, and — when the Target implements the optional CohortValidator contract — asks the target whether it could encode this cohort at all. A Target that is nil or does not implement that interface is predicted exactly as it was before the interface existed; see CohortValidator for why that promise is the whole compatibility story here.
A validating target's refusal is returned as the error, carrying the code the real export would carry, and its non-fatal diagnostics land on PredictReport.TargetWarnings. Predict remains a SOUND but INCOMPLETE filter: a validator only answers from schema and sidecar facts, so passing means no schema-level refusal was found, never that the export cannot fail.
func (*ExportJob) Run ¶
func (j *ExportJob) Run(ctx context.Context) (*ExportReport, error)
Run executes the export job, converting a .pulse file to a tabular target.
Total failure is an ERROR, not a zero-row report. If the cohort yields at least one record and the target accepts none of them, Run returns a nil report and a coded error (PULSE_EXPORT_ROW_ERROR, or the first row error's own code when it carries one) whose details name the record count, the failure count and the first failure. Partial failure is unchanged: some rows out, some on ExportReport.RowErrors, nil error. An empty cohort exports zero rows legitimately. See totalRowFailure.
The CohortWriter arm does not participate: it replaces the row loop, so it reports its own count and raises its own errors.
type ExportReport ¶
type ExportReport struct {
RowsExported int
RowErrors []RowError
LabelWarnings []LabelWarning
OverlayWarnings []*errors.CodedError
// TargetWarnings carries the non-fatal diagnostics the target
// Writer surfaced through the optional TargetWarningEmitter
// contract — today the PULSE_SPSS_SIDECAR_* and
// PULSE_SPSS_NAME_SANITIZED codes the `.sav` encode raises. Nil
// for targets that do not implement the interface and for those
// that implement it and raised nothing, so the report shape is
// unchanged for every pre-existing adapter.
TargetWarnings []*errors.CodedError
}
ExportReport summarizes the result of an export operation.
RowErrors is a PARTIAL-failure channel, exactly as on ImportReport: when a non-empty cohort yields zero exported rows, ExportJob.Run returns a coded error and no report.
OverlayWarnings carries the warn-and-skip codes the target Writer surfaced through the optional OverlayWarningEmitter contract (currently the CSV / TSV / SPSS adapters via PULSE_OVERLAY_EXPORT_CSV_UNSUPPORTED, and Excel via PULSE_OVERLAY_EXPORT_PARTS_DROPPED when a layer carries named parts). Empty / nil when the target adapter embedded the overlays whole (Arrow / Parquet / NDJSON; Excel for parts-free layers), when no overlays were supplied, or when IncludeOverlays explicitly opted out.
type GroupCandidate ¶
type GroupCandidate struct {
Label string `json:"label"`
// Key and Members are the structured declaration — the GroupDecl
// shape {key, members}; Declaration is the same as a ready-to-paste
// --group value (empty when a name holds ',' or ':', which the CLI
// form cannot carry).
Key []string `json:"key"`
Members []string `json:"members"`
Declaration string `json:"declaration"`
// Suggested marks a candidate in GroupDetection.Suggested.
// OverlapsWith names the better-ranked suggested candidate sharing
// a field with this one (a field belongs to at most one group).
Suggested bool `json:"suggested"`
OverlapsWith string `json:"overlaps_with,omitempty"`
// RejectedMembers were constant within the key across the
// nomination window but varied later in the file.
RejectedMembers []string `json:"rejected_members,omitempty"`
// Verdict / Reason as the viability gate judges the group
// (encoding.GroupVerdict*), or CandidateVerdictUnmeasured.
Verdict string `json:"verdict"`
Reason string `json:"reason,omitempty"`
EntryCount int `json:"entry_count"`
EntryWidth int `json:"entry_width"`
MemberRowBytes int `json:"member_row_bytes"`
IndexWidth int `json:"index_width"`
DictionaryBytes int64 `json:"dictionary_bytes"`
Ratio float64 `json:"ratio"`
BreakEvenRatio float64 `json:"break_even_ratio"`
RatioFloor float64 `json:"ratio_floor"`
ByteDelta int64 `json:"byte_delta"`
GrowsFile bool `json:"grows_file"`
// ProjectedFileBytes is the exact cohort size with this group alone
// declared (compare ImportProjection.FlatFileBytes).
ProjectedFileBytes int64 `json:"projected_file_bytes"`
}
GroupCandidate is one detected parent group and its measured figures. The figures carry the same names and meaning as GroupReport's.
type GroupDecl ¶
GroupDecl declares one parent group by field NAME.
Key names the fields that identify the parent (e.g. its ID); Members names the fields the key DETERMINES (the parent's attributes). The group stores Key ∪ Members. With a Key, every row that carries a key tuple already seen must agree with that earlier row on every Member — value and null state — or the import fails with PULSE_GROUP_MEMBER_NOT_CONSTANT naming the member and the row: a declaration that is not actually a parent group is refused, never silently turned into a larger dictionary. With no Key, Members is a plain tuple group: each distinct combination is one entry and there is nothing to violate.
func ParseGroupDecl ¶
ParseGroupDecl parses the CLI form of one group declaration:
KEY[,KEY...]:MEMBER[,MEMBER...] a keyed group (members determined by the key) MEMBER[,MEMBER...] a plain tuple group (no key check)
Names are trimmed of surrounding whitespace. An empty name, an empty side of the colon, or more than one colon is PULSE_GROUP_DECLARATION_INVALID. Field names containing ',' or ':' cannot be written in this form; use ImportJob.Groups directly.
type GroupDetection ¶
type GroupDetection struct {
// Rows is the number of rows every candidate was measured over —
// the rows the import would write (row-error rows excluded).
Rows int64 `json:"rows"`
// WindowRows is how many leading rows nomination looked at;
// WindowBound is the most it would have looked at for this schema.
WindowRows int `json:"window_rows"`
WindowBound int `json:"window_bound"`
// FieldsConsidered counts the fields eligible as key or member (not
// declared in a group, not constant across the window).
FieldsConsidered int `json:"fields_considered"`
// KeysEvaluated / KeysOverBound: candidate keys whose dependencies
// were evaluated, and those skipped past detectMaxKeys.
KeysEvaluated int `json:"keys_evaluated"`
KeysOverBound int `json:"keys_over_bound"`
// CandidatesOverBound counts nominated candidates not confirmed
// because detectMaxCandidates were already carried forward.
CandidatesOverBound int `json:"candidates_over_bound"`
// CandidatesDisproved counts nominated candidates every one of
// whose members varied within the key later in the file.
CandidatesDisproved int `json:"candidates_disproved"`
// Candidates, best projected saving first. Every measured candidate
// is listed with its verdict — one below the width or ratio floor
// says so rather than disappearing.
Candidates []GroupCandidate `json:"candidates"`
// Suggested holds the --group values of the admitted candidates
// that do not overlap a better one, in rank order: the declaration
// set detection recommends. Empty when no candidate is viable.
Suggested []string `json:"suggested"`
}
GroupDetection is import predict's candidate parent-group report (ImportJob.SuggestGroups). Candidates are SUGGESTIONS: declaring one is always the user's decision (--group / ImportJob.Groups).
type GroupReport ¶
type GroupReport struct {
// Label names the group in errors and output ("group 1 [key: id]").
Label string `json:"label"`
// Key and Members are as declared; Fields is every member in
// logical (schema) order.
Key []string `json:"key,omitempty"`
Members []string `json:"members"`
Fields []string `json:"fields"`
// Verdict is admitted, low_ratio (written, with a
// PULSE_DEDUP_LOW_RATIO warning) or dropped_too_narrow (not
// written, PULSE_GROUP_TOO_NARROW). Reason is the code behind a
// non-admitted verdict.
Verdict string `json:"verdict"`
Reason string `json:"reason,omitempty"`
// EntryCount is the number of distinct tuples stored.
EntryCount int `json:"entry_count"`
// EntryWidth is the bytes per dictionary entry (member bytes plus a
// member null bitmap when any member is nullable).
EntryWidth int `json:"entry_width"`
// MemberRowBytes is the bytes the members occupied in each flat row.
MemberRowBytes int `json:"member_row_bytes"`
// IndexWidth is the bytes of the per-row index that replaces them.
IndexWidth int `json:"index_width"`
// DictionaryBytes is EntryCount × EntryWidth, resident in memory
// whenever the cohort is open.
DictionaryBytes int64 `json:"dictionary_bytes"`
// Ratio is rows ÷ EntryCount; BreakEvenRatio the ratio below which
// the group grows the file; RatioFloor the floor it was judged
// against.
Ratio float64 `json:"ratio"`
BreakEvenRatio float64 `json:"break_even_ratio"`
RatioFloor float64 `json:"ratio_floor"`
// ByteDelta is the grouped bytes (indexes + dictionary + descriptor)
// minus the members stored per row: negative is a saving.
ByteDelta int64 `json:"byte_delta"`
}
GroupReport describes one declared group: its verdict from the per-group viability gate (encoding.DedupGate) and the numbers behind it. A dropped group (verdict dropped_too_narrow) was not formed — its members stay row fields — and carries only its widths; an admitted or low_ratio group was written and carries the measured ratio, the dictionary it holds resident and the byte delta versus storing its members per row.
type ImportJob ¶
type ImportJob struct {
Source Reader
Target string // output .pulse path
// Schema is the caller-authored .pulse schema. When non-nil it wins
// over everything: inference is skipped AND a SchemaAwareReader
// source is not consulted at all. It is therefore the escape hatch
// for overriding an authoritative source dictionary.
Schema *encoding.Schema
// SampleRows caps the inference sample: default 500, min 50.
// Inert when Schema is supplied or the Source is a
// SchemaAwareReader that yields a schema — there is nothing to
// sample.
SampleRows int
FS afero.Fs
// SetInferenceMinPct configures the delimited-cell heuristic for
// inferring set_* field types during the inference pass. A column
// is classified as set_* when at least this percentage of non-
// null sampled cells contain the inferred delimiter, the
// post-split unique token count fits the widest set rung (≤256),
// and the average post-split cardinality is > 1. Zero is treated
// as 30%.
// Ignored when Schema is supplied, and inert when the Source is a
// SchemaAwareReader that yields a schema.
SetInferenceMinPct int
// FloatWidth is the type inference gives an all-float column: "f64"
// (the default; "" means the same) or "f32", a size opt-in that
// rounds every value to ~7 significant digits. Under "f32" an
// out-of-sample value past f32's range still promotes the field to
// f64 with PULSE_IMPORT_WIDTH_PROMOTED. Any other value refuses the
// import (Run and Predict alike, with or without a Schema) with
// PULSE_IMPORT_FLOAT_WIDTH_INVALID. Steers inference only: inert when
// Schema is supplied or a SchemaAwareReader yields a schema, and a
// ColumnTypeOverrides entry wins for its column. CLI `--float`.
FloatWidth string
// ColumnTypeOverrides bypasses inference for the named columns
// (keyed by exact header name). Used by the managed-import
// sidecar's force_type escape hatch. An override is applied exactly
// or refused with PULSE_IMPORT_OVERRIDE_INVALID — never narrowed,
// widened or ignored: an unknown column, a present value the forced
// type cannot hold (on ANY row, not just the inference sample —
// never a skipped row), and an override on a job with no inferred
// schema (Schema supplied, or a SchemaAwareReader source whose
// authoritative dictionary is not a guess to override) are all
// refused. Re-type an authoritative column by supplying Schema.
// See SchemaAwareReader and import_override.go.
ColumnTypeOverrides map[string]encoding.FieldType
// SourceTZ is the zone naive datetime literals are read in: an
// IANA Area/Location name, "UTC", or a fixed offset "+HH:MM" /
// "-HH:MM" (accepted here, never in a request). It applies to every
// `datetime` field of the resolved schema and skips `date` fields
// (a calendar day has no zone). A literal carrying its own `Z` or
// offset names that instant and ignores the zone. Storage is
// unchanged: the stored value is always UTC epoch seconds. Empty
// (the default) reads naive literals as UTC, byte-identically to an
// import without the field. An unknown zone is PULSE_TIMEZONE_UNKNOWN.
SourceTZ string
// ColumnSourceTZ sets the source zone per column (keyed by exact
// field name, same spelling as SourceTZ) and wins over SourceTZ for
// that column. A key naming no field, or a field that is not
// `datetime` (a `date` column included), is refused with
// SERVICE_VALIDATION before the row pass.
ColumnSourceTZ map[string]string
// DSTPolicy decides a naive literal a source zone's DST transition
// makes ambiguous (shown twice) or nonexistent (skipped): DSTPolicyError
// (the default; "" means it) refuses the import at the first such row
// with PULSE_IMPORT_DST_AMBIGUOUS / PULSE_IMPORT_DST_NONEXISTENT;
// DSTPolicyEarlier / DSTPolicyLater resolve with the pre- / post-
// transition offset and report the counts in one
// PULSE_IMPORT_DST_RESOLVED warning (ImportReport.ZoneWarnings).
// Inert without a source zone and under a fixed-offset zone.
DSTPolicy DSTPolicy
// SetDelimiters maps set-typed column name to the delimiter the
// importer should use when splitting cell strings into tokens
// for per-row mask packing. Populated by inference; absent
// entries (explicit-schema imports or non-set columns) fall back
// to DefaultSetDelimiter ("|"). Inert when the Source is a
// SchemaAwareReader that yields a schema: such a source builds
// set_* masks from its own set definitions, not by splitting
// delimited cell strings.
SetDelimiters map[string]string
// InferredSchema marks a supplied Schema as inference-originated so
// the row pass promotes non-nullable fields to nullable on an
// out-of-sample null instead of failing the row (see Run). When
// Schema is nil this is implied — Run infers the schema and always
// promotes. Set it explicitly only when handing Run a pre-built
// schema that came from inference (e.g. ConvertJob's KeepPulseAt
// re-import) so it inherits the same tolerance. Leave false for a
// user-authored explicit schema, where a null in a declared
// non-nullable field must stay a PULSE_IMPORT_ROW_ERROR.
//
// Inert when the Source is a SchemaAwareReader that yields a
// schema. Such a schema is authoritative, not inference-originated,
// so its declared nullability is a contract: an unexpected null is
// a row error, never a silent widening. See SchemaAwareReader.
InferredSchema bool
// IgnoreExtra relaxes by-name matching of a user-authored Schema:
// a source column no schema field names is DROPPED instead of
// refusing the import with PULSE_IMPORT_SCHEMA_COLUMN_UNMAPPED, and a
// keyed source's (NDJSON, JSON array) key first seen after the first
// object is dropped instead of refused with
// PULSE_IMPORT_SCHEMA_KEY_LATE. A schema field with no column is
// still PULSE_IMPORT_SCHEMA_FIELD_MISSING. An explicit Schema is
// always matched to the source header by exact name, never by
// position. Inert without a user-authored Schema. CLI
// `--ignore-extra`. Default false.
IgnoreExtra bool
// ElideConstants stores every field that holds exactly one value
// (or is null) on EVERY imported row once, in the schema block, and
// drops it from each record — a format 0x02 cohort, which binaries
// older than 0x02 support cannot open. Constancy is decided over the
// full row pass, never the inference sample. Nothing is elided (and
// the output stays a byte-identical 0x01 cohort) for fewer than two
// rows, when no field is constant, or when declaring the constants
// would cost more schema bytes than it saves. When every field is
// constant the lowest-index one stays in the row. Default false.
// See encoding.PlanConstantElision.
ElideConstants bool
// Groups declares parent groups (see GroupDecl): each stores its
// distinct member tuples ONCE in the schema block and every record a
// u32 index into them — a format 0x02 cohort, which binaries older
// than 0x02 support cannot open. Groups are independent; a field
// belongs to at most one. Names are checked against the resolved
// schema (inferred, authoritative or explicit alike) before the row
// pass; the dictionaries are built in one pass over the imported
// rows. Composes with ElideConstants: declared members are never
// elided. Empty (the default) writes the 0x01 cohort unchanged.
//
// Every declared group passes the per-group viability gate
// (encoding.DedupGate): one no wider than its u32 index is dropped
// with PULSE_GROUP_TOO_NARROW; one below DedupRatioFloor rows per
// distinct tuple, or that makes the file no smaller, is written with
// PULSE_DEDUP_LOW_RATIO. Both land in ImportReport.GroupWarnings.
Groups []GroupDecl
// Vectors folds sibling source columns into native vec_f32 /
// vec_f64 fields (see VectorDecl) — a format 0x02 cohort. Each
// vector takes its first member's source position; its members
// vanish from the cohort. Per row: every element cell empty is a
// null vector (an inferred field is promoted to nullable), some
// empty are NaN elements, a non-numeric cell fails the row
// (PULSE_IMPORT_ROW_ERROR). Refused before any row is read with
// PULSE_IMPORT_VECTOR_INVALID: a dim outside 2..1024, a pattern
// matching no column, a column claimed twice (two vectors, or a
// vector and a Groups entry), an unknown column, a bad kind or
// scale, or an authoritative-schema (SPSS) source. With an explicit
// Schema each vec field must be a declared vector of the schema's
// dim. Empty (the default) imports unchanged. CLI `--vector` /
// `--vector-kind`.
Vectors []VectorDecl
// DedupRatioFloor is the rows-per-distinct-tuple floor below which
// a declared group draws PULSE_DEDUP_LOW_RATIO. Zero (the default)
// selects encoding.DefaultDedupRatioFloor (2); a value in (0, 1]
// disables the floor, leaving only the grows-the-file check.
DedupRatioFloor float64
// StrictDedup turns the viability gate's warnings into errors: Run
// fails with the finding's own code (PULSE_GROUP_TOO_NARROW or
// PULSE_DEDUP_LOW_RATIO) and writes nothing. It governs the gate
// only — other import warnings are unaffected.
StrictDedup bool
// SuggestGroups makes Predict detect candidate parent groups —
// single-field keys and the fields they determine — and measure
// each over the full row pass (PredictReport.GroupCandidates). It
// SUGGESTS only: Run ignores it, and a candidate is formed only when
// declared through Groups. Costs Predict a full conversion pass (as
// Groups and ElideConstants do) plus the bounded detection work
// documented on GroupDetection.
SuggestGroups bool
}
ImportJob converts tabular source data into a .pulse file.
func NewImportJob ¶
NewImportJob creates an ImportJob with default settings.
func (*ImportJob) Predict ¶
func (j *ImportJob) Predict(ctx context.Context) (*PredictReport, error)
Predict validates the import without writing any output.
func (*ImportJob) Run ¶
func (j *ImportJob) Run(ctx context.Context) (*ImportReport, error)
Run executes the import job, converting tabular source into a .pulse file.
Total failure is an ERROR, not a zero-row report. If the row pass reads at least one row and converts none of them, Run returns a nil report and a coded error (PULSE_IMPORT_ROW_ERROR, or the first row error's own code when it carries one) whose details name the row count, the failure count and the first failure — and no .pulse file is written. Partial failure is unchanged: some rows in, some on ImportReport.RowErrors, nil error. A source with no data rows at all is an empty cohort, which is a legitimate outcome and not an error. See totalRowFailure.
type ImportProjection ¶
type ImportProjection struct {
// RowsImported / RowErrors: rows that would import, and rows that
// would be skipped with a row error.
RowsImported int `json:"rows_imported"`
RowErrors int `json:"row_errors"`
// FlatFileBytes is the exact size of the 0x01 cohort (no groups,
// no elision).
FlatFileBytes int64 `json:"flat_file_bytes"`
// ProjectedFileBytes is the exact size of the cohort this job would
// write: its admitted Groups plus, with ElideConstants, the
// constant group. Equal to FlatFileBytes when neither applies.
ProjectedFileBytes int64 `json:"projected_file_bytes"`
// ElisionBytesSaved is what ElideConstants would save (0 when off
// or nothing is elided).
ElisionBytesSaved int64 `json:"elision_bytes_saved,omitempty"`
}
ImportProjection is the measured pass's view of the file the import would write.
type ImportReport ¶
type ImportReport struct {
RowsImported int
Schema *encoding.Schema
RowErrors []RowError
PromotedFields []string
// WidthWarnings carries one PULSE_IMPORT_WIDTH_PROMOTED warning per
// field the row pass promoted past its sample-inferred width
// (categorical_* rung, integer width, or integer → f64), with
// field / from / to / source_row in Details. Empty (and omitted from
// JSON) when nothing outgrew its inferred width — always, for an
// explicit or authoritative schema. See import_widen.go.
WidthWarnings []*errors.CodedError `json:"WidthWarnings,omitempty"`
// ZoneWarnings carries the one PULSE_IMPORT_DST_RESOLVED warning a
// non-default ImportJob.DSTPolicy raises when it resolved at least
// one ambiguous or nonexistent source-zone wall clock (details:
// policy, ambiguous_n, nonexistent_n). Empty (and omitted from
// JSON) otherwise — always, without a source zone.
ZoneWarnings []*errors.CodedError `json:"ZoneWarnings,omitempty"`
// SourceWarnings carries the non-fatal diagnostics the source
// Reader surfaced through the optional SourceWarningEmitter
// contract — today the PULSE_SPSS_* family raised by the `.sav`
// dictionary walk, schema mapping and data pass. Nil for sources
// that do not implement the interface and for sources that
// implement it and raised nothing, so the report shape is
// unchanged for every pre-existing adapter.
SourceWarnings []*errors.CodedError
// ElidedConstants names the fields ImportJob.ElideConstants stored
// once in the schema block instead of per row, in schema order.
// Empty (and omitted from JSON) when elision was off or elided
// nothing, in which case the cohort is 0x01.
ElidedConstants []string `json:"ElidedConstants,omitempty"`
// Groups describes each ImportJob.Groups declaration as written, in
// declaration order: its label, fields, distinct-tuple count and
// the entry / member / index widths a viability check weighs. Empty
// (and omitted from JSON) when no group was declared.
Groups []GroupReport `json:"Groups,omitempty"`
// GroupWarnings carries the viability gate's findings, one per
// flagged group: PULSE_GROUP_TOO_NARROW (the group was dropped) and
// PULSE_DEDUP_LOW_RATIO (the group was written anyway), each with
// its numbers in Details. Empty (and omitted from JSON) when every
// declared group passed. Under ImportJob.StrictDedup a finding is
// returned as Run's error instead and there is no report.
GroupWarnings []*errors.CodedError `json:"GroupWarnings,omitempty"`
}
ImportReport summarizes the result of an import operation.
RowErrors records the rows that did not make it. It is a PARTIAL-failure channel only: a report exists precisely because some rows did import. When a non-empty source yields zero importable rows, ImportJob.Run returns a coded error and no report at all, so a caller that checks only the error return can no longer read total failure as success.
PromotedFields names the columns an inferred import widened to nullable because a null cell fell outside the bounded inference sample window (see ImportJob.InferredSchema). Empty for explicit-schema imports and for inferred imports with no out-of-sample nulls. Each promotion also surfaces a PULSE_IMPORT_NULL_PROMOTED warning to callers that thread coded warnings.
type InferOptions ¶
type InferOptions struct {
// SampleRows caps how many rows InferSchema reads before
// finalizing column types. Defaults to defaultSampleRows when
// <= 0; min-clamped to minSampleRows.
SampleRows int
// SetInferenceMinPct is the minimum percentage of non-null
// sampled cells that must contain the inferred delimiter for the
// column to be classified as set_*. Defaults to
// defaultSetInferenceMinPct (30) when 0.
SetInferenceMinPct int
// FloatWidth is the type an all-float column infers as: "f64" (the
// default; "" means the same) or "f32". f64 keeps every decimal the
// source wrote exact to ~15-17 significant digits; f32 is a size
// opt-in that rounds to ~7. Any other value is refused with
// PULSE_IMPORT_FLOAT_WIDTH_INVALID. An integer column, and a column
// carrying a negative integer (always f64), is unaffected.
FloatWidth string
// ColumnTypeOverrides maps column name to forced FieldType,
// bypassing the inference heuristics entirely for those columns.
// For set_* / categorical_* types the dictionary is still built
// from observed sample values during the inference pass; the
// override only fixes the column's storage type.
ColumnTypeOverrides map[string]encoding.FieldType
// contains filtered or unexported fields
}
InferOptions parameterises InferSchemaWithOptions. The zero value is safe — SampleRows / SetInferenceMinPct fall back to their package defaults and ColumnTypeOverrides is treated as empty.
type InferenceResult ¶
type InferenceResult struct {
Schema *encoding.Schema
Warnings []InferenceWarning
Delimiters map[string]string
}
InferenceResult bundles the inference output. The Delimiters map is populated for columns classified as set_*; callers (importers) use it to pack per-cell masks during the row pass.
func InferSchemaWithOptions ¶
func InferSchemaWithOptions(reader Reader, opts InferOptions) (*InferenceResult, error)
InferSchemaWithOptions is the parameterised inference entry. Returns the schema, accumulated warnings, AND the per-column delimiter map for columns classified as set_*. The delimiter map is used by ImportJob.Run during the row pass to split delimited cells into token lists for bit-packing.
type InferenceWarning ¶
InferenceWarning records a non-fatal observation during inference.
func InferSchema ¶
InferSchema samples up to sampleRows rows from reader and proposes a Schema. If sampleRows <= 0, defaultSampleRows is used. The minimum is minSampleRows. Wrapper over InferSchemaWithOptions that drops the delimiter map; only CSV/TSV/Excel paths that ignore set-typed import packing should call this entry. Importers should call InferSchemaWithOptions directly.
type LabelResolver ¶
type LabelResolver interface {
// Has reports whether the resolver carries any binding for the
// named field.
Has(field string) bool
// Mode returns the binding mode for the named field. Empty when
// no binding exists.
Mode(field string) types.LabelMode
// Apply translates a raw value through the binding for the named
// field. See processing.LabelResolver.Apply for semantics.
Apply(field, raw string) (out string, sibling string, ok bool)
// FieldsWithAugment returns the field names that should emit a
// "<field>_label" sibling column.
FieldsWithAugment() []string
// Warnings flushes the per-binding collision and miss summaries
// once the job finishes.
Warnings() []LabelWarning
}
LabelResolver is the io-package projection of the processing-layer label resolver. ExportJob / ConvertJob consume the interface so io stays free of the processing dependency.
processing.LabelResolver satisfies this interface as-is; the pulse-package facade builds the resolver from the user-facing LabelBinding slice + LabelTable registry and hands the value to the job via ExportJob.LabelResolver.
type LabelWarning ¶
LabelWarning is the io-package projection of one resolver diagnostic record. ExportReport surfaces these for the caller; the CLI / MCP envelope wrapper promotes them to envelope warnings.
type LateKeyRefuser ¶
type LateKeyRefuser = iocore.LateKeyRefuser
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type ListAwareReader ¶
type ListAwareReader = iocore.ListAwareReader
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type ListAwareWriter ¶
type ListAwareWriter = iocore.ListAwareWriter
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type ListCell ¶
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type ListColumn ¶
type ListColumn = iocore.ListColumn
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type NullAwareReader ¶
type NullAwareReader = iocore.NullAwareReader
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type NullAwareWriter ¶
type NullAwareWriter = iocore.NullAwareWriter
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type OverlayAwareWriter ¶
type OverlayAwareWriter = iocore.OverlayAwareWriter
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type OverlayWarningEmitter ¶
type OverlayWarningEmitter = iocore.OverlayWarningEmitter
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type PredictReport ¶
type PredictReport struct {
Schema *encoding.Schema
EstimatedRows int
Warnings []InferenceWarning
// ZoneWarnings is what ImportReport.ZoneWarnings would carry: the
// predict converts every source-zone datetime cell exactly as Run
// does, so a DST refusal is Predict's error too.
ZoneWarnings []*errors.CodedError `json:"ZoneWarnings,omitempty"`
// SourceWarnings carries the source Reader's non-fatal coded
// diagnostics — see ImportReport.SourceWarnings. Held apart from
// Warnings, which is the inference pass's own untyped channel: a
// predict against an authoritative source runs no inference, so
// Warnings is empty there and SourceWarnings is the only signal.
SourceWarnings []*errors.CodedError
// TargetWarnings carries the non-fatal diagnostics the TARGET
// Writer would raise if the export ran, lifted off the optional
// CohortValidator contract — today the PULSE_SPSS_SIDECAR_ABSENT /
// _IGNORED and PULSE_SPSS_NAME_SANITIZED codes a `.sav` export
// raises before it reads a single record. Symmetric with
// ExportReport.TargetWarnings, and held apart from SourceWarnings
// for the same reason ConvertReport holds the two apart: one is
// about what was read, the other about what would be written.
//
// Nil for a predict whose target does not implement
// CohortValidator, which is every format but `.sav` today, and nil
// for a validating target that raised nothing.
TargetWarnings []*errors.CodedError
// Columns is the header an ExportJob.Predict with a Target says the
// export of a cohort WITH A VECTOR FIELD would write: one column per
// projected field, a `_label` sibling per augment binding, and each
// vector as ONE column for a ListAwareWriter or as its dim expanded
// `<field>_<label>` / `<field>_1..N` columns for every other row
// writer. Nil for a vector-free cohort (its header is its field
// list), for a predict with no Target, for a CohortWriter target
// (which lays out its own variables) and for every ImportJob.Predict.
Columns []string `json:"Columns,omitempty"`
// The fields below are filled only by an ImportJob.Predict that runs
// the MEASURED pass — the job declares Groups, sets ElideConstants
// or sets SuggestGroups — and are nil (omitted from JSON) otherwise,
// so a plain predict's report is unchanged. The measured pass
// converts every row exactly as Run does, so each figure is what the
// import would produce, not a sample estimate.
//
// WidthWarnings are the PULSE_IMPORT_WIDTH_PROMOTED warnings Run
// would raise (see ImportReport.WidthWarnings), and Schema carries
// the promoted types. Only the measured pass converts values, so a
// plain predict never reports a width promotion: its Schema is the
// sample-inferred one.
WidthWarnings []*errors.CodedError `json:"WidthWarnings,omitempty"`
// Projection sizes the file the import would write.
Projection *ImportProjection `json:"Projection,omitempty"`
// Groups / GroupWarnings are what ImportReport.Groups /
// GroupWarnings would carry for the declared Groups. A declaration
// Run would refuse — an unknown field, or a member that varies
// within its key (PULSE_GROUP_MEMBER_NOT_CONSTANT) — is Predict's
// error too, and StrictDedup fails Predict as it fails Run.
Groups []GroupReport `json:"Groups,omitempty"`
GroupWarnings []*errors.CodedError `json:"GroupWarnings,omitempty"`
// ElidedConstants names what ElideConstants would elide.
ElidedConstants []string `json:"ElidedConstants,omitempty"`
// GroupCandidates is the SuggestGroups detection report.
GroupCandidates *GroupDetection `json:"GroupCandidates,omitempty"`
}
PredictReport summarizes a validation-only run.
type Reader ¶
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type ResetReader ¶
type ResetReader = iocore.ResetReader
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type SchemaAwareReader ¶
type SchemaAwareReader = iocore.SchemaAwareReader
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type SchemaAwareWriter ¶
type SchemaAwareWriter = iocore.SchemaAwareWriter
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type SchemaFileField ¶
type SchemaFileField struct {
Name string `json:"name"`
Type string `json:"type"`
Description string `json:"description"`
Nullable bool `json:"nullable"`
Precision uint8 `json:"precision,omitempty"`
Scale uint8 `json:"scale,omitempty"`
Dim int `json:"dim,omitempty"`
Labels []string `json:"labels,omitempty"`
Kind string `json:"kind,omitempty"`
ScaleMin *float64 `json:"scale_min,omitempty"`
ScaleMax *float64 `json:"scale_max,omitempty"`
}
SchemaFileField is one entry of an explicit schema file: the JSON array `import schema-template` emits and `--schema` reads. precision and scale apply to decimal128 only and are ignored for every other type. A schema file carries no layout — offsets and bit positions are a pure function of field order and types (encx.LayoutFields) — and no column index: ImportJob / ConvertJob match each field to its source column BY NAME (resolveExplicitSchema).
dim, labels, kind, scale_min and scale_max apply to vec_f32 / vec_f64 only: dim (2..1024) is REQUIRED for a vector — its width is element × dim — labels are nil or exactly dim names, kind is measure, scale, composition or binary, and the scale range is both bounds or neither. A vector key on any other type, or a vector without dim, is PULSE_IMPORT_SCHEMA_INVALID at parse.
func SchemaFileTemplate ¶
func SchemaFileTemplate(schema *encoding.Schema) []SchemaFileField
SchemaFileTemplate renders schema as an explicit schema document — the `import schema-template` output — in the SchemaFileField shape ParseSchemaJSON reads back, so a template round-trips through the same decoder. Descriptions are left empty for the author to fill in; decimal128 fields carry their precision and scale and vector fields their dim, labels, kind and scale range (omitted for every other type), without which the document could not be imported as written.
type SidecarEmitter ¶
type SidecarEmitter = iocore.SidecarEmitter
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type SourceAwareWriter ¶
type SourceAwareWriter = iocore.SourceAwareWriter
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type SourceWarningEmitter ¶
type SourceWarningEmitter = iocore.SourceWarningEmitter
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type TargetWarningEmitter ¶
type TargetWarningEmitter = iocore.TargetWarningEmitter
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
type TransferExportJob ¶
type TransferExportJob struct {
// FS is the filesystem both paths resolve against. Required.
FS afero.Fs
// Source is the cohort path.
Source string
// Output is the artifact path, conventionally Source + ".zst".
Output string
// Level is the zstd level, MinTransferLevel..MaxTransferLevel. Zero
// selects DefaultTransferLevel.
Level int
}
TransferExportJob compresses a cohort's exact bytes into a transfer artifact. Source must be an uncompressed `.pulse` (single-file or shard archive); Output is overwritten.
func (*TransferExportJob) Run ¶
func (j *TransferExportJob) Run(ctx context.Context) (*TransferReport, error)
Run compresses Source into Output.
type TransferImportJob ¶
type TransferImportJob struct {
// FS is the filesystem both paths resolve against. Required.
FS afero.Fs
// Source is the `.pulse.zst` artifact path.
Source string
// Output is the cohort path to write.
Output string
// Overwrite permits replacing an existing Output. Default false:
// silently replacing a working cohort is refused.
Overwrite bool
}
TransferImportJob decompresses a transfer artifact back into a byte-identical `.pulse` at rest. The output is staged beside Output and renamed over it only once the whole stream decoded, its checksum held and the decoded bytes began with a Pulse magic — a refusal or a damaged artifact leaves nothing behind.
func (*TransferImportJob) Run ¶
func (j *TransferImportJob) Run(ctx context.Context) (*TransferReport, error)
Run decompresses Source into Output.
type TransferReport ¶
type TransferReport struct {
Source string `json:"source"`
Output string `json:"output"`
Codec string `json:"codec"`
// Level is the zstd level used; set on compress only.
Level int `json:"level,omitempty"`
// Layout is single_file or shard_archive.
Layout string `json:"layout"`
// CohortBytes is the uncompressed cohort size.
CohortBytes int64 `json:"cohort_bytes"`
// CompressedBytes is the artifact size.
CompressedBytes int64 `json:"compressed_bytes"`
// Ratio is CohortBytes / CompressedBytes (0 when the artifact is
// empty, which cannot happen for a real stream).
Ratio float64 `json:"ratio"`
// SHA256 is the lowercase hex digest of the uncompressed cohort.
SHA256 string `json:"sha256"`
}
TransferReport describes one transfer compress or decompress. SHA256 is always the digest of the UNCOMPRESSED cohort bytes, so the sender's and the receiver's reports compare directly.
type VectorDecl ¶
type VectorDecl struct {
Name string `json:"name"`
Element string `json:"element,omitempty"`
Columns []string `json:"columns,omitempty"`
Pattern string `json:"pattern,omitempty"`
Kind string `json:"kind,omitempty"`
ScaleMin *float64 `json:"scale_min,omitempty"`
ScaleMax *float64 `json:"scale_max,omitempty"`
}
VectorDecl declares one native vector field at import.
Name is the cohort field the vector becomes. Element is "f64" (the default when empty) or "f32", selecting vec_f64 / vec_f32. Exactly one of Columns (the member columns, in element order) and Pattern (a Go regular expression matched against every source column name; the members are the matches in SOURCE column order) names the members. Labels come from the pattern's first capture group when it has one, else from the full member column names, and are always written. Kind is the optional vector kind (measure, scale, composition, binary); ScaleMin / ScaleMax the optional declared value range, both or neither, ScaleMin < ScaleMax. Kind is never inferred.
func ParseVectorDecl ¶
func ParseVectorDecl(s string) (VectorDecl, error)
ParseVectorDecl parses the CLI form of one vector declaration:
NAME:COL1,COL2,... listed member columns, element order as listed NAME:/REGEX/ members = columns the regex matches, source order NAME:f32:COL1,... / NAME:f64:/REGEX/ with an explicit element type NAME / NAME:f32 a native list column of that name
The element defaults to f64. Names are trimmed; the regex is taken verbatim between its slashes (it may contain ':' or ','). A column literally named "f32" or "f64" cannot be the sole listed member in this form (use VectorDecl directly). An empty name, an empty column name or an empty regex is PULSE_IMPORT_VECTOR_INVALID (reason "malformed").
type Writer ¶
The tabular I/O contracts live in the iocore leaf so the format adapters can implement them without importing this package (whose jobs the adapters' own tests drive). Every name is an alias: the types are identical, so an optional-interface assertion against either spelling resolves the same way.
Source Files
¶
- build_schema.go
- cell_encode.go
- cohort_build.go
- convert.go
- core.go
- dedup.go
- doc.go
- explicit_schema.go
- export.go
- export_vectors.go
- hash.go
- import.go
- import_detect.go
- import_groups.go
- import_override.go
- import_rows.go
- import_vectors.go
- import_widen.go
- import_zone.go
- infer.go
- io.go
- labels.go
- overlay_assertions.go
- schema_file.go
- total_failure.go
- transfer.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package arrow provides Arrow IPC (Feather V2) import and export for the pulse I/O pipeline, plus shared Arrow<->Pulse type-mapping helpers used by both this package and internal/io/parquet.
|
Package arrow provides Arrow IPC (Feather V2) import and export for the pulse I/O pipeline, plus shared Arrow<->Pulse type-mapping helpers used by both this package and internal/io/parquet. |
|
Package csv provides CSV format adapters for the Pulse I/O pipeline.
|
Package csv provides CSV format adapters for the Pulse I/O pipeline. |
|
Package excel provides Excel import and export for the pulse I/O pipeline.
|
Package excel provides Excel import and export for the pulse I/O pipeline. |
|
Package exportoverlay holds the higher-level integration tests for the ExportJob and ConvertJob overlay-embedding wiring.
|
Package exportoverlay holds the higher-level integration tests for the ExportJob and ConvertJob overlay-embedding wiring. |
|
Package jsonarray provides JSON-array import and export for the pulse I/O pipeline.
|
Package jsonarray provides JSON-array import and export for the pulse I/O pipeline. |
|
Package jsonshared holds value coercion helpers shared by the ndjson and jsonarray packages.
|
Package jsonshared holds value coercion helpers shared by the ndjson and jsonarray packages. |
|
Package ndjson provides NDJSON (newline-delimited JSON) import and export for the pulse I/O pipeline.
|
Package ndjson provides NDJSON (newline-delimited JSON) import and export for the pulse I/O pipeline. |
|
Package nullcell holds the cross-adapter integration tests for the TWO absent-looking states of a `categorical_*` column — a null cell and a cell whose value IS the empty string.
|
Package nullcell holds the cross-adapter integration tests for the TWO absent-looking states of a `categorical_*` column — a null cell and a cell whose value IS the empty string. |
|
Package parquet provides Parquet import and export for the pulse I/O pipeline.
|
Package parquet provides Parquet import and export for the pulse I/O pipeline. |
|
Package settristate holds the cross-adapter integration tests for the THREE states of a `set_*` column — null, empty mask ("answered, selected nothing") and non-empty mask.
|
Package settristate holds the cross-adapter integration tests for the THREE states of a `set_*` column — null, empty mask ("answered, selected nothing") and non-empty mask. |
|
Package setwide holds the per-adapter wide-set round-trip tests: one test per tabular format, proving that a 206-member `set_u256` column survives an export and a re-import with every bit in the place it started.
|
Package setwide holds the per-adapter wide-set round-trip tests: one test per tabular format, proving that a 206-member `set_u256` column survives an export and a re-import with every bit in the place it started. |
|
Package spss reads SPSS `.sav` system files for the Pulse I/O pipeline.
|
Package spss reads SPSS `.sav` system files for the Pulse I/O pipeline. |
|
Package tsv provides TSV import and export for the pulse I/O pipeline.
|
Package tsv provides TSV import and export for the pulse I/O pipeline. |
|
Package veclist holds the per-adapter tests for importing a NATIVE list column as a vector field (`--vector NAME` with no column list): Arrow FixedSizeList and LIST, Parquet LIST, an NDJSON array and a JSON-array file.
|
Package veclist holds the per-adapter tests for importing a NATIVE list column as a vector field (`--vector NAME` with no column list): Arrow FixedSizeList and LIST, Parquet LIST, an NDJSON array and a JSON-array file. |