<commit_before>package finder

import (
	"bytes"
	"context"
	"fmt"
	"net/url"
	"sort"
	"strings"
	"time"

	"github.com/go-graphite/carbonapi/pkg/parser"
	"github.com/lomik/graphite-clickhouse/helper/clickhouse"
)

type TaggedTermOp int

const (
	TaggedTermEq       TaggedTermOp = 1
	TaggedTermMatch    TaggedTermOp = 2
	TaggedTermNe       TaggedTermOp = 3
	TaggedTermNotMatch TaggedTermOp = 4
)

type TaggedTerm struct {
	Key   string
	Op    TaggedTermOp
	Value string
}

type TaggedTermList []TaggedTerm

func (s TaggedTermList) Len() int {
	return len(s)
}
func (s TaggedTermList) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}
func (s TaggedTermList) Less(i, j int) bool {
	return s[i].Op < s[j].Op
}

type TaggedFinder struct {
	url   string             // clickhouse dsn
	table string             // graphite_tag table
	opts  clickhouse.Options // clickhouse query timeout
	body  []byte             // clickhouse response
}

func NewTagged(url string, table string, opts clickhouse.Options) *TaggedFinder {
	return &TaggedFinder{
		url:   url,
		table: table,
		opts:  opts,
	}
}

func TaggedTermWhere1(term *TaggedTerm) string {
	switch term.Op {
	case TaggedTermEq:
		return fmt.Sprintf("Tag1=%s", Qf("%s=%s", term.Key, term.Value))
	case TaggedTermNe:
		return fmt.Sprintf("Tag1!=%s", Qf("%s=%s", term.Key, term.Value))
		// @TODO: not in Tags
	case TaggedTermMatch:
		return fmt.Sprintf(
			"(Tag1 LIKE %s) AND (match(Tag1, %s))",
			Qf("%s=%%", term.Key),
			Qf("%s=%s", term.Key, term.Value),
		)

	case TaggedTermNotMatch:
		return fmt.Sprintf(
			"NOT ((Tag1 LIKE %s) AND (match(Tag1, %s)))",
			Qf("%s=%%", term.Key),
			Qf("%s=%s", term.Key, term.Value),
		)
		// @TODO: not in Tags
	default:
		return ""
	}
}

func TaggedTermWhereN(term *TaggedTerm) string {
	// arrayExists((x) -> %s, Tags)
	switch term.Op {
	case TaggedTermEq:
		return fmt.Sprintf("arrayExists((x) -> x=%s, Tags)", Qf("%s=%s", term.Key, term.Value))
	case TaggedTermNe:
		return fmt.Sprintf("NOT arrayExists((x) -> x=%s, Tags)", Qf("%s=%s", term.Key, term.Value))
	case TaggedTermMatch:
		return fmt.Sprintf(
			"arrayExists((x) -> (x LIKE %s) AND (match(x, %s)), Tags)",
			Qf("%s=%%", term.Key),
			Qf("%s=%s", term.Key, term.Value),
		)
<commit_msg>fix first negative expression in tagged finder<commit_after>package finder

import (
	"bytes"
	"context"
	"fmt"
	"net/url"
	"sort"
	"strings"
	"time"

	"github.com/go-graphite/carbonapi/pkg/parser"
	"github.com/lomik/graphite-clickhouse/helper/clickhouse"
)

type TaggedTermOp int

const (
	TaggedTermEq       TaggedTermOp = 1
	TaggedTermMatch    TaggedTermOp = 2
	TaggedTermNe       TaggedTermOp = 3
	TaggedTermNotMatch TaggedTermOp = 4
)

type TaggedTerm struct {
	Key   string
	Op    TaggedTermOp
	Value string
}

type TaggedTermList []TaggedTerm

func (s TaggedTermList) Len() int {
	return len(s)
}
func (s TaggedTermList) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}
func (s TaggedTermList) Less(i, j int) bool {
	return s[i].Op < s[j].Op
}

type TaggedFinder struct {
	url   string             // clickhouse dsn
	table string             // graphite_tag table
	opts  clickhouse.Options // clickhouse query timeout
	body  []byte             // clickhouse response
}

func NewTagged(url string, table string, opts clickhouse.Options) *TaggedFinder {
	return &TaggedFinder{
		url:   url,
		table: table,
		opts:  opts,
	}
}

func TaggedTermWhere1(term *TaggedTerm) string {
	// positive expression check only in Tag1
	// negative check in all Tags
	switch term.Op {
	case TaggedTermEq:
		return fmt.Sprintf("Tag1=%s", Qf("%s=%s", term.Key, term.Value))
	case TaggedTermNe:
		return fmt.Sprintf("NOT arrayExists((x) -> x=%s, Tags)", Qf("%s=%s", term.Key, term.Value))
	case TaggedTermMatch:
		return fmt.Sprintf(
			"(Tag1 LIKE %s) AND (match(Tag1, %s))",
			Qf("%s=%%", term.Key),
			Qf("%s=%s", term.Key, term.Value),
		)
	case TaggedTermNotMatch:
		return fmt.Sprintf(
			"NOT arrayExists((x) -> (x LIKE %s) AND (match(x, %s)), Tags)",
			Qf("%s=%%", term.Key),
			Qf("%s=%s", term.Key, term.Value),
		)
	default:
		return ""
	}
}

func TaggedTermWhereN(term *TaggedTerm) string {
	// arrayExists((x) -> %s, Tags)
	switch term.Op {
	case TaggedTermEq:
		return fmt.Sprintf("arrayExists((x) -> x=%s, Tags)", Qf("%s=%s", term.Key, term.Value))
	case TaggedTermNe:
		return fmt.Sprintf("NOT arrayExists((x) -> x=%s, Tags)", Qf("%s=%s", term.Key, term.Value))
	case TaggedTermMatch:
		return fmt.Sprintf(
			"arrayExists((x) -> (x LIKE %s) AND (match(x, %s)), Tags)",
			Qf("%s=%%", term.Key),
			Qf("%s=%s", term.Key, term.Value),
		)
{'fraction_non_alphanumeric': 0.16429665281120104, 'fraction_numerical': 0.004375410194705754, 'mean_word_length': 3.6416243654822336, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 13, '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': '181465', 'n_tokens_mistral': 1864, 'n_tokens_neox': 1776, 'n_words': 432}