Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add postgres support to the todo application to facilitate postgres UDT demo. #2256

Open
wants to merge 1 commit into
base: edge
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
537 changes: 446 additions & 91 deletions samples/demo/package-lock.json

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion samples/demo/package.json
Original file line number Diff line number Diff line change
@@ -27,13 +27,16 @@
"@dapr/dapr": "^3.3.1",
"@types/mongodb": "^4.0.7",
"@types/morgan": "^1.9.9",
"@types/pg": "^8.11.11",
"@types/redis": "^4.0.11",
"@types/uuid": "^9.0.8",
"bootstrap": "^5.3.3",
"dotenv": "^16.4.5",
"express": "^4.21.1",
"mongodb": "^6.5.0",
"morgan": "^1.10.0",
"redis": "^4.6.13",
"pg": "^8.14.0",
"redis": "^4.7.0",
"uuid": "^9.0.1"
}
}
76 changes: 76 additions & 0 deletions samples/demo/src/db/postgres.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { Pool } from 'pg';
import { Repository, Item, RepositoryFactory } from './repository';
import { v4 as uuidv4 } from 'uuid';

export class PostgresFactory implements RepositoryFactory {
private connectionString: string;

constructor(connectionString: string) {
this.connectionString = connectionString;
}

async create(): Promise<Repository> {
const pool = new Pool({
connectionString: this.connectionString,
});

// Ensure the table exists
await pool.query(`
CREATE TABLE IF NOT EXISTS items (
id UUID PRIMARY KEY,
title TEXT NOT NULL,
done BOOLEAN NOT NULL
);
`);

return new PostgresRepository(pool);
}
}

export class PostgresRepository implements Repository {
private pool: Pool;

constructor(pool: Pool) {
this.pool = pool;
}

async dispose(): Promise<void> {
await this.pool.end();
}

isRealDatabase(): boolean {
return true;
}

async get(id: string): Promise<Item | null> {
const result = await this.pool.query('SELECT * FROM items WHERE id = $1', [id]);
if (result.rows.length === 0) {
return null;
}
return result.rows[0];
}

async list(): Promise<Item[]> {
const result = await this.pool.query('SELECT * FROM items');
return result.rows;
}

async update(item: Item): Promise<Item | null> {
const result = await this.pool.query('UPDATE items SET title = $1, done = $2 WHERE id = $3 RETURNING *', [item.title, item.done, item.id]);
if (result.rows.length === 0) {
return null;
}
return result.rows[0];
}

async create(item: Item): Promise<Item> {
const id = uuidv4();
item.id = id;
const result = await this.pool.query('INSERT INTO items (id, title, done) VALUES ($1, $2, $3) RETURNING *', [item.id, item.title, item.done]);
return result.rows[0];
}

async delete(id: string): Promise<void> {
await this.pool.query('DELETE FROM items WHERE id = $1', [id]);
}
}
77 changes: 46 additions & 31 deletions samples/demo/src/db/repository.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { MongoFactory } from './mongo';
import { MongoFactory } from './mongo';
import { RedisFactory } from './redis';
import { InMemoryFactory } from './inmemory';
import { DaprFactory } from './dapr';
import { PostgresFactory } from './postgres';
import { CommunicationProtocolEnum } from '@dapr/dapr';

