Musoq.Parser 17.0.14-alpha.2

This is a prerelease version of Musoq.Parser.
dotnet add package Musoq.Parser --version 17.0.14-alpha.2
                    
NuGet\Install-Package Musoq.Parser -Version 17.0.14-alpha.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Musoq.Parser" Version="17.0.14-alpha.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Musoq.Parser" Version="17.0.14-alpha.2" />
                    
Directory.Packages.props
<PackageReference Include="Musoq.Parser" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Musoq.Parser --version 17.0.14-alpha.2
                    
#r "nuget: Musoq.Parser, 17.0.14-alpha.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Musoq.Parser@17.0.14-alpha.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Musoq.Parser&version=17.0.14-alpha.2&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Musoq.Parser&version=17.0.14-alpha.2&prerelease
                    
Install as a Cake Tool

Musoq

Musoq — an investigation runtime that uses SQL.

Decode binary records, parse structured text, search code, inspect logs, and follow dependencies. Combine these steps in SQL to explore your data and return structured results you can inspect.

License: MIT Maintenance Nuget Tests

Declare a binary or text format beside your query to turn bytes or text into fields you can select, filter, and combine in SQL.

Decode a binary record

Declare field widths and a length-dependent payload, then select the interpreted fields.

binary Header {
    Kind: byte,
    Size: short le,
    Payload: byte[Size]
};

with input as (
    select FromHexToBytes('010300AABBCC') as Data
    from system.dual()
)
select
    h.Kind as Kind,
    h.Size as Size,
    Length(h.Payload) as PayloadBytes
from input i
cross apply Interpret<Header>(i.Data) h

Result: Kind = 1, Size = 3, PayloadBytes = 3.

Requires the System provider.

Binary format specification · More format examples.

Parse structured text

Describe the input format beside the query; its fields become available to the rest of the SQL.

text Entry {
    Level: token,
    _: whitespace,
    Message: rest
};

select e.Level as Level, e.Message as Message
from values {
    (Line: 'INFO ready'),
    (Line: 'ERROR retry failed')
} s
cross apply Parse<Entry>(s.Line) e
order by Level

Result:

Level Message
ERROR retry failed
INFO ready

Text format specification · More format examples.

Search and summarize logs

Search the sample logs for several patterns and count each label separately.

param(root: string = './docs/examples/readme/fixtures')

select m.PatternId as Level, Count(*) as Occurrences
from search.many($root, patterns: array {
    (id: 'ERROR', pattern: 'ERROR'),
    (id: 'WARN', pattern: 'WARN')
}, options: (scope: (include: array { '*.log' }))) m
group by m.PatternId
order by Level

Result:

Level Occurrences
ERROR 3
WARN 1

Requires the Search provider.

A datasource provider makes a source available as rows and columns that your query can use. The companion shows additional Search recipes and absolute-root execution commands.

Search provider reference · Grouping and HAVING.

These 24 examples are part of a collection of 28 runnable examples with inputs, prerequisites, and expected results. Run file-based examples from the repository root; inline examples include their own data.

Binary decoding · Text parsing · Search · Select and calculate · Group and rank · Combine data · Reuse queries · More formats

Select and calculate

Start with rows, choose the fields you need, and express conditions.

Create rows and calculate values · VALUES

Create a small input, calculate a total, and filter its rows.

select s.Name as Name, s.Price * s.Quantity as Total
from values {
    (Name: 'A', Price: 12, Quantity: 2),
    (Name: 'B', Price: 8, Quantity: 1)
} s
where s.Price >= 10
order by Name

Result: Name = A, Total = 24.

Match names and allowed values · LIKE and IN

Combine a filename pattern with a list of allowed values.

select s.Name as Name
from values {
    (Name: 'api.cs', Kind: 'source'),
    (Name: 'app.cs', Kind: 'source'),
    (Name: 'notes.txt', Kind: 'document')
} s
where s.Name like 'a%.cs' and s.Kind in ('source', 'test')
order by Name

Result:

Name
api.cs
app.cs

Choose values conditionally · CASE

Assign a label according to each row's score.

