Querying the Database
Domain Locker supports both Supabase and PostgreSQL as database backends. The application dynamically selects which to use based on the configured environment variables. This guide explains how the database integration works, the request flow, and how to interact with the database.
Database Options
Domain Locker determines the database type by checking the available environment variables:
- If Supabase credentials (
SUPABASE_URL
,SUPABASE_ANON_KEY
) are set, the app uses Supabase. - If PostgreSQL credentials (
DL_PG_HOST
,DL_PG_USER
, etc.) are set instead, it will use PostgreSQL. - Managed instances default to Supabase, whereas self-hosted instances default to PostgreSQL.
The entry point for database operations is database.service.ts
, which forwards calls to the appropriate database service.
Database Setup
(Coming soon...)
How the Database Files Fit Together
Database interactions are managed through multiple services:
database.service.ts
- Determines the active database type (Supabase/Postgres) and routes calls to the correct sub-service.
sb-database.service.ts
(for Supabase)- Handles queries using the Supabase client.
pg-database.service.ts
(for PostgreSQL)- Executes queries via the Postgres API executor.
db-query-services
- Contains sub-services for specific parts of the app, e.g., tags, domains, billing.
db-proxy.factory.ts
- Restricts write operations based on feature flags (e.g., disabling edits on a demo instance).
pg-api.util.ts
- Sends SQL queries to the Postgres API.
pg-executer.ts
- A server route that executes raw SQL queries for Postgres.
Request Flow
graph TD User -->|Triggers DB action| Angular_Component Angular_Component -->|Calls database.service.ts| DatabaseService DatabaseService -->|Checks Env Variables| EnvService EnvService -->|Supabase enabled?| SupabaseService EnvService -->|Postgres enabled?| PgDatabaseService SupabaseService -->|Executes query| SupabaseDB PgDatabaseService -->|Executes query| PgApiUtilService PgApiUtilService -->|Sends request| PgExecuter PgExecuter -->|Executes SQL| PostgresDB PostgresDB -->|Returns Data| PgExecuter SupabaseDB -->|Returns Data| SupabaseService DatabaseService -->|Returns Data| Angular_Component Angular_Component -->|Displays data| User
Using the Database in Code
Writing a New Query (Postgres & Supabase)
To add a new query, define it in the appropriate query service.
PostgreSQL example from (db-tags.service.ts
)
addTag(tag: Omit<Tag, 'id'>): Observable<Tag> {
const query = \`INSERT INTO tags (name, color, icon, description, user_id) VALUES ($1, $2, $3, $4, $5) RETURNING *\`;
const params = [tag.name, tag.color || null, tag.icon || null, tag.description || null];
return from(this.pgApiUtil.postToPgExecutor(query, params)).pipe(
map(response => response.data[0] as Tag),
catchError(error => this.handleError(error))
);
}
Supabase example from (db-tags.service.ts
)
addTag(tag: Omit<Tag, 'id'>): Observable<Tag> {
return from(this.supabase.from('tags').insert(tag).single()).pipe(
map(({ data, error }) => {
if (error) throw error;
if (!data) throw new Error('Failed to add tag');
return data as Tag;
}),
catchError(error => this.handleError(error))
);
}
Consuming a Query in an Angular Component
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
+ import DatabaseService from '~/app/services/database.service';
@Component({
standalone: true,
selector: 'app-example',
template: \`
<p>Tags: {{ tags | json }}</p>
\`,
imports: [CommonModule],
})
export class ExampleComponent {
+ tags: any[] = [];
+ constructor(private databaseService: DatabaseService) {}
+ ngOnInit() {
+ this.databaseService.instance.tagQueries.getTags().subscribe((tags) => {
+ this.tags = tags;
+ });
+ }
}
Additional Notes
- Queries should be added to the correct query service (
db-tags.service.ts
,db-domains.service.ts
, etc.). - Use Observables (
rxjs
) for async operations. - Errors should be handled via
handleError()
, which logs errors and prevents crashes. - Postgres uses the API executor, so queries must be structured correctly to be executed remotely.
- Use feature flags to control write operations (see
db-proxy.factory.ts
).