Skip to content

Instantly share code, notes, and snippets.

@a1300
Created June 1, 2025 15:15
Show Gist options
  • Save a1300/eeb5b3978b444f9819e269263a416d0c to your computer and use it in GitHub Desktop.
Save a1300/eeb5b3978b444f9819e269263a416d0c to your computer and use it in GitHub Desktop.
svg
@a1300
Copy link
Author

a1300 commented Jun 17, 2025

@a1300
Copy link
Author

a1300 commented Jun 17, 2025

import { pgTable, text } from "drizzle-orm/pg-core";

const users = pgTable("users", {
  id: text("id"),
  // This column is stored as text in the DB, but we want its type to be a specific union in TS
  role: text("role").$type<"admin" | "user" | "guest">(),
});

@a1300
Copy link
Author

a1300 commented Jun 17, 2025

@a1300
Copy link
Author

a1300 commented Jun 17, 2025

server.ts

import { createHTTPServer } from "@trpc/server/adapters/standalone";
import { router, publicProcedure } from "./trpc";
import { instance } from "./db-instance";
import { Categories } from "./db";
import z from "zod";


// from tanstack/table
export type SortDirection = 'asc' | 'desc';
export type ColumnSort = {
  id: string
  desc: boolean
}
export type SortingState = ColumnSort[];







const categoryKeys = z.enum([
  "CategoryID",
  "CategoryName",
  "Description",
  "Picture",
]);
export type CategoryKeysType = z.infer<typeof categoryKeys>;


const columnSort = z.object({
  id: categoryKeys,
  desc: z.boolean(),
});


const dynamicInput = z.object({
  select: z.array(categoryKeys),
  sorting: z.array(columnSort),
});
export type DynamicInputType = z.infer<typeof dynamicInput>;

const appRouter = router({
  dynamic: publicProcedure
    .input(dynamicInput)
    .query(async ({ input }) => {
      console.log(`input: ${JSON.stringify(input, null, 2)}`);
      let query = instance.selectFrom("categories")

      for (let i = 0; i < input.sorting.length; ++i) {

        query = query.orderBy(input.sorting[i].id, input.sorting[i].desc ? 'desc' : 'asc')
      }

      query = query.select(input.select);
      
      const result = await query.execute();

      return result;
    }),
});

// Export type router type signature,
// NOT the router itself.
export type AppRouter = typeof appRouter;




const server = createHTTPServer({
  router: appRouter,
});
 
server.listen(3000);
console.log('trpc server listening on port 3000');

``

@a1300
Copy link
Author

a1300 commented Jun 17, 2025

@a1300
Copy link
Author

a1300 commented Jun 17, 2025

@a1300
Copy link
Author

a1300 commented Jun 18, 2025

@a1300
Copy link
Author

a1300 commented Jun 19, 2025

@a1300
Copy link
Author

a1300 commented Jun 20, 2025

@a1300
Copy link
Author

a1300 commented Jun 21, 2025

@a1300
Copy link
Author

a1300 commented Jun 21, 2025

@a1300
Copy link
Author

a1300 commented Jun 21, 2025

@a1300
Copy link
Author

a1300 commented Jun 21, 2025

@a1300
Copy link
Author

a1300 commented Jun 21, 2025

@a1300
Copy link
Author

a1300 commented Jun 21, 2025

resize images on server with sharp

https://www.npmjs.com/package/sharp

@a1300
Copy link
Author

a1300 commented Jun 23, 2025

@a1300
Copy link
Author

a1300 commented Jun 27, 2025

@a1300
Copy link
Author

a1300 commented Jul 4, 2025

Yes, you can **dynamically access (or call) a Drizzle ORM table** in your code, but exactly how you do it depends on your setup and what you mean by "dynamically":

## If you mean selecting a table by name at runtime

