fix(session): Include where clause with order and limit

When applying the limit and order by, the where clause also needs to be
applied to yield the correct results. This can be seen with an example.

Assuming a data set where there are 100 sessions, with 10 sessions
belonging to a user with id `u_user1` and 90 sessions belonging to
`u_user2`. If the constructed query is like:

    select *
    from
        (select public_id from session limit 10) s,
        session_list ss
    where
        s.public_id = ss.public_id
        and s.user_id = 'u_user1'
    order by create_time asc;

The initial sub-query with the limit could return sessions only
belonging to `u_user2`, then it would apply the where clause and exclude
all of the rows.

Instead if the query is:

    with
    session_ids as (
        select public_id
        from sessions as s
        where
            s.user_id = 'u_user1'
        order by create_time asc
        limit 10
    )
    select *
    from session_list
    where
        session_list.public_id in (select * from session_ids)
    order by create_time asc;

The CTE applies the where clause ensuring that only sessions for
`u_user1` are used for the final select from the view.
Note that the CTE is use primarily for readability.

This also adds an index on `session (create_time)` to aide the query
planner in performing the order by.
This commit is contained in:
Timothy Messier committed 2022-04-29 16:33:44 -04:00
1 parent 4cf2a87e8d
commit f00af362dc
3 files changed
+28 -8

No files matched your search

@@ -0,0 +1,11 @@
begin;
-- Session list queries always use an order by on create_time.
-- This index can aide in performing this order by.
create index
session_create_time
on
session (create_time);
analyze session;
commit;
+15 -6
View File
@@ -126,13 +126,22 @@ select public_id, scope_id, user_id from session
`
sessionList = `
select *
from
(select public_id from session %s) s,
session_list ss
where
s.public_id = ss.public_id
with
session_ids as (
select public_id
from session as s
-- where clause is constructed
%s
-- order by clause is constructed
%s
-- limit is constructed
%s
)
select *
from session_list
where
session_list.public_id in (select * from session_ids)
-- order by clause again since order from cte is not guaranteed to be preserved
%s
;
`
+2 -2
View File
@@ -319,10 +319,10 @@ func (r *Repository) ListSessions(ctx context.Context, opt ...Option) ([]*Sessio
var whereClause string
if len(where) > 0 {
whereClause = " and " + strings.Join(where, " and ")
whereClause = " where " + strings.Join(where, " and ")
}
q := sessionList
query := fmt.Sprintf(q, limit, whereClause, withOrder)
query := fmt.Sprintf(q, whereClause, withOrder, limit, withOrder)
rows, err := r.reader.Query(ctx, query, args)
if err != nil {