select
    s.Name as Name,
    case when s.Score >= 20 then 'high' else 'low' end as Band
from values {
    (Name: 'Ada', Score: 30),
    (Name: 'Ben', Score: 10)
} s
order by Name

Result:

Name Band
Ada high
Ben low

Keep rows with a matching record · EXISTS

Select customers for whom at least one matching order exists.

select c.Name as Name
from values { (Id: 1, Name: 'Ada'), (Id: 2, Name: 'Ben') } c
where exists (
    select 1
    from values { (CustomerId: 1) } o
    where o.CustomerId = c.Id
)
order by Name

Result: Name = Ada.

Expressions · Filtering.

Group and rank

Summarize rows or select the strongest result in each group.

Filter group totals · HAVING

Sum amounts by team, then keep groups whose total reaches 20.

select s.Team as Team, Sum(s.Amount) as Total
from values {
    (Team: 'api', Amount: 10),
    (Team: 'api', Amount: 15),
    (Team: 'worker', Amount: 5)
} s
group by s.Team
having Sum(s.Amount) >= 20
order by Team

Result: Team = api, Total = 25.

Count selected rows · FILTER

Count every row in a group and ERROR rows in the same query.

select
    s.Component as Component,
    Count(*) as Total,
    Count(*) filter (where s.Level = 'ERROR') as Errors
from values {
    (Component: 'api', Level: 'INFO'),
    (Component: 'api', Level: 'ERROR'),
    (Component: 'worker', Level: 'INFO')
} s
group by s.Component
order by Component

Result:

Component Total Errors
api 2 1
worker 1 0

Pick the highest score per category · Windows and QUALIFY

Rank rows within each category, then keep its first-ranked row.

select
    s.Category as Category,
    s.Name as Name,
    s.Score as Score,
    RowNumber() over (
        partition by s.Category
        order by s.Score desc, s.Name
    ) as Position
from values {
    (Category: 'Books', Name: 'A', Score: 30),
    (Category: 'Books', Name: 'B', Score: 10),
    (Category: 'Games', Name: 'C', Score: 20),
    (Category: 'Games', Name: 'D', Score: 15)
} s
qualify Position = 1
order by Category

Result:

Category Name Score Position
Books A 30 1
Games C 20 1

Aggregation · Window results and QUALIFY.

Combine data

Match records, expand collections, or append results.

Keep unmatched rows · LEFT JOIN

Keep left-side records even when the right side has no match.

select a.Name as Name, b.Score as Score
from values { (Id: 1, Name: 'A'), (Id: 2, Name: 'B') } a
left join values { (Id: 1, Score: 30) } b on a.Id = b.Id
order by Name

Result:

Name Score
A 30
B NULL

Find rows without a match · ANTI JOIN

Select left-side records for which no right-side match exists.

select a.Name as Name
from values { (Id: 1, Name: 'A'), (Id: 2, Name: 'B') } a
anti join values { (Id: 1) } b on a.Id = b.Id
order by Name

Result: Name = B.

Match the nearest earlier time · ASOF

Match each error to the nearest preceding deployment for the same service.

with errors as (
    select e.Service as Service, e.At::datetime as ErrorTime
    from values {
        (Service: 'checkout', At: '2026-10-11T10:05:00'),
        (Service: 'checkout', At: '2026-10-11T10:20:00')
    } e
), deployments as (
    select
        d.Service as Service,
        d.At::datetime as DeployedAt,
        d.Version as Version
    from values {
        (Service: 'checkout', At: '2026-10-11T10:00:00', Version: 'v1'),
        (Service: 'checkout', At: '2026-10-11T10:15:00', Version: 'v2')
    } d
)
select e.ErrorTime as ErrorTime, d.Version as Version
from errors e
asof join deployments d
    on e.Service = d.Service and e.ErrorTime >= d.DeployedAt
order by e.ErrorTime

Result:

ErrorTime Version
2026-10-11T10:05:00 v1
2026-10-11T10:20:00 v2

This establishes temporal association, not causation.

Expand a collection · CROSS APPLY

Turn collection items into rows alongside their parent record.

