Skip to content

Commit 91e5b69

Browse files
committed
Migrate mimir-rag from Supabase to generic Postgres with Prisma
1 parent 01b0345 commit 91e5b69

9 files changed

Lines changed: 61 additions & 708 deletions

File tree

mimir-rag/Dockerfile

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,27 @@
22

33
FROM node:20-alpine AS builder
44
WORKDIR /app
5+
6+
# Install Python and build tools needed for tree-sitter native modules
7+
RUN apk add --no-cache python3 make g++
8+
59
COPY package*.json ./
610
COPY tsconfig.json ./
11+
COPY prisma.config.ts ./
712
COPY prisma ./prisma
813
COPY src ./src
9-
RUN npm ci --omit=optional && \
10-
npx prisma generate && \
11-
npm run build && \
12-
npm prune --omit=dev --omit=optional && \
13-
# Remove unnecessary files from node_modules
14-
find node_modules -type f \( -name "*.md" -o -name "*.ts" -o -name "*.map" \) -delete && \
15-
find node_modules -type d \( -name "test" -o -name "tests" -o -name "__tests__" -o -name "docs" \) -exec rm -rf {} + 2>/dev/null || true
14+
15+
RUN npm ci --omit=optional
16+
RUN PRISMA_SKIP_DATABASE_URL_CHECK=true npx prisma generate
17+
RUN npm run build || (echo "Build failed!" && exit 1)
18+
RUN ls -la dist/ || (echo "dist directory not found after build" && exit 1)
19+
RUN npm prune --omit=dev --omit=optional
20+
21+
# Clean up build tools to reduce image size (they're no longer needed after npm install)
22+
RUN apk del python3 make g++
23+
24+
RUN find node_modules -type f \( -name "*.md" -o -name "*.ts" -o -name "*.map" \) -delete 2>/dev/null || true
25+
RUN find node_modules -type d \( -name "test" -o -name "tests" -o -name "__tests__" -o -name "docs" \) -exec rm -rf {} + 2>/dev/null || true
1626

1727
FROM node:20-alpine AS runner
1828
WORKDIR /app
@@ -26,10 +36,14 @@ RUN apk add --no-cache postgresql-client && \
2636
COPY --from=builder /app/node_modules ./node_modules
2737
COPY --from=builder /app/dist ./dist
2838
COPY --from=builder /app/package.json ./package.json
39+
COPY --from=builder /app/prisma.config.ts ./
2940
COPY --from=builder /app/prisma ./prisma
3041
COPY .env.example ./
3142
COPY scripts ./scripts
3243

44+
# Make entrypoint script executable
45+
RUN chmod +x ./scripts/docker-entrypoint.sh
46+
3347
# Create non-root user and switch to it
3448
RUN addgroup -g 1001 -S nodejs && \
3549
adduser -S nodejs -u 1001 && \

mimir-rag/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ baseline-db:
5959
echo "Baselining existing database schema (marking migration as applied)..."; \
6060
npx prisma migrate resolve --applied 0_init && echo "Baseline complete! You can now run 'make setup-db' or 'make server'." || echo "Note: Migration may already be marked as applied."
6161

62-
server:
62+
server: setup-db
6363
@if [ -f "$(CONFIG_PATH)" ]; then \
6464
set -a; \
6565
. "$(CONFIG_PATH)"; \

mimir-rag/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ The database schema is automatically initialized when you run `make server` if y
4141
Provide the full PostgreSQL connection string in `.env`:
4242
```bash
4343
MIMIR_DATABASE_URL=postgresql://user:password@host:5432/database
44+
# For Supabase: Use Session Pooler (port 6543) if using Docker - see README for details
4445
```
4546

4647
**Important:** The default schema uses `vector(3072)` for embeddings. If your embedding model uses a different dimension, you must update the database schema:
@@ -141,6 +142,8 @@ Key configuration variables include:
141142
- **Database**: `MIMIR_DATABASE_URL` (required) - PostgreSQL connection string
142143

143144
**Note:** Update the embedding dimension in the database schema (`vector(3072)`) to match your embedding model's output dimension.
145+
146+
**For Supabase users with Docker:** If your Supabase database shows "Not IPv4 compatible", use the **Session Pooler** connection string instead of the direct connection. Get it from: Supabase Dashboard → Settings → Database → Connection Pooling → Session mode (port 6543). This provides IPv4 compatibility required for Docker.
144147
- **GitHub** (language-agnostic code + docs ingestion):
145148
- `MIMIR_GITHUB_URL` - Main repository URL (fallback if separate repos not set)
146149
- `MIMIR_GITHUB_CODE_URL` - Separate repository for code (TypeScript, Python, etc.) (optional)

