Conversation
|
I have no further comments, this pull request can be merged when review passes 👍 |
|
@sparsetable also remove |
|
Since this PR is closed, re-open another PR for this branch. |
ngjunsiang
left a comment
There was a problem hiding this comment.
See code review
| """ | ||
| Describes a day in a repeating timetable. | ||
| """ |
There was a problem hiding this comment.
[C#01]
We follow PEP257 on docstring formatting; one-line docstrings should have both triple-quotes on the same line.
See https://peps.python.org/pep-0257/
| """ | |
| Describes a day in a repeating timetable. | |
| """ | |
| """Describes a day in a repeating timetable.""" |
| """ | ||
| Describes a day in a repeating timetable. | ||
| """ | ||
| id: schema.CampusID = unique_field |
There was a problem hiding this comment.
[C#02]
While this isn't specified in Campus API/schema, it should (and I'll probably update it sometime or have one of you take it on):
- We reserve Campus IDs for entities that will be queried by the API: Users, Venues, Circles, Clients, ...
- These are entities that will have their own URL in the Campus API (
/api/v1/users/{user_uuid}) - We give them a string UUID to avoid the confusion of integer IDs: getting an ID isn't enough to tell what you're looking at--e.g. "is this User ID 1, Client ID 1, or Venue ID 1"? Campus ID is designed to tell you at a glance what you "have"
- This means non-queryable entities are not required/obliged to use Campus schema, and since we are not tracking their use in the DB/API, we should avoiding creating Campus IDs unless necessary
WeekDay and TimeSlot are not Campus entities, but technically enum values. This is a common feature in many programming languages, e.g. https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum, but we will not force their use because enum types often have their own constraints. Here we define the model for reference, i.e. to help other readers understand what we mean by a WeekDay or TimeSlot when they encounter it in the DB or in code.
So we can stick/revert to using int IDs
| id: schema.CampusID = unique_field | |
| id: int |
There was a problem hiding this comment.
Hi Mr Ng, i realise the reason i used CampusID initially is because setting id to schema.Integer triggers a type error. Model constrains id to be id: schema.CampusID | schema.UserID.
There was a problem hiding this comment.
Hi Mr Ng, i realise the reason i used
CampusIDinitially is because setting id to schema.Integer triggers a type error.Modelconstrainsidto beid: schema.CampusID | schema.UserID.
@sparsetable I forgot to mention: for "internal representations" (won't be queried directly through Campus API), there is no need to inherit base.Model. We use that primarily to enforce that all public Campus models have an id and created_at property polymorphically.
Internal representations will never be returned by the resource/API, just used as intermediate representations between JSON and database rows, and do not need to be polymorphic in the same way.
I realise that means we need another way to create the database table; let me investigate this and get back to you
There was a problem hiding this comment.
@sparsetable I just added an InternalModel class without id and created_at fields that you can use: #345
This has been merged into weekly branch, merge those changes in to see and use the class.
| id: schema.CampusID = field(default_factory=( | ||
| lambda: uid.generate_category_uid("timetable", length=8) | ||
| )) |
There was a problem hiding this comment.
See [C#02].
| id: schema.CampusID = field(default_factory=( | |
| lambda: uid.generate_category_uid("timetable", length=8) | |
| )) | |
| id: int |
| from dataclasses import dataclass, field | ||
|
|
||
| from campus.common import schema | ||
| from campus.common.schema.openapi import String, Integer, Boolean, DateTime |
There was a problem hiding this comment.
Prefer referencing String, Integer, Boolean, DateTime from schema (they are re-exported under the schema namespace for ease of use)
See docs/STYLE-GUIDE.md for examples
| Describes a day in a repeating timetable. | ||
| """ | ||
| id: schema.CampusID = unique_field | ||
| label: String |
There was a problem hiding this comment.
[C#03]
Reference String datatype from schema namespace for clarity.
| label: String | |
| label: schema.String |
| id: schema.CampusID = field(default_factory=( | ||
| lambda: uid.generate_category_uid("timetable", length=8) | ||
| )) | ||
| weekday_id: schema.CampusID # FK -> weekday_id | ||
| timeslot_id: schema.CampusID | ||
| venue_id: schema.CampusID |
There was a problem hiding this comment.
See [C#02].
| id: schema.CampusID = field(default_factory=( | |
| lambda: uid.generate_category_uid("timetable", length=8) | |
| )) | |
| weekday_id: schema.CampusID # FK -> weekday_id | |
| timeslot_id: schema.CampusID | |
| venue_id: schema.CampusID | |
| id: int | |
| weekday_id: int # FK -> weekday_id | |
| timeslot_id: int | |
| venue_id: int |
| id: schema.CampusID = field(default_factory=( | ||
| lambda: uid.generate_category_uid("timetable", length=8) | ||
| )) |
There was a problem hiding this comment.
[C#05]
These are essentially what we understand as TTCodes. We can name the category more explicitly.
| id: schema.CampusID = field(default_factory=( | |
| lambda: uid.generate_category_uid("timetable", length=8) | |
| )) | |
| id: schema.CampusID = field(default_factory=( | |
| lambda: uid.generate_category_uid("timetable-group", length=8) | |
| )) |
| id: schema.CampusID = field(default_factory=( | ||
| lambda: uid.generate_category_uid("timetable", length=8) | ||
| )) |
There was a problem hiding this comment.
[C#06]
We use 16-char UUIDs for IDs that we know are likely to be much more numerous (due to the logic of combinatorics)
| id: schema.CampusID = field(default_factory=( | |
| lambda: uid.generate_category_uid("timetable", length=8) | |
| )) | |
| id: schema.CampusID = field(default_factory=( | |
| lambda: uid.generate_category_uid("timetable-groupmember", length=16) | |
| )) |
| class Timetable(Model): | ||
| """ | ||
| A timetable represents a lesson for a LessonGroup | ||
| at some VenueTimeSlot | ||
| """ |
There was a problem hiding this comment.
[C#07]
On 2nd thought, let's make this more explicit.
| class Timetable(Model): | |
| """ | |
| A timetable represents a lesson for a LessonGroup | |
| at some VenueTimeSlot | |
| """ | |
| class TimetableEntry(Model): | |
| """ | |
| A timetable entry represents the intersection of: | |
| - a LessonGroup (students + tutor(s)) | |
| - a TimetableVenue | |
| - a WeekDay | |
| - a TimeSlot | |
| """ |
| id: schema.CampusID = field(default_factory=( | ||
| lambda: uid.generate_category_uid("timetable", length=8) | ||
| )) |
There was a problem hiding this comment.
[C#08]
See [C#05], [C#06]
| id: schema.CampusID = field(default_factory=( | |
| lambda: uid.generate_category_uid("timetable", length=8) | |
| )) | |
| id: schema.CampusID = field(default_factory=( | |
| lambda: uid.generate_category_uid("timetable-entry", length=16) | |
| )) |
|
@SavioNYJC to confirm, only the following database tables are needed in Campus:
These are the only |
By @lomnom (issue comment):
A commit has been made containing the preliminary schema definition and its corresponding Python schema outline.
First, a few small changes have been made to the schema:
CampusIDs, as enforced byModel. By convention, all foreign keys therefore also point toCampusIDprimary keys.WeekDayandTimeSlot, where 0 denotes the earliest instance and larger indices represent later instances.[unique]constraints have been added.For convenience, an image of the current schema, rendered from the committed DBML using the tool referenced in the docstring of
timetable.py, is shown.Secondly, it seems that the Python schema syntax currently in use does not support specifying foreign key constraints. Perhaps it is somewhere besides
constraints.pyand I do not see it. While this does not preventJOINs, it does mean that PostgreSQL cannot enforce reference validity, and intent is not communicated fully.Do let me know if any design changes should be made at this stage. I understand the importance of addressing such issues early.