Skip to content

Commit 5f4e0c8

Browse files
authored
Dev (#291)
* TODO - oapi runtime support for discriminators * showcase dynamic filters and update runtime now that it supports discriminators * update bad notes on indexes * refactor cache index creation in post migrations * update runtime * notes * standard filter modes labels - fix filter inputs * log before oapi 400 middleware * update pagination params and filters * notes to fix runtime package for arrays * update towards support for discriminator in query params * go mod update * attempt at discriminator json parsing * working example of query params with array oneof * generate fixed query params with arrays in anyof oneof allof and frontend filters update * no right section now that we have filter mode labels * fix filters and heleprs * dont export oidc mock user models * css
1 parent e8162b0 commit 5f4e0c8

File tree

65 files changed

+2398
-503
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+2398
-503
lines changed

bin/.helpers.sh

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -495,20 +495,10 @@ docker.postgres.drop_and_recreate_db() {
495495

496496
docker.postgres.wait_until_ready
497497

498-
docker.postgres psql --no-psqlrc \
499-
-U "$POSTGRES_USER" \
500-
-d "postgres" \
501-
-c "CREATE DATABASE db_template OWNER $POSTGRES_USER;" 2>/dev/null || true
502-
503498
echo "${RED}${BOLD}Dropping database $db.${OFF}"
504-
docker.postgres \
505-
dropdb --if-exists -f "$db"
499+
docker.postgres dropdb --force --if-exists -f "$db"
506500

507-
echo "${BLUE}${BOLD}Creating database $db.${OFF}"
508-
docker.postgres psql --no-psqlrc \
509-
-U "$POSTGRES_USER" \
510-
-d db_template \
511-
-c "CREATE DATABASE $db OWNER $POSTGRES_USER;"
501+
docker.postgres.create_db $db
512502
}
513503

514504
# Create database `db`.
@@ -518,12 +508,7 @@ docker.postgres.create_db() {
518508
docker.postgres.wait_until_ready
519509

520510
echo "${BLUE}${BOLD}Creating database $db.${OFF}"
521-
{
522-
docker.postgres psql --no-psqlrc -U "$POSTGRES_USER" \
523-
-tc "SELECT 1 FROM pg_database WHERE datname = '$db'" |
524-
grep -q 1
525-
} ||
526-
docker.postgres psql --no-psqlrc -U "$POSTGRES_USER" -c "CREATE DATABASE $db" ||
511+
docker.postgres createdb $db -U "$POSTGRES_USER" -O "$POSTGRES_USER" ||
527512
echo "Skipping $db database creation"
528513
}
529514

bin/project

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1393,7 +1393,6 @@ pre_build_cmd="project setup-swagger-ui"
13931393
# Run backend.
13941394
x.run.backend() {
13951395
$pre_build_cmd
1396-
run_shared_services up -d --build --remove-orphans --force-recreate --wait
13971396
go run ./cmd/rest-server/main.go -env=.env.$X_ENV
13981397
}
13991398

@@ -1402,7 +1401,6 @@ x.run.backend-hr() {
14021401
# TODO replace healthcheck with adhoc calls and bring services up in btaches
14031402
# to prevent either bombarding with req or having to wait too long at startup.
14041403
# see https://github.com/moby/moby/issues/33410
1405-
run_shared_services up -d --build --remove-orphans --force-recreate --wait
14061404

14071405
# https://github.com/cosmtrek/air/blob/master/air_example.toml
14081406
# NOTE: building binary unreliable, leads to bin not found.

cmd/initial-data/main.go

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package main
22

33
import (
44
"context"
5-
"encoding/json"
65
"flag"
76
"fmt"
87
"log"
@@ -105,16 +104,6 @@ func main() {
105104
os.Exit(0)
106105
}
107106

108-
// TODO: use users which will exist in auth server. that way we can test out these users as well.
109-
// no need to do it for local.json. as for e2e, we dont want any initial data apart from the superadmin at all
110-
// so that it mimics real usage from an empty project.
111-
authServerUsersPath := "cmd/oidc-server/data/users/base.json"
112-
usersBlob, err := os.ReadFile(authServerUsersPath)
113-
handleError(err)
114-
var uu map[string]*models.AuthServerUser
115-
err = json.Unmarshal(usersBlob, &uu)
116-
handleError(err)
117-
118107
logger.Info("Creating users...")
119108
for i := 0; i < 50; i++ {
120109
u, err := svc.User.Register(ctx, pool, services.UserRegisterParams{
@@ -254,7 +243,7 @@ func main() {
254243
demoWorkItems := []*db.WorkItem{}
255244
var wg sync.WaitGroup
256245
semaphore := make(chan struct{}, 2000)
257-
for i := 1; i <= 200; i++ {
246+
for i := 1; i <= 1000; i++ {
258247
semaphore <- struct{}{} // acquire
259248
wg.Add(1)
260249

cmd/oapi-codegen/oapi-templates/inline.tmpl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ var swaggerSpec = []string{
44
"{{.}}",{{end}}
55
}
66

7+
var spec, _ = GetSwagger()
8+
79
// GetSwagger returns the content of the embedded swagger specification file
810
// or error if failed to decode
911
func decodeSpec() ([]byte, error) {
@@ -40,7 +42,7 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
4042
if len(pathToFile) > 0 {
4143
res[pathToFile] = rawSpec
4244
}
43-
{{ if .ImportMapping }}
45+
{{/* {{ if .ImportMapping }}
4446
pathPrefix := path.Dir(pathToFile)
4547
{{ end }}
4648
{{ range $key, $value := .ImportMapping }}
@@ -50,7 +52,7 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
5052
}
5153
res[rawPath] = rawFunc
5254
}
53-
{{- end }}
55+
{{- end }} */}}
5456
return res
5557
}
5658

cmd/oapi-codegen/oapi-templates/union.tmpl

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,33 @@
88
// As{{$name}} returns the union data inside the {{$typeName}} as a {{$name}}
99
func (t {{$typeName}}) As{{$name}}() ({{$name}}, error) {
1010
var body {{$name}}
11-
err := json.Unmarshal(t.union, &body)
11+
if !t.FromQueryParams {
12+
err := json.Unmarshal(t.union, &body)
13+
return body, err
14+
}
15+
// arrays are passed as maps, so reconstruct json properly
16+
var unionm map[string]interface{}
17+
err := json.Unmarshal(t.union, &unionm)
18+
if err != nil {
19+
return {{$name}}{}, err
20+
}
21+
22+
s := "{{$typeName}}"
23+
discriminatorSchema:= "{{$name}}"
24+
fp, ok := spec.Components.Schemas[s]
25+
if !ok {
26+
return {{$name}}{}, fmt.Errorf("schema %s not found", s)
27+
}
28+
union, err := openapi.ReconstructQueryParamsValues(fp.Value, unionm, discriminatorSchema)
29+
if err != nil {
30+
return {{$name}}{}, fmt.Errorf("could not reconstruct query params for schema %s: %v", discriminatorSchema, err)
31+
}
32+
jsonUnion, err := json.Marshal(union)
33+
if err != nil {
34+
return {{$name}}{}, fmt.Errorf("reconstructed params are not valid json: %v", err)
35+
}
36+
err = json.Unmarshal(jsonUnion, &body)
37+
1238
return body, err
1339
}
1440

cmd/oidc-server/main.go

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import (
66

77
oidc_server "github.com/danicc097/oidc-server/v3"
88
"github.com/danicc097/oidc-server/v3/storage"
9-
"github.com/danicc097/openapi-go-gin-postgres-sqlc/internal/models"
109
"github.com/zitadel/oidc/v2/pkg/oidc"
10+
"golang.org/x/text/language"
1111
)
1212

1313
const (
@@ -39,7 +39,7 @@ func getPrivateClaimsFromScopesFunc(ctx context.Context, userID, clientID string
3939
return claims, nil
4040
}
4141

42-
func setUserInfoFunc(user *models.AuthServerUser, userInfo *oidc.UserInfo, scope, clientID string) {
42+
func setUserInfoFunc(user *AuthServerUser, userInfo *oidc.UserInfo, scope, clientID string) {
4343
switch scope {
4444
case oidc.ScopeOpenID:
4545
userInfo.Subject = user.ID()
@@ -75,7 +75,7 @@ func main() {
7575

7676
flag.Parse()
7777

78-
config := oidc_server.Config[models.AuthServerUser]{
78+
config := oidc_server.Config[AuthServerUser]{
7979
SetUserInfoFunc: setUserInfoFunc,
8080
GetPrivateClaimsFromScopesFunc: getPrivateClaimsFromScopesFunc,
8181
PathPrefix: pathPrefix,
@@ -93,3 +93,41 @@ func main() {
9393

9494
oidc_server.Run(config)
9595
}
96+
97+
// AuthServerUser implements oidc-server storage.User.
98+
// It is used for development and testing purposes only.
99+
// nolint: revive
100+
// Still cannot access common interface fields:
101+
//
102+
// https://go101.org/generics/888-the-status-quo-of-go-custom-generics.html
103+
type AuthServerUser struct {
104+
ID_ string `json:"id"` // need exported for unmarshalling
105+
Username_ string `json:"username"`
106+
Password_ string `json:"password"`
107+
FirstName string `json:"firstName"`
108+
LastName string `json:"lastName"`
109+
Email string `json:"email"`
110+
EmailVerified bool `json:"emailVerified"`
111+
Phone string `json:"phone"`
112+
PhoneVerified bool `json:"phoneVerified"`
113+
PreferredLanguage language.Tag `json:"preferredLanguage"`
114+
IsAdmin_ bool `json:"isAdmin"`
115+
}
116+
117+
func (u AuthServerUser) ID() string {
118+
return u.ID_
119+
}
120+
121+
func (u AuthServerUser) Username() string {
122+
return u.Username_
123+
}
124+
125+
func (u AuthServerUser) IsAdmin() bool {
126+
return u.IsAdmin_
127+
}
128+
129+
func (u AuthServerUser) Password() string {
130+
return u.Password_
131+
}
132+
133+
var _ storage.User = (*AuthServerUser)(nil)

db/migrations/0000002_init.up.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ create table users (
270270
user_id uuid default gen_random_uuid () primary key
271271
, username text not null unique
272272
, email text not null unique
273+
, age int
273274
, first_name text
274275
, last_name text
275276
, full_name text generated always as ( case when first_name is null then

db/post-migrations/003_cache_tables_triggers.up.sql

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,23 @@ end;
208208
$$
209209
language plpgsql;
210210

211+
-- NOTE: concurrently not supported in migration transactions
212+
create or replace function create_or_update_index (idx_name text , project_name text , idx_def text)
213+
returns VOID
214+
as $$
215+
begin
216+
if idx_def <> '' and not same_index_definition (idx_name , idx_def) then
217+
raise notice 'recreating differing index: %' , idx_name;
218+
execute FORMAT('create index newidx on cache__%I %s;' , project_name , idx_def);
219+
execute FORMAT('drop index if exists %I;' , idx_name);
220+
execute FORMAT('alter index newidx rename to %I;' , idx_name);
221+
else
222+
raise notice 'skipping identical create index statement: %' , idx_name;
223+
end if;
224+
end;
225+
$$
226+
language plpgsql;
227+
211228
--
212229
--
213230
-- Sync project work item tables cache
@@ -224,9 +241,14 @@ begin
224241
work_items_table_name
225242
from
226243
projects loop
244+
--
245+
-- sync cache table - idempotent
246+
--
227247
perform
228248
create_or_update_work_item_cache_table (project_name);
229-
249+
--
250+
-- at least one gin index mandatory for all projects
251+
--
230252
idx_name := FORMAT('public.cache__%I_gin_index' , project_name);
231253

232254

@@ -237,18 +259,23 @@ begin
237259
- gin is apparently not too helpful for very short string searches.
238260
- btree not usable for text except for equals and startsWith.
239261
240-
create index on cache__demo_work_items using gin (
262+
263+
make sure the index used in explain is the one being tested...
264+
265+
drop index if exists lastmsg;
266+
create index lastmsg on cache__demo_work_items using btree (
267+
last_message_at desc);
268+
269+
drop index if exists abc;
270+
create index abc on cache__demo_work_items using gin (
241271
description gin_trgm_ops
242272
, last_message_at
243273
, reopened);
244274
245275
set enable_seqscan = "off";
246-
explain analyze select * from cache__demo_work_items where description ilike '%54%' order by last_message_at desc;
247-
248-
1000 rows dataset: (to properly test index, rows returned must be >0)
249-
Index Scan Backward using cache__demo_work_items_last_message_at_idx on cache__demo_work_items (cost=0.28..58.22 rows=20 width=145) (actual time=0.059..0.725 rows=20 loops=1)
250-
Filter: (description ~~* '%54%'::text)
251-
Rows Removed by Filter: 980
276+
-- with 1000 rows
277+
explain analyze select * from cache__demo_work_items where description ilike '%4%' order by last_message_at desc limit 20;
278+
-> Index Scan using lastmsg on cache__demo_work_items (cost=0.28..58.23 rows=263 width=145) (actual time=0.018..0.160 rows=20 loops=1)
252279
*/
253280
case project_name
254281
when 'demo_work_items' then
@@ -257,7 +284,6 @@ begin
257284
, line gin_trgm_ops
258285
, description gin_trgm_ops
259286
, ref gin_trgm_ops
260-
, last_message_at
261287
, reopened)';
262288
when 'demo_two_work_items' then
263289
idx_def := 'using gin (
@@ -268,22 +294,27 @@ begin
268294
idx_def := ''; raise exception 'No index definition found for cache__%' , project_name;
269295
end case;
270296

271-
if idx_def <> '' and not same_index_definition (idx_name , idx_def) then
272-
raise notice 'recreating differing index: %' , idx_name;
297+
perform
298+
create_or_update_index (idx_name , project_name , idx_def);
273299
--
274-
execute FORMAT('create index newidx on cache__%I %s;' , project_name , idx_def);
300+
-- adhoc indexes. TODO: abstract away idx create/replace
275301
--
276-
execute FORMAT('drop index if exists %I;' , idx_name);
302+
case project_name
303+
when 'demo_work_items' then
304+
idx_name := FORMAT('public.cache__%I_last_message_at_index' , project_name);
305+
--
306+
idx_def := 'using btree (last_message_at)';
307+
perform
308+
create_or_update_index (idx_name , project_name , idx_def);
309+
else
310+
end case;
277311
--
278-
execute FORMAT('alter index newidx rename to %I;' , idx_name);
279-
else
280-
raise notice 'skipping identical create index statement: %' , idx_name;
281-
end if;
282-
283-
execute FORMAT('create or replace trigger work_items_sync_trigger_%1$I
312+
-- triggers
313+
--
314+
execute FORMAT('create or replace trigger work_items_sync_trigger_%1$I
284315
after insert or update on %1$I for each row
285316
execute function sync_work_items (%1$s);' , project_name);
286-
end loop;
287-
end;
317+
end loop;
318+
end;
288319
$BODY$
289320
language plpgsql;

e2e/client/gen/model/dbUser.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type { Scopes } from './scopes'
99
import type { DbUserID } from './dbUserID'
1010

1111
export interface DbUser {
12+
age?: number | null
1213
createdAt: Date
1314
deletedAt?: Date | null
1415
email: string

e2e/client/gen/model/getPaginatedUsersParams.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
* OpenAPI spec version: 2.0.0
77
*/
88
import type { Direction } from './direction'
9+
import type { GetPaginatedUsersQueryParameters } from './getPaginatedUsersQueryParameters'
910
import type { GetPaginatedUsersFilterObjectsItem } from './getPaginatedUsersFilterObjectsItem'
1011
import type { GetPaginatedUsersNestedObj } from './getPaginatedUsersNestedObj'
1112

1213
export type GetPaginatedUsersParams = {
1314
limit: number
1415
direction: Direction
1516
cursor: string
17+
searchQuery?: GetPaginatedUsersQueryParameters
1618
filter?: {
1719
bools?: boolean[]
1820
ints?: number[]

0 commit comments

Comments
 (0)