mimir-rag/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@
2525
"@types/node": "^24.10.0",
2626
"@types/pg": "^8.11.10",
2727
"pino-pretty": "^13.1.2",
28-
"prisma": "^7.0.0",
2928
"tsx": "^4.20.6"
3029
},
3130
"dependencies": {
31+
"prisma": "^7.0.0",
3232
"@ai-sdk/anthropic": "^2.0.50",
3333
"@ai-sdk/google": "^2.0.44",
3434
"@ai-sdk/mistral": "^2.0.25",

mimir-rag/prisma.config.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,29 @@
1+
/// <reference types="node" />
12
import "dotenv/config";
23
import { defineConfig } from "prisma/config";
3-
import { getDatabaseUrl } from "./src/utils/getDatabaseUrl";
44

5-
const databaseUrl = getDatabaseUrl();
5+
function getDatabaseUrl(): string {
6+
if (process.env.DATABASE_URL) {
7+
return process.env.DATABASE_URL;
8+
}
9+
if (process.env.MIMIR_DATABASE_URL) {
10+
return process.env.MIMIR_DATABASE_URL;
11+
}
12+
throw new Error("DATABASE_URL or MIMIR_DATABASE_URL must be set");
13+
}
14+
15+
function getDatabaseUrlSafe(): string {
16+
if (process.env.PRISMA_SKIP_DATABASE_URL_CHECK === "true") {
17+
return process.env.DATABASE_URL || process.env.MIMIR_DATABASE_URL || "postgresql://placeholder";
18+
}
19+
try {
20+
return getDatabaseUrl();
21+
} catch (error) {
22+
throw error;
23+
}
24+
}
25+
26+
const databaseUrl = getDatabaseUrlSafe();
627

728
export default defineConfig({
829
schema: "prisma/schema.prisma",

mimir-rag/src/config/loadConfig.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { config as loadDotenv } from "dotenv";
22
import path from "node:path";
33
import type { AppConfig, LLMProviderName, CodeRepoConfig, DocsRepoConfig } from "./types";
4+
import { getDatabaseUrl } from "../utils/getDatabaseUrl";
45

56
const PACKAGE_ROOT = path.resolve(__dirname, "..", "..");
67

@@ -157,7 +158,7 @@ export async function loadAppConfig(configPath?: string): Promise<AppConfig> {
157158
throw new Error("Server configuration must include MIMIR_SERVER_API_KEY.");
158159
}
159160

160-
const databaseUrl = getEnv("MIMIR_DATABASE_URL");
161+
const databaseUrl = getDatabaseUrl();
161162
const databaseTable = getEnv("MIMIR_DATABASE_TABLE", false) ?? "docs";
162163

163164
const embeddingProvider = getEnv("MIMIR_LLM_EMBEDDING_PROVIDER") as LLMProviderName;

mimir-rag/src/database/chunks.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export async function upsertChunks(
8686
const chunkValues: any[] = [
8787
chunk.content,
8888
chunk.contextualText,
89-
`[${chunk.embedding.join(",")}]`, // Format as PostgreSQL array for vector type
89+
`[${chunk.embedding.join(",")}]`,
9090
chunk.filepath,
9191
chunk.chunkId,
9292
chunk.chunkTitle,
@@ -99,7 +99,13 @@ export async function upsertChunks(
9999
chunk.startLine ?? null,
100100
chunk.endLine ?? null
101101
];
102-
const chunkPlaceholders = chunkValues.map((_, i) => `$${values.length + i + 1}`).join(", ");
102+
const chunkPlaceholders = chunkValues.map((_, i) => {
103+
const paramIndex = values.length + i + 1;
104+
if (i === 2) {
105+
return `$${paramIndex}::vector`;
106+
}
107+
return `$${paramIndex}`;
108+
}).join(", ");
103109
placeholders.push(`(${chunkPlaceholders})`);
104110
values.push(...chunkValues);
105111
});

mimir-rag/src/database/search.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ export async function matchDocuments(
1111
similarityThreshold?: number
1212
): Promise<RetrievedChunk[]> {
1313
const threshold = similarityThreshold ?? 0.75;
14-
const embeddingArray = `[${embedding.join(",")}]`;
14+
const embeddingString = `[${embedding.join(",")}]`;
1515
const result = await pool.query(
1616
`SELECT * FROM match_docs($1::vector, $2, $3)`,
17-
[embeddingArray, matchCount, threshold]
17+
[embeddingString, matchCount, threshold]
1818
);
1919

2020
return result.rows.map((row: PostgresDocRow) => ({

0 commit comments

Comments
 (0)