fragments-forge

scrap your boilerplate by auto-generating dependencies

Usage no npm install needed!

<script type="module">
  import fragmentsForge from 'https://cdn.skypack.dev/fragments-forge';
</script>

README

fragments-forge

NPM Package Build Status Dependencies

the documentation in this readme is work in progress, chaotic and incomplete

scrap your boilerplate by auto-generating dependencies!

env

quickly read and parse environment variables!

pattern:

"env" ("Maybe")? ("String" | "Bool" | "Int" | "Float" | "Json") EnvVar

EnvVar is converted from camelcase (example: BaseUrl) to uppercase-underscored (example: BASE_URL) and looked up as property on the env dependency.

  • envIntPort parses int from envvar PORT. throws if not present or not parseable.
  • envBoolEnableEtags parses bool from envvar ENABLE_ETAGS. throws if not present or not parseable.
  • envStringDatabaseUrl reads string from envvar DATABASE_URL. throws if not present or blank.
  • envFloatCommisionPercentage parses float from envvar COMMISSION_PERCENTAGE. throws if not present or not parseable.
  • envMaybeStringMandrillApikey reads string from envvar MANDRILL_APIKEY. returns null if not present or blank.
  • envMaybeIntPoolSize parses int from envvar POOL_SIZE. returns null if not present. throws if present and not parseable.
  • envMaybeJsonPaymentConfig parses json from envvar PAYMENT_CONFIG. returns null if not present. throws if present and not parseable.
  • ...

serverside only

table

now you don't even need to define your mesa tables...

pattern:

"table" Table

auto generate table:

  • userTable will return mesa.table('user')
  • orderReportTable will return mesa.table('order_report')
  • ...

serverside only

table object

mesa tables often need circular dependencies for associations. hinoki doesn't support circular dependencies. table object resolvers fix that.

pattern:

"table" Table

Table will be converted to start with a lowercase letter and looked up as property on the table dependency.

  • userTable will return table.user
  • orderReportTable will return table.orderReport
  • ...

serverside only

select

pattern:

("first" | "select") Table ("Where" Column)* ("OrderBy" Column ("Asc" | "Desc")?)* ("WithConnection")?

this code

selectPublicContentWhereIsActiveWhereViewCountOrderByViewCountOrderByIdDesc(
  true,
  {$lt: 100}
).then(function(rows) {
  // ...
});

would execute a query similar to

SELECT *
FROM public_content
WHERE is_active = true
AND view_count < 100
ORDER BY view_count ASC, id DESC;

if it starts with first it will limit the query by 1 and resolve to the first row or undefined if no rows were returned.

the optional suffix WithConnection accepts an explicit connection as the last argument. this is useful for transactions.

serverside only - for now

insert

pattern:

"insert" Table ("WithConnection")?

this code

insertUser({
  email: 'test@example.com',
  password: 'secret'
}).then(function(insertedUser) {
  // ...
});

would execute a query similar to

INSERT INTO user (email, password)
VALUES ('test@example.com', 'secret');

the optional suffix WithConnection accepts an explicit connection as the last argument. this is useful for transactions.

WARNING!

in order to prevent a mass-assignment security vulnerability the factory returned by "insert" Table requires a dependency named table "InsertableColumns" (example: userInsertableColumns) to be present!

serverside only - for now

update

pattern:

"update" Table ("Where" Column)+ ("WithConnection")?

note the + at the end of the Where: updates without conditions are not allowed for security reasons!

this code

updateUserWhereIdWhereName(
  {email: 'test@example.com'},
  100,
  {$null: false}
).then(function(updatedUser) {
  // ...
});

would execute a query similar to

UPDATE user
SET email = 'test@example.com'
WHERE id = 100
AND name IS NOT NULL;

the optional suffix WithConnection accepts an explicit connection as the last argument. this is useful for transactions.

WARNING!

in order to prevent a mass-assignment security vulnerability the factory returned by "update" Table requires a dependency called table "UpdateableColumns" (example: userUpdateableColumns) to be present!

serverside only - for now

delete

pattern:

"delete" Table ("Where" Column)+ ("WithConnection")?

note the + at the end of the Where: deletes without conditions are not allowed for security reasons!

this code

deleteUserWhereName('alice').then(function(deletedUser) {
  // ...
});

would execute a query similar to

DELETE FROM user WHERE name = 'alice';

the optional suffix WithConnection accepts an explicit connection as the last argument. this is useful for transactions.

serverside only - for now

simple regex-like pattern language used in this document

  • "String" - static string
  • Variable - user-provided, non-empty, camelcased string that is parsed from the pattern
  • (a | b | c) - a or b or c
  • (a)* - zero or many a
  • (a)+ - one or many a
  • (a)? - optional a (zero or one)
  • spaces are used purely for readability

for example the pattern "env" ("Maybe")? ("String" | "Bool" | "Int" | "Float" | "Json") EnvVar means the string env followed by the optional string Maybe followed by either String, Bool, Int, Float, or Json followed by any camelcased string which will be bound to EnvVar.

the string envMaybeStringDatabaseUrl would satisfy that pattern with EnvVar = DatabaseUrl.

todos, ideas and raw thoughts

you can not give arguments to the factories but through resolvers you can give some sort of arguments through the dependency names

insertMany

data loaders

select should take an optional last options argument which can contain limit, offset, orderBy, orderDir, orderAsc as well as a condition which can be any valid criterion for filtering and could be parsed from jsurl

$firstPageWhereIdIsParamsId

$pageWhereIsActive

$pageOrderByCreatedAtDesc

$pageByQuery

? scrap url boilerplate

this is heavy on conventions!!!

? make the conventions changeable

document that custom code with the same name takes precedence

its like rubys method missing.

fragments-forge is a resolver for hinoki containers that can autogenerate common data accessor functions, loaders, etc. according to some conventions and greatly reduce the amount of code needed.

  • greatly reduces the amount of code needed

it allows you to ask for things that don't yet exist.

opinionated convention over configuration. entirely opt in. provides defaults which can all be explicitely overwritten.

license: MIT