0

I recently decided to try to work with a database without an additional layer like ORMs. The problem that currently bothers me is how to convert flat SQL query results into domain models with nested entities.

Let me show what I mean

I have a domain entity WorkingDay (with nested entities Appointment[], Break[]) that looks like this in my application

WorkingDay (Entity/AggregateRoot)
- id
- date
- start_time
- end_time
- appointments: Appointment[]
- breaks: Break[]

Appointment (Entity)
- id
- start_time
- end_time
- services: AppointmentService[]

AppointmentService (Entity)
- id
- name
- price
- duration

Break (Entity)
- id
- start_time
- end_time

All the data needed to create this "aggregate" is contained in several SQL tables

- working_days (table)
- appointments (table)
- breaks (table)
- appointment_services (table)

This is the the query that I currently have

SELECT WORKING_DAYS.ID,
    WORKING_DAYS.BEAUTY_PAGE_ID,
    WORKING_DAYS.SPECIALIST_ID,
    WORKING_DAYS.DATE,
    WORKING_DAYS.START_TIME,
    WORKING_DAYS.END_TIME,
    WORKING_DAYS.CREATED_AT,
    WORKING_DAYS.UPDATED_AT,
    BREAKS.ID AS BREAK_ID,
    BREAKS.START_TIME AS BREAK_START_TIME,
    BREAKS.END_TIME AS BREAK_END_TIME,
    APPOINTMENTS.ID AS APPOINTMENT_ID,
    APPOINTMENTS.CLIENT_ID AS APPOINTMENT_CLIENT_ID,
    APPOINTMENTS.START_TIME AS APPOINTMENTS_START_TIME,
    APPOINTMENTS.END_TIME AS APPOINTMENTS_END_TIME,
    APPOINTMENTS.STATUS AS APPOINTMENTS_STATUS,
    APPOINTMENT_SERVICES.ID AS APPOINTMENT_SERVICE_ID,
    APPOINTMENT_SERVICES.NAME AS APPOINTMENT_SERVICE_NAME,
    APPOINTMENT_SERVICES.PRICE AS APPOINTMENT_SERVICE_PRICE,
    APPOINTMENT_SERVICES.DURATION AS APPOINTMENT_SERVICE_DURATION
FROM WORKING_DAYS

LEFT OUTER
JOIN BREAKS ON BREAKS.WORKING_DAY_ID = WORKING_DAYS.ID AND BREAKS.REMOVED = FALSE

LEFT OUTER
JOIN APPOINTMENTS ON APPOINTMENTS.WORKING_DAY_ID = WORKING_DAYS.ID AND APPOINTMENTS.STATUS = 'PENDING'

LEFT OUTER
JOIN APPOINTMENT_SERVICES ON APPOINTMENTS.ID = APPOINTMENT_SERVICES.APPOINTMENT_ID AND APPOINTMENT_SERVICES.REMOVED = FALSE

WHERE WORKING_DAYS.SPECIALIST_ID = '91404483-d7dc-4d7b-9781-118c8e31e646'
    AND WORKING_DAYS.DATE = '2030-01-01';

And the result is something like this

id beauty_page_id specialist_id date start_time end_time created_at updated_at break_id break_start_time break_end_time appointment_id appointment_client_id appointment_start_time appointment_end_time appointment_status appointment_service_id appointment_service_name appointment_service_price appointment_service_duration
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *

Asterisk (*) is a mocked data

In my application, these rows will be represented as an array of rows and require me manually to traverse this array and make a conversation into a domain model.

It seems like a common issue and all ORMs must handle this under the hood. The question is there a better approach to converting flat SQL response into a nested domain model?

I saw that SQL allows returning JSON which supports nested values, but I'm not sure if this is the correct way.

P.S. I use sqlx + PostgreSQL and Rust in my project

Roman Mahotskyi
  • 4,576
  • 5
  • 35
  • 68

0 Answers0