export interface Item {
@@ -18,51 +19,65 @@ export interface Repository {
dispose(): Promise<void>
isRealDatabase(): boolean
get(id: string): Promise<Item | null>
list() : Promise<Item[]>
update(item: Item) : Promise<Item | null>
list(): Promise<Item[]>
update(item: Item): Promise<Item | null>
create(item: Item): Promise<Item>
delete(id: string): Promise<void>
}

export function createFactory(): RepositoryFactory {
if (process.env.CONNECTION_STATESTORE_COMPONENTNAME) {
console.log(`Using Dapr state store: found component name '${process.env.CONNECTION_STATESTORE_COMPONENTNAME}'in environment variable CONNECTION_STATESTORE_COMPONENTNAME`);
return new DaprFactory(process.env.CONNECTION_STATESTORE_COMPONENTNAME, { communicationProtocol: CommunicationProtocolEnum.GRPC });
console.log(`Using Dapr state store: found component name '${process.env.CONNECTION_STATESTORE_COMPONENTNAME}' in environment variable CONNECTION_STATESTORE_COMPONENTNAME`);
return new DaprFactory(process.env.CONNECTION_STATESTORE_COMPONENTNAME, { communicationProtocol: CommunicationProtocolEnum.GRPC });
}

if (process.env.CONNECTION_MONGODB_CONNECTIONSTRING) {
console.log("Using MongoDB: found connection string in environment variable CONNECTION_MONGODB_CONNECTIONSTRING");
return new MongoFactory(process.env.CONNECTION_MONGODB_CONNECTIONSTRING);
console.log("Using MongoDB: found connection string in environment variable CONNECTION_MONGODB_CONNECTIONSTRING");
return new MongoFactory(process.env.CONNECTION_MONGODB_CONNECTIONSTRING);
}

if (process.env.CONNECTION_REDIS_URL) {
console.log("Using Redis: found url in environment variable CONNECTION_REDIS_URL");
return new RedisFactory(process.env.CONNECTION_REDIS_URL);
console.log("Using Redis: found url in environment variable CONNECTION_REDIS_URL");
return new RedisFactory(process.env.CONNECTION_REDIS_URL);
}

if (process.env.CONNECTION_REDIS_HOST) {
console.log("Using Redis: found hostname in environment variable CONNECTION_REDIS_HOST");
const connection = {
host: process.env.CONNECTION_REDIS_HOST!,
port: process.env.CONNECTION_REDIS_PORT!,
username: process.env.CONNECTION_REDIS_USERNAME || '',
password: process.env.CONNECTION_REDIS_PASSWORD || '',
}
let scheme = "redis"
if (connection.port === "6380") {
scheme = "rediss"
}
let usernamePass = "";
if (connection.username !== "" || connection.password !== "") {
usernamePass = `${connection.username}:${connection.password}@`
}
const url = `${scheme}://${usernamePass}${connection.host}:${connection.port}`
return new RedisFactory(url);
console.log("Using Redis: found hostname in environment variable CONNECTION_REDIS_HOST");
const connection = {
host: process.env.CONNECTION_REDIS_HOST!,
port: process.env.CONNECTION_REDIS_PORT!,
username: process.env.CONNECTION_REDIS_USERNAME || '',
password: process.env.CONNECTION_REDIS_PASSWORD || '',
}

let scheme = "redis"
if (connection.port === "6380") {
scheme = "rediss"
}

let usernamePass = "";
if (connection.username !== "" || connection.password !== "") {
usernamePass = `${connection.username}:${connection.password}@`
}

const url = `${scheme}://${usernamePass}${connection.host}:${connection.port}`
return new RedisFactory(url);
}


if (process.env.CONNECTION_POSTGRES_HOST) {
console.log("Using PostgreSQL: found hostname in environment variable CONNECTION_POSTGRES_HOST");
const connection = {
host: process.env.CONNECTION_POSTGRES_HOST!,
port: process.env.CONNECTION_POSTGRES_PORT!,
username: process.env.CONNECTION_POSTGRES_USERNAME || '',
password: process.env.CONNECTION_POSTGRES_PASSWORD || '',
database: process.env.CONNECTION_POSTGRES_DATABASE || '',
}
const url = `postgresql://${connection.username}:${connection.password}@${connection.host}:${connection.port}/${connection.database}`
console.log(`Postgres URL: ${url}`);
return new PostgresFactory(url);
}

console.log("Using in-memory store: no connection string found");
return new InMemoryFactory();
}
}