<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sergii Stotskyi</title>
    <description>The latest articles on DEV Community by Sergii Stotskyi (@stalniy).</description>
    <link>https://dev.to/stalniy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F369049%2Ff35a5bc7-4943-438f-ab8d-83d4057e951b.jpeg</url>
      <title>DEV Community: Sergii Stotskyi</title>
      <link>https://dev.to/stalniy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stalniy"/>
    <language>en</language>
    <item>
      <title>CASL. Pursuing Perfection II: New Engine</title>
      <dc:creator>Sergii Stotskyi</dc:creator>
      <pubDate>Mon, 09 Nov 2020 22:25:32 +0000</pubDate>
      <link>https://dev.to/stalniy/casl-pursuing-perfection-ii-new-engine-3a8e</link>
      <guid>https://dev.to/stalniy/casl-pursuing-perfection-ii-new-engine-3a8e</guid>
      <description>&lt;p&gt;This is the second part in the series of articles where I share my experience building and optimizing CASL v5:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/stalniy/casl-pursuing-perfection-i-why-2j2c"&gt;CASL. Pursuing Perfection I: Why?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CASL. Pursuing Perfection II: New Engine&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;CASL. Pursuing Perfection III: Big O&lt;/li&gt;
&lt;li&gt;CASL. Pursuing Perfection IV: Type Safety&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First time you've heard about CASL? You may want to read "&lt;a href="https://casl.js.org/v4/en/guide/intro"&gt;What is CASL?&lt;/a&gt;".&lt;/p&gt;

&lt;p&gt;As I said in the previous article, to support SQL databases, CASL needed a new checking engine which can evaluate conditions in runtime and can transform them into any database query language. And &lt;strong&gt;this is why &lt;a href="https://github.com/stalniy/ucast"&gt;UCAST&lt;/a&gt; was born!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But, let's get deeper into what UCAST actually is&lt;/p&gt;

&lt;h2&gt;
  
  
  The harness
&lt;/h2&gt;

&lt;p&gt;So, the task is &lt;strong&gt;to translate any language to any other language&lt;/strong&gt;. Doesn't it sound familiar? Think for a moment, please.&lt;/p&gt;

&lt;p&gt;If we ask Wikipedia &lt;a href="https://en.wikipedia.org/wiki/Compiler"&gt;"What is compiler?"&lt;/a&gt;, we get:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In computing, a compiler is a computer program that &lt;strong&gt;translates computer code written in one programming language&lt;/strong&gt; (the source language) &lt;strong&gt;into another language&lt;/strong&gt; (the target language).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Aha! The task converts  to writing a compiler that can translate MongoDB into JavaScript and SQL. There is a lot of theory around compilers, I knew I could read some of it but it would take a lot of time which I didn't have. That's why I used Wikipedia as a reference :)&lt;/p&gt;

&lt;p&gt;So, according to Wikipedia:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A compiler is likely to perform many or all of the following operations: &lt;strong&gt;preprocessing, lexical analysis, parsing, semantic analysis&lt;/strong&gt; (syntax-directed translation), &lt;strong&gt;conversion of input programs to an intermediate representation, code optimization and code generation&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Quite a lot right? Hopefully, not all are necessary. The most &lt;strong&gt;3 important operations&lt;/strong&gt; we need to concentrate at is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;parsing&lt;/li&gt;
&lt;li&gt;conversion of input programs to an intermediate representation, usually &lt;a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree"&gt;&lt;strong&gt;A&lt;/strong&gt;bstract &lt;strong&gt;S&lt;/strong&gt;yntax &lt;strong&gt;T&lt;/strong&gt;ree (AST)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;code generation or AST interpreter (we do not always need to generate another code)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, to translate MongoDB query to something else, it needs to be parsed into an intermediate representation (i.e., AST) which later can be consumed by a code generator (or an interpreter) to do some useful work.&lt;/p&gt;

&lt;p&gt;And you know what? All these I've implemented in &lt;a href="https://github.com/stalniy/ucast#ecosystem"&gt;@ucast/* ecosystem&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstract Syntax Tree
&lt;/h2&gt;

&lt;p&gt;In spite of the somewhat complex naming, Abstract Syntax Tree is a regular &lt;a href="https://en.wikipedia.org/wiki/Tree_(data_structure)"&gt;tree data structure&lt;/a&gt; of objects that contain information about parsed language.&lt;/p&gt;

