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

@bucky24/database

v3.8.3

Published

A simple model system for node that allows connecting to multiple types of data source

Downloads

153

Readme

@bucky24/database

A simple model system for node that allows connecting to multiple types of data source.

If you've found this, there are probably better modules for this with lots of fancy bells and whistles. I built this because I was bored but not bored enough to actually look up and learn any of those other modules.

Usage

There are two steps to using the module. The first is to setup a connection, and the second is to create models to actually manipulate the data. You can do these in the same file or different ones. See the examples for examples.

Connection

Supports JSON file, MySQL, and Postgres connections. While you can create a Connection directly, it's recommended to call one of the helper methods.

Connection.fileConnection

Creates a connection to a flat file (not a sqlite file). Returns a Promise that resolves to the connection.

| Param | Type | Description | |---|---|---| | data directory | String | A file path indicating where to place the data files |

Example:

const connection = await Connection.fileConnection(path.join(__dirname, "cache"));

Connection.mysqlConnection

Creates a connection to a mysql database. Returns a Promise that resolves to the connection.

NOTE: In order to use mysql you must have the mysql2 module installed. This project has been tested with version 2 of mysql2.

| Param | Type | Description | |---|---|---| | connectionObject | Object | An object containing the following keys: "password", "username", "host", "database", or "url", which is a standard MySQL Url string (if "url" is passed all other keys are ignored) |

Examples:

const connection = await Connection.mysqlConnection({
    host: 'localhost',
    username: 'user',
    password: 'secretpassword',
    database: 'app_database',
});

const connection = Connection.mysqlConnection({
    url: "mysql://user:secretpassword@localhost/app_database",
});

Connection.postgresConnection

Creates a connection to a postgres database. Returns a Promise that resolves to the connection.

Note: In order to use postgres you must have the pg module installed. This project has been tested on version 8 of pg.

| Param | Type | Description | |---|---|---| | connectionObject | Object | An object containing the following keys: "password", "username", "host", "database", "port", or "url", which is a standard PostgreSQL URL string (if "url" is passed all other keys are ignored) |

Examples:

const connection = await Connection.postgresConnection({
    host: 'localhost',
    usern 'user',
    password: 'secretpassword',
    database: 'app_database',
    port: 3211
});

const connection = Connection.postgresConnection({
    url: "postgresql://user:secretpassword@localhost:3211/app_database",
});

Connection.setDefaultConnection

This method takes in a Connection and sets it as the default connection for all models to use going forward. Note that this affects previously created models as well.

| Param | Type | Description | |---|---|---| | connection | Connection | Connection to set as the new default connection |

Example:

Connection.setDefaultConnection(connection);

Connection.getDefaultConnection

This method returns the currently set default connection.

Example:

const connection = Connection.getDefaultConnection();

close

This method closes a current connection

const connection = Connection.getDefaultConnection();
await connection.close();

Model

Models contain the code to actually setup and manipulate data.

Model.create

Allows creating a new Model for use in your program. It's recommended that you create these as singletons. The following parameters must be passed in as a settings object.

| Param | Type | Description | |---|---|---| | table | String | Name of the table to manipulate | | fields | Object | Keys being the name of the field, and values being a Field object | | version | Integer | Version of the table structure. Unused currently, though it is stored in a versions table in the database |

Note that the Model will automatically add an "id" field with type of FIELD_TYPE.INT that is a required auto-increment field. You can override this field if you desire.

Also note that you must call init on the new Model and wait for it to finish before you can use the model. This ensures that all tables exist in the chosen data system.

Field

A Field is an object with the following parameters:

| Param | Type | Description | |---|---|---| | type | FIELD_TYPE | Type of the field. Required | | meta | Array | Array of FIELD_META. Optional | | size | Int | Size of the field. Used with FIELD_TYPE.STRING. Optional | | foreign | ForeignKey | Data for any foreign key connections. Optional |

Note: The foreign keys must be added as the field is. The system does not know how to add them to an already existing field.

Example:

const tableModel = Model.create({
    table: "sample_table",
    fields: {
        field1: {
            type: FIELD_TYPE.STRING,
            meta: [FIELD_META.REQUIRED, FIELD_META.AUTO],
            size: <optional number, only used for the STRING type>
        },
    },
    version: 1,
});

ForeignKey

A ForeignKey is data that tells the Model how to create a foreign key relationship.

| Param | Type | Description | |---|---|---| | table | Model | Model instance of the table to connect to. Required | | field | String | Field on foreign table to connect to. Required |

FIELD_TYPE

The values of FIELD_TYPE are:

| Name | Description | |---|---| | INT | Integer value | | STRING | Open length text value | | BIGINT | Larger integer value | | JSON | Open length text value that contains JSON data | | BOOLEAN | Boolean data |

FIELD_META

The values of FIELD_META are:

| Name | Description | |---|---| | AUTO | Indicates this field is an auto-increment field. There should only be one of these. | | REQUIRED | Indicates the given field is required (inserts that do not contain this field will fail and updates that set it to null will fail) | | FILTERED | Indicates the given field shouldn't be exposed to clients and should be filtered out upon request. |

ORDER

The values of ORDER are:

| Name | Description | |---|---| | ASC | Indicates it should be ordered ascending | | DESC | Indicates that it should be ordered descending |

