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

feat(postgres): sim support #5

Merged
merged 7 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion postgres/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ When you deploy Terraform that uses the `Database` class, you will need to have
- [x] Support `tf-aws` platform using Neon
- [ ] Support `sim` platform
- [ ] Make all Neon databases share a Neon project to stay within the free tier
- [ ] Initialize secret value only `cloud.Secret` APIs
- [ ] Reuse postgres client across multiple queries by requiring users to call `connect()` / `end()` methods
- [ ] Initialize secret value through `cloud.Secret` APIs - https://github.com/winglang/wing/issues/2726
- [ ] Support [parameterized queries](https://node-postgres.com/features/queries#parameterized-query) for preventing SQL injection
- [ ] Customize [type parser](https://node-postgres.com/features/queries#types) for most popular postgres types / conversions to Wing types
- [ ] Have `query()` return both rows and a list of field names
Expand Down
11 changes: 5 additions & 6 deletions postgres/lib.test.w
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ bring expect;
bring util;
bring "./lib.w" as l;

if util.env("WING_TARGET") == "tf-aws" {
let db = new l.Database(name: "test", pgVersion: 15);
let db = new l.Database(name: "test", pgVersion: 15);

test "run a simple query" {
let result = db.query("SELECT 1 as one, 2 as two;");
expect.equal(result.at(0), {one: 1, two: 2});
}
test "run a simple query" {
util.sleep(1s);
Chriscbr marked this conversation as resolved.
Show resolved Hide resolved
let result = db.query("SELECT 1 as one, 2 as two;");
expect.equal(result.at(0), {one: 1, two: 2});
}
86 changes: 68 additions & 18 deletions postgres/lib.w
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
bring aws;
bring cloud;
bring containers;
bring http;
bring util;
bring "constructs" as constructs;
bring "cdktf" as cdktf;
bring "@rybickic/cdktf-provider-neon" as rawNeon;
bring "@cdktf/provider-aws" as tfaws;

struct Credentials {
host: str;
user: str;
password: str;
dbname: str;
}

pub struct DatabaseProps {
/**
* The database name.
Expand All @@ -22,7 +17,7 @@ pub struct DatabaseProps {
* The postgres version.
* @default 15
*/
pgVersion: num;
pgVersion: num?;
}

pub interface IDatabase {
Expand All @@ -31,9 +26,11 @@ pub interface IDatabase {

pub class Database {
inner: IDatabase;
init(props: DatabaseProps) {
new(props: DatabaseProps) {
let target = util.env("WING_TARGET");
if target == "tf-aws" {
if target == "sim" {
this.inner = new DatabaseSim(props);
} elif target == "tf-aws" {
this.inner = new DatabaseNeon(props);
} else {
throw "Unsupported target: " + target;
Expand All @@ -45,16 +42,52 @@ pub class Database {
}
}

pub class DatabaseNeon impl IDatabase {
class DatabaseSim impl IDatabase {
Chriscbr marked this conversation as resolved.
Show resolved Hide resolved
url: str?;
new(props: DatabaseProps) {
let image = "postgres:${props.pgVersion ?? 15}";
let container = new containers.Workload(
name: "postgres",
image: image,
env: {
POSTGRES_PASSWORD: "password"
},
port: 5432,
public: true,
);
this.url = container.getPublicUrl();
Chriscbr marked this conversation as resolved.
Show resolved Hide resolved
}

pub inflight query(query: str): Array<Map<Json>> {
let port = num.fromStr(http.parseUrl(this.url ?? "error").port);
return PgUtil._query(query, {
host: "localhost",
password: "password",
database: "postgres",
user: "postgres",
port: port,
ssl: false,
});
}
}

struct DbCredentials {
host: str;
user: str;
password: str;
database: str;
}

class DatabaseNeon impl IDatabase {
Chriscbr marked this conversation as resolved.
Show resolved Hide resolved
creds: cloud.Secret;

init(props: DatabaseProps) {
new(props: DatabaseProps) {
this.neonProvider();

// TODO: share a project between multiple databases
let project = new rawNeon.project.Project(
name: props.name,
pgVersion: props.pgVersion,
pgVersion: props.pgVersion ?? 15,
);

let db = new rawNeon.database.Database(
Expand All @@ -74,7 +107,7 @@ pub class DatabaseNeon impl IDatabase {
host: project.databaseHost,
user: project.databaseUser,
password: project.databasePassword,
dbname: project.databaseName,
database: project.databaseName,
})
) as "NeonCredentialsVersion";
}
Expand All @@ -90,10 +123,27 @@ pub class DatabaseNeon impl IDatabase {
return new rawNeon.provider.NeonProvider() as singletonKey in stack;
}

extern "./pg.js" static inflight _query(query: str, creds: Credentials): Array<Map<Json>>;

pub inflight query(query: str): Array<Map<Json>> {
let creds = Credentials.fromJson(this.creds.valueJson());
return DatabaseNeon._query(query, creds);
let creds = DbCredentials.fromJson(this.creds.valueJson());
return PgUtil._query(query, {
host: creds.host,
user: creds.user,
password: creds.password,
database: creds.database,
ssl: true,
});
}
}

struct ConnectionOptions {
host: str;
port: num?; // default: 5432
user: str;
password: str;
database: str;
ssl: bool;
}

class PgUtil {
pub extern "./pg.js" static inflight _query(query: str, creds: ConnectionOptions): Array<Map<Json>>;
}
Loading
Loading