vectra-client 0.1.2
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.
- checksums.yaml +7 -0
- data/.codecov.yml +31 -0
- data/.rspec +4 -0
- data/.rubocop.yml +183 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +88 -0
- data/CODE_OF_CONDUCT.md +127 -0
- data/CONTRIBUTING.md +239 -0
- data/LICENSE +21 -0
- data/README.md +456 -0
- data/Rakefile +34 -0
- data/SECURITY.md +196 -0
- data/lib/vectra/client.rb +304 -0
- data/lib/vectra/configuration.rb +169 -0
- data/lib/vectra/errors.rb +73 -0
- data/lib/vectra/providers/base.rb +265 -0
- data/lib/vectra/providers/pgvector/connection.rb +75 -0
- data/lib/vectra/providers/pgvector/index_management.rb +122 -0
- data/lib/vectra/providers/pgvector/sql_helpers.rb +115 -0
- data/lib/vectra/providers/pgvector.rb +297 -0
- data/lib/vectra/providers/pinecone.rb +308 -0
- data/lib/vectra/providers/qdrant.rb +48 -0
- data/lib/vectra/providers/weaviate.rb +48 -0
- data/lib/vectra/query_result.rb +257 -0
- data/lib/vectra/vector.rb +155 -0
- data/lib/vectra/version.rb +5 -0
- data/lib/vectra.rb +133 -0
- metadata +226 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Vectra
|
|
4
|
+
# Unified client for vector database operations
|
|
5
|
+
#
|
|
6
|
+
# The Client class provides a unified interface to interact with various
|
|
7
|
+
# vector database providers. It automatically routes operations to the
|
|
8
|
+
# configured provider.
|
|
9
|
+
#
|
|
10
|
+
# @example Using global configuration
|
|
11
|
+
# Vectra.configure do |config|
|
|
12
|
+
# config.provider = :pinecone
|
|
13
|
+
# config.api_key = ENV['PINECONE_API_KEY']
|
|
14
|
+
# config.environment = 'us-east-1'
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# client = Vectra::Client.new
|
|
18
|
+
# client.upsert(index: 'my-index', vectors: [...])
|
|
19
|
+
#
|
|
20
|
+
# @example Using instance configuration
|
|
21
|
+
# client = Vectra::Client.new(
|
|
22
|
+
# provider: :pinecone,
|
|
23
|
+
# api_key: ENV['PINECONE_API_KEY'],
|
|
24
|
+
# environment: 'us-east-1'
|
|
25
|
+
# )
|
|
26
|
+
#
|
|
27
|
+
class Client
|
|
28
|
+
attr_reader :config, :provider
|
|
29
|
+
|
|
30
|
+
# Initialize a new Client
|
|
31
|
+
#
|
|
32
|
+
# @param provider [Symbol, nil] provider name (:pinecone, :qdrant, :weaviate)
|
|
33
|
+
# @param api_key [String, nil] API key
|
|
34
|
+
# @param environment [String, nil] environment/region
|
|
35
|
+
# @param host [String, nil] custom host URL
|
|
36
|
+
# @param options [Hash] additional options
|
|
37
|
+
def initialize(provider: nil, api_key: nil, environment: nil, host: nil, **options)
|
|
38
|
+
@config = build_config(provider, api_key, environment, host, options)
|
|
39
|
+
@config.validate!
|
|
40
|
+
@provider = build_provider
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Upsert vectors into an index
|
|
44
|
+
#
|
|
45
|
+
# @param index [String] the index/collection name
|
|
46
|
+
# @param vectors [Array<Hash, Vector>] vectors to upsert
|
|
47
|
+
# @param namespace [String, nil] optional namespace (provider-specific)
|
|
48
|
+
# @return [Hash] upsert response with :upserted_count
|
|
49
|
+
#
|
|
50
|
+
# @example Upsert vectors
|
|
51
|
+
# client.upsert(
|
|
52
|
+
# index: 'my-index',
|
|
53
|
+
# vectors: [
|
|
54
|
+
# { id: 'vec1', values: [0.1, 0.2, 0.3], metadata: { text: 'Hello' } },
|
|
55
|
+
# { id: 'vec2', values: [0.4, 0.5, 0.6], metadata: { text: 'World' } }
|
|
56
|
+
# ]
|
|
57
|
+
# )
|
|
58
|
+
#
|
|
59
|
+
def upsert(index:, vectors:, namespace: nil)
|
|
60
|
+
validate_index!(index)
|
|
61
|
+
validate_vectors!(vectors)
|
|
62
|
+
|
|
63
|
+
provider.upsert(index: index, vectors: vectors, namespace: namespace)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Query vectors by similarity
|
|
67
|
+
#
|
|
68
|
+
# @param index [String] the index/collection name
|
|
69
|
+
# @param vector [Array<Float>] query vector
|
|
70
|
+
# @param top_k [Integer] number of results to return (default: 10)
|
|
71
|
+
# @param namespace [String, nil] optional namespace
|
|
72
|
+
# @param filter [Hash, nil] metadata filter
|
|
73
|
+
# @param include_values [Boolean] include vector values in response
|
|
74
|
+
# @param include_metadata [Boolean] include metadata in response
|
|
75
|
+
# @return [QueryResult] query results
|
|
76
|
+
#
|
|
77
|
+
# @example Simple query
|
|
78
|
+
# results = client.query(
|
|
79
|
+
# index: 'my-index',
|
|
80
|
+
# vector: [0.1, 0.2, 0.3],
|
|
81
|
+
# top_k: 5
|
|
82
|
+
# )
|
|
83
|
+
#
|
|
84
|
+
# @example Query with filter
|
|
85
|
+
# results = client.query(
|
|
86
|
+
# index: 'my-index',
|
|
87
|
+
# vector: [0.1, 0.2, 0.3],
|
|
88
|
+
# top_k: 10,
|
|
89
|
+
# filter: { category: 'programming' }
|
|
90
|
+
# )
|
|
91
|
+
#
|
|
92
|
+
def query(index:, vector:, top_k: 10, namespace: nil, filter: nil,
|
|
93
|
+
include_values: false, include_metadata: true)
|
|
94
|
+
validate_index!(index)
|
|
95
|
+
validate_query_vector!(vector)
|
|
96
|
+
|
|
97
|
+
provider.query(
|
|
98
|
+
index: index,
|
|
99
|
+
vector: vector,
|
|
100
|
+
top_k: top_k,
|
|
101
|
+
namespace: namespace,
|
|
102
|
+
filter: filter,
|
|
103
|
+
include_values: include_values,
|
|
104
|
+
include_metadata: include_metadata
|
|
105
|
+
)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Fetch vectors by IDs
|
|
109
|
+
#
|
|
110
|
+
# @param index [String] the index/collection name
|
|
111
|
+
# @param ids [Array<String>] vector IDs to fetch
|
|
112
|
+
# @param namespace [String, nil] optional namespace
|
|
113
|
+
# @return [Hash<String, Vector>] hash of ID to Vector
|
|
114
|
+
#
|
|
115
|
+
# @example Fetch vectors
|
|
116
|
+
# vectors = client.fetch(index: 'my-index', ids: ['vec1', 'vec2'])
|
|
117
|
+
# vectors['vec1'].values # => [0.1, 0.2, 0.3]
|
|
118
|
+
#
|
|
119
|
+
def fetch(index:, ids:, namespace: nil)
|
|
120
|
+
validate_index!(index)
|
|
121
|
+
validate_ids!(ids)
|
|
122
|
+
|
|
123
|
+
provider.fetch(index: index, ids: ids, namespace: namespace)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Update a vector's metadata or values
|
|
127
|
+
#
|
|
128
|
+
# @param index [String] the index/collection name
|
|
129
|
+
# @param id [String] vector ID
|
|
130
|
+
# @param metadata [Hash, nil] new metadata (merged with existing)
|
|
131
|
+
# @param values [Array<Float>, nil] new vector values
|
|
132
|
+
# @param namespace [String, nil] optional namespace
|
|
133
|
+
# @return [Hash] update response
|
|
134
|
+
#
|
|
135
|
+
# @example Update metadata
|
|
136
|
+
# client.update(
|
|
137
|
+
# index: 'my-index',
|
|
138
|
+
# id: 'vec1',
|
|
139
|
+
# metadata: { category: 'updated' }
|
|
140
|
+
# )
|
|
141
|
+
#
|
|
142
|
+
def update(index:, id:, metadata: nil, values: nil, namespace: nil)
|
|
143
|
+
validate_index!(index)
|
|
144
|
+
validate_id!(id)
|
|
145
|
+
|
|
146
|
+
raise ValidationError, "Must provide metadata or values to update" if metadata.nil? && values.nil?
|
|
147
|
+
|
|
148
|
+
provider.update(
|
|
149
|
+
index: index,
|
|
150
|
+
id: id,
|
|
151
|
+
metadata: metadata,
|
|
152
|
+
values: values,
|
|
153
|
+
namespace: namespace
|
|
154
|
+
)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Delete vectors
|
|
158
|
+
#
|
|
159
|
+
# @param index [String] the index/collection name
|
|
160
|
+
# @param ids [Array<String>, nil] vector IDs to delete
|
|
161
|
+
# @param namespace [String, nil] optional namespace
|
|
162
|
+
# @param filter [Hash, nil] delete by metadata filter
|
|
163
|
+
# @param delete_all [Boolean] delete all vectors in namespace
|
|
164
|
+
# @return [Hash] delete response
|
|
165
|
+
#
|
|
166
|
+
# @example Delete by IDs
|
|
167
|
+
# client.delete(index: 'my-index', ids: ['vec1', 'vec2'])
|
|
168
|
+
#
|
|
169
|
+
# @example Delete by filter
|
|
170
|
+
# client.delete(index: 'my-index', filter: { category: 'old' })
|
|
171
|
+
#
|
|
172
|
+
# @example Delete all
|
|
173
|
+
# client.delete(index: 'my-index', delete_all: true)
|
|
174
|
+
#
|
|
175
|
+
def delete(index:, ids: nil, namespace: nil, filter: nil, delete_all: false)
|
|
176
|
+
validate_index!(index)
|
|
177
|
+
|
|
178
|
+
if ids.nil? && filter.nil? && !delete_all
|
|
179
|
+
raise ValidationError, "Must provide ids, filter, or delete_all"
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
provider.delete(
|
|
183
|
+
index: index,
|
|
184
|
+
ids: ids,
|
|
185
|
+
namespace: namespace,
|
|
186
|
+
filter: filter,
|
|
187
|
+
delete_all: delete_all
|
|
188
|
+
)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# List all indexes
|
|
192
|
+
#
|
|
193
|
+
# @return [Array<Hash>] list of index information
|
|
194
|
+
#
|
|
195
|
+
# @example
|
|
196
|
+
# indexes = client.list_indexes
|
|
197
|
+
# indexes.each { |idx| puts idx[:name] }
|
|
198
|
+
#
|
|
199
|
+
def list_indexes
|
|
200
|
+
provider.list_indexes
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Describe an index
|
|
204
|
+
#
|
|
205
|
+
# @param index [String] the index name
|
|
206
|
+
# @return [Hash] index details
|
|
207
|
+
#
|
|
208
|
+
# @example
|
|
209
|
+
# info = client.describe_index(index: 'my-index')
|
|
210
|
+
# puts info[:dimension]
|
|
211
|
+
#
|
|
212
|
+
def describe_index(index:)
|
|
213
|
+
validate_index!(index)
|
|
214
|
+
provider.describe_index(index: index)
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Get index statistics
|
|
218
|
+
#
|
|
219
|
+
# @param index [String] the index name
|
|
220
|
+
# @param namespace [String, nil] optional namespace
|
|
221
|
+
# @return [Hash] index statistics
|
|
222
|
+
#
|
|
223
|
+
# @example
|
|
224
|
+
# stats = client.stats(index: 'my-index')
|
|
225
|
+
# puts "Total vectors: #{stats[:total_vector_count]}"
|
|
226
|
+
#
|
|
227
|
+
def stats(index:, namespace: nil)
|
|
228
|
+
validate_index!(index)
|
|
229
|
+
provider.stats(index: index, namespace: namespace)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Get the provider name
|
|
233
|
+
#
|
|
234
|
+
# @return [Symbol]
|
|
235
|
+
def provider_name
|
|
236
|
+
provider.provider_name
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
private
|
|
240
|
+
|
|
241
|
+
def build_config(provider_name, api_key, environment, host, options)
|
|
242
|
+
# Start with global config or new config
|
|
243
|
+
cfg = Vectra.configuration.dup
|
|
244
|
+
|
|
245
|
+
# Override with provided values
|
|
246
|
+
cfg.provider = provider_name if provider_name
|
|
247
|
+
cfg.api_key = api_key if api_key
|
|
248
|
+
cfg.environment = environment if environment
|
|
249
|
+
cfg.host = host if host
|
|
250
|
+
cfg.timeout = options[:timeout] if options[:timeout]
|
|
251
|
+
cfg.open_timeout = options[:open_timeout] if options[:open_timeout]
|
|
252
|
+
cfg.max_retries = options[:max_retries] if options[:max_retries]
|
|
253
|
+
cfg.retry_delay = options[:retry_delay] if options[:retry_delay]
|
|
254
|
+
cfg.logger = options[:logger] if options[:logger]
|
|
255
|
+
|
|
256
|
+
cfg
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def build_provider
|
|
260
|
+
case config.provider
|
|
261
|
+
when :pinecone
|
|
262
|
+
Providers::Pinecone.new(config)
|
|
263
|
+
when :qdrant
|
|
264
|
+
Providers::Qdrant.new(config)
|
|
265
|
+
when :weaviate
|
|
266
|
+
Providers::Weaviate.new(config)
|
|
267
|
+
when :pgvector
|
|
268
|
+
Providers::Pgvector.new(config)
|
|
269
|
+
else
|
|
270
|
+
raise UnsupportedProviderError, "Provider '#{config.provider}' is not supported"
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def validate_index!(index)
|
|
275
|
+
raise ValidationError, "Index name cannot be nil" if index.nil?
|
|
276
|
+
raise ValidationError, "Index name must be a string" unless index.is_a?(String)
|
|
277
|
+
raise ValidationError, "Index name cannot be empty" if index.empty?
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def validate_vectors!(vectors)
|
|
281
|
+
raise ValidationError, "Vectors cannot be nil" if vectors.nil?
|
|
282
|
+
raise ValidationError, "Vectors must be an array" unless vectors.is_a?(Array)
|
|
283
|
+
raise ValidationError, "Vectors cannot be empty" if vectors.empty?
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
def validate_query_vector!(vector)
|
|
287
|
+
raise ValidationError, "Query vector cannot be nil" if vector.nil?
|
|
288
|
+
raise ValidationError, "Query vector must be an array" unless vector.is_a?(Array)
|
|
289
|
+
raise ValidationError, "Query vector cannot be empty" if vector.empty?
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def validate_ids!(ids)
|
|
293
|
+
raise ValidationError, "IDs cannot be nil" if ids.nil?
|
|
294
|
+
raise ValidationError, "IDs must be an array" unless ids.is_a?(Array)
|
|
295
|
+
raise ValidationError, "IDs cannot be empty" if ids.empty?
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def validate_id!(id)
|
|
299
|
+
raise ValidationError, "ID cannot be nil" if id.nil?
|
|
300
|
+
raise ValidationError, "ID must be a string" unless id.is_a?(String)
|
|
301
|
+
raise ValidationError, "ID cannot be empty" if id.empty?
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
end
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Vectra
|
|
4
|
+
# Configuration class for Vectra
|
|
5
|
+
#
|
|
6
|
+
# @example Configure Vectra globally
|
|
7
|
+
# Vectra.configure do |config|
|
|
8
|
+
# config.provider = :pinecone
|
|
9
|
+
# config.api_key = ENV['PINECONE_API_KEY']
|
|
10
|
+
# config.environment = 'us-east-1'
|
|
11
|
+
# end
|
|
12
|
+
#
|
|
13
|
+
class Configuration
|
|
14
|
+
SUPPORTED_PROVIDERS = %i[pinecone qdrant weaviate pgvector].freeze
|
|
15
|
+
|
|
16
|
+
attr_accessor :api_key, :environment, :host, :timeout, :open_timeout,
|
|
17
|
+
:max_retries, :retry_delay, :logger
|
|
18
|
+
|
|
19
|
+
attr_reader :provider
|
|
20
|
+
|
|
21
|
+
def initialize
|
|
22
|
+
@provider = nil
|
|
23
|
+
@api_key = nil
|
|
24
|
+
@environment = nil
|
|
25
|
+
@host = nil
|
|
26
|
+
@timeout = 30
|
|
27
|
+
@open_timeout = 10
|
|
28
|
+
@max_retries = 3
|
|
29
|
+
@retry_delay = 1
|
|
30
|
+
@logger = nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Set the provider
|
|
34
|
+
#
|
|
35
|
+
# @param value [Symbol, String] the provider name
|
|
36
|
+
# @raise [UnsupportedProviderError] if provider is not supported
|
|
37
|
+
def provider=(value)
|
|
38
|
+
provider_sym = value.to_sym
|
|
39
|
+
|
|
40
|
+
unless SUPPORTED_PROVIDERS.include?(provider_sym)
|
|
41
|
+
raise UnsupportedProviderError,
|
|
42
|
+
"Provider '#{value}' is not supported. " \
|
|
43
|
+
"Supported providers: #{SUPPORTED_PROVIDERS.join(', ')}"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
@provider = provider_sym
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Validate the configuration
|
|
50
|
+
#
|
|
51
|
+
# @raise [ConfigurationError] if configuration is invalid
|
|
52
|
+
def validate!
|
|
53
|
+
raise ConfigurationError, "Provider must be configured" if provider.nil?
|
|
54
|
+
raise ConfigurationError, "API key must be configured" if api_key.nil? || api_key.empty?
|
|
55
|
+
|
|
56
|
+
validate_provider_specific!
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Check if configuration is valid
|
|
60
|
+
#
|
|
61
|
+
# @return [Boolean]
|
|
62
|
+
def valid?
|
|
63
|
+
validate!
|
|
64
|
+
true
|
|
65
|
+
rescue ConfigurationError
|
|
66
|
+
false
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Create a duplicate configuration
|
|
70
|
+
#
|
|
71
|
+
# @return [Configuration]
|
|
72
|
+
def dup
|
|
73
|
+
config = Configuration.new
|
|
74
|
+
config.instance_variable_set(:@provider, @provider)
|
|
75
|
+
config.api_key = @api_key
|
|
76
|
+
config.environment = @environment
|
|
77
|
+
config.host = @host
|
|
78
|
+
config.timeout = @timeout
|
|
79
|
+
config.open_timeout = @open_timeout
|
|
80
|
+
config.max_retries = @max_retries
|
|
81
|
+
config.retry_delay = @retry_delay
|
|
82
|
+
config.logger = @logger
|
|
83
|
+
config
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Convert configuration to hash
|
|
87
|
+
#
|
|
88
|
+
# @return [Hash]
|
|
89
|
+
def to_h
|
|
90
|
+
{
|
|
91
|
+
provider: provider,
|
|
92
|
+
api_key: api_key,
|
|
93
|
+
environment: environment,
|
|
94
|
+
host: host,
|
|
95
|
+
timeout: timeout,
|
|
96
|
+
open_timeout: open_timeout,
|
|
97
|
+
max_retries: max_retries,
|
|
98
|
+
retry_delay: retry_delay
|
|
99
|
+
}
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
private
|
|
103
|
+
|
|
104
|
+
def validate_provider_specific!
|
|
105
|
+
case provider
|
|
106
|
+
when :pinecone
|
|
107
|
+
validate_pinecone!
|
|
108
|
+
when :qdrant
|
|
109
|
+
validate_qdrant!
|
|
110
|
+
when :weaviate
|
|
111
|
+
validate_weaviate!
|
|
112
|
+
when :pgvector
|
|
113
|
+
validate_pgvector!
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def validate_pinecone!
|
|
118
|
+
return unless environment.nil? && host.nil?
|
|
119
|
+
|
|
120
|
+
raise ConfigurationError,
|
|
121
|
+
"Pinecone requires either 'environment' or 'host' to be configured"
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def validate_qdrant!
|
|
125
|
+
return unless host.nil?
|
|
126
|
+
|
|
127
|
+
raise ConfigurationError, "Qdrant requires 'host' to be configured"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def validate_weaviate!
|
|
131
|
+
return unless host.nil?
|
|
132
|
+
|
|
133
|
+
raise ConfigurationError, "Weaviate requires 'host' to be configured"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def validate_pgvector!
|
|
137
|
+
return unless host.nil?
|
|
138
|
+
|
|
139
|
+
raise ConfigurationError, "pgvector requires 'host' (connection URL or hostname) to be configured"
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
class << self
|
|
144
|
+
attr_writer :configuration
|
|
145
|
+
|
|
146
|
+
# Get the current configuration
|
|
147
|
+
#
|
|
148
|
+
# @return [Configuration]
|
|
149
|
+
def configuration
|
|
150
|
+
@configuration ||= Configuration.new
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Configure Vectra
|
|
154
|
+
#
|
|
155
|
+
# @yield [Configuration] the configuration object
|
|
156
|
+
# @return [Configuration]
|
|
157
|
+
def configure
|
|
158
|
+
yield(configuration)
|
|
159
|
+
configuration
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Reset configuration to defaults
|
|
163
|
+
#
|
|
164
|
+
# @return [Configuration]
|
|
165
|
+
def reset_configuration!
|
|
166
|
+
@configuration = Configuration.new
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Vectra
|
|
4
|
+
# Base error class for all Vectra errors
|
|
5
|
+
class Error < StandardError
|
|
6
|
+
attr_reader :original_error, :response
|
|
7
|
+
|
|
8
|
+
def initialize(message = nil, original_error: nil, response: nil)
|
|
9
|
+
@original_error = original_error
|
|
10
|
+
@response = response
|
|
11
|
+
super(message)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Raised when configuration is invalid or missing
|
|
16
|
+
class ConfigurationError < Error; end
|
|
17
|
+
|
|
18
|
+
# Raised when authentication fails
|
|
19
|
+
class AuthenticationError < Error; end
|
|
20
|
+
|
|
21
|
+
# Raised when a resource is not found
|
|
22
|
+
class NotFoundError < Error; end
|
|
23
|
+
|
|
24
|
+
# Raised when rate limit is exceeded
|
|
25
|
+
class RateLimitError < Error
|
|
26
|
+
attr_reader :retry_after
|
|
27
|
+
|
|
28
|
+
def initialize(message = nil, retry_after: nil, **kwargs)
|
|
29
|
+
@retry_after = retry_after
|
|
30
|
+
super(message, **kwargs)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Raised when request validation fails
|
|
35
|
+
class ValidationError < Error
|
|
36
|
+
attr_reader :errors
|
|
37
|
+
|
|
38
|
+
def initialize(message = nil, errors: [], **kwargs)
|
|
39
|
+
@errors = errors
|
|
40
|
+
super(message, **kwargs)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Raised when there's a connection problem
|
|
45
|
+
class ConnectionError < Error; end
|
|
46
|
+
|
|
47
|
+
# Raised when the server returns an error
|
|
48
|
+
class ServerError < Error
|
|
49
|
+
attr_reader :status_code
|
|
50
|
+
|
|
51
|
+
def initialize(message = nil, status_code: nil, **kwargs)
|
|
52
|
+
@status_code = status_code
|
|
53
|
+
super(message, **kwargs)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Raised when the provider is not supported
|
|
58
|
+
class UnsupportedProviderError < Error; end
|
|
59
|
+
|
|
60
|
+
# Raised when an operation times out
|
|
61
|
+
class TimeoutError < Error; end
|
|
62
|
+
|
|
63
|
+
# Raised when batch operation partially fails
|
|
64
|
+
class BatchError < Error
|
|
65
|
+
attr_reader :succeeded, :failed
|
|
66
|
+
|
|
67
|
+
def initialize(message = nil, succeeded: [], failed: [], **kwargs)
|
|
68
|
+
@succeeded = succeeded
|
|
69
|
+
@failed = failed
|
|
70
|
+
super(message, **kwargs)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|