npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@malloydata/malloy-query-builder

v0.0.361

Published

Get started with the {@link ASTQuery} class.

Readme

Malloy Query AST

Get started with the {@link ASTQuery} class.

Serialize itself to a Malloy Query string

{@link ASTQuery.toMalloy}

query.setSource('flights');
query.setView('by_carrier');
query.toMalloy();
run: flights -> by_carrier

Provide an interface to walk the tree

This is for the Explorer, e.g., to create the query summary UI

To the empty query, add a starting point which is either a new literal view or a view reference which can later be refined

{@link ASTQuery.getOrAddDefaultSegment}

query.setSource('flights');
query.getOrAddDefaultSegment().addGroupBy("carrier");
run: flights -> { group_by: carrier }

{@link ASTQuery.setViewToEmptySegment}

query.setSource('flights');
query.setViewToEmptySegment().addGroupBy("carrier");
run: flights -> { group_by: carrier }

{@link ASTQuery.setView}

query.setSource('flights');
query.setView('by_carrier');
run: flights -> by_carrier

Determine if the query can be run

{@link ASTSegmentViewDefinition.isRunnable}

run: flights -> { }
query.isRunnable() // false

Add a new field to a particular literal view

{@link ASTSegmentViewDefinition.addGroupBy} {@link ASTSegmentViewDefinition.addAggregate} {@link ASTSegmentViewDefinition.addNest}

const segment = query.getOrAddDefaultSegment();
segment.addGroupBy('carrier');
segment.addAggregate('flight_count');
segment.addNest('by_origin');
run: flights -> {
  group_by: carrier
  aggregate: flight_count
  nest: by_origin
}

A field reference

A time truncation of a field reference

{@link ASTSegmentViewDefinition.addDateGroupBy} {@link ASTSegmentViewDefinition.addTimestampGroupBy}

const segment = query.getOrAddDefaultSegment();
segment.addTimestampGroupBy('dep_time', 'month');
run: flights -> {
  group_by: dep_time.month
}

A measure reference with filters

Rename/delete a field

{@link ASTGroupByViewOperation.delete} {@link ASTAggregateViewOperation.delete} {@link ASTNestViewOperation.delete} {@link ASTGroupByViewOperation.rename} {@link ASTAggregateViewOperation.rename} {@link ASTNestViewOperation.rename}

run: flights -> {
  group_by: carrier
  aggregate: flight_count
}
groupBy.delete();
aggregate.rename("flight_count_2");
run: flights -> { aggregate: flight_count_2 is flight_count }

Check if a field is present

{@link ASTSegmentViewDefinition.hasField}

query.getOrAddDefaultSegment().hasField('carrier');

Add/edit/delete order by

{@link ASTOrderByViewOperation.delete}

run: flights -> {
  group_by: carrier
  order_by: carrier desc
}
orderBy.delete();
run: flights -> { group_by: carrier }

{@link ASTOrderByViewOperation.setField}

run: flights -> {
  group_by:
    carrier
    flight_count
  order_by: carrier desc
}
orderBy.setField("flight_count");
run: flights -> {
  group_by:
    carrier
    flight_count
  order_by: flight_count desc
}

{@link ASTOrderByViewOperation.setDirection}

run: flights -> {
  group_by: carrier
  order_by: carrier desc
}
orderBy.setDirection(Malloy.OrderByDirection.ASC);
run: flights -> {
  group_by: carrier
  order_by: flight_count asc
}

Add/edit/delete filter

  • {@link ASTSegmentViewDefinition.addWhere}
  • {@link ASTFilterWithFilterString.setFilterString}
  • {@link ASTFilterWithFilterString.setFilter}
  • {@link ASTFilterWithFilterString.getFilter}
  • {@link ASTWhereViewOperation.delete}
  • {@link ASTWhere.delete}
query.getOrAddDefaultSegment().addWhere("carrier", "WN, AA");
run: flights -> { where: carrier ~ f`WN, AA` }

Add/edit/delete limit

  • {@link ASTSegmentViewDefinition.setLimit}
  • {@link ASTLimitViewOperation.delete}
query.getOrAddDefaultSegment().setLimit(10);
run: flights -> { limit: 10 }

Create new nest with name

{@link ASTSegmentViewDefinition.addEmptyNest}

query.getOrAddDefaultSegment().addEmptyNest("by_origin");
run: flights -> { nest: by_origin is { } }

Reorder fields

To a particular nesting level (literal view or view + refinements), reorder fields

For a particular literal view, list the fields which can be added

{@link ASTSegmentViewDefinition.getInputSchema}

query.getOrAddDefaultSegment().getInputSchema();
{
  fields: [
    { kind: "measure", name: "flight_count", type: { kind: "string_type" }}
    ...
  ]
}

