#fix lint errors

1 messages · Page 1 of 1 (latest)

keen steppe
#

fix the lint errors below

let query: OrderedQuery<typeof Tokens.schema.tokens>

    if (args.searchQuery) {
      query = ctx.db
        .query("tokens")
        .withSearchIndex("search_ticker", (q) =>
          q.search("ticker", args.searchQuery!)
        )
    } else {
      query = ctx.db.query("tokens")
    }

    const results = await query.order("desc").paginate(args.paginationOpts)

    const page = await Promise.all(
      results.page.map(async (token) => {
        // Get image URL
        let imageUrl: string | null = null
        if (token.imageId) {
          imageUrl = await ctx.storage.getUrl(token.imageId)
        }

        return {
          ...token,
          imageUrl
        }
      })
    )
fallow emberBOT
#

Hi @keen steppe. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

To fix the lint errors in your code, you need to address the TypeScript type issues that arise from dynamically building Convex queries. The main problem is that after applying a search index, the type of the query changes, and you can't use a single variable for all stages of building the query without explicit typing. This is a common issue in Convex, and the recommended solution is to use separate variables for each stage of the query, as described in the Convex dynamic query builder pattern Convex Cookbook: Dynamic Query Builders.

Here's how you can refactor your code to avoid lint/type errors:

import { OrderedQuery } from "convex/server"; // Adjust import as needed

let query;
if (args.searchQuery) {
  query = ctx.db
    .query("tokens")
    .withSearchIndex("search_ticker", (q) =>
      q.search("ticker", args.searchQuery!)
    );
} else {
  query = ctx.db.query("tokens");
}

// At this point, query may not be an OrderedQuery yet, so we need to apply order conditionally
let orderedQuery: OrderedQuery<any>;
orderedQuery = query.order("desc");

const results = await orderedQuery.paginate(args.paginationOpts);

const page = await Promise.all(
  results.page.map(async (token) => {
    // Get image URL
    let imageUrl: string | null = null;
    if (token.imageId) {
      imageUrl = await ctx.storage.getUrl(token.imageId);
    }

    return {
      ...token,
      imageUrl,
    };
  })
);

Key points:

  • Use separate variables for each stage of the query (query, then orderedQuery).
  • Avoid reassigning a variable to a different query type.
  • This pattern is recommended by Convex to avoid TypeScript errors when building queries dynamically Convex Cookbook: Dynamic Query Builders.
#

If you want to enforce best practices and catch similar issues early, consider setting up ESLint with the recommended Convex rules as described in the docs ESLint rules.

If you still encounter issues, please provide the specific lint error messages for more targeted help.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@keen steppe Kapa.ai is still learning and improving, please let me know how I did by reacting below.

keen steppe
#

@fallow ember

Property 'order' does not exist on type 'OrderedQuery<{ document: { _id: Id<"tokens">; _creationTime: number; walletAddress: string; platform: string; tokenAddress: string; source: string; ticker: string; description: string; imageId: Id<...>; }; fieldPaths: ExtractFieldPaths<...> | ...'.ts(2339)
fallow emberBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

The error message:

Property 'order' does not exist on type 'OrderedQuery<...>'

indicates that you are trying to call .order() on a value that is already an OrderedQuery. According to the Convex API, the .order() method is available on a Query or QueryInitializer, but once you call .order() (or use a search index, which also returns an OrderedQuery), you cannot call .order() again on the resulting OrderedQuery object. This is enforced by the Convex type system to prevent invalid query construction Convex Cookbook: Dynamic Query Builders Query.order docs.

How to fix:

  • Only call .order() once, and only on a Query or QueryInitializer.
  • If you use .withSearchIndex(), the result is already an OrderedQuery (with order by search relevance), so you should not call .order() again.

Corrected code:

let query;
if (args.searchQuery) {
  // withSearchIndex returns an OrderedQuery, already ordered by relevance
  query = ctx.db
    .query("tokens")
    .withSearchIndex("search_ticker", (q) =>
      q.search("ticker", args.searchQuery!)
    );
} else {
  // Here, you can apply .order() since it's still a Query
  query = ctx.db.query("tokens").order("desc");
}

// Now query is always an OrderedQuery, so you can paginate
const results = await query.paginate(args.paginationOpts);

const page = await Promise.all(
  results.page.map(async (token) => {
    let imageUrl: string | null = null;
    if (token.imageId) {
      imageUrl = await ctx.storage.getUrl(token.imageId);
    }
    return {
      ...token,
      imageUrl,
    };
  })
);
#

Summary:

If you need to conditionally apply ordering, ensure you only do so when the query is not already ordered.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: