// Copyright 2021-present The Atlas Authors. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.

package postgresop

import "sync"

// Class describes an index operator class.
type Class struct {
	Name    string // operator class name
	Method  string // index method
	Type    string // indexed data type
	Default bool   // default to the type/method above
}

// Classes defined in latest PostgreSQL version (15).
var Classes = []*Class{
	{Name: "bit_minmax_ops", Method: "BRIN", Type: "bit", Default: true},
	{Name: "box_inclusion_ops", Method: "BRIN", Type: "box", Default: true},
	{Name: "bpchar_bloom_ops", Method: "BRIN", Type: "character", Default: false},
	{Name: "bpchar_minmax_ops", Method: "BRIN", Type: "character", Default: true},
	{Name: "bytea_bloom_ops", Method: "BRIN", Type: "bytea", Default: false},
	{Name: "bytea_minmax_ops", Method: "BRIN", Type: "bytea", Default: true},
	{Name: "char_bloom_ops", Method: "BRIN", Type: "char", Default: false},
	{Name: "char_minmax_ops", Method: "BRIN", Type: "char", Default: true},
	{Name: "date_bloom_ops", Method: "BRIN", Type: "date", Default: false},
	{Name: "date_minmax_multi_ops", Method: "BRIN", Type: "date", Default: false},
	{Name: "date_minmax_ops", Method: "BRIN", Type: "date", Default: true},
	{Name: "float4_bloom_ops", Method: "BRIN", Type: "real", Default: false},
	{Name: "float4_minmax_multi_ops", Method: "BRIN", Type: "real", Default: false},
	{Name: "float4_minmax_ops", Method: "BRIN", Type: "real", Default: true},
	{Name: "float8_bloom_ops", Method: "BRIN", Type: "double precision", Default: false},
	{Name: "float8_minmax_multi_ops", Method: "BRIN", Type: "double precision", Default: false},
	{Name: "float8_minmax_ops", Method: "BRIN", Type: "double precision", Default: true},
	{Name: "inet_bloom_ops", Method: "BRIN", Type: "inet", Default: false},
	{Name: "inet_inclusion_ops", Method: "BRIN", Type: "inet", Default: true},
	{Name: "inet_minmax_multi_ops", Method: "BRIN", Type: "inet", Default: false},
	{Name: "inet_minmax_ops", Method: "BRIN", Type: "inet", Default: false},
	{Name: "int2_bloom_ops", Method: "BRIN", Type: "smallint", Default: false},
	{Name: "int2_minmax_multi_ops", Method: "BRIN", Type: "smallint", Default: false},
	{Name: "int2_minmax_ops", Method: "BRIN", Type: "smallint", Default: true},
	{Name: "int4_bloom_ops", Method: "BRIN", Type: "integer", Default: false},
	{Name: "int4_minmax_multi_ops", Method: "BRIN", Type: "integer", Default: false},
	{Name: "int4_minmax_ops", Method: "BRIN", Type: "integer", Default: true},
	{Name: "int8_bloom_ops", Method: "BRIN", Type: "bigint", Default: false},
	{Name: "int8_minmax_multi_ops", Method: "BRIN", Type: "bigint", Default: false},
	{Name: "int8_minmax_ops", Method: "BRIN", Type: "bigint", Default: true},
	{Name: "interval_bloom_ops", Method: "BRIN", Type: "interval", Default: false},
	{Name: "interval_minmax_multi_ops", Method: "BRIN", Type: "interval", Default: false},
	{Name: "interval_minmax_ops", Method: "BRIN", Type: "interval", Default: true},
	{Name: "macaddr8_bloom_ops", Method: "BRIN", Type: "macaddr8", Default: false},
	{Name: "macaddr8_minmax_multi_ops", Method: "BRIN", Type: "macaddr8", Default: false},
	{Name: "macaddr8_minmax_ops", Method: "BRIN", Type: "macaddr8", Default: true},
	{Name: "macaddr_bloom_ops", Method: "BRIN", Type: "macaddr", Default: false},
	{Name: "macaddr_minmax_multi_ops", Method: "BRIN", Type: "macaddr", Default: false},
	{Name: "macaddr_minmax_ops", Method: "BRIN", Type: "macaddr", Default: true},
	{Name: "name_bloom_ops", Method: "BRIN", Type: "name", Default: false},
	{Name: "name_minmax_ops", Method: "BRIN", Type: "name", Default: true},
	{Name: "numeric_bloom_ops", Method: "BRIN", Type: "numeric", Default: false},
	{Name: "numeric_minmax_multi_ops", Method: "BRIN", Type: "numeric", Default: false},
	{Name: "numeric_minmax_ops", Method: "BRIN", Type: "numeric", Default: true},
	{Name: "oid_bloom_ops", Method: "BRIN", Type: "oid", Default: false},
	{Name: "oid_minmax_multi_ops", Method: "BRIN", Type: "oid", Default: false},
	{Name: "oid_minmax_ops", Method: "BRIN", Type: "oid", Default: true},
	{Name: "pg_lsn_bloom_ops", Method: "BRIN", Type: "pg_lsn", Default: false},
	{Name: "pg_lsn_minmax_multi_ops", Method: "BRIN", Type: "pg_lsn", Default: false},
	{Name: "pg_lsn_minmax_ops", Method: "BRIN", Type: "pg_lsn", Default: true},
	{Name: "range_inclusion_ops", Method: "BRIN", Type: "anyrange", Default: true},
	{Name: "text_bloom_ops", Method: "BRIN", Type: "text", Default: false},
	{Name: "text_minmax_ops", Method: "BRIN", Type: "text", Default: true},
	{Name: "tid_bloom_ops", Method: "BRIN", Type: "tid", Default: false},
	{Name: "tid_minmax_multi_ops", Method: "BRIN", Type: "tid", Default: false},
	{Name: "tid_minmax_ops", Method: "BRIN", Type: "tid", Default: true},
	{Name: "time_bloom_ops", Method: "BRIN", Type: "time without time zone", Default: false},
	{Name: "time_minmax_multi_ops", Method: "BRIN", Type: "time without time zone", Default: false},
	{Name: "time_minmax_ops", Method: "BRIN", Type: "time without time zone", Default: true},
	{Name: "timestamp_bloom_ops", Method: "BRIN", Type: "timestamp without time zone", Default: false},
	{Name: "timestamp_minmax_multi_ops", Method: "BRIN", Type: "timestamp without time zone", Default: false},
	{Name: "timestamp_minmax_ops", Method: "BRIN", Type: "timestamp without time zone", Default: true},
	{Name: "timestamptz_bloom_ops", Method: "BRIN", Type: "timestamp with time zone", Default: false},
	{Name: "timestamptz_minmax_multi_ops", Method: "BRIN", Type: "timestamp with time zone", Default: false},
	{Name: "timestamptz_minmax_ops", Method: "BRIN", Type: "timestamp with time zone", Default: true},
	{Name: "timetz_bloom_ops", Method: "BRIN", Type: "time with time zone", Default: false},
	{Name: "timetz_minmax_multi_ops", Method: "BRIN", Type: "time with time zone", Default: false},
	{Name: "timetz_minmax_ops", Method: "BRIN", Type: "time with time zone", Default: true},
	{Name: "uuid_bloom_ops", Method: "BRIN", Type: "uuid", Default: false},
	{Name: "uuid_minmax_multi_ops", Method: "BRIN", Type: "uuid", Default: false},
	{Name: "uuid_minmax_ops", Method: "BRIN", Type: "uuid", Default: true},
	{Name: "varbit_minmax_ops", Method: "BRIN", Type: "bit varying", Default: true},
	{Name: "array_ops", Method: "BTREE", Type: "anyarray", Default: true},
	{Name: "bit_ops", Method: "BTREE", Type: "bit", Default: true},
	{Name: "bool_ops", Method: "BTREE", Type: "boolean", Default: true},
	{Name: "bpchar_ops", Method: "BTREE", Type: "character", Default: true},
	{Name: "bpchar_pattern_ops", Method: "BTREE", Type: "character", Default: false},
	{Name: "bytea_ops", Method: "BTREE", Type: "bytea", Default: true},
	{Name: "char_ops", Method: "BTREE", Type: "char", Default: true},
	{Name: "cidr_ops", Method: "BTREE", Type: "inet", Default: false},
	{Name: "date_ops", Method: "BTREE", Type: "date", Default: true},
	{Name: "enum_ops", Method: "BTREE", Type: "anyenum", Default: true},
	{Name: "float4_ops", Method: "BTREE", Type: "real", Default: true},
	{Name: "float8_ops", Method: "BTREE", Type: "double precision", Default: true},
	{Name: "inet_ops", Method: "BTREE", Type: "inet", Default: true},
	{Name: "int2_ops", Method: "BTREE", Type: "smallint", Default: true},
	{Name: "int4_ops", Method: "BTREE", Type: "integer", Default: true},
	{Name: "int8_ops", Method: "BTREE", Type: "bigint", Default: true},
	{Name: "interval_ops", Method: "BTREE", Type: "interval", Default: true},
	{Name: "jsonb_ops", Method: "BTREE", Type: "jsonb", Default: true},
	{Name: "macaddr8_ops", Method: "BTREE", Type: "macaddr8", Default: true},
	{Name: "macaddr_ops", Method: "BTREE", Type: "macaddr", Default: true},
	{Name: "money_ops", Method: "BTREE", Type: "money", Default: true},
	{Name: "multirange_ops", Method: "BTREE", Type: "anymultirange", Default: true},
	{Name: "name_ops", Method: "BTREE", Type: "name", Default: true},
	{Name: "numeric_ops", Method: "BTREE", Type: "numeric", Default: true},
	{Name: "oid_ops", Method: "BTREE", Type: "oid", Default: true},
	{Name: "oidvector_ops", Method: "BTREE", Type: "oidvector", Default: true},
	{Name: "pg_lsn_ops", Method: "BTREE", Type: "pg_lsn", Default: true},
	{Name: "range_ops", Method: "BTREE", Type: "anyrange", Default: true},
	{Name: "record_image_ops", Method: "BTREE", Type: "record", Default: false},
	{Name: "record_ops", Method: "BTREE", Type: "record", Default: true},
	{Name: "text_ops", Method: "BTREE", Type: "text", Default: true},
	{Name: "text_pattern_ops", Method: "BTREE", Type: "text", Default: false},
	{Name: "tid_ops", Method: "BTREE", Type: "tid", Default: true},
	{Name: "time_ops", Method: "BTREE", Type: "time without time zone", Default: true},
	{Name: "timestamp_ops", Method: "BTREE", Type: "timestamp without time zone", Default: true},
	{Name: "timestamptz_ops", Method: "BTREE", Type: "timestamp with time zone", Default: true},
	{Name: "timetz_ops", Method: "BTREE", Type: "time with time zone", Default: true},
	{Name: "tsquery_ops", Method: "BTREE", Type: "tsquery", Default: true},
	{Name: "tsvector_ops", Method: "BTREE", Type: "tsvector", Default: true},
	{Name: "uuid_ops", Method: "BTREE", Type: "uuid", Default: true},
	{Name: "varbit_ops", Method: "BTREE", Type: "bit varying", Default: true},
	{Name: "varchar_ops", Method: "BTREE", Type: "text", Default: false},
	{Name: "varchar_pattern_ops", Method: "BTREE", Type: "text", Default: false},
	{Name: "xid8_ops", Method: "BTREE", Type: "xid8", Default: true},
	{Name: "array_ops", Method: "GIN", Type: "anyarray", Default: true},
	{Name: "jsonb_ops", Method: "GIN", Type: "jsonb", Default: true},
	{Name: "jsonb_path_ops", Method: "GIN", Type: "jsonb", Default: false},
	{Name: "tsvector_ops", Method: "GIN", Type: "tsvector", Default: true},
	{Name: "box_ops", Method: "GIST", Type: "box", Default: true},
	{Name: "circle_ops", Method: "GIST", Type: "circle", Default: true},
	{Name: "inet_ops", Method: "GIST", Type: "inet", Default: false},
	{Name: "multirange_ops", Method: "GIST", Type: "anymultirange", Default: true},
	{Name: "point_ops", Method: "GIST", Type: "point", Default: true},
	{Name: "poly_ops", Method: "GIST", Type: "polygon", Default: true},
	{Name: "range_ops", Method: "GIST", Type: "anyrange", Default: true},
	{Name: "tsquery_ops", Method: "GIST", Type: "tsquery", Default: true},
	{Name: "tsvector_ops", Method: "GIST", Type: "tsvector", Default: true},
	{Name: "aclitem_ops", Method: "HASH", Type: "aclitem", Default: true},
	{Name: "array_ops", Method: "HASH", Type: "anyarray", Default: true},
	{Name: "bool_ops", Method: "HASH", Type: "boolean", Default: true},
	{Name: "bpchar_ops", Method: "HASH", Type: "character", Default: true},
	{Name: "bpchar_pattern_ops", Method: "HASH", Type: "character", Default: false},
	{Name: "bytea_ops", Method: "HASH", Type: "bytea", Default: true},
	{Name: "char_ops", Method: "HASH", Type: "char", Default: true},
	{Name: "cid_ops", Method: "HASH", Type: "cid", Default: true},
	{Name: "cidr_ops", Method: "HASH", Type: "inet", Default: false},
	{Name: "date_ops", Method: "HASH", Type: "date", Default: true},
	{Name: "enum_ops", Method: "HASH", Type: "anyenum", Default: true},
	{Name: "float4_ops", Method: "HASH", Type: "real", Default: true},
	{Name: "float8_ops", Method: "HASH", Type: "double precision", Default: true},
	{Name: "inet_ops", Method: "HASH", Type: "inet", Default: true},
	{Name: "int2_ops", Method: "HASH", Type: "smallint", Default: true},
	{Name: "int4_ops", Method: "HASH", Type: "integer", Default: true},
	{Name: "int8_ops", Method: "HASH", Type: "bigint", Default: true},
	{Name: "interval_ops", Method: "HASH", Type: "interval", Default: true},
	{Name: "jsonb_ops", Method: "HASH", Type: "jsonb", Default: true},
	{Name: "macaddr8_ops", Method: "HASH", Type: "macaddr8", Default: true},
	{Name: "macaddr_ops", Method: "HASH", Type: "macaddr", Default: true},
	{Name: "multirange_ops", Method: "HASH", Type: "anymultirange", Default: true},
	{Name: "name_ops", Method: "HASH", Type: "name", Default: true},
	{Name: "numeric_ops", Method: "HASH", Type: "numeric", Default: true},
	{Name: "oid_ops", Method: "HASH", Type: "oid", Default: true},
	{Name: "oidvector_ops", Method: "HASH", Type: "oidvector", Default: true},
	{Name: "pg_lsn_ops", Method: "HASH", Type: "pg_lsn", Default: true},
	{Name: "range_ops", Method: "HASH", Type: "anyrange", Default: true},
	{Name: "record_ops", Method: "HASH", Type: "record", Default: true},
	{Name: "text_ops", Method: "HASH", Type: "text", Default: true},
	{Name: "text_pattern_ops", Method: "HASH", Type: "text", Default: false},
	{Name: "tid_ops", Method: "HASH", Type: "tid", Default: true},
	{Name: "time_ops", Method: "HASH", Type: "time without time zone", Default: true},
	{Name: "timestamp_ops", Method: "HASH", Type: "timestamp without time zone", Default: true},
	{Name: "timestamptz_ops", Method: "HASH", Type: "timestamp with time zone", Default: true},
	{Name: "timetz_ops", Method: "HASH", Type: "time with time zone", Default: true},
	{Name: "uuid_ops", Method: "HASH", Type: "uuid", Default: true},
	{Name: "varchar_ops", Method: "HASH", Type: "text", Default: false},
	{Name: "varchar_pattern_ops", Method: "HASH", Type: "text", Default: false},
	{Name: "xid8_ops", Method: "HASH", Type: "xid8", Default: true},
	{Name: "xid_ops", Method: "HASH", Type: "xid", Default: true},
	{Name: "box_ops", Method: "SPGIST", Type: "box", Default: true},
	{Name: "inet_ops", Method: "SPGIST", Type: "inet", Default: true},
	{Name: "kd_point_ops", Method: "SPGIST", Type: "point", Default: false},
	{Name: "poly_ops", Method: "SPGIST", Type: "polygon", Default: true},
	{Name: "quad_point_ops", Method: "SPGIST", Type: "point", Default: true},
	{Name: "range_ops", Method: "SPGIST", Type: "anyrange", Default: true},
	{Name: "text_ops", Method: "SPGIST", Type: "text", Default: true},
	{Name: "gin_trgm_ops", Method: "GIN", Type: "text", Default: false},
	{Name: "gist_trgm_ops", Method: "GIN", Type: "text", Default: false},
	{Name: "btree_geography_ops", Method: "BTREE", Type: "geography", Default: true},
	{Name: "btree_geometry_ops", Method: "BTREE", Type: "geometry", Default: true},
	{Name: "gist_geography_ops", Method: "GIST", Type: "geography", Default: true},
	{Name: "gist_geometry_ops_2d", Method: "GIST", Type: "geometry", Default: true},
	{Name: "gist_geometry_ops_nd", Method: "GIST", Type: "geometry", Default: false},
	{Name: "gist_geometry_ops_3d", Method: "GIST", Type: "geometry", Default: false},
	{Name: "hash_geometry_ops", Method: "HASH", Type: "geometry", Default: true},
	{Name: "brin_geography_inclusion_ops", Method: "BRIN", Type: "geography", Default: true},
	{Name: "brin_geometry_inclusion_ops_2d", Method: "BRIN", Type: "geometry", Default: true},
	{Name: "brin_geometry_inclusion_ops_3d", Method: "BRIN", Type: "geometry", Default: false},
	{Name: "brin_geometry_inclusion_ops_4d", Method: "BRIN", Type: "geometry", Default: false},
	{Name: "spgist_geography_ops_nd", Method: "SPGIST", Type: "geography", Default: true},
	{Name: "spgist_geometry_ops_2d", Method: "SPGIST", Type: "geometry", Default: true},
	{Name: "spgist_geometry_ops_3d", Method: "SPGIST", Type: "geometry", Default: false},
	{Name: "spgist_geometry_ops_nd", Method: "SPGIST", Type: "geometry", Default: false},
}

var (
	mapOnce sync.Once
	byName  map[string]struct{}
)

// HasClass reports if the given operator class name exists.
func HasClass(name string) bool {
	mapOnce.Do(func() {
		byName = make(map[string]struct{}, len(Classes))
		for _, c := range Classes {
			byName[c.Name] = struct{}{}
		}
	})
	_, ok := byName[name]
	return ok
}
