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

kqb

v2.0.0

Published

Type-safe query builder for Kintone

Downloads

16

Readme

kqb

Type-safe query builder for Kintone

npm version supported Node.js version supported TypeScript version ci status coverage dependency count license

Why?

  • Type-safe for your app schema
  • Less typing with IDE completion
  • Human readable and Prettier friendly

Install

$ npm install kqb

Requires TypeScript >= 4.1 (for Template Literal Types)

Usage

import { createBuilder } from "kqb";

const fields = {
  name: "SINGLE_LINE_TEXT",
  age: "NUMBER",
  created: "CREATED_TIME",
} as const;

const { builder, field } = createBuilder(fields);
const query = builder
  .where(field("name").eq("foo"))
  .and(field("age").gt(20))
  .and(field("created").eq().THIS_MONTH())
  .orderBy("age", "desc")
  .limit(100)
  .offset(200)
  .build();
console.log(query);
// name = "foo" and age > "20" and created = THIS_MONTH() order by age desc limit 100 offset 200

API

createBuilder(fields?): { builder, field }

Returns a builder function and a field function.

The fields param is field definition JSON of your target kintone app. The key is a field code and the value is a field type like:

const fields = {
  name: "SINGLE_LINE_TEXT",
  age: "NUMBER",
} as const;
// In TypeScript, you MUST use `as const`

According to this, kqb performs static type checking and runtime validation.

  • Correct field codes
  • Correct type of value to compare for the field type
  • Condition operators available for the field type
  • Only sortable fields can be used in order by

If fields are omitted, the checking is mostly disabled. See tips below.

All field types are supported:

  • CALC
  • CHECK_BOX
  • CREATED_TIME
  • CREATOR
  • DATE
  • DATETIME
  • DROP_DOWN
  • FILE
  • GROUP_SELECT
  • LINK
  • MODIFIER
  • MULTI_LINE_TEXT
  • MULTI_SELECT
  • NUMBER
  • ORGANIZATION_SELECT
  • RADIO_BUTTON
  • RECORD_NUMBER
  • RICH_TEXT
  • SINGLE_LINE_TEXT
  • STATUS
  • STATUS_ASSIGNEE
  • TIME
  • UPDATED_TIME
  • USER_SELECT
  • SUBTABLE: see below
  • REFERENCE_TABLE: see below

Subtables and Reference tables

Specify subtables and reference tables as follows:

const defs = {
  id: "NUMBER"
  name: "SINGLE_LINE_TEXT",
  history: {
    $type: "SUBTABLE",
    $fields: {
      date: "DATE",
      title: "SINGLE_LINE_TEXT",
    },
  },
  items: {
    $type: "REFERENCE_TABLE",
    $fields: {
      price: "NUMBER",
      count: "NUMBER",
    },
  },
} as const;

Note the following spec of Kintone.

  • Fields in subtables and reference tables are not sortable.
  • Use in / not in instead of = / != for fields in subtables and reference tables.
  • Use "tableCode.fieldCode" as field code for fields in reference tables like field("items.price") in the example above.

builder

builder has the following methods.

  • .where(...condition[]): builder
    • Same as .and()
  • .and(...condition[]): builder
  • .or(...condition[]): builder
  • .orderBy(fieldCode, direction): builder
  • .orderBy(...[fieldCode, direction][]): builder
    • fieldCode: a field code of sortable field types
    • direction: "asc" or "desc"
  • .offset(num): builder
  • .limit(num): builder
  • .build(): string

condition is returned by operator methods. You can get it from field(fieldCode) with method chain like:

builder.where(field("name").eq("Bob"), field("age").gt(20)).build();
// name = "Bob" and age > "20"

field(fieldCode): operator

Returns a operator for the field with the fieldCode. The operator has only those of the following methods that are available for the field type.

  • .eq(value): "= value"
  • .notEq(value): "!= value"
  • .gt(value): "> value"
  • .gtOrEq(value): ">= value"
  • .lt(value): "< value"
  • .ltOrEq(value): "<= value"
  • .like(value): "like value"
  • .notLike(value): "not like value"
  • .in(...value[]): "in (value1, value2, ...)"
  • .notIn(...value[]): "not in (value1, value2, ...)"

and(...condition[]), or(...condition[])

If you want to use nested conditions, use and() or or().

import { createBuilder, and, or } from "kqb";

const fields = {
  foo: "NUMBER",
  bar: "NUMBER",
} as const;

const { builder, field } = createBuilder(fields);
const query = builder
  .where(or(field("foo").eq(1), field("bar").eq(2)))
  .and(or(field("foo").eq(3), field("bar").eq(4)))
  .or(and(field("foo").eq(5), field("bar").eq(6)))
  .build();
console.log(query);
// (foo = "1" or bar = "2") and (foo = "3" or bar = "4") or (foo = "5" and bar = "6")

Query Functions

Kintone provides query functions like TODAY() and LOGINUSER()

created_time = TODAY() and creator in (LOGINUSER())

You can use query functions with type-safety fluent method chaining.

import { createBuilder } from "kqb";

const fields = {
  created_time: "CREATED_TIME",
  creator: "CREATOR",
} as const;

const { builder, field } = createBuilder(fields);
const query = builder
  .where(field("created_time").eq().TODAY())
  .and(field("creator").in().LOGINUSER())
  .build();
console.log(query);
// created_time = TODAY() and creator in (LOGINUSER())

Also you can import each query function and specify it in a query operator.

import { createBuilder, LOGINUSER, TODAY } from "kqb";

const fields = {
  created_time: "CREATED_TIME",
  creator: "CREATOR",
} as const;

const { builder, field } = createBuilder(fields);
const query = builder
  .where(field("created_time").eq(TODAY()))
  .and(field("creator").in(LOGINUSER()))
  .build();
console.log(query);
// created_time = TODAY() and creator in (LOGINUSER())

All query functions are supported:

  • LOGINUSER
  • PRIMARY_ORGANIZATION
  • NOW
  • TODAY
  • YESTERDAY
  • TOMORROW
  • FROM_TODAY
  • THIS_WEEK
  • LAST_WEEK
  • NEXT_WEEK
  • THIS_MONTH
  • LAST_MONTH
  • NEXT_MONTH
  • THIS_YEAR
  • LAST_YEAR
  • NEXT_YEAR

Tips

Non type-safe query building

If you just want to build a query and do not want type-safety, you can omit the field definition argument of creatBuilder(fields?). You can get the query string easily, but note that type checking will not raise an error if the query is logically wrong. The operators has all methods and orderBy receives all fields, but potentially, it may not work.

const { builder, field } = createBuilder(); // omit the first argument
const query = builder
  .where(field("non_existent_field").gt(20))
  .and(
    field("number_field").like("can_not_actually_use_like_operator")
  )
  .orderBy("non_sortable_field", "asc")
  .build();

Multiple fields in order by

There are two ways to do this.

const query = builder
  .orderBy("foo", "asc")
  .orderBy("bar", "desc")
  .build();
console.log(query);
// order by foo asc, bar desc

const query = builder
  .orderBy(["foo", "asc"], ["bar", "desc"])
  .build();
console.log(query);
// order by foo asc, bar desc

License

MIT License: Teppei Sato <[email protected]>