with source as (
    select s.Name as Name, array { 1, 2 } as Items
    from values { (Name: 'A') } s
)
select s.Name as Name, item.Value as Value
from source s
cross apply s.Items item
order by Value

Result:

Name Value
A 1
A 2

Combine results and keep duplicates · UNION ALL

Append one result to another without removing duplicate rows.

with combined as (
    select a.Value as Value
    from values { (Value: 1), (Value: 2) } a
    union all
    select b.Value as Value
    from values { (Value: 2), (Value: 3) } b
)
select Value
from combined
order by Value

Result: 1, 2, 2, 3.

Joins · APPLY · Set operations.

Name values and intermediate results, or follow relationships repeatedly.

Reuse input values · Parameters and variables

Declare a default input and a local value, then reference them with $.

param(minScore: int = 20)
let category: string = 'Books'

select s.Name as Name
from values {
    (Category: 'Books', Name: 'A', Score: 30),
    (Category: 'Books', Name: 'B', Score: 10)
} s
where s.Category = $category and s.Score >= $minScore
order by Name

Result: Name = A.

See parameter overrides.

Name an intermediate result · CTE

Give a calculated result a name and query it in another stage.

with totals as (
    select s.Name as Name, Sum(s.Amount) as Total
    from values {
        (Name: 'A', Amount: 10),
        (Name: 'A', Amount: 15),
        (Name: 'B', Amount: 5)
    } s
    group by s.Name
)
select Name, Total
from totals
where Total >= 20
order by Name

Result: Name = A, Total = 25.

Follow dependency links while using Service as the identity of each admitted row.

with recursive edges as (
    select e.Service as Service, e.Dependency as Dependency
    from values {
        (Service: 'checkout', Dependency: 'payments'),
        (Service: 'payments', Dependency: 'ledger'),
        (Service: 'ledger', Dependency: 'checkout')
    } e
), dependencies (Service, Depth) as (
    select 'checkout', 0 from values { (Seed: 1) } seed
    union (Service)
    select e.Dependency, d.Depth + 1
    from dependencies d
    inner join edges e on d.Service = e.Service
)
select Service, Depth
from dependencies
order by Depth

Result:

Service Depth
checkout 0
payments 1
ledger 2

Depth 0 is the starting service. The edge back to checkout adds no new identity, so the cycle terminates.

Script parameters · CTEs and recursion.

More format examples and source contracts

Build on the opening format examples with tolerant parsing, nested records, arrays, tagged payloads, and source contracts.

Keep malformed text rows · TryParse

Combine TryParse with OUTER APPLY to retain rejected input rows.

text Entry {
    Prefix: literal 'OK:',
    Message: rest
};

select s.Id as Id, p.Message as Message
from values {
    (Id: 1, Line: 'OK:ready'),
    (Id: 2, Line: 'bad')
} s
outer apply TryParse<Entry>(s.Line) p
order by s.Id

Result:

Id Message
1 ready
2 NULL

Detailed semantics.

Read a record inside a record · Nested binary formats

Name a reusable record format and select a field from its nested value.

binary User {
    UserId: int le
};

binary Packet {
    Kind: byte,
    User: User
};

with input as (
    select FromHexToBytes('012A000000') as Data
    from system.dual()
)
select p.Kind as Kind, p.User.UserId as UserId
from input i
cross apply Interpret<Packet>(i.Data) p

Result: Kind = 1, UserId = 42.

Requires the System provider.

Detailed semantics.

Read repeated values · Binary arrays

Use a count field to read an array, then expand its items into rows.

binary Batch {
    Count: byte,
    Items: short le[Count]
};

with input as (
    select FromHexToBytes('0207002A00') as Data
    from system.dual()
)
select item.Value as Value
from input i
cross apply Interpret<Batch>(i.Data) b
cross apply b.Items item
order by Value

Result:

Value
7
42

Requires the System provider.

Detailed semantics.

Read different payload kinds · Binary switch

Choose a payload format from its Type and select a Login field only for that branch.

binary LoginPayload {
    UserId: int le
};