init

The init method performs the work to setup the table with given fields in your chosen database. It returns a promise that must resolve before any other methods are safe to call.

get

The get method takes in an ID and returns the data object associated with that ID (if it exists).

| Param | Type | Description | |---|---|---| | id | Integer | ID of the object to retrieve. Required |

Example:

const object = await tableModel.get(obj_id);

search

The search method takes in a query to search for and returns all objects that match (or an empty array if there are none).

| Param | Type | Description | |---|---|---| | query | Object | An object with keys being the fields to look for and values being the expected value. Required | | order | Object | An object with keys being the fields to order by and values being one of ORDER. Note these fields are not escaped due to a limitation in node-mysql. Optional | | limit | Integer | Indicates how many results to return. Optional | | offset | Integer | Indicates how many results should be skipped. Optional. Note MySQL does not allow an offset without a limit. |

Example:

const objects = await tableModel.get({
    field1: 5,
});

count

The count method takes in a query to search for and returns the total number of rows that matched.

| Param | Type | Description | |---|---|---| | query | Object | An object with keys being the fields to look for and values being the expected value. Required |

Example:

const numberOfRows = await tableModel.count({
    field1: 5,
});

insert

The insert method inserts a new object into the data store, returning the newly generated auto-incremented id. At this time it does not return other auto-incremented values.

| Param | Type | Description | |---|---|---| | data | Object | An object with keys being the fields and values being the value to insert. Required |

Example:

const new_id = await tableModel.insert({
    field1: 5,
});

update

The update method takes in an id and object, making changes to the object in the data store.

| Param | Type | Description | |---|---|---| | id | Integer | The ID of the object to update. Required | | data | Object | An object with keys being the fields and values being the value to update. Setting a field to null will attempt to remove that field from the data store (or set it to null, whichever is more appropriate). Required |

Example:

await tableModel.update(obj_id, {
    field1: 5,
});

delete

The delete method takes in an id and removes it if it exists.

| Param | Type | Description | |---|---|---| | id | Integer | The ID of the object to remove. Required |

Example:

await tableModel.remove(obj_id);

filterForExport

This method takes in a data object and returns a new object with all appropriate fields (fields with the FILTERED meta tag) removed. This can be used for prepping data to be returned from an API call or logged. It does not need to be called on an object that came from a Model call, but can be called on any plain JS object.

Example:

const userModel = Model.create({
    table: "user",
    fields: {
        password: {
            meta: [FIELD_META.REQUIRED, FIELD_META.FILTERED],
        },
        email: {
            meta: [FIELD_META.REQUIRED],
        },
    },
    version: 1,
});
const userObject = {
    password: 'a_password_hash',
    email: '[email protected]',
};
const filteredUserObject = userModel.filterForExport(userObject);

// at this point the password has been removed
console.log(filteredUserObject);

Table Changes

If you need to add new fields to a Model, add them to the list then bump the version number. The system will automatically add the new columns the next time init is called.

CRUD Methods

Each table has the capability to generate CRUD methods via Express. The following routes are created:

POST /table
PUT /table
GET /table
GET /table/:id

Where table is the name of the database table for the model.

To create these methods, the createCrudApis method can be called, with the following parameters:

| Param | Type | Description | |---|---|---| | app | Express App | The Express App or Router to add the new apis to | | options | CrudOptions | An options array. Optional |

CrudOptions

| Key | Type | Description | |---|---|---| | middleware | Function | Function[] | A singular or array of functions confirming to Express Middleware |

WhereBuilder

The WhereBuilder is a flexible way to define more complex queries. You can use its interface to create complex where clauses that aren't possible with the normal search functions.

Use

To use WhereBuilder, you can create a new instance of it using the new function:

$results = await SomeModel.search(WhereBuilder.new().compare(...));

Methods

new

This method creates a new instance of WhereBuilder. You can use the new keyword as well, but this method returns the new instance so that you can chain other methods onto it.

Example:

WhereBuilder.new()

compare

This method adds a comparison on a single field and a value or array of values.

| Param | Type | Description | | -- | -- | | field | String | The field name to compare | | operator | WHERE_COMPARE | The comparison operator to use | | value | Mixed | The value to compare on |

Note If the operator is EQ or NE, the value can be an array.

WhereBuilder.new()
    .compare("field", WHERE_COMPARE.EQ, 5)
    .compare("field2", WHERE_COMPARE.GT, 10)

and

This method allows adding an AND check into the builder.

Note A WhereBuilder acts as an and type by default, to allow multiple comparisons (and to mimic hte default of passing a normal object into search)

| Param | Type | Description | | -- | -- | | callback | Function | This callback function will be called with a WhereBuilder as its first argument.

WhereBuilder.new()
    .and((builder) => {
        builder.compare("field", WHERE_COMPARE.EQ, 5)
            .compare("field2", WHERE_COMPARE.NE, 10)
    });

#### or

This method allows adding an `OR` check into the builder.

| Param | Type | Description |
| -- | -- |
| callback | Function | This callback function will be called with a `WhereBuilder` as its first argument.

WhereBuilder.new() .or((builder) => { builder.compare("field", WHERE_COMPARE.EQ, 5) .compare("field2", WHERE_COMPARE.NE, 10) });