Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
11 changes: 6 additions & 5 deletions src/modules/measure/application/usecases/measureState.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import { createResource, createRoot } from 'solid-js'

import { createMeasureCrud } from '~/modules/measure/application/usecases/measureCrud'
import { initializeMeasureRealtime } from '~/modules/measure/infrastructure/supabase/realtime'
import { createMeasureRealtimeService } from '~/modules/measure/infrastructure/supabase/realtime'

const measureRealtimeService = createMeasureRealtimeService()

export function createMeasureState(deps: {
getCurrentUserIdOrGuestId: () => string
fetchUserBodyMeasures?: ReturnType<
typeof createMeasureCrud
>['fetchUserBodyMeasures']
initializeMeasureRealtime?: (deps: {
refetchBodyMeasures: () => void
}) => void
initializeMeasureRealtime?: typeof measureRealtimeService.initializeMeasureRealtime
}) {
const localFetch =
deps.fetchUserBodyMeasures ?? createMeasureCrud().fetchUserBodyMeasures
const localInitializeRealtime =
deps.initializeMeasureRealtime ?? initializeMeasureRealtime
deps.initializeMeasureRealtime ??
measureRealtimeService.initializeMeasureRealtime

return createRoot(() => {
const [bodyMeasures, { refetch: refetchBodyMeasures }] = createResource(
Expand Down
13 changes: 9 additions & 4 deletions src/modules/measure/infrastructure/measureRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import { logging } from '~/shared/utils/logging'

const supabaseGateway = createSupabaseBodyMeasureGateway()

/**
* Creates the measure repository backed by the Supabase gateway.
*
* @returns Repository implementation for measure CRUD operations.
*/
export function createMeasureRepository(): BodyMeasureRepository {
return {
fetchUserBodyMeasures,
Expand All @@ -18,7 +23,7 @@ export function createMeasureRepository(): BodyMeasureRepository {
}
}

export async function fetchUserBodyMeasures(
async function fetchUserBodyMeasures(
userId: User['uuid'],
): Promise<readonly BodyMeasure[]> {
try {
Expand All @@ -29,7 +34,7 @@ export async function fetchUserBodyMeasures(
}
}

export async function insertBodyMeasure(
async function insertBodyMeasure(
newBodyMeasure: NewBodyMeasure,
): Promise<BodyMeasure | null> {
try {
Expand All @@ -40,7 +45,7 @@ export async function insertBodyMeasure(
}
}

export async function updateBodyMeasure(
async function updateBodyMeasure(
bodyMeasureId: BodyMeasure['id'],
newBodyMeasure: NewBodyMeasure,
): Promise<BodyMeasure | null> {
Expand All @@ -55,7 +60,7 @@ export async function updateBodyMeasure(
}
}

export async function deleteBodyMeasure(
async function deleteBodyMeasure(
bodyMeasureId: BodyMeasure['id'],
): Promise<void> {
try {
Expand Down
1 change: 0 additions & 1 deletion src/modules/measure/infrastructure/supabase/constants.ts

This file was deleted.

73 changes: 41 additions & 32 deletions src/modules/measure/infrastructure/supabase/realtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,47 @@ import {
type BodyMeasure,
bodyMeasureSchema,
} from '~/modules/measure/domain/measure'
import { SUPABASE_TABLE_BODY_MEASURES } from '~/modules/measure/infrastructure/supabase/constants'
import { registerSubapabaseRealtimeCallback } from '~/shared/supabase/supabase'
import { logging } from '~/shared/utils/logging'

let initialized = false
const SUPABASE_TABLE_BODY_MEASURES = 'body_measures'

/**
* Sets up granular realtime subscription for body measure changes
* @param onBodyMeasureChange - Callback for granular updates with event details
*/
export function setupBodyMeasureRealtimeSubscription(
onBodyMeasureChange: (event: {
eventType: 'INSERT' | 'UPDATE' | 'DELETE'
old?: BodyMeasure
new?: BodyMeasure
}) => void,
): void {
registerSubapabaseRealtimeCallback(
SUPABASE_TABLE_BODY_MEASURES,
bodyMeasureSchema,
onBodyMeasureChange,
)
}
export function createMeasureRealtimeService() {
let initialized = false

export function initializeMeasureRealtime(deps: {
refetchBodyMeasures: () => void
}): void {
if (initialized) {
return
/**
* Sets up granular realtime subscription for body measure changes
* @param onBodyMeasureChange - Callback for granular updates with event details
*/
function setupBodyMeasureRealtimeSubscription(
onBodyMeasureChange: (event: {
eventType: 'INSERT' | 'UPDATE' | 'DELETE'
old?: BodyMeasure
new?: BodyMeasure
}) => void,
): void {
registerSubapabaseRealtimeCallback(
SUPABASE_TABLE_BODY_MEASURES,
bodyMeasureSchema,
onBodyMeasureChange,
)
}
logging.debug(`Measure realtime initialized!`)
initialized = true
registerSubapabaseRealtimeCallback(
SUPABASE_TABLE_BODY_MEASURES,
bodyMeasureSchema,
(event) => {

/**
* Initializes the body measure realtime subscription once per session.
*
* @param deps - Dependencies used to react to realtime body measure changes.
* @returns Nothing.
*/
function initializeMeasureRealtime(deps: {
refetchBodyMeasures: () => void
}): void {
if (initialized) {
return
}
logging.debug(`Measure realtime initialized!`)
initialized = true
setupBodyMeasureRealtimeSubscription((event) => {
logging.debug(`Event:`, event)

switch (event.eventType) {
Expand All @@ -49,6 +54,10 @@ export function initializeMeasureRealtime(deps: {
break
}
}
},
)
})
}

return {
initializeMeasureRealtime,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@ import {
type NewBodyMeasure,
} from '~/modules/measure/domain/measure'
import { type BodyMeasureGateway } from '~/modules/measure/domain/measureGateway'
import { SUPABASE_TABLE_BODY_MEASURES } from '~/modules/measure/infrastructure/supabase/constants'
import { supabaseBodyMeasureMapper } from '~/modules/measure/infrastructure/supabase/supabaseMeasureMapper'
import { createSupabaseBodyMeasureMapper } from '~/modules/measure/infrastructure/supabase/supabaseMeasureMapper'
import { type User } from '~/modules/user/domain/user'
import { supabase } from '~/shared/supabase/supabase'
import { wrapErrorWithStack } from '~/shared/utils/errorUtils'
import { logging } from '~/shared/utils/logging'

const SUPABASE_TABLE_BODY_MEASURES = 'body_measures'
const supabaseBodyMeasureMapper = createSupabaseBodyMeasureMapper()

/**
* Creates the Supabase gateway used to persist body measures.
*
* @returns Gateway implementation for body measure persistence operations.
*/
export function createSupabaseBodyMeasureGateway(): BodyMeasureGateway {
return {
fetchUserBodyMeasures,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ import {
import { type Database } from '~/shared/supabase/database.types'
import { parseWithStack } from '~/shared/utils/parseWithStack'

export type InsertBodyMeasureDTO =
type InsertBodyMeasureDTO =
Database['public']['Tables']['body_measures']['Insert']
export type BodyMeasureDTO =
Database['public']['Tables']['body_measures']['Row']
type BodyMeasureDTO = Database['public']['Tables']['body_measures']['Row']

// Conversion functions
function toInsertDTO(newBodyMeasure: NewBodyMeasure): InsertBodyMeasureDTO {
Expand All @@ -35,7 +34,15 @@ function toDomain(dto: BodyMeasureDTO): BodyMeasure {
})
}

export const supabaseBodyMeasureMapper = {
toDomain,
toInsertDTO,
/**
* Creates the mapper responsible for converting body measure data
* between Supabase DTOs and domain entities.
*
* @returns Mapper functions for reading and writing body measure records.
*/
export function createSupabaseBodyMeasureMapper() {
return {
toDomain,
toInsertDTO,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { describe, expect, it } from 'vitest'

import * as measureRepositoryModule from '~/modules/measure/infrastructure/measureRepository'
import * as realtimeModule from '~/modules/measure/infrastructure/supabase/realtime'
import * as gatewayModule from '~/modules/measure/infrastructure/supabase/supabaseBodyMeasureGateway'
import * as mapperModule from '~/modules/measure/infrastructure/supabase/supabaseMeasureMapper'

describe('measure infrastructure module exports', () => {
it('exports only the measure repository factory', () => {
expect(Object.keys(measureRepositoryModule)).toEqual([
'createMeasureRepository',
])
})

it('exports only the Supabase gateway factory', () => {
expect(Object.keys(gatewayModule)).toEqual([
'createSupabaseBodyMeasureGateway',
])
})

it('exports only the Supabase mapper factory', () => {
expect(Object.keys(mapperModule)).toEqual([
'createSupabaseBodyMeasureMapper',
])
})

it('keeps realtime exports limited to the public factory', () => {
expect(Object.keys(realtimeModule)).toEqual([
'createMeasureRealtimeService',
])
})

it('creates a realtime service with the public initializer', () => {
expect(Object.keys(realtimeModule.createMeasureRealtimeService())).toEqual([
'initializeMeasureRealtime',
])
})
})
Loading