binary Packet {
    Type: byte,
    Length: byte,
    Payload: switch Type {
        1 => Login: LoginPayload,
        _ => Raw: byte[Length]
    }
};

with input as (
    select 1 as Id, FromHexToBytes('01042A000000') as Data
    from system.dual()
    union all
    select 2 as Id, FromHexToBytes('0903AABBCC') as Data
    from system.dual()
)
select
    p.Payload.Case as PayloadKind,
    case when p.Payload.Case = 'Login'
        then p.Payload.Login.UserId
        else null
    end as UserId
from input i
cross apply Interpret<Packet>(i.Data) p
order by PayloadKind

Result:

PayloadKind UserId
Login 42
Raw NULL

Requires the System provider.

Detailed semantics.

Keep malformed binary rows · TryInterpret

Retain both valid and truncated input, with NULL fields when interpretation fails.

binary Header {
    Kind: byte,
    Size: short le,
    Payload: byte[Size]
};

with input as (
    select s.Id as Id, FromHexToBytes(s.Hex) as Data
    from values {
        (Id: 1, Hex: '010300AABBCC'),
        (Id: 2, Hex: '010300AA')
    } s
    cross join system.dual() seed
)
select i.Id as Id, h.Kind as Kind, h.Size as Size
from input i
outer apply TryInterpret<Header>(i.Data) h
order by i.Id

Result:

Id Kind Size
1 1 3
2 NULL NULL

Requires the System provider.

Detailed semantics.

Declare a source row contract · TABLE and COUPLE

Bind a declared row shape to a source method under a query-local name.

table Seed {
    Dummy: string
};

couple system.dual with table Seed as Seeds;

select s.Dummy as Dummy
from Seeds() s

Result: Dummy = X.

Requires the System provider.

Dummy: string is the observed system.dual() contract.

Text formats · Binary formats · TABLE and COUPLE.

Additional binary default-branch fixture.

Advanced: how a query executes

flowchart LR
    SQL[SQL] --> Planning[Binding and planning]
    Planning --> Operations[Executable operations]
    Operations --> Execution[Execution over sources]
    Execution --> Results[Structured results]

Binding resolves fields, types, and functions. Planning selects how relationships and data operations execute. Executable operations then run over source records and produce structured results. Providers supply records and metadata; the runtime combines and shapes them.

See the architecture reference for the current planning and execution pipeline.

Language references and further documentation

Diagnostic-aware compilation reports intent mistakes, including null-sensitive predicates such as where Name not in ('Alice', NULL) and impossible implicit conversions (MQ5025). See the diagnostic contract and catalog.

License

Musoq is licensed under the MIT License, permitting commercial and non-commercial use.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages (9)

Showing the top 5 NuGet packages that depend on Musoq.Parser:

Package Downloads
Musoq.Schema

Package Description

Musoq.Evaluator

Package Description

Musoq.Converter

Package Description

Musoq.DataSources.JsonHelpers

Package Description

Musoq.DataSources.Sqlite

Lets you connect to SQLite databases and run SQL-style queries from Musoq, ideal for lightweight local data exploration.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
17.0.14-alpha.2 165 10/24/2026
17.0.14-alpha.1 66 10/24/2026
17.0.13-alpha.1 213 10/17/2026
17.0.12-alpha.1 200 10/11/2026
17.0.11-alpha.1 184 9/17/2026
17.0.10-alpha.1 114 9/6/2026
17.0.9-alpha.1 216 9/2/2026
17.0.8-alpha.1 275 8/22/2026
17.0.7-alpha.1 130 8/18/2026
17.0.6-alpha.1 117 8/17/2026
17.0.5-alpha.1 235 8/8/2026
17.0.4-alpha.3 248 8/1/2026
17.0.4-alpha.2 102 8/1/2026
17.0.4-alpha.1 105 7/31/2026
17.0.3-alpha.2 221 7/26/2026
17.0.3-alpha.1 95 7/25/2026
17.0.2-alpha.4 230 7/19/2026
17.0.2-alpha.3 204 7/17/2026
17.0.2-alpha.2 336 7/13/2026
10.0.0 865 3/21/2026
Loading failed