Skip to content

feat: placeholder entities for nullable has-one (alternative to #15)#16

Merged
matej21 merged 1 commit intomainfrom
fix/nullable-has-one-placeholder
Apr 10, 2026
Merged

feat: placeholder entities for nullable has-one (alternative to #15)#16
matej21 merged 1 commit intomainfrom
fix/nullable-has-one-placeholder

Conversation

@matej21
Copy link
Copy Markdown
Member

@matej21 matej21 commented Apr 10, 2026

Summary

Alternative approach to #15. Instead of returning null for disconnected nullable has-one relations, this keeps the placeholder entity pattern from the original contember-oss binding.

Why not return null (#15's approach)?

  • Placeholder entities are the established binding pattern — they allow writing to disconnected relations (e.g. setting fields on a placeholder creates the entity on persist)
  • Returning null forces ! assertions everywhere in components (<HasOne field={article.author!}>) and requires a separate $hasOne('fieldName') string-based API for mutations
  • The type system already correctly maps nullable has-one to HasOneAccessor<NonNullable<T>> (never null)

What this PR does instead:

  • $isConnected boolean — convenient getter on HasOneAccessor for checking connection state (alternative to $state === 'connected')
  • Fix nullable: true in schema definitions — entity types say author: Author | null but schema definitions were missing { nullable: true }, causing $remove() to call $delete() instead of $disconnect()
  • Placeholder behavior tests — 5 new tests documenting that nullable has-one always returns an accessor, never null

API pattern (unchanged, just better documented)

// Reading — always safe, placeholder returns null for field values
const authorName = article.author.name.value ?? 'N/A'

// Check connection — use $isConnected or $state
if (article.author.$isConnected) {
  // author is a real entity
}

// Mutations — directly on the accessor (no $hasOne needed)
article.author.$connect('author-2')
article.author.$disconnect()

// Writing to placeholder — creates entity on persist
article.author.name.setValue('New Author')

Test plan

  • Typecheck passes
  • 5 new placeholder behavior tests pass
  • Full suite: 1388 pass (2 more than main), 58 fail (2 fewer than main — nullable: true fix helps)
  • Pre-existing failures unchanged (browser tests + form has-many)

🤖 Generated with Claude Code

Alternative approach to #15. Instead of returning null for disconnected
nullable has-one relations, keep the placeholder entity pattern from
contember-oss binding. This provides a consistent API where has-one
always returns an accessor, and users check connection state via
$isConnected or $state.

Changes:
- Add $isConnected boolean getter to HasOneHandle and HasOneRefInterface
- Fix schema definitions to include nullable: true where entity types
  have | null (enables correct $remove() behavior: disconnect vs delete)
- Add placeholder behavior tests for nullable has-one relations

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@matej21 matej21 merged commit cf2e23d into main Apr 10, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant