<commit_before>"use strict";

import m from "mithril";
import Filter from "../common/filter";
import * as config from "./config";
import * as filterParser from "../common/filter-parser";

let fulfillTimestamp = 0;

let unpackedFiltersCache = new WeakMap();
let expressionsCache = new WeakMap();

const queries = {
  filter: new WeakMap(),
  last: new WeakMap(),
  limit: new WeakMap(),
  fulfilled: new WeakMap(),
  fulfilling: new WeakSet(),
  mapper: new WeakMap(),
  accessed: new WeakMap(),
  value: new WeakMap()
};

const resources = {};
for (let r of ["devices", "faults"])
  resources[r] = {
    objects: new Map(),
    count: new Map(),
    fetch: new Map(),
    combinedFilter: null
  };

class QueryResponse {
  get fulfilled() {
    queries.accessed.set(this, Date.now());
    return !!queries.fulfilled.get(this);
  }

  get value() {
    queries.accessed.set(this, Date.now());
    const mapper = queries.mapper.get(this);
    const value = queries.value.get(this);

    if (mapper) return mapper(queries.value.get(this));
    else return value;
  }
}

function unpackFilter(filter) {
  let f = unpackedFiltersCache.get(filter);
  if (!f) {
    f = f.evaluateExpressions(fulfillTimestamp);
    unpackedFiltersCache.set(filter, f);
  }
  return f;
}

function count(resourceType, filter) {
  let queryResponse = resources[resourceType].count.get(filter.toString());
  if (queryResponse) return queryResponse;

  queryResponse = new QueryResponse();

  resources[resourceType].count.set(filter.toString(), queryResponse);
  queries.filter.set(queryResponse, filter);
  return queryResponse;
}

function limitFilter(resourceType, filter, last) {
  if (resourceType === "devices")
    return filter.and(new Filter(["<=", "DeviceID.ID", last]));
  else return filter.and(new Filter(["<=", "_id", last]));
}

function findMatches(resourceType, filter, limit) {
  let value = [];
  for (let [id, obj] of resources[resourceType].objects.entries())
    if (filter.test(obj)) value.push(id);

  value = value.sort();
  if (limit) value = value.slice(0, limit);

  return value;
}

function inferQuery(resourceType, queryResponse) {
  const limit = queries.limit.get(queryResponse);<commit_msg>Fix special case filter by tag<commit_after>"use strict";

import m from "mithril";
import Filter from "../common/filter";
import * as config from "./config";
import * as filterParser from "../common/filter-parser";

let fulfillTimestamp = 0;

let unpackedFiltersCache = new WeakMap();
let expressionsCache = new WeakMap();

const queries = {
  filter: new WeakMap(),
  last: new WeakMap(),
  limit: new WeakMap(),
  fulfilled: new WeakMap(),
  fulfilling: new WeakSet(),
  mapper: new WeakMap(),
  accessed: new WeakMap(),
  value: new WeakMap()
};

const resources = {};
for (let r of ["devices", "faults"])
  resources[r] = {
    objects: new Map(),
    count: new Map(),
    fetch: new Map(),
    combinedFilter: null
  };

class QueryResponse {
  get fulfilled() {
    queries.accessed.set(this, Date.now());
    return !!queries.fulfilled.get(this);
  }

  get value() {
    queries.accessed.set(this, Date.now());
    const mapper = queries.mapper.get(this);
    const value = queries.value.get(this);

    if (mapper) return mapper(queries.value.get(this));
    else return value;
  }
}

function unpackFilter(filter) {
  let f = unpackedFiltersCache.get(filter);
  if (!f) {
    f = f.evaluateExpressions(fulfillTimestamp);
    unpackedFiltersCache.set(filter, f);
  }
  return f;
}

function count(resourceType, filter) {
  let queryResponse = resources[resourceType].count.get(filter.toString());
  if (queryResponse) return queryResponse;

  queryResponse = new QueryResponse();

  resources[resourceType].count.set(filter.toString(), queryResponse);
  queries.filter.set(queryResponse, filter);
  return queryResponse;
}

function limitFilter(resourceType, filter, last) {
  if (resourceType === "devices")
    return filter.and(new Filter(["<=", "DeviceID.ID", last]));
  else return filter.and(new Filter(["<=", "_id", last]));
}

function findMatches(resourceType, filter, limit) {
  // Handle "tag =" and "tag <>" special cases
  if (resourceType === "devices" && filter.ast) {
    const ast = filterParser.map(filter.ast, e => {
      if (e[1] === "tag")
        if (e[0] === "=") return ["=", `Tags.${e[2]}`, true];
        else if (e[0] === "<>") return ["NOT", ["=", `Tags.${e[2]}`, true]];
    });
    filter = new Filter(ast);
  }

  let value = [];
  for (let [id, obj] of resources[resourceType].objects.entries())
    if (filter.test(obj)) value.push(id);

  value = value.sort();
  if (limit) value = value.slice(0, limit);

  return value;
}

function inferQuery(resourceType, queryResponse) {
  const limit = queries.limit.get(queryResponse);
{'fraction_non_alphanumeric': 0.16044463087248323, 'fraction_numerical': 0.0018875838926174498, 'mean_word_length': 4.144552319309601, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 6, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3572910', 'n_tokens_mistral': 1532, 'n_tokens_neox': 1506, 'n_words': 400}