oso-oso 0.21.0 → 0.24.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/Gemfile.lock +7 -6
- data/Makefile +1 -1
- data/ext/oso-oso/lib/libpolar.dylib +0 -0
- data/ext/oso-oso/lib/libpolar.so +0 -0
- data/ext/oso-oso/lib/polar.dll +0 -0
- data/lib/oso/oso.rb +31 -22
- data/lib/oso/polar/data/adapter/active_record_adapter.rb +56 -0
- data/lib/oso/polar/data/adapter.rb +22 -0
- data/lib/oso/polar/data/filter.rb +59 -0
- data/lib/oso/polar/data.rb +4 -0
- data/lib/oso/polar/data_filtering.rb +36 -6
- data/lib/oso/polar/errors.rb +0 -6
- data/lib/oso/polar/expression.rb +1 -1
- data/lib/oso/polar/ffi/error.rb +4 -41
- data/lib/oso/polar/ffi/polar.rb +60 -35
- data/lib/oso/polar/ffi/query.rb +48 -22
- data/lib/oso/polar/ffi/{source.rb → rust_string.rb} +9 -3
- data/lib/oso/polar/ffi.rb +28 -20
- data/lib/oso/polar/host.rb +29 -10
- data/lib/oso/polar/polar.rb +82 -15
- data/lib/oso/polar/query.rb +29 -11
- data/lib/oso/polar.rb +1 -0
- data/lib/oso/version.rb +1 -1
- metadata +7 -5
- data/lib/oso/polar/ffi/message.rb +0 -40
- data/lib/oso/polar/ffi/query_event.rb +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 719c88b2531d9c6d1e638928e6be3abba68b67d0
|
4
|
+
data.tar.gz: 327124db69d3aa57ff06a1089c24124d60175c26
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4af7eba0a1bcac195ae51719991191ea78d4c0437bf7aacad7f09fce54d848559178485e098b5a9b150353c3feececd415533e7f311592e38cd6df8d263772c1
|
7
|
+
data.tar.gz: 57bca613ce91ddf645d7cafb89641286c1c41f1aec70cb4c9378b3157b8cd4291315e08083f19add35dad38325e423539831ffdcce2bc610bd685d328d2703e1
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
oso-oso (0.
|
4
|
+
oso-oso (0.24.0)
|
5
5
|
ffi (~> 1.0)
|
6
6
|
|
7
7
|
GEM
|
@@ -21,14 +21,14 @@ GEM
|
|
21
21
|
arel (9.0.0)
|
22
22
|
ast (2.4.2)
|
23
23
|
backport (1.2.0)
|
24
|
-
benchmark (0.
|
24
|
+
benchmark (0.2.0)
|
25
25
|
byebug (11.1.3)
|
26
26
|
coderay (1.1.3)
|
27
27
|
concurrent-ruby (1.1.9)
|
28
28
|
diff-lcs (1.4.4)
|
29
29
|
e2mmap (0.1.0)
|
30
30
|
ffi (1.15.4)
|
31
|
-
i18n (1.8.
|
31
|
+
i18n (1.8.11)
|
32
32
|
concurrent-ruby (~> 1.0)
|
33
33
|
jaro_winkler (1.5.4)
|
34
34
|
maruku (0.7.3)
|
@@ -49,7 +49,7 @@ GEM
|
|
49
49
|
rainbow (3.0.0)
|
50
50
|
rake (12.3.3)
|
51
51
|
regexp_parser (2.1.1)
|
52
|
-
reverse_markdown (2.
|
52
|
+
reverse_markdown (2.1.1)
|
53
53
|
nokogiri
|
54
54
|
rexml (3.2.5)
|
55
55
|
rspec (3.10.0)
|
@@ -64,7 +64,7 @@ GEM
|
|
64
64
|
rspec-mocks (3.10.2)
|
65
65
|
diff-lcs (>= 1.2.0, < 2.0)
|
66
66
|
rspec-support (~> 3.10.0)
|
67
|
-
rspec-support (3.10.
|
67
|
+
rspec-support (3.10.3)
|
68
68
|
rubocop (0.89.1)
|
69
69
|
parallel (~> 1.10)
|
70
70
|
parser (>= 2.7.1.1)
|
@@ -97,12 +97,13 @@ GEM
|
|
97
97
|
tilt (2.0.10)
|
98
98
|
tzinfo (1.2.9)
|
99
99
|
thread_safe (~> 0.1)
|
100
|
-
unicode-display_width (1.
|
100
|
+
unicode-display_width (1.8.0)
|
101
101
|
yard (0.9.26)
|
102
102
|
|
103
103
|
PLATFORMS
|
104
104
|
ruby
|
105
105
|
x86_64-darwin-20
|
106
|
+
x86_64-linux
|
106
107
|
|
107
108
|
DEPENDENCIES
|
108
109
|
activerecord
|
data/Makefile
CHANGED
Binary file
|
data/ext/oso-oso/lib/libpolar.so
CHANGED
Binary file
|
data/ext/oso-oso/lib/polar.dll
CHANGED
Binary file
|
data/lib/oso/oso.rb
CHANGED
@@ -181,27 +181,17 @@ module Oso
|
|
181
181
|
# @param resource_cls The resource being accessed.
|
182
182
|
#
|
183
183
|
# @return A query for resources accessible to the actor.
|
184
|
-
def authorized_query(actor, action, resource_cls)
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
actor,
|
190
|
-
action,
|
191
|
-
resource,
|
192
|
-
bindings: { 'resource' => type_constraint(resource, resource_cls) },
|
193
|
-
accept_expression: true
|
194
|
-
)
|
195
|
-
|
196
|
-
results = results.each_with_object([]) do |result, out|
|
197
|
-
result.each do |key, val|
|
198
|
-
out.push({ 'bindings' => { key => host.to_polar(val) } })
|
184
|
+
def authorized_query(actor, action, resource_cls)
|
185
|
+
if host.use_new_data_filtering?
|
186
|
+
|
187
|
+
unless host.types[resource_cls].build_query == ::Oso::Polar::Host::DEFAULT_BUILD_QUERY
|
188
|
+
warn 'Warning: redundant data filtering configuration detected'
|
199
189
|
end
|
200
|
-
end
|
201
190
|
|
202
|
-
|
203
|
-
|
204
|
-
|
191
|
+
new_authorized_query(actor, action, resource_cls)
|
192
|
+
else
|
193
|
+
old_authorized_query(actor, action, resource_cls)
|
194
|
+
end
|
205
195
|
end
|
206
196
|
|
207
197
|
# Determine the resources of type +resource_cls+ that +actor+
|
@@ -213,10 +203,29 @@ module Oso
|
|
213
203
|
#
|
214
204
|
# @return A list of resources accessible to the actor.
|
215
205
|
def authorized_resources(actor, action, resource_cls)
|
216
|
-
q = authorized_query
|
217
|
-
|
206
|
+
q = authorized_query(actor, action, resource_cls)
|
207
|
+
|
208
|
+
if host.use_new_data_filtering?
|
209
|
+
host.adapter.execute_query q
|
210
|
+
elsif q.nil?
|
211
|
+
[]
|
212
|
+
else
|
213
|
+
host.types[resource_cls].exec_query[q]
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
# Register default values for data filtering query functions.
|
218
|
+
# These can be overridden by passing specific implementations to
|
219
|
+
# `register_class` or by defining `build_query`, `exec_query` and
|
220
|
+
# `combine_query` methods on the class object.
|
221
|
+
def set_data_filtering_query_defaults(build_query: nil, exec_query: nil, combine_query: nil)
|
222
|
+
host.build_query = build_query if build_query
|
223
|
+
host.exec_query = exec_query if exec_query
|
224
|
+
host.combine_query = combine_query if combine_query
|
225
|
+
end
|
218
226
|
|
219
|
-
|
227
|
+
def data_filtering_adapter=(adapter)
|
228
|
+
host.adapter = adapter
|
220
229
|
end
|
221
230
|
end
|
222
231
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Oso
|
4
|
+
module Polar
|
5
|
+
module Data
|
6
|
+
class Adapter
|
7
|
+
# Example data filtering adapter for ActiveRecord
|
8
|
+
class ActiveRecordAdapter < Adapter
|
9
|
+
def build_query(filter) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
10
|
+
types = filter.types
|
11
|
+
query = filter.relations.reduce(filter.model.all) do |q, rel|
|
12
|
+
rec = types[rel.left].fields[rel.name]
|
13
|
+
q.joins(
|
14
|
+
"INNER JOIN #{rel.right.table_name} ON " \
|
15
|
+
"#{rel.left.table_name}.#{rec.my_field} = " \
|
16
|
+
"#{rel.right.table_name}.#{rec.other_field}"
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
filter.conditions.map do |conjs|
|
21
|
+
conjs.reduce(query) do |q, conj|
|
22
|
+
q.where(*sqlize(conj))
|
23
|
+
end
|
24
|
+
end.reduce(:or).distinct
|
25
|
+
end
|
26
|
+
|
27
|
+
def execute_query(query)
|
28
|
+
query.to_a
|
29
|
+
end
|
30
|
+
|
31
|
+
OPS = {
|
32
|
+
'Eq' => '=', 'In' => 'IN', 'Nin' => 'NOT IN', 'Neq' => '!='
|
33
|
+
}.freeze
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def sqlize(cond)
|
38
|
+
args = []
|
39
|
+
lhs = add_side cond.left, args
|
40
|
+
rhs = add_side cond.right, args
|
41
|
+
args.unshift "#{lhs} #{OPS[cond.cmp]} #{rhs}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_side(side, args)
|
45
|
+
if side.is_a? ::Oso::Polar::Data::Filter::Projection
|
46
|
+
"#{side.source.table_name}.#{side.field || side.source.primary_key}"
|
47
|
+
else
|
48
|
+
args.push side
|
49
|
+
'?'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Oso
|
4
|
+
module Polar
|
5
|
+
module Data
|
6
|
+
# Abstract data adapter
|
7
|
+
#
|
8
|
+
# An Adapter has to implement two methods.
|
9
|
+
class Adapter
|
10
|
+
# Make a query object from a filter
|
11
|
+
def build_query(_filter)
|
12
|
+
raise "build_query not implemented for #{self}"
|
13
|
+
end
|
14
|
+
|
15
|
+
# Make a list of objects from a query
|
16
|
+
def execute_query(_query)
|
17
|
+
raise "execute_query not implemented for #{self}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Oso
|
4
|
+
module Polar
|
5
|
+
# Data filtering interface for Ruby
|
6
|
+
module Data
|
7
|
+
# Abstract data filter used by the Adapter API.
|
8
|
+
class Filter
|
9
|
+
attr_reader :model, :relations, :conditions, :types
|
10
|
+
|
11
|
+
def initialize(model:, relations:, conditions:, types:)
|
12
|
+
@model = model
|
13
|
+
@relations = relations
|
14
|
+
@conditions = conditions
|
15
|
+
@types = types
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.parse(polar, blob)
|
19
|
+
types = polar.host.types
|
20
|
+
model = types[blob['root']].klass.get
|
21
|
+
relations = blob['relations'].map do |rel|
|
22
|
+
Relation.parse(polar, *rel)
|
23
|
+
end
|
24
|
+
conditions = blob['conditions'].map do |disj|
|
25
|
+
disj.map { |conj| Condition.parse(polar, *conj) }
|
26
|
+
end
|
27
|
+
new(model: model, relations: relations, conditions: conditions, types: types)
|
28
|
+
end
|
29
|
+
|
30
|
+
Projection = Struct.new(:source, :field)
|
31
|
+
|
32
|
+
Relation = Struct.new(:left, :name, :right) do
|
33
|
+
def self.parse(polar, left, name, right)
|
34
|
+
Relation.new(polar.name_to_class(left), name, polar.name_to_class(right))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
Condition = Struct.new(:left, :cmp, :right) do
|
39
|
+
def self.parse(polar, left, cmp, right)
|
40
|
+
Condition.new(parse_side(polar, left), cmp, parse_side(polar, right))
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.parse_side(polar, side)
|
44
|
+
key = side.keys.first
|
45
|
+
val = side[key]
|
46
|
+
case key
|
47
|
+
when 'Field'
|
48
|
+
Projection.new(polar.name_to_class(val[0]), val[1])
|
49
|
+
when 'Immediate'
|
50
|
+
polar.host.to_ruby('value' => [[val.keys.first, val.values.first]])
|
51
|
+
else
|
52
|
+
raise key
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -4,6 +4,7 @@ module Oso
|
|
4
4
|
module Polar
|
5
5
|
# Data filtering interface for Ruby
|
6
6
|
module DataFiltering
|
7
|
+
GETATTR = ->(x, attr) { attr.nil? ? x : x.send(attr) }
|
7
8
|
# Represents a set of filter sequences that should allow the host
|
8
9
|
# to obtain the records satisfying a query.
|
9
10
|
class FilterPlan
|
@@ -29,7 +30,7 @@ module Oso
|
|
29
30
|
result_sets.each_with_object([]) do |rs, qb|
|
30
31
|
rs.resolve_order.each_with_object({}) do |i, set_results|
|
31
32
|
req = rs.requests[i]
|
32
|
-
cs = req.
|
33
|
+
cs = req.ground(set_results)
|
33
34
|
typ = @polar.host.types[req.class_tag]
|
34
35
|
q = typ.build_query[cs]
|
35
36
|
if i != rs.result_id
|
@@ -68,6 +69,7 @@ module Oso
|
|
68
69
|
attr_reader :constraints, :class_tag
|
69
70
|
|
70
71
|
def self.parse(polar, parsed_json)
|
72
|
+
@polar = polar
|
71
73
|
constraints = parsed_json['constraints'].map do |con|
|
72
74
|
Filter.parse polar, con
|
73
75
|
end
|
@@ -76,6 +78,29 @@ module Oso
|
|
76
78
|
new(constraints: constraints, class_tag: class_tag)
|
77
79
|
end
|
78
80
|
|
81
|
+
def ground(results) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
|
82
|
+
xrefs, rest = constraints.partition do |c|
|
83
|
+
c.value.is_a?(Ref) and !c.value.result_id.nil?
|
84
|
+
end
|
85
|
+
|
86
|
+
yrefs, nrefs = xrefs.partition { |r| %w[In Eq].include? r.kind }
|
87
|
+
[[yrefs, 'In'], [nrefs, 'Nin']].each do |refs, kind|
|
88
|
+
refs.group_by { |f| f.value.result_id }.each do |rid, fils|
|
89
|
+
if fils.length > 1
|
90
|
+
value = results[rid].map { |r| fils.map { |f| GETATTR[r, f.value.field] } }
|
91
|
+
field = fils.map(&:field)
|
92
|
+
rest.push(Filter.new(kind: kind, value: value, field: field))
|
93
|
+
else
|
94
|
+
fil = fils[0]
|
95
|
+
field = fil.value.field
|
96
|
+
value = results[rid].map { |r| field.nil? ? r : r.send(field) }
|
97
|
+
rest.push(Filter.new(kind: kind, field: fil.field, value: value))
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
rest
|
102
|
+
end
|
103
|
+
|
79
104
|
def initialize(constraints:, class_tag:)
|
80
105
|
@constraints = constraints
|
81
106
|
@class_tag = class_tag
|
@@ -127,6 +152,7 @@ module Oso
|
|
127
152
|
'Eq' => ->(a, b) { a == b },
|
128
153
|
'In' => ->(a, b) { b.include? a },
|
129
154
|
'Neq' => ->(a, b) { a != b },
|
155
|
+
'Nin' => ->(a, b) { !b.include?(a) },
|
130
156
|
'Contains' => ->(a, b) { a.include? b }
|
131
157
|
}.freeze
|
132
158
|
|
@@ -138,8 +164,6 @@ module Oso
|
|
138
164
|
@kind = kind
|
139
165
|
@field = field
|
140
166
|
@value = value
|
141
|
-
@check = CHECKS[kind]
|
142
|
-
raise "Unknown constraint kind `#{kind}`" if @check.nil?
|
143
167
|
end
|
144
168
|
|
145
169
|
def ground(results)
|
@@ -150,10 +174,16 @@ module Oso
|
|
150
174
|
@value = value.map { |v| v.send ref.field } unless ref.field.nil?
|
151
175
|
end
|
152
176
|
|
153
|
-
def check(item)
|
177
|
+
def check(item) # rubocop:disable Metrics/AbcSize
|
154
178
|
val = value.is_a?(Field) ? item.send(value.field) : value
|
155
|
-
item = field.nil?
|
156
|
-
|
179
|
+
item = if field.nil?
|
180
|
+
item
|
181
|
+
elsif field.is_a? Array
|
182
|
+
field.map { |f| GETATTR[item, f] }
|
183
|
+
else
|
184
|
+
item.send field
|
185
|
+
end
|
186
|
+
CHECKS[@kind][item, val]
|
157
187
|
end
|
158
188
|
|
159
189
|
def self.parse(polar, constraint) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
data/lib/oso/polar/errors.rb
CHANGED
@@ -23,11 +23,9 @@ module Oso
|
|
23
23
|
|
24
24
|
# Errors from across the FFI boundary.
|
25
25
|
|
26
|
-
class SerializationError < PolarRuntimeError; end
|
27
26
|
class UnsupportedError < PolarRuntimeError; end
|
28
27
|
class PolarTypeError < PolarRuntimeError; end
|
29
28
|
class StackOverflowError < PolarRuntimeError; end
|
30
|
-
class FileLoadingError < PolarRuntimeError; end
|
31
29
|
|
32
30
|
# Errors originating from this side of the FFI boundary.
|
33
31
|
|
@@ -96,10 +94,6 @@ module Oso
|
|
96
94
|
class UnrecognizedToken < ParseError; end
|
97
95
|
end
|
98
96
|
|
99
|
-
# Generic Polar API exception.
|
100
|
-
class ApiError < Error; end
|
101
|
-
class ParameterError < ApiError; end
|
102
|
-
|
103
97
|
class ValidationError < Error; end
|
104
98
|
|
105
99
|
UNEXPECTED_EXPRESSION_MESSAGE = <<~MSG
|
data/lib/oso/polar/expression.rb
CHANGED
data/lib/oso/polar/ffi/error.rb
CHANGED
@@ -6,29 +6,13 @@ module Oso
|
|
6
6
|
module Polar
|
7
7
|
module FFI
|
8
8
|
# Wrapper class for Error FFI pointer + operations.
|
9
|
-
class Error
|
10
|
-
def to_s
|
11
|
-
@to_s ||= read_string.force_encoding('UTF-8')
|
12
|
-
end
|
13
|
-
|
14
|
-
Rust = Module.new do
|
15
|
-
extend ::FFI::Library
|
16
|
-
ffi_lib FFI::LIB_PATH
|
17
|
-
|
18
|
-
attach_function :get, :polar_get_error, [], Error
|
19
|
-
attach_function :free, :string_free, [Error], :int32
|
20
|
-
end
|
21
|
-
private_constant :Rust
|
22
|
-
|
9
|
+
class Error
|
23
10
|
# Check for an FFI error and convert it into a Ruby exception.
|
24
11
|
#
|
25
12
|
# @return [::Oso::Polar::Error] if there's an FFI error.
|
26
13
|
# @return [::Oso::Polar::FFIErrorNotFound] if there isn't one.
|
27
|
-
def self.get(enrich_message) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
28
|
-
error =
|
29
|
-
return ::Oso::Polar::FFIErrorNotFound if error.null?
|
30
|
-
|
31
|
-
error = JSON.parse(error.to_s)
|
14
|
+
def self.get(error_str, enrich_message) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
15
|
+
error = JSON.parse(error_str.to_s)
|
32
16
|
msg = error['formatted']
|
33
17
|
kind, body = error['kind'].first
|
34
18
|
|
@@ -54,8 +38,6 @@ module Oso
|
|
54
38
|
runtime_error(subkind, msg: msg, details: details)
|
55
39
|
when 'Operational'
|
56
40
|
operational_error(subkind, msg: msg, details: details)
|
57
|
-
when 'Parameter'
|
58
|
-
api_error(subkind, msg: msg, details: details)
|
59
41
|
when 'Validation'
|
60
42
|
validation_error(msg, details: details)
|
61
43
|
end
|
@@ -92,18 +74,14 @@ module Oso
|
|
92
74
|
# @param msg [String]
|
93
75
|
# @param details [Hash<String, Object>]
|
94
76
|
# @return [::Oso::Polar::PolarRuntimeError] the object converted into the expected format.
|
95
|
-
private_class_method def self.runtime_error(kind, msg:, details:)
|
77
|
+
private_class_method def self.runtime_error(kind, msg:, details:)
|
96
78
|
case kind
|
97
|
-
when 'Serialization'
|
98
|
-
::Oso::Polar::SerializationError.new(msg, details: details)
|
99
79
|
when 'Unsupported'
|
100
80
|
::Oso::Polar::UnsupportedError.new(msg, details: details)
|
101
81
|
when 'TypeError'
|
102
82
|
::Oso::Polar::PolarTypeError.new(msg, details: details)
|
103
83
|
when 'StackOverflow'
|
104
84
|
::Oso::Polar::StackOverflowError.new(msg, details: details)
|
105
|
-
when 'FileLoading'
|
106
|
-
::Oso::Polar::FileLoadingError.new(msg, details: details)
|
107
85
|
else
|
108
86
|
::Oso::Polar::PolarRuntimeError.new(msg, details: details)
|
109
87
|
end
|
@@ -124,21 +102,6 @@ module Oso
|
|
124
102
|
end
|
125
103
|
end
|
126
104
|
|
127
|
-
# Map FFI API errors into Ruby exceptions.
|
128
|
-
#
|
129
|
-
# @param kind [String]
|
130
|
-
# @param msg [String]
|
131
|
-
# @param details [Hash<String, Object>]
|
132
|
-
# @return [::Oso::Polar::ApiError] the object converted into the expected format.
|
133
|
-
private_class_method def self.api_error(kind, msg:, details:)
|
134
|
-
case kind
|
135
|
-
when 'Parameter'
|
136
|
-
::Oso::Polar::ParameterError.new(msg, details: details)
|
137
|
-
else
|
138
|
-
::Oso::Polar::ApiError.new(msg, details: details)
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
105
|
# Map FFI Validation errors into Ruby exceptions.
|
143
106
|
#
|
144
107
|
# @param msg [String]
|