|
2 | 2 |
|
3 | 3 | module Weaviate |
4 | 4 | class Query < Base |
5 | | - # Meta-programming hack to dynamically create appropriate Weaviate GraphQL query. Expected query: |
6 | | - # |
7 | | - # Article(where: { |
8 | | - # ... |
9 | | - # operator: GreaterThan, # operator |
10 | | - # |
11 | | - # Since `operator:` parameter expects a literal value, the only way to pass it in Ruby is by defining a class and returning it |
12 | | - # inside of a lambda function when it's called. This is why we have the following code: |
13 | | - # standard:disable all |
14 | | - WHERE_OPERANDS = { |
15 | | - and: -> { class ::And; end; And }, |
16 | | - or: -> { class ::Or; end; Or }, |
17 | | - equal: -> { class ::Equal; end; Equal }, |
18 | | - not_equal: -> { class ::NotEqual; end; NotEqual }, |
19 | | - greater_than: -> { class ::GreaterThan; end; GreaterThan }, |
20 | | - greater_than_equal: -> { class ::GreaterThanEqual; end; GreaterThanEqual }, |
21 | | - less_than: -> { class ::LessThan; end; LessThan }, |
22 | | - less_than_equal: -> { class ::LessThanEqual; end; LessThanEqual }, |
23 | | - like: -> { class ::Like; end; Like }, |
24 | | - within_geo_range: -> { class ::WithinGeoRange; end; WithinGeoRange }, |
25 | | - is_null: -> { class ::IsNull; end; IsNull } |
26 | | - }.freeze |
27 | | - # standard:enable all |
28 | | - |
29 | 5 | def get( |
30 | 6 | class_name:, |
31 | 7 | fields:, |
| 8 | + after: nil, |
32 | 9 | limit: nil, |
33 | 10 | offset: nil, |
34 | | - after: nil, |
35 | 11 | sort: nil, |
36 | 12 | where: nil, |
37 | | - near_text: nil |
| 13 | + near_text: nil, |
| 14 | + near_vector: nil, |
| 15 | + near_object: nil |
38 | 16 | ) |
39 | | - params = {} |
40 | | - params["nearText"] = near_text unless near_text.nil? |
41 | | - params["limit"] = limit unless limit.nil? |
42 | | - params["offset"] = offset unless offset.nil? |
43 | | - params["after"] = after unless after.nil? |
44 | | - |
45 | | - if sort.present? |
46 | | - # TODO: Implement the `order:` param |
47 | | - # Unable to currently support the `order:` param. Weaviate GraphQL API expects a literal value, but we can't pass it in Ruby |
48 | | - # Article(sort: [{ |
49 | | - # order: asc # <--- this is the problem. |
50 | | - # https://weaviate.io/developers/weaviate/api/graphql/filters#sorting-api |
51 | | - # |
52 | | - sort.delete("order") |
53 | | - params["sort"] = sort |
54 | | - end |
55 | | - |
56 | | - if where.present? |
57 | | - params["where"] = where |
58 | | - if where[:operator].present? |
59 | | - params["where"][:operator] = WHERE_OPERANDS[where[:operator].to_sym].call |
60 | | - end |
61 | | - # TODO: Transform the multiple operands: [{}] case |
62 | | - end |
63 | | - |
64 | | - # TODO implement the rest of the API params |
65 | | - |
66 | | - response = client.graphql.execute(get_query(class_name, params, fields), near_text: near_text) |
| 17 | + response = client.graphql.execute( |
| 18 | + get_query( |
| 19 | + class_name: class_name, |
| 20 | + fields: fields, |
| 21 | + sort: sort, |
| 22 | + where: where, |
| 23 | + near_text: near_text, |
| 24 | + near_vector: near_vector, |
| 25 | + near_object: near_object |
| 26 | + ), |
| 27 | + after: after, |
| 28 | + limit: limit, |
| 29 | + offset: offset |
| 30 | + ) |
67 | 31 | response.data.get.send(class_name.downcase) |
| 32 | + rescue Graphlient::Errors::ExecutionError => error |
| 33 | + raise Weaviate::Error.new(error.response.data.get.errors.messages.to_h) |
| 34 | + end |
| 35 | + |
| 36 | + def aggs( |
| 37 | + class_name:, |
| 38 | + fields: nil, |
| 39 | + object_limit: nil, |
| 40 | + near_text: nil, |
| 41 | + near_vector: nil, |
| 42 | + near_object: nil, |
| 43 | + group_by: nil |
| 44 | + ) |
| 45 | + response = client.graphql.execute( |
| 46 | + aggs_query( |
| 47 | + class_name: class_name, |
| 48 | + fields: fields, |
| 49 | + near_text: near_text, |
| 50 | + near_vector: near_vector, |
| 51 | + near_object: near_object |
| 52 | + ), |
| 53 | + group_by: group_by, |
| 54 | + object_limit: object_limit |
| 55 | + ) |
| 56 | + response.data.aggregate.send(class_name.downcase) |
| 57 | + rescue Graphlient::Errors::ExecutionError => error |
| 58 | + raise Weaviate::Error.new(error.response.data.aggregate.errors.messages.to_h) |
68 | 59 | end |
69 | 60 |
|
70 | 61 | private |
71 | 62 |
|
72 | | - def get_query(class_name, params, fields) |
73 | | - client.graphql.parse do |
74 | | - query do |
75 | | - Get do |
76 | | - public_send(class_name, params) do |
77 | | - fields.map do |field| |
78 | | - public_send(field) |
79 | | - end |
80 | | - end |
81 | | - end |
82 | | - end |
83 | | - end |
| 63 | + def get_query( |
| 64 | + class_name:, |
| 65 | + fields:, |
| 66 | + where: nil, |
| 67 | + near_text: nil, |
| 68 | + near_vector: nil, |
| 69 | + near_object: nil, |
| 70 | + sort: nil |
| 71 | + ) |
| 72 | + client.graphql.parse <<~GRAPHQL |
| 73 | + query( |
| 74 | + $after: String, |
| 75 | + $limit: Int, |
| 76 | + $offset: Int, |
| 77 | + ) { |
| 78 | + Get { |
| 79 | + #{class_name}( |
| 80 | + after: $after, |
| 81 | + limit: $limit, |
| 82 | + offset: $offset, |
| 83 | + #{near_text.present? ? "nearText: #{near_text}" : ""}, |
| 84 | + #{near_vector.present? ? "nearVector: #{near_vector}" : ""}, |
| 85 | + #{near_object.present? ? "nearObject: #{near_object}" : ""}, |
| 86 | + #{where.present? ? "where: #{where}" : ""}, |
| 87 | + #{sort.present? ? "sort: #{sort}" : ""} |
| 88 | + ) { |
| 89 | + #{fields} |
| 90 | + } |
| 91 | + } |
| 92 | + } |
| 93 | + GRAPHQL |
| 94 | + end |
| 95 | + |
| 96 | + def aggs_query( |
| 97 | + class_name:, |
| 98 | + fields:, |
| 99 | + near_text: nil, |
| 100 | + near_vector: nil, |
| 101 | + near_object: nil |
| 102 | + ) |
| 103 | + client.graphql.parse <<~GRAPHQL |
| 104 | + query( |
| 105 | + $group_by: [String], |
| 106 | + $object_limit: Int, |
| 107 | + ) { |
| 108 | + Aggregate { |
| 109 | + #{class_name}( |
| 110 | + objectLimit: $object_limit, |
| 111 | + groupBy: $group_by, |
| 112 | + #{near_text.present? ? "nearText: #{near_text}" : ""}, |
| 113 | + #{near_vector.present? ? "nearVector: #{near_vector}" : ""}, |
| 114 | + #{near_object.present? ? "nearObject: #{near_object}" : ""} |
| 115 | + ) { |
| 116 | + #{fields} |
| 117 | + } |
| 118 | + } |
| 119 | + } |
| 120 | + GRAPHQL |
84 | 121 | end |
85 | 122 | end |
86 | 123 | end |
0 commit comments