tricoredb 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TriCoreDB
4
+ # Builders for the server's `DocumentFilter`, externally tagged.
5
+ #
6
+ # @example
7
+ # TriCoreDB::Filter.all_of(TriCoreDB::Filter.eq("city", "Pune"), TriCoreDB::Filter.gt("visits", 4))
8
+ module Filter
9
+ module_function
10
+
11
+ # @return [String] matches every document
12
+ def all
13
+ "All"
14
+ end
15
+
16
+ %w[Eq Ne Gt Gte Lt Lte Contains].each do |variant|
17
+ define_method(variant.downcase) do |field, value|
18
+ { variant => { "field" => field.to_s, "value" => value } }
19
+ end
20
+ end
21
+
22
+ # `field` equals any of `values`.
23
+ # @return [Hash]
24
+ def in_list(field, values)
25
+ { "In" => { "field" => field.to_s, "values" => Array(values) } }
26
+ end
27
+
28
+ # Every sub-filter must match.
29
+ # @return [Hash]
30
+ def all_of(*filters)
31
+ { "And" => filters.flatten }
32
+ end
33
+
34
+ class << self
35
+ alias_method :and, :all_of
36
+ end
37
+ end
38
+
39
+ # Builders for `GroupAccumulator`.
40
+ module Acc
41
+ module_function
42
+
43
+ %w[Sum Avg Min Max].each do |variant|
44
+ define_method(variant.downcase) do |output, field|
45
+ { "output" => output.to_s, "op" => { variant => field.to_s } }
46
+ end
47
+ end
48
+
49
+ # Counts documents in the group.
50
+ # @return [Hash]
51
+ def count(output)
52
+ { "output" => output.to_s, "op" => "Count" }
53
+ end
54
+ end
55
+
56
+ # Builders for `AggregateStage`. Stages apply strictly in order.
57
+ module Stage
58
+ module_function
59
+
60
+ # @return [Hash]
61
+ def match(filter)
62
+ { "Match" => filter }
63
+ end
64
+
65
+ # @param by [Hash] from {by_field} or {by_constant}
66
+ # @param accumulators [Array<Hash>] from {Acc}
67
+ # @return [Hash]
68
+ def group(by, accumulators = [])
69
+ { "Group" => { "by" => by, "accumulators" => accumulators } }
70
+ end
71
+
72
+ # @param keys [Array<Array(String, Boolean)>, Array<Hash>] `[field, descending]` pairs or `{field:, descending:}`
73
+ # @return [Hash]
74
+ def sort(*keys)
75
+ list = keys.flatten(1).map do |k|
76
+ if k.is_a?(Hash)
77
+ { "field" => (k[:field] || k["field"]).to_s, "descending" => !!(k[:descending] || k["descending"]) }
78
+ elsif k.is_a?(Array)
79
+ { "field" => k[0].to_s, "descending" => !!k[1] }
80
+ else
81
+ { "field" => k.to_s, "descending" => false }
82
+ end
83
+ end
84
+ { "Sort" => list }
85
+ end
86
+
87
+ def skip(n)
88
+ { "Skip" => Integer(n) }
89
+ end
90
+
91
+ def limit(n)
92
+ { "Limit" => Integer(n) }
93
+ end
94
+
95
+ def project(fields, include: true)
96
+ { "Project" => { "fields" => Array(fields).map(&:to_s), "include" => include ? true : false } }
97
+ end
98
+
99
+ # Collapse the stream to one document `{field => n}`.
100
+ def count(field)
101
+ { "Count" => { "field" => field.to_s } }
102
+ end
103
+
104
+ def by_field(field)
105
+ { "Field" => field.to_s }
106
+ end
107
+
108
+ def by_constant(value)
109
+ { "Constant" => value }
110
+ end
111
+ end
112
+
113
+ # Builders for `LlmSource`.
114
+ module LlmSource
115
+ module_function
116
+
117
+ # @return [Hash]
118
+ def sql(query)
119
+ { "Sql" => { "query" => query.to_s } }
120
+ end
121
+
122
+ # @return [Hash]
123
+ def documents(collection, filter: Filter.all, limit: nil)
124
+ { "DocumentFind" => { "collection" => collection.to_s, "filter" => filter, "limit" => limit } }
125
+ end
126
+
127
+ # Accepts a built source, or `{sql:}` / `{collection:, filter:, limit:}`.
128
+ # @return [Hash]
129
+ def coerce(src)
130
+ return src if src.is_a?(Hash) && (src.key?("Sql") || src.key?("DocumentFind"))
131
+ raise ArgumentError, "an LLM source must be a Hash" unless src.is_a?(Hash)
132
+
133
+ sql_text = src[:sql] || src["sql"]
134
+ return sql(sql_text) if sql_text
135
+
136
+ coll = src[:collection] || src["collection"]
137
+ raise ArgumentError, "an LLM source needs :sql or :collection" unless coll
138
+
139
+ documents(coll, filter: src[:filter] || src["filter"] || Filter.all, limit: src[:limit] || src["limit"])
140
+ end
141
+ end
142
+ end