&lt;p&gt;There are 3 classes in &lt;a href="https://github.com/stalniy/ucast/tree/master/packages/core"&gt;@ucast/core&lt;/a&gt; package that is used to represent any boolean condition in AST:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;FieldCondition&lt;/code&gt; represents a condition based on an object's field and operator (e.g., &lt;code&gt;x === 3&lt;/code&gt; or &lt;code&gt;{ x: 3 }&lt;/code&gt; in terms of MongoDB)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DocumentCondition&lt;/code&gt; represents condition that restricts a document or a row as whole (e.g., &lt;code&gt;$where&lt;/code&gt; operator in MongoDB query language and &lt;code&gt;EXISTS&lt;/code&gt; in SQL)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CompoundCondition&lt;/code&gt; represents a compound boolean operation (e.g., logical "and", "or", etc). This one aggregates other conditions in itself what allows us to represent complex expressions such as
&lt;code&gt;(x === 5 &amp;amp;&amp;amp; x &amp;lt; 2) || (y &amp;gt; 0 &amp;amp;&amp;amp; status === "available")&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  MongoDB query Parser
&lt;/h2&gt;

&lt;p&gt;As we already know, the responsibility of parser is to transform code into AST. And this is exactly what &lt;code&gt;MongoQueryParser&lt;/code&gt; class from &lt;code&gt;@ucast/mongo&lt;/code&gt; package does. Basically, the result of its work of is a tree of &lt;code&gt;FieldCondition&lt;/code&gt;, &lt;code&gt;DocumentCondition&lt;/code&gt; and &lt;code&gt;CompoundCondition&lt;/code&gt; objects. The really cool thing which I like about this class is that it's composite and consists of parsing instructions that allows us to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;To implement custom operators and extend our own MongoDB-like query language.&lt;/li&gt;
&lt;li&gt;To restrict what operators can be used in our MongoDB-like query language, to prevent usage of complex conditions.&lt;/li&gt;
&lt;li&gt;To use only pieces we need and get rid of unused code using JavaScript bundlers (e.g., rollup, webpack).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s see a working example to understand how it works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MongoQueryParser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$eq&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ucast/mongo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;MongoQueryParser&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;$eq&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;authorId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The parser above can parse only &lt;code&gt;$eq&lt;/code&gt; operator, so if you try to use &lt;code&gt;$lt&lt;/code&gt; for example, it will throw an error. The produced result is a single object of &lt;code&gt;FieldCondition&lt;/code&gt; type with &lt;code&gt;eq&lt;/code&gt; operator. &lt;code&gt;$eq&lt;/code&gt; is actually a special operator which you need to pass in order to use POJO style query.&lt;/p&gt;

&lt;p&gt;To learn more about MongoDB query parser, its optimization logic and customization, please refer to the &lt;a href="https://github.com/stalniy/ucast/tree/master/packages/mongo#getting-started"&gt;&lt;strong&gt;README file of @ucast/mongo&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interpreter or Code Generator?
&lt;/h2&gt;

&lt;p&gt;UCAST uses word "interpreter" instead of "code generator" as it more clearly explains its purpose. For example, it may interpret it into JavaScript boolean value or into another language.&lt;/p&gt;

&lt;p&gt;There are 2 packages that implements interpreter interface:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/stalniy/ucast/blob/master/packages/js"&gt;@ucast/js&lt;/a&gt; converts AST into boolean value&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/stalniy/ucast/blob/master/packages/sql"&gt;@ucast/sql&lt;/a&gt; converts AST into SQL string (also provides integration with major ORM libraries through sub modules)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An interpreter is designed in very similar way to a parser but instead of using parsing instructions, it consists of more granular interpreters (1 per operator). Frankly speaking, &lt;strong&gt;an interpreter is just a pure function that is composed of other pure functions&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createJsInterpreter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;gt&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ucast/js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;interpret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createJsInterpreter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;gt&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Later, we can use this function to interpret AST into boolean value. So, to mimic &lt;a href="https://github.com/crcn/sift.js"&gt;sift.js&lt;/a&gt; functionality all we need to do is to compose MongoDB query parser and JavaScript interpreter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MongoQueryParser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;allParsingInstructions&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ucast/mongo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createJsInterpreter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;allInterpreters&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ucast/js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;MongoQueryParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;allParsingInstructions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;interpret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createJsInterpreter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;allInterpreters&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;authorId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;published&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interpret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;authorId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;published&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interpret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;authorId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;published&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To reduce boilerplate of building MongoDB query language JavaScript runtime interpreter, I created a separate @ucast/mongo2js package which do this for us. &lt;a href="https://github.com/stalniy/ucast/tree/master/packages/mongo2js"&gt;&lt;strong&gt;@ucast/mongo2js&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;is a drop-in replacement for sift.js and actually used by casl v5 to evaluate conditions in runtime!&lt;/strong&gt; Moreover, it &lt;strong&gt;speeds up conditions evaluation by ~2x times!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The only difference between @ucast/mongo2js and sift.js is how they interpret equal operation on objects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;guard&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ucast/mongo2js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;sift&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sift&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;guard&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sifter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sift&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sifter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, UCAST doesn’t check deep equality of objects but this can be changed by creating a custom &lt;code&gt;guard&lt;/code&gt; function and custom &lt;code&gt;compare&lt;/code&gt; function.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Refer to documentation of &lt;a href="https://github.com/stalniy/ucast/tree/master/packages/js"&gt;@ucast/js&lt;/a&gt; and &lt;a href="https://github.com/stalniy/ucast/tree/master/packages/mongo2js"&gt;@ucast/mongo2js&lt;/a&gt; for more details&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Usually, you don’t even need such capability because it can be rephrased using dot notation which is supported by ucast as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;guard&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;author.id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sifter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sift&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;author.id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sifter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;All UCAST packages are written in TypeScript&lt;/strong&gt;, so you additionally get type safety and hints in your IDE.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;UCAST ecosystem is not only fast, lightweight but also very powerful! By implementing different parsers and interpreters, &lt;strong&gt;we can achieve outstanding results by combining one parser with different interpreters and many parsers with one interpreter.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example, by implementing &lt;a href="https://json-schema.org/"&gt;json-schema&lt;/a&gt; parser, we will be able to reuse existing interpreters and convert the result either to JavaScript boolean value or SQL query or MongoDB query or Cassandra query or REST query or GraphQL query or any query language you can imagine!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you feel about that?&lt;/strong&gt; I’m excited.&lt;/p&gt;




&lt;p&gt;Did I deserve &lt;a href="https://opencollective.com/casljs/contribute/barista-13740/checkout"&gt;a cup of coffee&lt;/a&gt;?&lt;/p&gt;




&lt;p&gt;In the next article, I'll explain what JavaScript optimization technics allowed me to optimize Ability creation &lt;strong&gt;by more than 15x times&lt;/strong&gt;! Stay tuned!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>casl</category>
      <category>ucast</category>
    </item>
    <item>
      <title>CASL. Pursuing Perfection I: Why?</title>
      <dc:creator>Sergii Stotskyi</dc:creator>
      <pubDate>Wed, 28 Oct 2020 06:27:35 +0000</pubDate>
      <link>https://dev.to/stalniy/casl-pursuing-perfection-i-why-2j2c</link>
      <guid>https://dev.to/stalniy/casl-pursuing-perfection-i-why-2j2c</guid>
      <description>&lt;p&gt;This is the first part in the series of articles where I plan to share my experience building and optimizing CASL v5:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CASL. Pursuing Perfection I: Why?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/stalniy/casl-pursuing-perfection-ii-new-engine-3a8e"&gt;CASL. Pursuing Perfection II: New Engine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;CASL. Pursuing Perfection III: Big O&lt;/li&gt;
&lt;li&gt;CASL. Pursuing Perfection IV: Type Safety&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First time you've heard about CASL? You may want to read "&lt;a href="https://casl.js.org/v4/en/guide/intro"&gt;What is CASL?&lt;/a&gt;".&lt;/p&gt;

&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/stalniy/casl/issues/8"&gt;The long standing issue&lt;/a&gt; regarding SQL integration was created 2 months after the initial CASL's release and was not addressed for years. To understand why and why it was a challenge, we need to go back to the days when CASL was designed.&lt;/p&gt;

&lt;h3&gt;
  
  
  A bit of history
&lt;/h3&gt;

&lt;p&gt;CASL was heavily inspired by &lt;a href="https://github.com/ryanb/cancan"&gt;cancan ruby gem&lt;/a&gt;. This gem provides 3 ways to define conditions for rules: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;hash maps, \
can be used for runtime checks and can be transformed to SQL query&lt;/li&gt;
&lt;li&gt;ruby blocks, \
similar to lambdas in other languages, only runtime checks&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ActiveRecord::Relation&lt;/code&gt; and raw SQL queries&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Why CASL did not inherited the name of "cancan" is a different story but if you are curious, just read &lt;a href="https://github.com/vadimdemedes/cancan/issues/28"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Values in hash maps are interpreted as "equal" operation, so &lt;code&gt;{ author_id: 1 }&lt;/code&gt; is transformed to &lt;code&gt;post.author_id == 1&lt;/code&gt; in runtime and to &lt;code&gt;author_id = 1&lt;/code&gt; in SQL.&lt;/p&gt;

&lt;p&gt;At that time, I worked with MongoDB and our use-cases were a bit more complex. MongoDB itself allows to store and query a bit more complex data structures than SQL databases (before JSON data type). That's why I decided to use MongoDB query language to define conditions for permissions. But there was another issue: I needed a way to interpret MongoDB in JavaScript. &lt;/p&gt;

&lt;p&gt;And &lt;strong&gt;thanks to &lt;a href="https://github.com/crcn/sift.js"&gt;sift.js&lt;/a&gt;&lt;/strong&gt;, library that evaluates MongoDB conditions in runtime, the issue was pretty easy to solve :)&lt;/p&gt;

&lt;p&gt;Eventually, sift.js was used to interpret conditions in JavaScript and the same conditions, without additional processing were used to query the database. &lt;/p&gt;

&lt;p&gt;As I said, there was no additional preprocessing and it was the main reason why there was no official SQL support.&lt;/p&gt;

&lt;h3&gt;
  
  
  So, no SQL at all?
&lt;/h3&gt;

&lt;p&gt;Frankly speaking, &lt;strong&gt;there is a possibility to use CASL with SQL&lt;/strong&gt; databases thanks to &lt;a href="https://sequelize.org/"&gt;sequelize&lt;/a&gt; which accepts "where" conditions that are pretty similar to MongoDB query language. This works pretty well even today but only for cases when all the data required to check conditions is in a single table.&lt;/p&gt;

&lt;p&gt;But as soon as you try to define permissions base on a related table, you are on your own because there is no custom operators support, no AST and no all that stuff which is required for transforming languages from one to another.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finally. Solution
&lt;/h2&gt;

&lt;p&gt;To add better SQL support, I decided to go the same road and ask Craig to implement it :) The details of our conversion can be found in &lt;a href="https://github.com/crcn/sift.js/pull/204"&gt;this PR&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Craig is the author of sift.js library and I'd like to say a "Big Thank You" for his awesome work!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unfortunately, due to how sift.js was internally implemented there was no easy way to change it to the form that would satisfy CASL's requirements. Also a lack of free time didn't allow us to work together effectively.&lt;/p&gt;

&lt;p&gt;That's why I decided to implement my own MongoDB query language interpreter, &lt;strong&gt;an interpreter that allows us to use CASL not only with MongoDB but also with SQL, ElasticSearch, Cassandra&lt;/strong&gt; and actually whatever is required for your business case!&lt;/p&gt;

&lt;h3&gt;
  
  
  Universal Conditions AST (UCAST)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/stalniy/ucast"&gt;UCAST&lt;/a&gt; is a new conditions checking engine which was specifically implemented for CASL v5. Despite that fact, it can be used on its own and &lt;strong&gt;its goal is to interpret any conditions to any language&lt;/strong&gt;. Some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;to transform MongoDB to JavaScript boolean value. In other words, interpret MongoDB conditions in JavaScript runtime on Plain Old JavaScript Objects &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;transform MongoDB to SQL!&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;transform &lt;a href="https://json-schema.org/"&gt;json-schema&lt;/a&gt; to SQL&lt;/li&gt;
&lt;li&gt;transform MongoDB query to json-schema and vice-versa&lt;/li&gt;
&lt;li&gt;transform an HTTP request to a MongoDB or SQL query&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hopefully, now it's clear that it provides a way &lt;strong&gt;to transform X query to Y query or interpret X query in JavaScript&lt;/strong&gt;. How do you feel about this? I'm excited!&lt;/p&gt;

&lt;h2&gt;
  
  
  Free Perks
&lt;/h2&gt;

&lt;p&gt;Additionally to database polyglot ability, UCAST makes CASL v5 to check permissions based on attributes in &lt;strong&gt;~2 times faster than in v4&lt;/strong&gt;! This was the reason which inspired me to further optimize performance in CASL but this is another story.&lt;/p&gt;

&lt;p&gt;If you would like to test this yourself, please use the latest &lt;a href="https://github.com/stalniy/casl/releases/tag/%40casl%2Fability%405.1.0-next.9"&gt;@casl/ability@5.1.0-next.9&lt;/a&gt; pre-release version.&lt;/p&gt;




&lt;p&gt;Did I deserve &lt;a href="https://opencollective.com/casljs/contribute/barista-13740/checkout"&gt;a cup of coffee&lt;/a&gt;?&lt;/p&gt;




&lt;p&gt;More about ucast, compilers and performance improvements, you will find in the next article. Stay tuned!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>acl</category>
      <category>casl</category>
    </item>
    <item>
      <title>CASL 4.0. — What’s inside?</title>
      <dc:creator>Sergii Stotskyi</dc:creator>
      <pubDate>Sat, 18 Apr 2020 14:08:42 +0000</pubDate>
      <link>https://dev.to/stalniy/casl-4-0-what-s-inside-2cj2</link>
      <guid>https://dev.to/stalniy/casl-4-0-what-s-inside-2cj2</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;First time you’ve heard about&lt;/em&gt; &lt;a href="https://github.com/stalniy/casl" rel="noopener noreferrer"&gt;&lt;em&gt;CASL&lt;/em&gt;&lt;/a&gt;&lt;em&gt;? You may want to read “&lt;/em&gt;&lt;a href="https://stalniy.github.io/casl/v4/en/guide/intro" rel="noopener noreferrer"&gt;&lt;em&gt;What is CASL?&lt;/em&gt;&lt;/a&gt;&lt;em&gt;”.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’m glad to announce that &lt;strong&gt;CASL 4.0 was released few days ago&lt;/strong&gt; and brought several powerful possibilities on our desk:&lt;/p&gt;

&lt;h1&gt;
  
  
  Type Safety
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;@casl/*&lt;/code&gt; packages were rewritten to &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt;. This makes your apps safer and developer experience more enjoyable. Let’s see how:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I know I know… I was one of those skeptics who have never liked TypeScript until recent time. It’s really powerful now, especially inference logic!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Starting from 4.0 &lt;code&gt;Ability&lt;/code&gt; class accepts 2 generic parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  application abilities (actions defined for subjects)&lt;/li&gt;
&lt;li&gt;  conditions shape&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This allows you restrict what actions can be applied on specified subjects. For example, in a blog app which has &lt;code&gt;Article&lt;/code&gt;, &lt;code&gt;Comment&lt;/code&gt;, and &lt;code&gt;User&lt;/code&gt; entities, logged in user can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;create&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;delete&lt;/code&gt; &lt;code&gt;Article&lt;/code&gt;s&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;create&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt; &lt;code&gt;Comment&lt;/code&gt;s&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;read&lt;/code&gt; other &lt;code&gt;User&lt;/code&gt;s&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And we can express this as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Ability&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@casl/ability&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;AppAbilities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;read&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;update&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;create&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Article&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Comment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;AppAbility&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Ability&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AppAbilities&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or even stricter&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Ability&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@casl/ability&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;AppAbilities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;create&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;read&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;update&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Article&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;create&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;read&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;update&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Comment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;read&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;AppAbility&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Ability&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AppAbilities&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows TypeScript to check that you don’t make a typo in action or subject name at compile time! Moreover, IDE (e.g., VSCode) will suggest possible options to choose from:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq2o2t5889a45q843vlmj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq2o2t5889a45q843vlmj.png" alt="CASL Typescript VSCode hints"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This types hints works even in your favorite frontend libraries, thanks to complementary packages! So, you will get hints for React’s &lt;code&gt;Can&lt;/code&gt; component and Vue’s &lt;code&gt;$can&lt;/code&gt; function in templates. The nice thing about VSCode is that it uses typescript definition files even for JavaScript files, so you will get better IDE support for JavaScript apps as well. Isn’t that cool?&lt;/p&gt;

&lt;p&gt;To get more details about new &lt;a href="https://stalniy.github.io/casl/v4/en/advanced/typescript" rel="noopener noreferrer"&gt;TypeScript support in CASL&lt;/a&gt;, read about it in the &lt;a href="https://stalniy.github.io/casl/v4/en" rel="noopener noreferrer"&gt;docs&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Smaller library size
&lt;/h1&gt;

&lt;p&gt;The library is smaller, &lt;a href="https://bundlephobia.com/result?p=@casl/ability" rel="noopener noreferrer"&gt;~4.5KB mingzipped&lt;/a&gt; (together with sift.js!) and has better support for tree-shaking. This was achieved thanks to &lt;a href="https://github.com/terser/terser" rel="noopener noreferrer"&gt;terser.js minifier&lt;/a&gt; and several breaking changes that you can find in the &lt;a href="https://github.com/stalniy/casl/blob/master/packages/casl-ability/CHANGELOG.md#breaking-changes" rel="noopener noreferrer"&gt;CHANGELOG&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Starting from 4.0, there are classes that allows to create &lt;code&gt;Ability&lt;/code&gt; instance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;PureAbility&lt;/code&gt; base class that implements core logic&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;Ability&lt;/code&gt; that extends &lt;code&gt;PureAbility&lt;/code&gt; and configures it to use &lt;code&gt;mongoQueryMatcher&lt;/code&gt; and &lt;code&gt;fieldPatternMatcher&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This was done in order to be able to shake out &lt;code&gt;sift.js&lt;/code&gt; dependency in case you don’t use conditions at all or when you implement a custom matcher. As a result &lt;code&gt;AbilityBuilder&lt;/code&gt; now accepts Ability class as a first argument. By default, the argument is &lt;code&gt;PureAbility&lt;/code&gt;, so if you used &lt;code&gt;AbilityBuilder.extract&lt;/code&gt;, you will need to change it from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cannot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rules&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;AbilityBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  
&lt;span class="c1"&gt;// rule definitions  &lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ability&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Ability&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cannot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rules&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AbilityBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Ability&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="c1"&gt;// rule definitions  &lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ability&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Ability&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Customization
&lt;/h1&gt;

&lt;p&gt;In 4.0, you can customize &lt;code&gt;Ability&lt;/code&gt; instance behavior. Do you want to extend MongoDB query with custom operator, use &lt;a href="https://json-schema.org" rel="noopener noreferrer"&gt;json-schema&lt;/a&gt; or arrow functions as conditions? Not a problem anymore, just implement a custom &lt;code&gt;conditionsMatcher&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To get more in depth details, read &lt;a href="https://stalniy.github.io/casl/v4/en/advanced/customize-ability" rel="noopener noreferrer"&gt;Customize Ability&lt;/a&gt; in the docs.&lt;/p&gt;

&lt;h1&gt;
  
  
  Better subject type detection support
&lt;/h1&gt;

&lt;p&gt;If you use &lt;strong&gt;P&lt;/strong&gt;lain &lt;strong&gt;O&lt;/strong&gt;ld &lt;strong&gt;J&lt;/strong&gt;avaScript &lt;strong&gt;O&lt;/strong&gt;bjects as models, you have a simpler option to specify subject type now. No need to provide custom &lt;code&gt;detectSubjectType&lt;/code&gt; function (&lt;code&gt;subjectName&lt;/code&gt; option was renamed to &lt;code&gt;detectSubjectType&lt;/code&gt;), just use &lt;code&gt;subject&lt;/code&gt; helper:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineAbility&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;subject&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;an&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@casl/ability&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My article&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;ability&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;can&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;read&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;an&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Article&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// or&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;article&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;an&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Article&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;ability&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;can&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;read&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;article&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get better understanding of how CASL detect subject type, check &lt;a href="https://stalniy.github.io/casl/v4/en/guide/subject-type-detection" rel="noopener noreferrer"&gt;Subject Type Detection&lt;/a&gt; page.&lt;/p&gt;

&lt;h1&gt;
  
  
  Much better documentation
&lt;/h1&gt;

&lt;p&gt;Documentation was completely rewritten. First of all, now it’s a Single Page Application written on top of awesome &lt;a href="https://lit-html.polymer-project.org/" rel="noopener noreferrer"&gt;lit-html&lt;/a&gt; and &lt;a href="https://lit-element.polymer-project.org" rel="noopener noreferrer"&gt;lit-element&lt;/a&gt; libraries (the final mingzipped size of the app is 47KB for modern browsers! It even somehow works in IE11). It’s available for offline usage, all documentation texts less than 1MB, so don’t worry it won’t take much of your disk :)&lt;/p&gt;

&lt;p&gt;Now it’s organized and easily extendable. It also tries to be beginner friendly and have cookbook and examples sections! Every complementary package now have a separate page with documentation for it, so you don’t need to look for README files through repository.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Future
&lt;/h1&gt;

&lt;p&gt;CASL gets more and more attraction from developers. This requires additional time to write new features, complementary packages, documentation and answering questions in &lt;a href="https://gitter.im/stalniy-casl/casl" rel="noopener noreferrer"&gt;gitter chat&lt;/a&gt;. Besides doing my best to do all of this, I need to use my unique talents to fill important roles for the organization, otherwise my wife would expel me a long time ago ;)&lt;/p&gt;

&lt;p&gt;I like CASL and like to contribute to Open Source. That’s why I’m seeking for a way to work more on Open Source projects. Thankfully, there are platforms that help to support people like me. And I’m thrilled to announce that&lt;a href="https://opencollective.com/casljs" rel="noopener noreferrer"&gt;&lt;strong&gt;CASL is now on Open Collective&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;!&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want to get more details about what Open Collective is, and you can contribute, please read &lt;a href="https://medium.com/@sergiy.stotskiy/sustaining-casl-js-development-c25628e7648b" rel="noopener noreferrer"&gt;Sustaining CASL development&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you have the same vision of the world, and you like CASL, your contributions are very welcome! You are not restricted to financial contributions, as usually you can just share CASL with your colleague from another project, help to answer questions in &lt;a href="https://gitter.im/stalniy-casl/casl" rel="noopener noreferrer"&gt;gitter chat&lt;/a&gt; and triage issues, share your examples of CASL integrations, and contribute code and documentation! Finally, you can become a core contributor and support CASL on regular basis.&lt;/p&gt;

&lt;h1&gt;
  
  
  How do I migrate?
&lt;/h1&gt;

&lt;p&gt;CASL has introduced several breaking changes in all &lt;code&gt;@casl/*&lt;/code&gt; packages, so &lt;strong&gt;please spend time&lt;/strong&gt; &lt;strong&gt;reading CHANGELOG.md&lt;/strong&gt; of the packages you use. You can find all changes (including breaking ones) in that file of each package in &lt;a href="https://github.com/stalniy/casl/tree/master/packages" rel="noopener noreferrer"&gt;casl repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you find any issues or something is unclear, please fill in &lt;a href="https://github.com/stalniy/casl/issues/new" rel="noopener noreferrer"&gt;an issue on github&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Where can I start as a beginner?
&lt;/h1&gt;

&lt;p&gt;As of now, CASL has quite good documentation, so start from the &lt;a href="https://stalniy.github.io/casl/v4/en/guide/intro" rel="noopener noreferrer"&gt;Guide&lt;/a&gt;. Then move to documentation for the frontend or backend package of your choice and read it. Later you can check existing articles that explains how to integrate CASL in popular frameworks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://medium.com/dailyjs/managing-user-permissions-in-angular-application-504c83752f83" rel="noopener noreferrer"&gt;Managing User Permissions in Angular application&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://medium.com/dailyjs/vue-acl-with-casl-781a374b987a" rel="noopener noreferrer"&gt;Vue ACL with CASL&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://medium.com/dailyjs/managing-user-permissions-in-your-react-app-a93a94ff9b40" rel="noopener noreferrer"&gt;Managing user permissions in React app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://medium.com/@sergiy.stotskiy/casl-based-authorization-in-aurelia-app-3e44c0fe1703" rel="noopener noreferrer"&gt;Permissions in Aurelia&lt;/a&gt; app&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://medium.com/@sergiy.stotskiy/authorization-with-casl-in-express-app-d94eb2e2b73b" rel="noopener noreferrer"&gt;Authorization in Expressjs app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://blog.feathersjs.com/authorization-with-casl-in-feathersjs-app-fd6e24eefbff" rel="noopener noreferrer"&gt;Easy API Authorization with CASL and Feathers&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Despite the fact, that they are a bit outdated, CASL was not changed much during its lifetime, so they are still relevant.&lt;/p&gt;




&lt;p&gt;Thanks for trusting CASL! I hope CASL made permission management in your app as easy as pie&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>acl</category>
      <category>casl</category>
    </item>
  </channel>
</rss>
