Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite4d6381

Browse files
committed
feat: add trigram search
1 parent9765d58 commite4d6381

File tree

4 files changed

+231
-1
lines changed

4 files changed

+231
-1
lines changed

‎README.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
11
#AshPostgres
2+
3+
#TODO
4+
5+
##Configuration
6+
7+
- Need to figure out how to only fetch config one time in the configuration of the repo.
8+
Right now, we are calling the`installed_extensions()` function in both`supervisor` and
9+
`runtime` but that could mean checking the system environment variables every time (is that bad?)

‎lib/ash_postgres.ex‎

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ defmodule AshPostgres do
1717
)
1818

1919
aliasAsh.Filter.{And,Eq,In,NotEq,NotIn,Or}
20+
aliasAshPostgres.Predicates.Trigram
2021

2122
@moduledoc"""
2223
A postgres data layer that levereges Ecto's postgres tools.
@@ -67,6 +68,21 @@ defmodule AshPostgres do
6768
resource.repo()
6869
end
6970

71+
@impltrue
72+
defcustom_filters(resource)do
73+
config=repo(resource).config()
74+
75+
add_pg_trgm_search(%{},config)
76+
end
77+
78+
defpadd_pg_trgm_search(filters,config)do
79+
if"pg_trgm"inconfig[:installed_extensions]do
80+
Map.update(filters,:string,[{:trigram,AshPostgres.Predicates.Trigram}],fnfilters->
81+
[{:trigram,AshPostgres.Predicates.Trigram}|filters]
82+
end)
83+
end
84+
end
85+
7086
importEcto.Query,only:[from:2]
7187

7288
@impltrue
@@ -82,6 +98,7 @@ defmodule AshPostgres do
8298
defcan?({:filter,:and}),do:true
8399
defcan?({:filter,:or}),do:true
84100
defcan?({:filter,:not}),do:true
101+
defcan?({:filter,:trigram}),do:true
85102
defcan?({:filter_related,_}),do:true
86103
defcan?(_),do:false
87104

@@ -443,7 +460,7 @@ defmodule AshPostgres do
443460
not_filter->
444461
{params,new_expr}=filter_to_expr(not_filter,bindings,params,current_binding,path)
445462

446-
{params,join_exprs(expr,{:not,new_expr},:and)}
463+
{params,join_exprs(expr,{:not,[],[new_expr]},:and)}
447464
end
448465

449466
{params,expr}=
@@ -505,6 +522,72 @@ defmodule AshPostgres do
505522
]}}}
506523
end
507524

525+
defpfilter_value_to_expr(
526+
attribute,
527+
%Trigram{}=trigram,
528+
current_binding,
529+
params
530+
)do
531+
param_count=Enum.count(params)
532+
533+
casetrigramdo
534+
%{equals:equals,greater_than:nil,less_than:nil,text:text}->
535+
{params++[{text,{current_binding,attribute}},{equals,:float}],
536+
{:fragment,[],
537+
[
538+
raw:"similarity(",
539+
expr:{{:.,[],[{:&,[],[current_binding]},attribute]},[],[]},
540+
raw:", ",
541+
expr:{:^,[],[param_count]},
542+
raw:") = ",
543+
expr:{:^,[],[param_count+1]},
544+
raw:""
545+
]}}
546+
547+
%{equals:nil,greater_than:greater_than,less_than:nil,text:text}->
548+
{params++[{text,{current_binding,attribute}},{greater_than,:float}],
549+
{:fragment,[],
550+
[
551+
raw:"similarity(",
552+
expr:{{:.,[],[{:&,[],[current_binding]},attribute]},[],[]},
553+
raw:", ",
554+
expr:{:^,[],[param_count]},
555+
raw:") > ",
556+
expr:{:^,[],[param_count+1]},
557+
raw:""
558+
]}}
559+
560+
%{equals:nil,greater_than:nil,less_than:less_than,text:text}->
561+
{params++[{text,{current_binding,attribute}},{less_than,:float}],
562+
{:fragment,[],
563+
[
564+
raw:"similarity(",
565+
expr:{{:.,[],[{:&,[],[current_binding]},attribute]},[],[]},
566+
raw:", ",
567+
expr:{:^,[],[param_count]},
568+
raw:") < ",
569+
expr:{:^,[],[param_count+1]},
570+
raw:""
571+
]}}
572+
573+
%{equals:nil,greater_than:greater_than,less_than:less_than,text:text}->
574+
{params++
575+
[{text,{current_binding,attribute}},{less_than,:float},{greater_than,:float}],
576+
{:fragment,[],
577+
[
578+
raw:"similarity(",
579+
expr:{{:.,[],[{:&,[],[current_binding]},attribute]},[],[]},
580+
raw:", ",
581+
expr:{:^,[],[param_count]},
582+
raw:") BETWEEN ",
583+
expr:{:^,[],[param_count+1]},
584+
raw:" AND ",
585+
expr:{:^,[],[param_count+2]},
586+
raw:""
587+
]}}
588+
end
589+
end
590+
508591
defpfilter_value_to_expr(
509592
attribute,
510593
%And{left:left,right:right},

‎lib/predicates/trigram.ex‎

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
defmoduleAshPostgres.Predicates.Trigramdo
2+
defstruct[:text,:greater_than,:less_than,:equals]
3+
4+
defnew(_resource,attr_name,attr_type,opts)do
5+
with:ok<-required_options_provided(opts),
6+
{:ok,value}<-Ash.Type.cast_input(attr_type,opts[:text]),
7+
{:ok,less_than}<-validate_similarity(opts[:less_than]),
8+
{:ok,greater_than}<-validate_similarity(opts[:greater_than]),
9+
{:ok,equals}<-validate_similarity(opts[:equals])do
10+
{:ok,
11+
%__MODULE__{text:value,greater_than:greater_than,less_than:less_than,equals:equals}}
12+
else
13+
_->
14+
{:error,
15+
Ash.Error.Filter.InvalidFilterValue.exception(
16+
filter:%__MODULE__{
17+
text:opts[:text],
18+
less_than:opts[:less_than],
19+
greater_than:opts[:greater_than],
20+
equals:opts[:equals]
21+
},
22+
value:opts,
23+
field:attr_name
24+
)}
25+
end
26+
end
27+
28+
defpvalidate_similarity(nil),do:{:ok,nil}
29+
defpvalidate_similarity(1),do:{:ok,1}
30+
defpvalidate_similarity(0),do:{:ok,0}
31+
32+
defpvalidate_similarity(similarity)
33+
whenis_float(similarity)andsimilarity<=1.0andsimilarity>=0.0do
34+
{:ok,similarity}
35+
end
36+
37+
defpvalidate_similarity(similarity)whenis_binary(similarity)do
38+
sanitized=
39+
casesimilaritydo
40+
"."<>decimal_part->"0."<>decimal_part
41+
other->other
42+
end
43+
44+
caseFloat.parse(sanitized)do
45+
{float,""}->{:ok,float}
46+
_->:error
47+
end
48+
end
49+
50+
defprequired_options_provided(opts)do
51+
ifKeyword.has_key?(opts,:text)do
52+
case{opts[:greater_than],opts[:less_than],opts[:equals]}do
53+
{nil,nil,nil}->:error
54+
{nil,nil,_equals}->:ok
55+
{_greater_than,nil,nil}->:ok
56+
{nil,_less_than,nil}->:ok
57+
{_greater_than,_less_than,nil}->:ok
58+
end
59+
else
60+
:error
61+
end
62+
end
63+
end
64+
65+
defimplInspect,for:AshPostgres.Predicates.Trigramdo
66+
importInspect.Algebra
67+
importAsh.Filter.InspectHelpers
68+
69+
definspect(%{text:text,equals:nil,less_than:nil,greater_than:greater_than},opts)do
70+
concat([
71+
attr(opts),
72+
" trigram similarity to ",
73+
to_doc(text,opts),
74+
" is greater than ",
75+
to_doc(greater_than,opts)
76+
])
77+
end
78+
79+
definspect(%{text:text,equals:nil,less_than:less_than,greater_than:nil},opts)do
80+
concat([
81+
attr(opts),
82+
" trigram similarity to ",
83+
to_doc(text,opts),
84+
" is less than ",
85+
to_doc(less_than,opts)
86+
])
87+
end
88+
89+
definspect(%{text:text,equals:nil,less_than:less_than,greater_than:greater_than},opts)do
90+
concat([
91+
attr(opts),
92+
" trigram similarity to ",
93+
to_doc(text,opts),
94+
" is between ",
95+
to_doc(less_than,opts),
96+
" and ",
97+
to_doc(greater_than,opts)
98+
])
99+
end
100+
101+
definspect(%{text:text,equals:equals,less_than:nil,greater_than:nil},opts)do
102+
concat([
103+
attr(opts),
104+
" trigram similarity to ",
105+
to_doc(text,opts),
106+
" == ",
107+
to_doc(equals,opts)
108+
])
109+
end
110+
end

‎lib/repo.ex‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
defmoduleAshPostgres.Repodo
2+
@callbackinstalled_extensions()::[String.t()]
3+
4+
defmacro__using__(opts)do
5+
quotebind_quoted:[opts:opts]do
6+
otp_app=opts[:otp_app]||raise("Must configure OTP app")
7+
8+
useEcto.Repo,
9+
adapter:Ecto.Adapters.Postgres,
10+
otp_app:otp_app
11+
12+
definstalled_extensions()do
13+
[]
14+
end
15+
16+
definit(:supervisor,config)do
17+
new_config=Keyword.put(config,:installed_extensions,installed_extensions())
18+
19+
{:ok,new_config}
20+
end
21+
22+
definit(:runtime,config)do
23+
init(:supervisor,config)
24+
end
25+
26+
defoverridableinstalled_extensions:0
27+
end
28+
end
29+
end

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp