DB: start using ORM

This commit is contained in:
2024-02-06 21:14:23 -03:00
parent 1aa9f6992b
commit e47a0b3275
8 changed files with 66 additions and 151 deletions

View File

@@ -5,7 +5,7 @@ copyright "Copyright © 2024, Marisa"
license "MIT" license "MIT"
dependency "slf4d" version="~>3.0.0" dependency "slf4d" version="~>3.0.0"
dependency "handy-httpd" version="~>8.2.0" dependency "handy-httpd" version="~>8.2.0"
dependency "ddbc" version="~>0.5.8"
dependency "requests" version="~>2.1.3" dependency "requests" version="~>2.1.3"
dependency "ddbc" version="~>0.6.0" dependency "hibernated" version="~>0.4.0"
subConfiguration "ddbc" "PGSQL" subConfiguration "ddbc" "PGSQL"

View File

@@ -4,7 +4,7 @@
"automem": "0.6.9", "automem": "0.6.9",
"cachetools": "0.3.1", "cachetools": "0.3.1",
"d-unit": "0.10.2", "d-unit": "0.10.2",
"ddbc": "0.6.0", "ddbc": "0.5.9",
"derelict-pq": "2.2.0", "derelict-pq": "2.2.0",
"derelict-util": "2.0.6", "derelict-util": "2.0.6",
"handy-httpd": "8.2.0", "handy-httpd": "8.2.0",

View File

@@ -3,6 +3,8 @@ module db.db;
import slf4d; import slf4d;
import ddbc.core; import ddbc.core;
import hibernated.core;
import db.types;
enum DBConnector { enum DBConnector {
DB_MYSQL, DB_MYSQL,
@@ -21,68 +23,60 @@ struct DBSettings {
class DB { class DB {
protected DBSettings m_settings; protected DBSettings m_settings;
protected EntityMetaData m_schema;
protected DataSource m_ds; protected DataSource m_ds;
protected Connection m_conn; protected SessionFactory m_factory;
protected Statement m_stmt = null; protected Session m_session;
this(DBSettings settings) { this(DBSettings settings) {
this.m_settings = settings; this.m_settings = settings;
this.m_schema = new SchemaInfoImpl!(User);
} }
static DB getDB(DBSettings settings) {
switch (settings.connector) {
case DBConnector.DB_PGSQL:
import db.pgsql;
debugF!"DB type is PostgreSQL";
return new PostgresDB(settings);
default:
throw new Exception("DB not supported");
}
}
protected abstract DataSource getDataSource();
void connect() { void connect() {
this.m_ds = this.getDataSource(); Driver driver;
this.m_conn = this.m_ds.getConnection(); string url;
this.m_conn.setAutoCommit(false); string[string] params;
} Dialect dialect;
int runUpdate(string statement) { switch (this.m_settings.connector) {
if (this.m_stmt is null) case DBConnector.DB_PGSQL:
this.m_stmt = this.m_conn.createStatement(); debugF!"Using PGSQL driver";
debugF!"Running update: %s"(statement); import ddbc.drivers.pgsqlddbc;
return this.m_stmt.executeUpdate(statement); driver = new PGSQLDriver();
}
ResultSet runQuery(string statement) { with (this.m_settings) {
if (this.m_stmt is null) url = PGSQLDriver.generateUrl(host, port, dbname);
this.m_stmt = this.m_conn.createStatement(); params = PGSQLDriver.setUserAndPassword(username, password);
}
debugF!"Running query: %s"(statement); dialect = new PGSQLDialect();
break;
return this.m_stmt.executeQuery(statement); default:
} throw new Exception("Database connector not supported (yet)");
}
void runMigrations() { debugF!"Connecting to DB with URL: %s"(url);
ResultSet rs = this.runQuery(
`select * from information_schema.tables where table_name = 'migrations';`,
);
bool exists = rs.next(); this.m_ds = new ConnectionPoolDataSourceImpl(driver, url, params);
int ret = 0; this.m_factory = new SessionFactoryImpl(this.m_schema, dialect, this.m_ds);
if (exists == false) { { // Create schema if necessary
ret |= this.runUpdate( Connection conn = this.m_ds.getConnection();
`create table migrations( scope (exit)
id serial, conn.close();
name character varying this.m_factory.getDBMetaData().updateDBSchema(conn, false, true);
)`,
);
} }
} }
void close() {
if (this.m_session && this.m_session.isOpen())
this.m_session.close();
if (this.m_factory && this.m_factory.isClosed() == false)
this.m_factory.close();
}
} }

View File

@@ -1,25 +0,0 @@
module db.migrations.m_001_initial;
import db.migrations.migration;
Migration Initial = Migration(
[
`create table users(
id uuid not null,
name character varying(255),
handle character varying(255),
local boolean not null,
ap_id character varying(255) not null,
ap_privkey text,
ap_pubkey text,
ap_shared_inbox text,
ap_inbox text,
ap_outbox text,
ap_followers_addr text,
ap_following_addr text
);`
],
[
`drop table users;`
],
);

View File

@@ -1,31 +0,0 @@
module db.migrations.migration;
import singletons;
import db.migrations.m_001_initial;
struct Migration {
string[] upStatements;
string[] downStatements;
bool up() {
int result;
foreach (string statement; upStatements)
result |= Db.runUpdate(statement);
return result == 0;
}
bool down() {
int result;
foreach (string statement; downStatements)
result |= Db.runUpdate(statement);
return result == 0;
}
}
Migration[string] migrations = [
"001_initial": Initial,
];

View File

@@ -1,31 +0,0 @@
module db.pgsql;
import db.db;
import ddbc.core;
import ddbc.common;
import slf4d;
class PostgresDB : DB {
this(Args...)(auto ref Args args) {
super(args);
}
protected override DataSource getDataSource() {
import ddbc.drivers.pgsqlddbc;
Driver driver = new PGSQLDriver();
string url;
string[string] params;
with (this.m_settings) {
url = PGSQLDriver.generateUrl(host, port, dbname);
params = PGSQLDriver.setUserAndPassword(username, password);
}
debugF!"DB URL: %s"(url);
return new ConnectionPoolDataSourceImpl(driver, url, params);
}
}

View File

@@ -1,17 +1,23 @@
module db.types; module db.types;
class User { import hibernated.core;
string id;
string name;
string handle;
bool local;
string ap_id; @Entity
string ap_privkey; @Table("users")
string ap_pubkey; class User {
string ap_shared_inbox; @Generator(UUID_GENERATOR)
string ap_inbox; string id;
string ap_outbox;
string ap_followers_addr; @Column string name;
string ap_following_addr; @Column string handle;
@Column bool local;
@Column string ap_id;
@Column string ap_privkey;
@Column string ap_pubkey;
@Column string ap_shared_inbox;
@Column string ap_inbox;
@Column string ap_outbox;
@Column string ap_followers_addr;
@Column string ap_following_addr;
} }

View File

@@ -38,9 +38,11 @@ int main() {
} }
} }
Db = DB.getDB(dbSettings); Db = new DB(dbSettings);
Db.connect(); Db.connect();
Db.runMigrations();
scope (exit)
Db.close();
return 0; return 0;
} }