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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@anrok/mammoth

v0.3.1

Published

This is a fork of [@ff00ff/mammoth](https://github.com/Ff00ff/mammoth). We made this fork because the upstream project has not been active. We'd love to get rid of this fork if that changes.

Downloads

671

Readme

This is a fork of @ff00ff/mammoth. We made this fork because the upstream project has not been active. We'd love to get rid of this fork if that changes.

This fork is based on the 1.x version rather than newer 2.x version. We made this decision because the 2.x version is still in alpha, and we ran into memory issues during TS compilation in the probject we were using it for. We start from c7c525c978aa6326042b35ca95f93699a69370c5 because that is the last commit before the big 2.x refactor.

List of changes (commits)

  • Changes nullable expressions to use the null data type, rather than undefined.
  • Fixes with query to return the value provided by constructed query.
  • Adds support for constant tables using VALUES lists.
  • Adds support for LATERAL joins.

Mammoth

Mammoth: A type-safe Postgres query builder pur sang for TypeScript

Build Status Coverage Status MIT License

📖 Work-in-progress documentation site is available at https://mammoth.tools/.

npm i @ff00ff/mammoth

Mammoth is a type-safe query builder. It only supports Postgres which we consider a feature. It's syntax is as close to SQL as possible so you already know how to use it. It's autocomplete features are great. It helps you avoid mistakes so you can develop applications faster.

const rows = await db
  .select(star())
  .from(db.foo)
  .leftJoin(db.bar)
  .on(db.foo.barId.eq(db.bar.id))
  .where(db.foo.id.eq(`1`));

The above query produces the following SQL:

SELECT
  *
FROM foo
LEFT JOIN bar ON (foo.bar_id = bar.id)
WHERE
  foo.id = $1

More importantly, the resulting type of rows is { id: string; barId: string; name: string | undefined }[]. Notice how the name is automatically nullable because of the left join.

Query examples

const updateCount = await db.update(db.foo).set({ name: `Test` }).where(db.foo.value.gt(0));
UPDATE foo
SET
  name = $1
WHERE
  value > $2
const rows = await db
  .insertInto(db.foo)
  .values({
    name: `Test`,
    value: 123,
  })
  .returning(`id`);
INSERT INTO foo (
  name,
  value
) VALUES (
  $1,
  $2
)
RETURNING
  id
const affectedCount = await db
  .insertInto(db.foo, ['name'])
  .select(db.bar.name)
  .from(db.bar)
  .where(db.bar.name.isNotNull());
INSERT INTO foo (name)
SELECT
  bar.name
FROM bar
WHERE
  bar.name IS NOT NULL
db.select(count()).from(db.foo);
SELECT COUNT(*) FROM foo
db.select(arrayAgg(db.foo.name.orderBy(db.foo.name.desc()))).from(db.foo);
SELECT array_agg(foo.name ORDER BY foo.name DESC) "arrayAgg" FROM foo
db.with(
  `regionalSales`,
  () =>
    db
      .select(db.orderLog.region, sum(db.orderLog.amount).as(`totalSales`))
      .from(db.orderLog)
      .groupBy(db.orderLog.region),
  `topRegions`,
  ({ regionalSales }) =>
    db
      .select(regionalSales.region)
      .from(regionalSales)
      .where(
        regionalSales.totalSales.gt(
          db.select(sum(regionalSales.totalSales).divide(10)).from(regionalSales),
        ),
      ),
  ({ topRegions }) =>
    db
      .select(
        db.orderLog.region,
        db.orderLog.product,
        sum(db.orderLog.quantity).as(`productUnits`),
        sum(db.orderLog.amount).as(`productSales`),
      )
      .from(db.orderLog)
      .where(db.orderLog.region.in(db.select(topRegions.region).from(topRegions)))
      .groupBy(db.orderLog.region, db.orderLog.product),
);
WITH "regionalSales" AS (SELECT order_log.region, SUM (order_log.amount) "totalSales" FROM order_log GROUP BY order_log.region), "topRegions" AS (SELECT "regionalSales".region FROM "regionalSales" WHERE "regionalSales"."totalSales" > (SELECT SUM ("regionalSales"."totalSales") / $1 FROM "regionalSales")) SELECT order_log.region, order_log.product, SUM (order_log.quantity) "productUnits", SUM (order_log.amount) "productSales" FROM order_log WHERE order_log.region IN (SELECT "topRegions".region FROM "topRegions") GROUP BY order_log.region, order_log.product

Quick start

Mammoth is a query builder pur sang so it doesn't include a database driver. You need to create a db and pass a callback to execute the query.

import { defineDb } from '@ff00ff/mammoth';
import { foo, bar } from './tables';

const db = defineDb({ foo, bar }, async (query, parameters) => {
  const result = await pool.query(query, parameters);

  return {
    affectedCount: result.rowCount,
    rows: result.rows,
  };
});

In the defineDb call you pass all your tables so they can be access through the db instance. You have to define all the tables to make sure Mammoth understands the type information. This should be close to the CREATE TABLE syntax.

const foo = defineTable({
  id: uuid().primaryKey().default(`gen_random_uuid()`),
  createDate: timestampWithTimeZone().notNull().default(`now()`),
  name: text().notNull(),
  value: integer(),
});

You should keep your column names camelCase in the defineTable call as they are automatically transformed to train_case throughout Mammoth.

Compatibility

Below is a list of clauses per query and a short description on what we Mammoth supports.

  • [ WITH [ RECURSIVE ] with_query [, ...] ] — Partial support. Recursive not supported yet.
  • SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ] — Mostly supported. Distinct not yet.
  • [ * | expression [ [ AS ] output_name ] [, ...] ] — mostly supported. Selecting certain expressions like update queries, insert and delete queries are not supported yet. Select queries are though.
  • [ FROM from_item [, ...] ] — partially supported. Only 1 table is currently supported in the from.
  • [ WHERE condition ] — mostly supported. The condition concept is pretty broad but it should contain a lot of cases.
  • [ GROUP BY grouping_element [, ...] ] — supported.
  • [ HAVING condition [, ...] ] — supported.
  • [ WINDOW window_name AS ( window_definition ) [, ...] ] — not supported.
  • [ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] select ] — not supported yet
  • [ ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...] ] — supported, but expressions are pretty broad and there might be cases not covered yet.
  • [ LIMIT { count | ALL } ] — supported.
  • [ OFFSET start [ ROW | ROWS ] ] — supported.
  • [ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY ] — supported
  • [ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } [ OF table_name [, ...] ] [ NOWAIT | SKIP LOCKED ] [...] ] — supported
  • [ WITH [ RECURSIVE ] with_query [, ...] ] — Partial support. Recursive not supported yet.
  • UPDATE [ ONLY ] table_name [ * ] [ [ AS ] alias ] — supported
  • SET { column_name = { expression | DEFAULT } | — supported, but expression concept is very broad and might be incomplete
  • ( column_name [, ...] ) = [ ROW ] ( { expression | DEFAULT } [, ...] ) | — supported, but expression concept is very broad and might be incomplete in some cases
  • ( column_name [, ...] ) = ( sub-SELECT ) — not supported
  • } [, ...]
  • [ FROM from_item [, ...] ] — partially supported. Only 1 table as from item is supported
  • [ WHERE condition | WHERE CURRENT OF cursor_name ] — supported, but the condition concept is very broad and is incomplete in some cases.
  • [ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ] — supported, but up to 10 expressions
  • [ WITH [ RECURSIVE ] with_query [, ...] ] — Partial support. Recursive not supported yet.
  • DELETE FROM [ ONLY ] table_name [ * ] [ [ AS ] alias ] — supported
  • [ USING from_item [, ...] ] — supported
  • [ WHERE condition | WHERE CURRENT OF cursor_name ] — supported, but the condition concept is very broad and might be incomplete
  • [ RETURNING * | output_expression [ [ AS ] output_name ] [, ... ] ] — supported, but up to 10 expressions
  • [ WITH [ RECURSIVE ] with_query [, ...] ] — Partial support. Recursive not supported yet.
  • INSERT INTO table_name [ AS alias ] [ ( column_name [, ...] ) ] — supported
  • [ OVERRIDING { SYSTEM | USER } VALUE ] — not supported
  • { DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query } - supported, but expression is a broad concept and may not be complete
  • [ ON CONFLICT [ conflict_target ] conflict_action ] — supported
  • [ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ] — supported, but limited to 10 expressions
  • RESTART IDENTITY
  • CASCADE

Versioning

Now that we've hit 1.0 Mammoth will stick to semantic versioning, meaning, breaking changes will only be included in major updates.

Contribute

Once you clone the repo, do a npm install + npm run build. Now you should be able to run npm test seeing everything turn green. Feel free to pick up one of the open issues — in particular you can pick up one labeled with "good first issue". Be sure to claim the issue before you start so we avoid two or more people working on the same thing.


Mammoth logo created by Eucalyp from the Noun Project.