Skip to content

Commit

Permalink
update rfc: database schema design
Browse files Browse the repository at this point in the history
  • Loading branch information
tyrchen committed Oct 8, 2022
1 parent 7201367 commit 15777e7
Showing 1 changed file with 79 additions and 0 deletions.
79 changes: 79 additions & 0 deletions rfcs/0001-core-reservation.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ enum ReservationStatus {
BLOCKED = 3;
}
enum ReservationUpdateType {
UNKNOWN = 0;
CREATE = 1;
UPDATE = 2;
DELETE = 3;
}
message Reservation {
string id = 1;
string user_id = 2;
Expand Down Expand Up @@ -92,16 +99,88 @@ message QueryRequest {
google.protobuf.Timestamp end = 5;
}
message ListenRequest {}
message ListenResponse {
int8 op = 1;
Reservation reservation = 2;
}
service ReservationService {
rpc reserve(ReserveRequest) returns (ReserveResponse);
rpc confirm(ConfirmRequest) returns (ConfirmResponse);
rpc update(UpdateRequest) returns (UpdateResponse);
rpc cancel(CancelRequest) returns (CancelResponse);
rpc get(GetRequest) returns (GetResponse);
rpc query(QueryRequest) returns (stream Reservation);
// another system could monitor newly added/confirmed/cancelled reservations
rpc listen(ListenRequest) returns (stream Reservation);
}
```

### Database schema

We use postgres as the database. Below is the schema:

```sql
CREATE SCHEMA rsvp;
CREATE TYPE rsvp.reservation_status AS ENUM ('unknown', 'pending', 'confirmed', 'blocked');
CREATE TYPE rsvp.reservation_update_type AS ENUM ('unknown', 'create', 'update', 'delete');

CREATE TABLE rsvp.reservations (
id uuid NOT NULL DEFAULT uuid_generate_v4(),
user_id VARCHAR(64) NOT NULL,
status rsvp.reservation_status NOT NULL DEFAULT 'pending',

resource_id VARCHAR(64) NOT NULL,
timespan TSTZRANGE NOT NULL,

note TEXT,

CONSTRAINT reservations_pkey PRIMARY KEY (id),
CONSTRAINT reservations_conflict EXCLUDE USING gist (resource_id WITH =, timespan WITH &&)
);
CREATE INDEX reservations_resource_id_idx ON rsvp.reservations (resource_id);
CREATE INDEX reservations_user_id_idx ON rsvp.reservations (user_id);

-- if user_id is null, find all reservations within during for the resource
-- if resource_id is null, find all reservations within during for the user
-- if both are null, find all reservations within during
-- if both set, find all reservations within during for the resource and user
CREATE OR REPLACE FUNCTION rsvp.query(uid text, rid text, during: TSTZRANGE) RETURNS TABLE rsvp.reservations AS $$ $$ LANGUAGE plpgsql;

-- resevation change queue
CREATE TABLE rsvp.reservation_changes (
id SERIAL NOT NULL,
reservation_id uuid NOT NULL,
op rsvp.reservation_update_type NOT NULL,
);

-- trigger for add/update/delete a reservation
CREATE OR REPLACE FUNCTION rsvp.reservations_trigger() RETURNS TRIGGER AS $$
BEGIN
IF TG_OP = 'INSERT' THEN
-- update reservation_changes
INSERT INTO rsvp.reservation_changes (reservation_id, op) VALUES (NEW.id, 'create');
ELSIF TG_OP = 'UPDATE' THEN
-- if status changed, update reservation_changes
IF OLD.status <> NEW.status THEN
INSERT INTO rsvp.reservation_changes (reservation_id, op) VALUES (NEW.id, 'update');
END IF;
ELSIF TG_OP = 'DELETE' THEN
-- update reservation_changes
INSERT INTO rsvp.reservation_changes (reservation_id, op) VALUES (OLD.id, 'delete');
END IF;
-- notify a channel called reservation_update
NOTIFY reservation_update;
RETURN NULL;
END;
END
$$ LANGUAGE plpgsql;
CREATE TRIGGER reservations_trigger
AFTER INSERT OR UPDATE OR DELETE ON rsvp.reservations
FOR EACH ROW EXECUTE PROCEDURE rsvp.reservations_trigger();
```

Explain the proposal as if it was already included in the language and you were teaching it to another Rust programmer. That generally means:

- Introducing new named concepts.
Expand Down

0 comments on commit 15777e7

Please sign in to comment.