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

fauna-fp

v0.1.17

Published

Functional query builder for fauna db

Downloads

6

Readme

fauna-fp: Functional Programming for FaunaDB

fql is clearly a functional programming language, with functions like map and reduce as first-class tools. Despite that, we don't have all the tooling that is associated with modern functional languages like function composition, parameter currying and strong type inference. fauna-fp is a project trying to bridge that gap.

Vision

To allow writing complex FQL queries using elevant function composition that looks like this:

const emailValidator = compose(q.select("email"), q.containsStrRegex("^.+@.+..+$"));
const passwordValidator = compose(q.select("password"), q.length, q.gte(8));

const validate = (f) => (x) => q.iff(f(x), x, q.abort("invalid data"));

const validateEmail = validate();
const validatePassword = validate(compose());

const register = compose(
  validate(emailValidator),
  validate(passwordValidator),
  (x) => ({ data: x }),
  q.create(usersCollection)
);

or, with types:

interface User {
  email: string;
  password: string;
}

// emailValidator: (x: Arg<{email: string}>) => Query<boolean> (inferred automatically)
const emailValidator = compose(select("email"), containsStrRegex("^.+@.+..+$"));
// passwordValidator: (x: Arg<{password: string}>) => Query<boolean> (inferred automatically)
const passwordValidator = compose(select("password"), length, gte(8));

const usersCollection = collection<User>("users");

const validate = <T>(f: (x: Arg<T>) => Query<boolean>) => (x: Arg<T>) =>
  iff(f(x), x, abort("invalid data")); // inferred as Query<T>

// register : (x: Arg<User>) => Query<Document<User>>;
const register = compose(
  validate(emailValidator),
  validate(passwordValidator),
  (x) => ({ data: x }),
  q.create(usersCollection)
);

Image showing type inference of newUser variable

Image showing type inference of insertedEmail variable

Here's what the query above might look like in "vanilla" FQL.

const Validator = (f: (x: ExprArg) => ExprArg) => (x: ExprArg) =>
  q.If(f(x), x, q.Abort("invalid data"));

const PasswordValidator = Validator((x) => q.GTE([8, q.Length(q.Select(["password"], x))]));

const EmailValidator = Validator((x) => q.ContainsStrRegex(q.Select(["email"], x), "^.+@.+..+$"));

const Register = (x: User) =>
  q.Create(q.Collection("users"), {
    data: PasswordValidator(EmailValidator(x)),
  });

const NewUser = Register({ email: "", password: "" });

const Email = q.Select(["data", "email"], newUser);

Status

Experimental. See some test files for example usage.

I think a critical advantage of this library comes from getting the types right, so I have started there. I did try to add function composition at the same time, but I'm not enough of a TypeScript expert to be able to pull off all the generic shenanigans that are required.

I haven't written analogues for all FQL functions yet, but I've written enough that I'm starting to see dividends in my own codebase. Having strongly-typed queries is really valuable!

Approach

Separate Library

To get the benefits of strong typing, it might have been possible to simply write an alternative type definition for the fauna JS client. I have chosen not to do that because I have broader ambitions for fauna-fp than just types. Things liks parameter order is inconsistent in FQL (see Map and Reduce which take data as first and last parameters respectively). Currying wouldn't be possible if I just wrote typedefs. I think we can do better.

Opaque types

I don't want to expose this library to the particular data structure used by Fauna under-the-hood. Instead, I have created a generic opaque Query<T> type which represents the result of computing a query. This type should never be constructed manually - it should only ever be returned by a fauna-fp function. Similarly, a Query type should never be inspected or used directly (it will appear to only have a __TYPE__ property upon inspection). Instead, it should be passed to the fauna-fp query function, which will execute the query and return the actual payload.

These opaque types allow me to represent the conceptual types being represented by the various FQL datatypes, withouot coupling to the internal structure, and while safeguarding myself from future changes to this structure.