Skip to content

aarongodin/slonik-iterable

Repository files navigation

slonik-iterable

CI npm

Helpers for query building with iterables. Ships with TS definitions.

Motivation

I've been really enjoying slonik for all of my projects using Postgres. This is a collection of helper functions I have been passing around from project to project for operating on arrays, plain objects, Maps, and Sets.

Requirements

Docs & Examples

The module exports several objects that group types of functionality.

values

Create a list of values from an object.

import { sql } from "slonik"
import { values } from "slonik-iterable"

const payload = {
  col1: "val1",
  col2: "val2",
}

const query = sql`
  INSERT INTO table (col1, col2)
  VALUES (${values.fromObject(payload)})
`

fromMap()

Convenience for passing a Map<string, any>.

import { sql } from "slonik"
import { values } from "slonik-iterable"

const payload = new Map([
  ["col1", "first value"],
  ["col2", 222],
])

const query = sql`
  INSERT INTO table (col1, col2)
  VALUES (${values.fromMap(payload)})
`

identifiers

Create a set of identifiers from an array of strings.

import { sql } from "slonik"
import { identifiers } from "slonik-iterable"

const query = sql`
  SELECT ${identifiers.fromArray(['col1', 'col2'], 'table')}
  FROM table
`

Create a set of identifiers from an object.

import { sql } from "slonik"
import { identifiers } from "slonik-iterable"

const payload = {
  col1: "val1",
  col2: "val2",
}

const query = sql`
  SELECT ${identifiers.fromObject(payload, 'table')}
  FROM table
`

fromSet()

Convenience for passing a Set<string> (behaves the same as fromArray()).

import { values } from "slonik-iterable"

const PUBLIC_COLUMNS = values.fromSet(new Set(["col_1", "col_2", "col_3"]), "table")

assignment

Create an assignment statement from an object for an update.

import { sql } from "slonik"
import { assignment } from "slonik-iterable"

const payload = {
  col1: "val1",
  col2: "val2",
}

const query = sql`
  UPDATE table SET ${assignment.fromObject(payload)}
`

fromMap()

Convenience for passing a Map<string, any>.

import { sql } from "slonik"
import { assignment } from "slonik-iterable"

const payload = new Map([
  ["col1", "first value"],
  ["col2", 222],
])

const query = sql`
  UPDATE table SET ${assignment.fromMap(payload)}
`

TranslateFn

Methods that insert values into sql statements accept an optional translate argument as a function. You can use this as a callback to modify the value inserted into the statement. This allows making sure the value is handled with the proper sql query building helper.

import { sql } from "slonik"
import { assignment } from "slonik-iterable"

const payload = {
  col1: "val1",
  col2: {
    nested1: "val2",
    nested2: "val3",
  },
  col4: 'val4'
}

const expression = assignment.fromObject(payload, (col, val) => {
  switch (col) {
    case 'col2':
      return sql.json(val) // val is { nested1: "val2", nested2: "val3" }
    case 'col3':
      return sql.binary(Buffer.from(val)) // val is 'val4'
    default:
      return val
  }
})

const query = sql`
  UPDATE table
  SET ${expression}
`

Returning a Tuple

The TranslateFn function type also allows returning a Tuple with arity-2 where the first element is a string and the second element the translated value (any ValueExpressionType from slonik). This allows translation of the column name at the same time as value translation.

import { sql } from "slonik"
import { assignment } from "slonik-iterable"
import { snakeCase } from "lodash"

const payload = {
  myColumn: "val1",
  anotherColumn: "val2",
}

const expression = assignment.fromObject(payload, (col, val) => [snakeCase(col), val])

const query = sql`
  UPDATE table
  SET ${expression}
`