Giter Club home page Giter Club logo

Comments (4)

MarceloPrado avatar MarceloPrado commented on May 29, 2024 1

Regarding ^, I've built another example and I'm not seeing the issue anymore. Feel free to ignore!
Would you mind publishing the latest commits to NPM? Thanks in advance 🙂

from ruls.

decs avatar decs commented on May 29, 2024 1

Done! Published as v1.0.1

from ruls.

decs avatar decs commented on May 29, 2024

Hey, Marcelo!

Thanks for the thorough feedback!

  1. You have a good point. "less than" is the most commonly used term. I'll send a diff renaming the function (and the related lowerThanOrEquals).
  2. I like the idea. Indeed it can be repetitive when there are many signals with the same context. Let me think on where to surface a function like that.
  3. Rules work just like TypeScript expressions. And the operators that help combine them (rule.some(), rule.every(), rule.none()) are rules themselves, which makes them nestable. That example you provided works as intended. Or you could also make betweenSignal return a rule directly.
const betweenSignal = (min: number, max: number) =>
  rule.every([
    signals.amountInCents.greaterThanOrEquals(min),
    signals.amountInCents.lowerThan(max),
  ]);

const starbucksRule = rule.every([
  betweenSignal(300, 1000),
  signals.name.equals("Starbucks"),
]);
  1. Yeah, I should add an example on how to use async signals in the documentation. The intention is to delay data fetching to when the signal gets evaluated, which helps make the Context simpler. That way, some data won't even be fetched depending on how the rule evaluation goes. As an example, we could update your sample code to fetch transaction data from a database like this:
import { rule, signal } from "ruls";

type Transaction = { amountInCents: number; name: string };
type Context = { transactionId: number };

// Here you'd plug a real database
const transactionsDatabase = new Map([
  [123, { amountInCents: 500, name: "Starbucks" }],
  [246, { amountInCents: 200, name: "Starbucks" }],
]);
async function fetchTransaction(transactionId: number): Promise<Transaction> {
  const transaction = transactionsDatabase.get(transactionId);
  if (transaction == null) {
    throw new Error("Transaction not found");
  }
  return transaction;
}

const signals = {
  amountInCents: signal.number.value<Context>(
    async ({ transactionId }) =>
      (await fetchTransaction(transactionId)).amountInCents
  ),
  name: signal.string.value<Context>(
    async ({ transactionId }) => (await fetchTransaction(transactionId)).name
  ),
};


// ... same as before

(async () => {
  console.log(await isCoffeeTransaction(123)); // true
  console.log(await isCoffeeTransaction(246)); // false
})();

(in the process of coming up with this example I found a bug on type checking async signals, which I'll also patch)

Keep the questions coming and I can help make things clearer! I'm also curious on your use case, so we can look for further opportunities to improve the developer experience. Thanks!

from ruls.

MarceloPrado avatar MarceloPrado commented on May 29, 2024

That's great André! I'm sure there will be moref feedback, I'll keep them coming 🙂. The idea is awesome, and something that's lacking in the community. I've briefly prototyped ruls and json-rules-engine and ruls's API feels so much nicer - great work so far!

My use case is kind of neat. I'm building a personal finance app that enables users to create rules to match their transactions. While I've modeled my own engine at the API level, I also need an interpreter. I could try building my own, but it seems the goals of ruls are similar to mines (for instance, being fully type safe). For the time being, I'll try building an interpreter around ruls.

Thanks for the between idea, love it!

There's one other thing you might be able to help - I'm having a hard time with the encoder. I cannot make the encode function to pass:
CleanShot 2023-07-01 at 08 44 58@2x

This is the code I'm using

import { rule, signal } from "ruls";

type Context = {
  transaction: { amountInCents: number; name: string };
};

const signals = {
  amountInCents: signal.number.value<Context>(
    (ctx) => ctx.transaction.amountInCents
  ),
  name: signal.string.value<Context>(({ transaction }) => transaction.name),
};

const betweenSignal = (min: number, max: number) =>
  rule.every([
    signals.amountInCents.greaterThanOrEquals(min),
    signals.amountInCents.lowerThan(max),
  ]);

const starbucksRule = rule.every([
  betweenSignal(300, 1000),
  signals.name.equals("Starbucks"),
]);

const philzCoffeeRule = rule.every([
  betweenSignal(300, 1000),
  signals.name.equals("Philz Coffee"),
]);

const ruleDef = rule.some([starbucksRule, philzCoffeeRule]);

/**
 * A coffee transaction is a transaction between $3 and $10 at Starbucks or
 * Philz Coffee
 */
export const isCoffeeTransaction = async (transaction: {
  amountInCents: number;
  name: string;
}) => await ruleDef.evaluate({ transaction });

export const encode = () => ruleDef.encode(signals);

I've copied the progammers example from your docs and it worked. However, I don't understand what am I doing wrong here. Any ideas?

from ruls.

Related Issues (3)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.