Member Junction
    Preparing search index...

    Handles server-side pagination for query SQL by applying platform-specific paging clauses.

    Data SQL — appends OFFSET/FETCH (SQL Server) or LIMIT/OFFSET (PostgreSQL) directly to the original SQL. The query is not wrapped in a CTE, so all column scopes, ORDER BY references, and table aliases remain valid. TOP is stripped on SQL Server since it conflicts with OFFSET.

    Count SQL — wraps the original SQL (minus ORDER BY) in a CTE and produces SELECT COUNT(*) AS TotalRowCount FROM [__count]. ORDER BY is irrelevant for counting and must be removed since SQL Server forbids it in CTEs without TOP.

    This approach eliminates the need for ORDER BY remapping (mapping column references from the inner query scope to the outer CTE scope), which was the primary source of paging bugs.

    Index

    Constructors

    Methods

    • Extracts the top-level ORDER BY clause from SQL, ignoring ORDER BY inside subqueries, block comments, line comments, single-quoted strings, and bracket/double-quoted identifiers.

      Preserves the public static API for existing callers and tests.

      Parameters

      Returns { orderByClause: string | null; sqlWithoutOrder: string }

    • Determines whether the given params indicate paging should be applied.

      Parameters

      • startRow: number | undefined
      • maxRows: number | undefined

      Returns boolean

    • Strips a TOP N or TOP (N) clause from the beginning of a SELECT statement.

      Parameters

      • sql: string

      Returns { sql: string; topRemoved: boolean }

    • Applies a row cap to the outermost SELECT.

      maxRows is treated as a hard ceiling: the result is guaranteed to return at most maxRows rows whenever the SQL shape can be capped without corrupting the query.

      Strategy:

      1. Parse via AST. If the outermost SELECT has no existing cap, inject TOP N (SQL Server) or LIMIT N (PostgreSQL).
      2. If an existing numeric TOP/LIMIT is present, reduce it to min(existing, maxRows). The tighter cap wins.
      3. If the AST recognizes the shape but can't inject (TOP PERCENT, non-numeric TOP, UNION, WITH TIES, etc.), wrap with an outer SELECT TOP N * FROM (…) AS _mj_capped (or LIMIT on PG).
      4. If the parser can't handle the input but the SQL is CTE-headed, append OFFSET 0 ROWS FETCH NEXT N ROWS ONLY via buildDataSQL.
      5. Shapes that can't legally appear inside a derived table (FOR JSON, FOR XML, OPTION (...), SELECT INTO, mutations) are returned unchanged — the cap is moot (FOR JSON/XML return one row) or the validator should have rejected them earlier (mutations, SELECT INTO).

      Non-positive, non-finite, or fractional maxRows are sanitized (<= 0 and non-finite are no-ops; fractional values are floored).

      Parameters

      Returns string