NAME
    JSON::LINQ - LINQ-style query interface for JSON, JSONL, and LTSV files

VERSION
    Version 1.01

SYNOPSIS
        use JSON::LINQ;

        # Read JSON file (array of objects) and query
        my @results = JSON::LINQ->FromJSON("users.json")
            ->Where(sub { $_[0]{age} >= 18 })
            ->Select(sub { $_[0]{name} })
            ->Distinct()
            ->ToArray();

        # Read JSONL (JSON Lines) file - streaming, one object per line
        my @errors = JSON::LINQ->FromJSONL("events.jsonl")
            ->Where(sub { $_[0]{level} eq 'ERROR' })
            ->ToArray();

        # Read LTSV (Labeled Tab-Separated Values) file - streaming
        my @rows = JSON::LINQ->FromLTSV("access.ltsv")
            ->Where(sub { $_[0]{status} eq '200' })
            ->ToArray();

        # DSL syntax for simple filtering
        my @active = JSON::LINQ->FromJSON("users.json")
            ->Where(status => 'active')
            ->ToArray();

        # Grouping and aggregation
        my @stats = JSON::LINQ->FromJSON("orders.json")
            ->GroupBy(sub { $_[0]{category} })
            ->Select(sub {
                my $g = shift;
                return {
                    Category => $g->{Key},
                    Count    => scalar(@{$g->{Elements}}),
                    Total    => JSON::LINQ->From($g->{Elements})
                                    ->Sum(sub { $_[0]{amount} }),
                };
            })
            ->OrderByDescending(sub { $_[0]{Total} })
            ->ToArray();

        # Write results back as JSON, JSONL, or LTSV
        JSON::LINQ->From(\@results)->ToJSON("output.json");
        JSON::LINQ->From(\@results)->ToJSONL("output.jsonl");
        JSON::LINQ->From(\@results)->ToLTSV("output.ltsv");

        # JOIN: main JSON table x sub-table LTSV (department lookup)
        my $depts = JSON::LINQ->FromLTSV("departments.ltsv");
        my @joined = JSON::LINQ->FromJSON("employees.json")
            ->Join($depts,
                sub { $_[0]{dept_id} },
                sub { $_[0]{id}      },
                sub { { name => $_[0]{name}, dept => $_[1]{name} } })
            ->ToArray();

        # JOIN: main LTSV log x sub-table JSON (price master)
        my $prices = JSON::LINQ->FromJSON("prices.json");
        my @priced = JSON::LINQ->FromLTSV("orders.ltsv")
            ->Join($prices,
                sub { $_[0]{sku} },
                sub { $_[0]{sku} },
                sub { { order_id => $_[0]{id},
                        amount   => $_[0]{qty} * $_[1]{price} } })
            ->ToArray();

        # Boolean values
        my $rec = { active => JSON::LINQ::true, count => 0 };

DESCRIPTION
    JSON::LINQ provides a LINQ-style query interface for JSON, JSONL
    (JSON Lines), and LTSV (Labeled Tab-Separated Values) files.  It is
    the JSON counterpart of LTSV::LINQ, sharing the same LINQ API and
    adding JSON- and LTSV-specific I/O methods.

    Key features:

    * Lazy evaluation - O(1) memory for JSONL and LTSV streaming
    * Method chaining - Fluent, readable query composition
    * DSL syntax - Simple key-value filtering without code references
    * 65 LINQ methods - including JSON I/O (FromJSON, FromJSONL,
      FromJSONString, ToJSON, ToJSONL), LTSV I/O (FromLTSV, ToLTSV),
      and all 60 methods from LTSV::LINQ
    * Built-in JSON parser - No CPAN JSON module required
    * Pure Perl - No XS dependencies
    * Perl 5.005_03+ - Works on ancient and modern Perl

INCLUDED DOCUMENTATION
    The eg/ directory contains sample programs:

        eg/01_json_query.pl       FromJSON/Where/Select/OrderByDescending/Distinct/ToLookup
        eg/02_jsonl_query.pl      FromJSONL streaming, GroupBy, aggregation, ToJSONL
        eg/03_grouping.pl         GroupBy, ToLookup, GroupJoin, SelectMany, Join
        eg/04_sorting.pl          OrderBy/ThenBy multi-key sort, OrderByNum vs OrderByStr
        eg/05_json_ltsv_join.pl   JOIN main JSON x sub-table LTSV
        eg/06_ltsv_json_join.pl   JOIN main LTSV x sub-table JSON

    The doc/ directory contains JSON::LINQ cheat sheets in 21 languages:

        doc/json_linq_cheatsheet.EN.txt   English
        doc/json_linq_cheatsheet.JA.txt   Japanese
        doc/json_linq_cheatsheet.ZH.txt   Chinese (Simplified)
        doc/json_linq_cheatsheet.TW.txt   Chinese (Traditional)
        doc/json_linq_cheatsheet.KO.txt   Korean
        doc/json_linq_cheatsheet.FR.txt   French
        doc/json_linq_cheatsheet.ID.txt   Indonesian
        doc/json_linq_cheatsheet.VI.txt   Vietnamese
        doc/json_linq_cheatsheet.TH.txt   Thai
        doc/json_linq_cheatsheet.HI.txt   Hindi
        doc/json_linq_cheatsheet.BN.txt   Bengali
        doc/json_linq_cheatsheet.TR.txt   Turkish
        doc/json_linq_cheatsheet.MY.txt   Burmese
        doc/json_linq_cheatsheet.TL.txt   Filipino
        doc/json_linq_cheatsheet.KM.txt   Khmer
        doc/json_linq_cheatsheet.MN.txt   Mongolian
        doc/json_linq_cheatsheet.NE.txt   Nepali
        doc/json_linq_cheatsheet.SI.txt   Sinhala
        doc/json_linq_cheatsheet.UR.txt   Urdu
        doc/json_linq_cheatsheet.UZ.txt   Uzbek
        doc/json_linq_cheatsheet.BM.txt   Malay

TARGET USE CASES
    * Querying JSON API response files
    * Streaming analysis of JSONL log files
    * Joining JSON master tables with LTSV log files (or vice versa)
    * Data transformation pipelines (JSON in, JSON/JSONL/LTSV out)
    * In-memory array queries using LINQ-style API
    * Systems where no CPAN JSON module is available

DATA SOURCES
    FromJSON($file)
        Read a JSON file containing a top-level array.  The entire file is
        parsed once into memory, then iterated lazily.

    FromJSONL($file)
        Read a JSONL file.  Each non-empty line is parsed as a separate
        JSON value.  Lazy: one line at a time.  O(1) memory usage.

    FromJSONString($json)
        Parse a JSON string and iterate its elements.

    FromLTSV($file)
        Read an LTSV (Labeled Tab-Separated Values) file.  Each line is
        split on TAB, and each field on the first colon, producing a hash
        reference per record.  Lazy: one line at a time.  O(1) memory.

    From(\@array)
        Query an in-memory Perl array.

    Range($start, $count)
        Generate an integer sequence.

    Empty()
        Return an empty sequence.

    Repeat($element, $count)
        Repeat one element N times.

LINQ METHODS (65)
    Data Sources:  From, FromJSON, FromJSONL, FromJSONString, FromLTSV,
                   Range, Empty, Repeat
    Filtering:     Where (with DSL key=>value form)
    Projection:    Select, SelectMany
    Concatenation: Concat, Zip
    Partitioning:  Take, Skip, TakeWhile, SkipWhile
    Ordering:      OrderBy, OrderByDescending, OrderByStr, OrderByStrDescending,
                   OrderByNum, OrderByNumDescending, Reverse,
                   ThenBy, ThenByDescending, ThenByStr, ThenByStrDescending,
                   ThenByNum, ThenByNumDescending
    Grouping:      GroupBy
    Set ops:       Distinct, Union, Intersect, Except
    Joins:         Join, GroupJoin
    Quantifiers:   All, Any, Contains, SequenceEqual
    Element:       First, FirstOrDefault, Last, LastOrDefault,
                   Single, SingleOrDefault, ElementAt, ElementAtOrDefault
    Aggregation:   Count, Sum, Min, Max, Average, AverageOrDefault, Aggregate
    Conversion:    ToArray, ToList, ToDictionary, ToLookup,
                   ToJSON, ToJSONL, ToLTSV, DefaultIfEmpty
    Utility:       ForEach

INSTALLATION
    Standard CPAN installation:

        cpan JSON::LINQ

    Or manually:

        perl Makefile.PL
        make
        make test
        make install

    No C compiler required.  No non-core CPAN dependencies.

COMPATIBILITY
    Perl 5.005_03 and later.  Tested on Perl 5.005_03 through 5.42.
    Works on Windows and UNIX/Linux.  Pure Perl, no XS.

LIMITATIONS
    * Query objects can only be consumed once (iterator is exhausted
      after a terminal method).  Re-create the query to re-iterate.
    * FromJSON loads the entire file into memory.  Use FromJSONL for
      large files where streaming matters.
    * The built-in JSON parser does not support surrogate pairs
      (\uD800-\uDFFF) or circular reference detection in encoding.
    * ToLTSV sanitizes TAB/CR/LF in field values to single space to
      preserve the LTSV record/field structure.
    * The iterator protocol uses undef to signal end-of-sequence, so
      a JSON null cannot appear as a top-level element of a sequence.
      A Select() that projects a nullable JSON field will be truncated
      at the first null.  Project to a sentinel value (0, '', or {}),
      or wrap each element in a hashref so the element itself is
      never undef.  See "Iterator Protocol and JSON null" in the POD.

AUTHOR
    INABA Hitoshi <ina@cpan.org>

SEE ALSO
    LTSV::LINQ  - The LTSV counterpart of this module
    mb::JSON    - The JSON encoder/decoder this module's parser derives from
    JSONL spec  - https://jsonlines.org/
    LTSV spec   - http://ltsv.org/
    LINQ ref    - https://docs.microsoft.com/dotnet/api/system.linq

COPYRIGHT AND LICENSE
    Copyright (c) 2026 INABA Hitoshi

    This library is free software; you can redistribute it and/or modify
    it under the same terms as Perl itself.
