Queries for Observables: Crazy & Simple!
Tags: rxjs, angular, react, webdev
Published: 2020-10-07 13:57:10

In the previous post we explored API to select events from streams using RegExp-like syntax, e.g.:

```ts
const D = fromEvent(element, 'mousedown');
const M = fromEvent(document, 'mousemove');
const U = fromEvent(document, 'mouseup');

exec(
  'DM*U'         // <- regular expression
  , { D, M, U }  // <- streams that will be used
)
  .pipe(…)
  .subscribe(console.log);
```

In this post we'll review it's functional API counterpart:

```ts
query(D, some(M), U) // select some Ms between Ds and Us
  .pipe(…)
  .subscribe(console.log)
```

But first, we'll recap the thought process. If you're already familiar with the idea — [hop here](#solution)

**tl;dr:** package @ https://github.com/erql/rx-rql 📦

## 💡 Recap the idea

Imagine we need to implement a drag-n-drop behavior.

For that, we have three event streams: `mousemove$`, `mousedown$`, `mouseup$`. So we want to capture `mousemove$` events after `mousedown$` emitted and before `mouseup$`.

Let's draw a marble diagram of the event streams we have:

```js
mousedown$  --o------------
mousemove$  -o-o-o-o-o-o-o-
mouseup$    ------------o--
```

<figcaption>Every event stream is represented with separate line.<br/><code>o</code> stands for event on the stream. <code>-</code> is a separator to represent passing time</figcaption>

For better readability let's substitute all the `o`s to respective letters of the streams:

```js
mousedown$  --d------------
mousemove$  -m-m-m-m-m-m-m-
mouseup$    ------------u--
```

<figcaption>'d' will now stand for mouse-down event, 'm' for mouse-move, 'u' for mouse-up</figcaption>

Now that we have distinct event names, we can simplify our diagram to a single line of events:

```js
events$     -mdm-m-m-m-mum-
```

Let's remove the time `-` signs as well, we don't them:

```js
events$      mdmmmmmum
```

Okay, to rephrase our task in terms of the new diagram: we need to capture the `m` events between `d` and `u` emissions.

## 🤔

Hmm...

> "we need `m`s between `d` and `u`"...

Sounds familiar...

Ah! If that was a string, we could easily do it with a regular expression:

```js
/dm*u/.exec('mdmmmum')
```

Would give us the needed `dmmmu` without trailing mouse-move `m` events...

Right?

If only we had a library to select events from streams with regexes...

## 🚀 Solution

```ts
query(D, some(M), U)
  .pipe(…)
  .subscribe(console.log)
```

**[Rx-RQL](https://github.com/erql/rx-rql)** 📦 package provides following API to make such selections:

- `query(…)` — root of your selection
- `A` — select 1 emission from the stream
- `some(A)` — select 0 to ∞ emissions from A
- `maybe(A)` — select 0 or 1 emission from A
- `many(n,m)(A)` — select from n to m emissions from A
- `mute(A)`  — select emission from A & mute it

And you can group them as you like:

- `some(A, some(B), mute(C))` — select as many emissions from: select as many Bs as possible between emissions from A and muted C

Here's how to create a simple drag-n-drop behavior using this package:

{% stackblitz rx-rql %}

And here's a **[Mr. Potato-Head DnD](https://stackblitz.com/edit/rx-rql-mr-potato-head?file=index.ts)** 🥔 — a more sophisticated example based on [this amazing article](https://dev.to/dailydevtips1/vanilla-javascript-draggable-mr-potato-head-e5g) by @dailydevtips1 ! Thx, Chris 🙏

## 👋 Outro

**Thank you for reading this article! Stay reactive and have a nice day 🙂**

If you enjoyed reading — please, indicate that with ❤️ 🦄 📘 buttons

And in case you're not yet following me here and on [twitter](https://twitter.com/kddsky) — then **you've probably missed** my recent experiments: [Rx + Proxy](https://dev.to/rxjs/turn-a-stream-of-objects-into-an-object-of-streams-2aed), [Rx Autorun](https://twitter.com/kddsky/status/1309840969072807936), [React + Rx](https://dev.to/rxjs/fetching-data-in-react-with-rxjs-and-lt-gt-fragment-54h7)

{% twitter 1313544826558783488 %}

Now I'd love to hear your thoughts! 👂