cheatcode / joystick

A full-stack JavaScript framework for building stable, easy-to-maintain apps and websites.
https://cheatcode.co/joystick
Other
209 stars 11 forks source link

Add a utils/standard library package to Joystick #255

Open rglover opened 1 year ago

rglover commented 1 year ago

Just came to mind looking at some functions I've copy/pasted across several projects. Would be great to just organize these into something like @joystick.js/utils. Easy enough to do. Just want to avoid recreating something like Lodash.

Keeping a list...

rglover commented 1 year ago

See also #49

rglover commented 1 year ago

For types, I want to have a type checker function that can be called anywhere to validate the type/shape of things. So, if I pass an object, I can validate the types like this:

const user = { firstName: 'Ryan' };

utils.types.validate(user, {
  firstName: {
    type: 'string',
    required: true,
  },
}):

I should be able to adapt the existing input validation from the server and just make it globally available via the utils package.

Note: The value passed as the second argument could be an object, or, a type string like this: utils.types.validate(user, 'object') for generic type checking.

rglover commented 11 months ago

For dates, I'd like to have some basic Date-object based helpers like:

Right now I use dayjs for this stuff but it's unnecessary. It'd be best to standardize it and have control over all dates running through the framework so there's zero confusion.

rglover commented 11 months ago

For SQL:

const generate_sql_from_object = {
  insert: (options = {}) => {
    const column_names = Object.keys(options?.data)?.join(',');
    const value_placeholders = Object.keys(options?.data)?.map((_, index) => `$${index + 1}`)?.join(',');

    return {
      statement: `INSERT INTO ${options?.table} (${column_names}) VALUES (${value_placeholders})`,
      column_names,
      value_placeholders,
      values: Object.values(options?.data),
    };
  },
  update: (options = {}) => {
    const whereEntries = Object.entries(options?.where);
    const sets = Object.keys(options?.data).map((key, index) => {
      return `${key} = $${whereEntries.length + index + 1}`;
    })?.join(',');
    const where = whereEntries?.map(([key], index) => {
        return `${key} = $${index + 1}`;
    })?.join(',');

    return {
      statement: `UPDATE ${options?.table} SET ${sets} WHERE ${where}`,
      sets,
      where,
      values: [
        ...(Object.values(options?.where)),
        ...(Object.values(options?.data))
      ],
    };
  },
};

Usage:

const insert = generate_sql_from_object.insert({
  table: 'users',
  data: {
    user_id: 'abc123',
    pancakes: 'good',
    sausage: 'decent',
    pizza: 'oh baby',
  },
});

await process.databases.postgresql.query(insert.statement, insert.values);

const update = generate_sql_from_object.update({
  table: 'users',
  data: {
    pancakes: 'good',
    sausage: 'decent',
    pizza: 'oh baby',
  },
  where: { user_id: 'abc123', role: 'eater' }
});

await process.databases.postgresql.query(update.statement, update.values);

Consider offering the above as a single wrapper on the postgresql object like process.databases.postgresql.insert() or process.databases.postgresql.update() which takes in a table, data, and optional where object and wraps the example code above.