defmodule Noizu.Weaviate.Class do
@moduledoc """
Main class to provide functionalities for Weaviate classes.
"""
defmodule Meta do
defmodule Classification do
defstruct [
id: nil,
based_on: nil,
classified_fields: nil,
completed: nil,
scope: nil,
vector: nil
]
end
defstruct [
id: nil,
class: nil,
description: nil,
creation_time_unix: nil,
last_update_time_unix: nil,
vector: nil,
tenant: nil,
classification: nil,
feature_projection: nil,
]
end
defmacro __using__(options \\ nil) do
quote do
Module.register_attribute(__MODULE__, :properties, accumulate: true)
Module.register_attribute(__MODULE__, :class_description, accumulate: false)
Module.register_attribute(__MODULE__, :class_vector_index_type, accumulate: false)
Module.register_attribute(__MODULE__, :class_vector_index_config, accumulate: false)
Module.register_attribute(__MODULE__, :class_vectorizer, accumulate: false)
Module.register_attribute(__MODULE__, :class_module_config, accumulate: false)
Module.register_attribute(__MODULE__, :class_inverted_index_config, accumulate: false)
Module.register_attribute(__MODULE__, :class_replication_config, accumulate: false)
Module.register_attribute(__MODULE__, :class_multi_tenancy_config, accumulate: false)
require Noizu.Weaviate.Class
import Noizu.Weaviate.Class, only: [weaviate_class: 2]
end
end
defmacro weaviate_class(class_name, [do: block]) do
quote do
import Noizu.Weaviate.Class
unquote(block)
# Define the struct
struct_params =
[meta: %Noizu.Weaviate.Class.Meta{
id: nil,
class: unquote(class_name),
description: @class_description,
creation_time_unix: nil,
last_update_time_unix: nil,
vector: nil,
tenant: nil,
classification: nil,
feature_projection: nil,
}, id: nil] ++ Enum.map(@properties, fn {name, _} -> {name, nil} end)
@derive Noizu.Weaviate.Class.Protocol
defstruct struct_params
def __class__(), do: unquote(class_name)
def __properties__(), do: @properties
def __property__(name), do: Enum.find_value(@properties, fn {k,v} -> k == name && v end)
def definition() do
%Noizu.Weaviate.Struct.Class{
name: unquote(class_name),
description: @class_description,
vector_index: @class_vector_index_type,
vector_index_config: @class_vector_index_config,
vectorizer: @class_vectorizer,
module_config: @class_module_config,
inverted_index_config: @class_inverted_index_config,
replication_config: @class_replication_config,
multi_tenancy_config: @class_multi_tenancy_config,
properties: Enum.map(@properties, fn({_, v}) -> v end),
}
end
def from_json(json) do
meta = %Noizu.Weaviate.Class.Meta{
id: json[:id],
class: json[:class],
creation_time_unix: json[:creationTimeUnix],
last_update_time_unix: json[:lastUpdateTimeUnix],
vector: json[:vector],
tenant: json[:tenant],
classification: json[:classification],
feature_projection: json[:featureProjection]
}
properties = Enum.map(apply(__MODULE__,:__properties__, []), fn {name, _} -> {name, json[:properties][name]} end)
__MODULE__.__struct__([{:meta, meta}, {:id, json[:id]} |properties])
end
defimpl Jason.Encoder do
def encode(this, opts) do
[
id: this.id,
class: this.meta.class,
vector: this.meta.vector,
tenant: this.meta.tenant,
properties:
Enum.map(apply(this.__struct__,:__properties__, []), fn({k, _}) -> {k, get_in(this, [Access.key(k)])} end)
|> Enum.reject(fn({_,v}) -> is_nil(v) end)
|> Map.new()
] |> Enum.reject(fn({_,v}) -> is_nil(v) end)
|> Map.new()
|> Jason.Encode.map(opts)
end
end
defoverridable [
__properties__: 0,
__property__: 1,
definition: 0,
from_json: 1
]
end
end
def definition(class, options \\ nil)
def definition(%Noizu.Weaviate.Struct.Class{} = class, options), do: class
def definition(class, options), do: apply(class, :definition, [])
def json_handler(class, options \\ nil)
def json_handler(%Noizu.Weaviate.Struct.Class{}, _options), do: Noizu.Weaviate.Struct.Class
def json_handler(class, _options) when is_atom(class), do: class
def json_handler(_, _options), do: Noizu.Weaviate.Struct.Class
#===================================
# Macros
#===================================
defmacro description(value) do
quote do
Module.put_attribute(__MODULE__, :class_description, unquote(value))
end
end
defmacro vector_index_type(value) do
quote do
Module.put_attribute(__MODULE__, :class_vector_index_type, unquote(value))
end
end
defmacro vector_index_config(value) do
quote do
Module.put_attribute(__MODULE__, :class_vector_index_config, unquote(value))
end
end
defmacro vectorizer(value) do
quote do
Module.put_attribute(__MODULE__, :class_vectorizer, unquote(value))
end
end
defmacro module_config(value) do
quote do
Module.put_attribute(__MODULE__, :class_module_config, unquote(value))
end
end
defmacro inverted_index_config(value) do
quote do
Module.put_attribute(__MODULE__, :class_inverted_index_config, unquote(value))
end
end
defmacro replication_config(value) do
quote do
Module.put_attribute(__MODULE__, :class_replication_config, unquote(value))
end
end
defmacro multi_tenancy_config(value) do
quote do
Module.put_attribute(__MODULE__, :class_multi_tenancy_config, unquote(value))
end
end
defmacro property(name, data_type, opts \\ []) do
quote do
Module.put_attribute(__MODULE__, :properties, {unquote(name), %Noizu.Weaviate.Struct.Property{
name: unquote(name),
data_type: ["#{unquote(data_type)}"],
description: Keyword.get(unquote(opts), :description, nil),
index_filterable: Keyword.get(unquote(opts), :index_filterable, nil),
index_searchable: Keyword.get(unquote(opts), :index_searchable, nil),
index_inverted: Keyword.get(unquote(opts), :index_inverted, nil),
tokenization: Keyword.get(unquote(opts), :tokenization, nil),
module_config: Keyword.get(unquote(opts), :module_config, nil)
}})
end
end
end