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

crud-controller

v1.0.2

Published

Generate crud functions for Kysely databases

Downloads

4

Readme

CrudController

CrudController is a library indended for serverless environments to make basic CRUD (Create, Read, Update, and Delete) endpoints quick and easy. It currently assumes you are using the Kysely database query builder but it is possible that dependency will be moved to the adapter level so that it can support more databases in the future.

CrudController generates functions that map an input context (usually an HTTP request) into database queries and a result value. For example, the CrudController.show function generates a function that takes a context and finds the first result that matches it on the given table:

const crud = new CrudController(models, adapter);
const showThing = crud.show("things"); // generates a show function for the "things" table
await showThing({ params: { show_id: 1 } }); // does a SELECT * FROM things WHERE id = 1 and returns the result as an object

Context Adapter

The first thing you will need to set up is a context adapter. This object is used to interface between CrudController and whatever context your code is running in.

  • useDatabase: (c: C) => Kysely<Models>

This function returns an instance of Kysely. In a Cloudflare Worker, for example, you might pull out a D1Database from the env and use that to make a Kysely instance. Or you might pull out a DATABASE_URL from the env to setup a Planetscale database connection. If your database connection can be used between multiple requests, this function could return a saved instance of Kysely instead.

  • set(c: C, key: string, value: any): void

This function sets some arbitrary key-value in the context. In Honojs, this maps to the Context.set function. In Hapi.js, there's request.app. In Express.js, it's response locals.

  • get(c: C, key: string): any

This function retrieves a value previously set using set.

  • getRequestParams(c: C): AnyObject

This function returns an object of all the request params given as URL parameters in the router. For example, given a route organizations/:organization_id/users/:user_id/things/:thing_id, this function should return an object with keys organization_id, user_id, and thing_id with whatever values are in the URL.

  • getRequestBody(c: C): any

This function returns an object of the request body. For example, in the Fetch API, this function should return the equivalent of calling await response.json().

  • response(c: C, body: any, statusCode?: number): any

This function converts the response body and statusCode generated by the CrudController with a proper Response object for your environment.

CrudController

The CrudController is a class with a constructor that takes two parameters: the first is a Models object and the second is a context adapter (described above. The models object is an object with a key for each database table in your system and a Zod schema describing that table's schema as the value. Think the Database type parameter you would give to Kysely, but with a Zod schemas instead of the interface of the table.

index

This function lists all records for the given context and table.

create

This function inserts a record for the given context and table. It requires an attribute picker describing how the context maps to each column of the table:

// given this model:
const models = {
  things: z.object({
    thing_id: z.string().uuid(),
    name: z.string(),
    description: z.string().nullish(),
    created_at: z.string(),
    updated_at: z.string(),
  }),
};

// given this create function:

const createThing = crud.create("things", {
  attributes: {
    thing_id: "uuid",
    name: "payload",
    description: "payload",
    created_at: "inserted_at",
    updated_at: "updated_at",
  },
});

// calling it with this body

await createThing({
  body: {
    name: "My thing",
    description: null,
  },
});

// would run this SQL:

// INSERT INTO things (thing_id, name, description, created_at, updated_at)
    VALUES (randomUUID(), 'My thing', NULL, NOW(), NOW())

The attributes picker has several options you can use:

  • payload - take the value from the body of the request
  • param - take the value from the params (where the param name matches this column's name)
  • get - take the value from the context (using adapter.get)
  • arg - take the value from the argument object

For example,

const createThing = crud.create("things", {
  attributes: {
    thing_id: "uuid",
    name: "payload",
    description: "arg",
    created_at: "inserted_at",
    updated_at: "updated_at",
  },
});

// The second parameter for the generated create function is the argument object
await createThing({
  body: {
    name: "My thing"
  },
}, { description: "description" });

This is useful for doing nested CRUD operations.

  • uuid - generate a uuid for this column
  • inserted_at - generates the current timestamp for this column
  • updated_at - generates the current timestamp for this column
  • null - sets this column to NULL
  • default - use the database default value for this column

show

This function returns the first record for the given context and table. This should be limited via a route parameter with the primary key of the table.

update

This function updates first record for the given context and table. It also takes an attributes picker like the create function.

destroy

This function deleetes first record for the given context and table.

Example Usage

See the examples in examples/.