To a particular view reference, add a new literal view as a refinement

{@link IASTViewDefinition.addEmptyRefinement}

const view = query.setView("by_carrier");
const segment = view.addEmptyRefinement();
segment.setLimit(10);
run: flights -> by_carrier + { limit: 10 }

To a particular view reference, add a new view reference as a refinement

{@link IASTViewDefinition.addViewRefinement}

const view = query.setView("by_carrier");
view.addViewRefinement("top10");
run: flights -> by_carrier + top10

To a particular view (literal or reference), specify the order of fields by way of adding/editing an annotation

{@link ASTQuery.reorderFields} {@link ASTView.reorderFields}

If the view or query is a simple segment, it will automatically reorder the clauses.

run: flights -> {
  group_by: carrier
  aggregate: flight_count
}
query.reorderFields(['flight_count', 'carrier']);
run: flights -> {
  aggregate: flight_count
  group_by: carrier
}

Otherwise, it will add an annotation:

run: flights -> by_carrier
query.reorderFields(['flight_count', 'carrier']);
# field_order = [flight_count, carrier]
run: flights -> by_carrier

To a particular aggregate field in the query, add/edit/delete filter

  • {@link ASTAggregateViewOperation.addWhere}
  • {@link ASTFilterWithFilterString.setFilter}
  • {@link ASTWhere.delete}
query.getOrAddDefaultSegment().addAggregate('flight_count').addWhere('carrier', 'WN, AA');
run: flights -> { aggregate: flight_count { where: carrier ~ f`WN, AA`} }

Specify or remove source parameter value

{@link ASTReferenceQueryArrowSource.setParameter}

query.definition.as.ArrowQueryDefinition().source.as.ReferenceQueryArrowSource().parameters.setParameter("param", 1)
run: flights(param is 1) ->

List parameters of the source and whether they are required

{@link ASTReferenceQueryArrowSource.getSourceParameters}

query.definition.as.ArrowQueryDefinition().source.as.ReferenceQueryArrowSource().getSourceParameters();

To a particular field in the query (including nests), add/edit/delete annotation

{@link IASTAnnotatable.setTagProperty} {@link IASTAnnotatable.removeTagProperty}

query
  .getOrAddDefaultSegment()
  .addGroupBy('carrier');
  .setTagProperty(['a', 'b', 'c'], 10);
run: flights -> {
  # a.b.c = 10
  group_by: carrier
}
// Assume that 'by_carrier' has, in the model, a tag "bar_chart"
query
  .getOrAddDefaultSegment()
  .addNest('by_carrier');
  .removeTagProperty(['bar_chart']);
run: flights -> {
  # -bar_chart
  nest: by_carrier
}

To a particular field, ask which annotations come from the input field vs in the query itself

{@link IASTAnnotatable.getIntrinsicTag} {@link IASTAnnotatable.getInheritedTag}

query
  .getOrAddDefaultSegment()
  .addGroupBy('carrier');
  .getIntrinsicTag()
  .has('some_tag');
query
  .getOrAddDefaultSegment()
  .addGroupBy('carrier');
  .getInheritedTag()
  .has('some_tag');

To the query itself, add/edit/delete annotation

query.setTagProperty(['bar_chart']);
query.setSource('flights');
query.setView('by_carrier');
# bar_chart
run: flights -> by_carrier

After any operation of a QueryBuilder, perform a partial validation of the query

This is only ever a partial validation: cube resolution, aggregate validation, and expression validation (and possibly other validation) must happen in the translator, and will not be replicated in the QueryBuilder We will do as much validation as we can do, but it is possible some queries will only generate errors when you do a full translation (probably when you run it)

Given a filter string and a field type, parse it into a StableFilterDef

Given a StableFilterDef, serialize it into a filter string

Automatically determine where in a literal view is most appropriate to place a new field

This happens automatically when you call {@link ASTSegmentViewDefinition.addGroupBy}, {@link ASTSegmentViewDefinition.addAggregate}, {@link ASTSegmentViewDefinition.addNest}, {@link ASTSegmentViewDefinition.addWhere}, {@link ASTSegmentViewDefinition.addOrderBy}, {@link ASTSegmentViewDefinition.setLimit}, etc..

Finding the default place in the tree to put a new field

{@link ASTQuery.getOrAddDefaultSegment}

query.setSource('flights');
query.getOrAddDefaultSegment().addGroupBy("carrier");
run: flights -> { group_by: carrier }
run: flights -> by_carrier
query.setSource('flights');
query.getOrAddDefaultSegment().setLimit(10);
run: flights -> by_carrier + { limit: 10 }