Skip to content

Inconsistent Numeric Types across Adapters (JSON Strict vs YAML/Markdown) #1

@aretw0

Description

@aretw0

Summary

When building applications that support multiple file formats (e.g., .json and .md with frontmatter), enabling "Strict Mode" for JSON introduces a type inconsistency that forces consumer code to handle disparate numeric types depending on the data source.

Context

I am using Loam v0.10.3 in a project (Trellis) that loads state from both JSON and Markdown files.
To prevent large integers (IDs, timestamps) from being corrupted by float64 conversion in encoding/json, I enabled the strict JSON serializer:

loam.WithSerializer(".json", fs.NewJSONSerializer(true))

The Problem

This setting successfully preserves integers in JSON files by returning json.Number. However, the YAML parser (used for Markdown frontmatter) continues to return native Go types (int, float64).

This results in a situation where the same logical data field has different runtime types based on the file extension:

  1. Source data.json:

    { "count": 123 }

    Loaded Type: json.Number ("123")

  2. Source data.md:

    ---
    count: 123
    ---

    Loaded Type: int (123)

Consequence

Consumer code dealing with map[string]any (via TypedRepository or untyped Get) must implement defensive type assertions for all possibilities, leading to brittle boilerplate:

val := doc.Data["count"]
switch v := val.(type) {
case json.Number:
    // handle JSON strict
case int:
    // handle YAML/MD
case float64:
    // handle JSON default / YAML float
}

Proposal

Loam should consider offering a Type Normalization strategy or middleware.

Ideas:

  1. Unified Numeric Type: An option to force all adapters to return a specific numeric type (e.g., json.Number or int64 where possible).
  2. Smart Accessors: A helper (maybe in TypedDocument or something that abstracts this retrieval, e.g., node.GetInt64("field"), similar to how viper or other config libs handle it.

This would allow "Polyglot" repositories (supporting multiple formats) to offer a consistent API to the domain layer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions