function countUnique()

in packages/sqrl-redis-functions/src/CountUniqueFunctions.ts [201:335]


    function countUnique(state: CompileState, ast: CustomCallAst): Ast {
      const args: CountUniqueArguments = parse(ast.source, {
        startRule: "CountUniqueArguments",
      });
      const { whereAst, whereFeatures, whereTruth } = state.combineGlobalWhere(
        args.where
      );

      const sortedUniques: AliasedFeature[] = sortByAlias(args.uniques);
      const sortedGroup: AliasedFeature[] = sortByAlias(args.groups);

      const uniquesAst = AstBuilder.list(sortedUniques.map((f) => f.feature));
      const windowMsAst = AstBuilder.constant(args.windowMs);

      const groupAliases = args.groups.map((feature) => feature.alias);
      const groupFeatures = args.groups.map((feature) => feature.feature.value);
      const groupHasAliases = args.groups.some(
        (f) => f.feature.value !== f.alias
      );
      const sortedGroupAliases = sortedGroup.map((feature) => feature.alias);

      const { entityId, entityAst } = state.addHashedEntity(
        ast,
        "UniqueCounter",
        {
          groups: sortedGroupAliases,
          uniques: sortedUniques.map((feature) => feature.alias),

          // Only include the where clauses if they're non-empty
          ...(whereTruth ? { whereFeatures, whereTruth } : {}),
        }
      );

      const originalKeysAst = state.setGlobal(
        ast,
        AstBuilder.call("_getKeyList", [
          entityAst,
          ...groupAliases.map((alias) => AstBuilder.feature(alias)),
        ]),
        `key(${entityId.getIdString()})`
      );

      // Always bump the counter according to the original keys (aliases)
      const slotAst = state.setGlobal(
        ast,
        AstBuilder.call("_bumpCountUnique", [
          AstBuilder.branch(
            whereAst,
            originalKeysAst,
            AstBuilder.constant(null)
          ),
          uniquesAst,
          windowMsAst,
        ])
      );
      state.addStatement("SqrlCountUniqueStatements", slotAst);

      let keysAst = originalKeysAst;
      let countExtraUniques: Ast = AstBuilder.branch(
        AstBuilder.and([whereAst, AstBuilder.feature("SqrlIsClassify")]),
        uniquesAst,
        AstBuilder.constant([])
      );

      if (groupHasAliases) {
        keysAst = state.setGlobal(
          ast,
          AstBuilder.call("_getKeyList", [
            entityAst,
            ...groupFeatures.map((feature) => AstBuilder.feature(feature)),
          ]),
          `key(${entityId.getIdString()}:${groupFeatures.join(",")})`
        );

        // If we're using aliases we only count the uniques in this request if
        // they exactly match the aliases that we used
        const aliasesEqualAst = AstBuilder.call("_cmpE", [
          AstBuilder.list(
            groupAliases.map((alias) => AstBuilder.feature(alias))
          ),
          AstBuilder.list(
            groupFeatures.map((feature) => AstBuilder.feature(feature))
          ),
        ]);
        countExtraUniques = AstBuilder.branch(
          aliasesEqualAst,
          countExtraUniques,
          AstBuilder.constant([])
        );
      }

      if (args.beforeAction) {
        countExtraUniques = AstBuilder.constant([]);
      }

      const originalCall = AstBuilder.call("_fetchCountUnique", [
        keysAst,
        windowMsAst,
        countExtraUniques,
      ]);

      if (args.setOperation) {
        throw new Error("@todo setOperation transform");
        /*
      const { operation, features } = args.setOperation;
      const rightCountArgs = Object.assign({}, args, {
        groups: features,
        setOperation: null
      });

      const rightCall = state._wrapped.transform(
        Object.assign({}, ast, {
          args: [rightCountArgs, ...ast.args.slice(1)]
        })
      );

      let setFunction;
      if (operation === "intersect") {
        setFunction = "_intersectCountUnique";
      } else if (operation === "union") {
        setFunction = "_unionCountUnique";
      } else {
        throw new Error("Unknown set operation: " + operation);
      }

      return AstBuilder.call(setFunction, [
        Object.assign({}, originalCall, {
          func: "_fetchCountUniqueElements"
        }),
        Object.assign({}, rightCall, { func: "_fetchCountUniqueElements" })
      ]);*/
      }

      return originalCall;
    },