Drizzle tables are usually statically imported as JavaScript/TypeScript objects, e.g.:
```ts
import { users, posts } from './schema';

But if you want to access a table "dynamically" based on a variable (say, a table name string from user input), you need to map those names to their table objects.

Example: Dynamic Table Access

Suppose you have several tables:

import * as schema from "./schema";

// schema exports: users, posts, comments, etc

You can create a map:

const tables = {
  users: schema.users,
  posts: schema.posts,
  comments: schema.comments,
};

function getTableByName(name: string) {
  return tables[name as keyof typeof tables];
}

// Usage:
const tableName = "users";
const table = getTableByName(tableName);

Note:

  • You cannot do db[tableName] directly (as you might with some ORMs) because Drizzle's tables are not registered on a global object.
  • You cannot "create" or "import" a table at runtime; you must import all possible table objects at build time.

If you mean querying a table without hardcoding its name

You still need to access the table object, as above, then use Drizzle's query API:

const table = getTableByName(tableName);
const results = await db.select().from(table).all();

Security Note

Be careful with dynamic table access: never use unchecked user input directly to select tables, as this can expose sensitive data or enable attacks.

Summary Table

What you want Can you do it? How?
Access table by name Yes (with mapping) Map names to imported table objects
Import table at runtime No Tables must be imported at build time
Query table dynamically Yes (with mapping) Use mapped table object in your Drizzle queries

If you have a specific use case or code snippet, I can help you adapt it for dynamic table access in Drizzle!

@a1300
Copy link
Author

a1300 commented Jul 5, 2025

@a1300
Copy link
Author

a1300 commented Jul 5, 2025

@a1300
Copy link
Author

a1300 commented Jul 5, 2025

@a1300
Copy link
Author

a1300 commented Jul 5, 2025

@a1300
Copy link
Author

a1300 commented Jul 6, 2025

@a1300
Copy link
Author

a1300 commented Jul 6, 2025

@a1300
Copy link
Author

a1300 commented Jul 7, 2025

@a1300
Copy link
Author

a1300 commented Jul 8, 2025

To handle dependent queries in TanStack React Query (react-query), you typically want the second query to wait until the first query has completed and provided the necessary data. The key is to use the enabled option in your second query, so it only runs when the first query is successful and its data is available.

Here’s how you can do it:

import { useQuery } from '@tanstack/react-query';

// First query
const { data: firstData, isLoading: loadingFirst } = useQuery({
  queryKey: ['first'],
  queryFn: fetchFirstData,
});

// Second query, only enabled when firstData is available
const { data: secondData, isLoading: loadingSecond } = useQuery({
  queryKey: ['second', firstData?.id], // Use firstData as part of the key if relevant
  queryFn: () => fetchSecondData(firstData.id),
  enabled: !!firstData, // Only run when firstData exists
});

Explanation:

  • The first query fetches some data.
  • The second query is dependent on the data from the first query. It uses the enabled property to ensure it only runs when firstData is available (i.e., after the first query has finished successfully).
  • This pattern ensures the second request waits for the first to complete.

References:

Let me know if you need a more detailed example!

@a1300
Copy link
Author

a1300 commented Jul 12, 2025

use ref for performance gains:

https://www.youtube.com/watch?v=TgpTG5XYoz4

@a1300
Copy link
Author

a1300 commented Jul 12, 2025

Great question! To efficiently sync a user's interests (stored as a JS array) with your Drizzle/Postgres backend when they update their interests via a mutation, you should:

1. Data Model

Assume:

  • persons table (id, name, ...)
  • interests table (id, name)
  • person_interests table (person_id, interest_id) — many-to-many relationship

2. Frontend Flow

  • User sends the full, updated array of interests (e.g. ["music", "coding", "cooking"]) when they save.

3. Backend Mutation Steps

a. Upsert interests

  • For each interest in the array, ensure it exists in the interests table.
    • Use Drizzle’s insert with onConflictDoNothing (or similar) to avoid duplicates.

b. Fetch Interest IDs

  • Retrieve all interest IDs for the submitted names.

c. Sync Person's Interests

  • Fetch the current interests for the person from person_interests.
  • Compute:
    • To Add: Interests in the new array but not in DB.
    • To Remove: Interests in DB but not in the new array.
  • Use Drizzle to insert new links and delete old ones.

Sample Drizzle Code

// 1. Upsert interests
await db.insert(interests).values(
  newInterests.map(name => ({ name }))
).onConflictDoNothing(); // prevents duplicate interest names

// 2. Get interest IDs
const interestRecords = await db
  .select({ id: interests.id, name: interests.name })
  .from(interests)
  .where(in(interests.name, newInterests));

const interestIdMap = Object.fromEntries(
  interestRecords.map(rec => [rec.name, rec.id])
);

// 3. Get current user's interests
const currentLinks = await db
  .select({ interest_id: person_interests.interest_id })
  .from(person_interests)
  .where(eq(person_interests.person_id, personId));

const currentInterestIds = new Set(currentLinks.map(l => l.interest_id));
const newInterestIds = new Set(Object.values(interestIdMap));

// 4. Compute changes
const toAdd = [...newInterestIds].filter(id => !currentInterestIds.has(id));
const toRemove = [...currentInterestIds].filter(id => !newInterestIds.has(id));

// 5. Add new links
if (toAdd.length > 0) {
  await db.insert(person_interests).values(
    toAdd.map(interest_id => ({
      person_id: personId,
      interest_id,
    }))
  );
}

// 6. Remove old links
if (toRemove.length > 0) {
  await db.delete(person_interests)
    .where(
      and(
        eq(person_interests.person_id, personId),
        in(person_interests.interest_id, toRemove)
      )
    );
}

Why this approach?

  • Efficient: Only adds/removes what's changed.
  • Prevents duplicates.
  • Handles many-to-many properly.
  • Works with Drizzle and Postgres.

Tips

  • Wrap in a transaction for atomicity.
  • Validate input on the backend.
  • You do not update interests themselves, just the linking table.

If your interests are not a separate table (i.e., you store them as a JSON array), the approach is simpler (just update the array), but you'll lose normalization, searchability, and de-duplication features.

Let me know if you want the code adapted for a different schema or want transaction handling!

@a1300
Copy link
Author

a1300 commented Jul 13, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment