internal/storage/postgres/storage.go
func (s *Storage) List(ctx context.Context, offset, limit int64, expiredAtFrom, expiredAtTo *time.Time) ([]*mnemosynerpc.Session, error) {
	span, ctx := opentracing.StartSpanFromContext(ctx, "postgres.storage.list")
	defer span.Finish()

	if limit == 0 {
		return nil, errors.New("cannot retrieve list of sessions, limit needs to be higher than 0")
	}

	args := []interface{}{offset, limit}
	query := "SELECT access_token, refresh_token, subject_id, subject_client, bag, expire_at FROM " + s.schema + "." + s.table + " "
	if expiredAtFrom != nil || expiredAtTo != nil {
		query += " WHERE "
	}
	switch {
	case expiredAtFrom != nil && expiredAtTo == nil:
		query += "expire_at > $3"
		args = append(args, expiredAtFrom)
	case expiredAtFrom == nil && expiredAtTo != nil:
		query += "expire_at < $3"
		args = append(args, expiredAtTo)
	case expiredAtFrom != nil && expiredAtTo != nil:
		query += "expire_at > $3 AND expire_at < $4"
		args = append(args, expiredAtFrom, expiredAtTo)
	}

	query += " OFFSET $1 LIMIT $2"
	labels := prometheus.Labels{"query": "list"}

	start := time.Now()
	rows, err := s.db.QueryContext(ctx, query, args...)
	s.incQueries(labels, start)
	if err != nil {
		s.incError(labels)
		return nil, err
	}
	defer rows.Close()

	sessions := make([]*mnemosynerpc.Session, 0, limit)
	for rows.Next() {
		var ent sessionEntity

		err = rows.Scan(
			&ent.AccessToken,
			&ent.RefreshToken,
			&ent.SubjectID,
			&ent.SubjectClient,
			&ent.Bag,
			&ent.ExpireAt,
		)
		if err != nil {
			s.incError(labels)
			return nil, err
		}

		expireAt, err := ptypes.TimestampProto(ent.ExpireAt)
		if err != nil {
			return nil, err
		}
		sessions = append(sessions, &mnemosynerpc.Session{
			AccessToken:   ent.AccessToken,
			RefreshToken:  ent.RefreshToken,
			SubjectId:     ent.SubjectID,
			SubjectClient: ent.SubjectClient,
			Bag:           ent.Bag,
			ExpireAt:      expireAt,
		})
	}
	if rows.Err() != nil {
		s.incError(labels)
		return nil, rows.Err()
	}

	return sessions, nil
}
func (s *Storage) List(ctx context.Context, offset, limit int64, expiredAtFrom, expiredAtTo *time.Time) ([]*mnemosynerpc.Session, error) {
	span, ctx := opentracing.StartSpanFromContext(ctx, "postgres.storage.list")
	defer span.Finish()

	if limit == 0 {
		return nil, errors.New("cannot retrieve list of sessions, limit needs to be higher than 0")
	}

	args := []interface{}{offset, limit}
	query := "SELECT access_token, refresh_token, subject_id, subject_client, bag, expire_at FROM " + s.schema + "." + s.table + " "
	if expiredAtFrom != nil || expiredAtTo != nil {
		query += " WHERE "
	}
	switch {
	case expiredAtFrom != nil && expiredAtTo == nil:
		query += "expire_at > $3"
		args = append(args, expiredAtFrom)
	case expiredAtFrom == nil && expiredAtTo != nil:
		query += "expire_at < $3"
		args = append(args, expiredAtTo)
	case expiredAtFrom != nil && expiredAtTo != nil:
		query += "expire_at > $3 AND expire_at < $4"
		args = append(args, expiredAtFrom, expiredAtTo)
	}

	query += " OFFSET $1 LIMIT $2"
	labels := prometheus.Labels{"query": "list"}

	start := time.Now()
	rows, err := s.db.QueryContext(ctx, query, args...)
	s.incQueries(labels, start)
	if err != nil {
		s.incError(labels)
		return nil, err
	}
	defer rows.Close()

	sessions := make([]*mnemosynerpc.Session, 0, limit)
	for rows.Next() {
		var ent sessionEntity

		err = rows.Scan(
			&ent.AccessToken,
			&ent.RefreshToken,
			&ent.SubjectID,
			&ent.SubjectClient,
			&ent.Bag,
			&ent.ExpireAt,
		)
		if err != nil {
			s.incError(labels)
			return nil, err
		}

		expireAt, err := ptypes.TimestampProto(ent.ExpireAt)
		if err != nil {
			return nil, err
		}
		sessions = append(sessions, &mnemosynerpc.Session{
			AccessToken:   ent.AccessToken,
			RefreshToken:  ent.RefreshToken,
			SubjectId:     ent.SubjectID,
			SubjectClient: ent.SubjectClient,
			Bag:           ent.Bag,
			ExpireAt:      expireAt,
		})
	}
	if rows.Err() != nil {
		s.incError(labels)
		return nil, rows.Err()
	}

	return sessions, nil
}
// List implements storage interface.