.do
SdkData

$ (ctx)

Build semantic triple patterns with $.Subject.predicate.Object

The $ is a JavaScript Proxy that enables building semantic triple patterns following the $.Subject.predicate.Object convention. It's the foundation of SDK.do's semantic architecture.

Overview

The $ proxy allows you to construct semantic paths through simple property access:

import { $ } from 'sdk.do'

$.Person.worksFor.Organization
$.Order.contains.Product
$.User.created.Account
$.Business.owns.Brand

How It Works

The $ is implemented as a JavaScript Proxy that:

  1. Intercepts property access
  2. Builds a semantic path string
  3. Converts to string when needed
  4. Provides type hints through TypeScript
const path = $.Business.owns.Brand
console.log(String(path)) // "$.Business.owns.Brand"
console.log(path.path) // "$.Business.owns.Brand"
flowchart LR Start[Access $] --> Proxy[JavaScript Proxy] Proxy --> Get[Get Property<br/>Business] Get --> Build1[Build Path<br/>$.Business] Build1 --> NewProxy1[Return New Proxy] NewProxy1 --> Get2[Get Property<br/>owns] Get2 --> Build2[Build Path<br/>$.Business.owns] Build2 --> NewProxy2[Return New Proxy] NewProxy2 --> Get3[Get Property<br/>Brand] Get3 --> Build3[Build Path<br/>$.Business.owns.Brand] Build3 --> Final[Return Final Proxy] Final --> ToString[toString] Final --> ValueOf[valueOf] Final --> Path[.path property] ToString --> String[$.Business.owns.Brand] ValueOf --> String Path --> String

Semantic Triple Pattern

Semantic triples follow the Subject-Predicate-Object pattern from RDF:

  • Subject: The entity (e.g., Person, Business, Order)
  • Predicate: The relationship or property (e.g., worksFor, owns, contains)
  • Object: The target entity or value (e.g., Organization, Brand, Product)

Examples

// Relationships
$.Person.worksFor.Organization
$.Employee.reportsTo.Manager
$.Product.manufacturedBy.Company

// Properties
$.User.hasEmail.EmailAddress
$.Order.hasStatus.OrderStatus
$.Document.createdBy.User

// Events
$.Order.created.Event
$.User.updated.Event
$.Payment.processed.Event

// Specific entities
$.John.worksFor.Acme
$.Order123.contains.Product456
$.Alice.manages.Team

Usage in SDK Functions

With Events

Use $ to define semantic event paths:

import { $, on, send } from 'sdk.do'

// Subscribe to events
on.Order.created(async (order) => {
  console.log('Order created:', order.id)
})

// Send events
send.User.updated({
  userId: 'user-123',
  changes: { name: 'Alice' },
})

With Database Relationships

Query relationships using semantic paths:

import { $, db } from 'sdk.do'

// Query related entities
const brands = await db.related({ collection: 'businesses', id: 'acme-inc' }, $.owns, 'brands')

const employees = await db.related({ collection: 'companies', id: 'company-123' }, $.employs, 'users')

Pattern Matching

Use wildcards for pattern matching in events:

// Match any Order event
on($.Order['*'], async (data) => {
  // Matches $.Order.created, $.Order.updated, $.Order.deleted
  console.log('Any order event:', data)
})

// Match specific patterns
on($.User['*'].completed, async (data) => {
  // Matches $.User.registration.completed, $.User.purchase.completed, etc.
})

String Conversion

The $ proxy automatically converts to string:

const path = $.Business.owns.Brand

// Explicit conversion
String(path) // "$.Business.owns.Brand"
path.toString() // "$.Business.owns.Brand"
path.valueOf() // "$.Business.owns.Brand"

// Direct property access
path.path // "$.Business.owns.Brand"

// Implicit conversion in template literals
console.log(`Path: ${path}`) // "Path: $.Business.owns.Brand"

TypeScript Support

Basic Usage

import { $ } from 'sdk.do'
import type { PathProxy } from 'sdk.do'

const path: PathProxy = $.Person.worksFor.Organization

Typed Path Proxy

For full autocomplete support:

import { $ } from 'sdk.do'
import type { TypedPathProxy } from 'graphdl'

// Cast for autocomplete
const typed = $ as unknown as TypedPathProxy

// Now get autocomplete for Schema.org entities
typed.Person.      // Autocomplete shows: worksFor, knows, owns, etc.
typed.Organization. // Autocomplete shows: employs, produces, etc.

Type Safety in Functions

import { $, on } from 'sdk.do'
import type { PathProxy } from 'sdk.do'

function subscribeToEvent(event: PathProxy, handler: (data: any) => void) {
  return on(event, handler)
}

// Type-safe usage
subscribeToEvent($.Order.created, (order) => {
  console.log(order.id)
})

Best Practices

Use Semantic Names

Choose descriptive, semantic predicates:

// Good - semantic and clear
$.Person.worksFor.Organization
$.Order.contains.Product
$.User.hasRole.Admin

// Avoid - not semantic
$.Person.has.Organization
$.Order.related.Product
$.User.is.Admin

Follow Schema.org Conventions

Use established Schema.org predicates when possible:

// Schema.org predicates
$.Person.worksFor.Organization // from Schema.org
$.Product.manufacturer.Organization
$.Event.location.Place
$.Book.author.Person

Keep Paths Readable

Make paths human-readable:

// Good - readable
$.Employee.reportsTo.Manager
$.Customer.placedOrder.Order
$.Article.writtenBy.Author

// Avoid - not readable
$.Emp.rpts.Mgr
$.Cust.ord.Ord
$.Art.auth.Auth

Use Consistent Casing

Follow PascalCase for entities, camelCase for predicates:

// Correct casing
$.Person.worksFor.Organization
$.Product.hasCategory.Category
$.Order.createdBy.User

// Inconsistent (avoid)
$.person.WorksFor.organization
$.PRODUCT.hasCategory.CATEGORY

Common Patterns

Entity Relationships

// Ownership
$.Business.owns.Brand
$.Company.owns.Subsidiary
$.Person.owns.Asset

// Employment
$.Person.worksFor.Organization
$.Employee.reportsTo.Manager
$.Contractor.providesServicesTo.Client

// Hierarchy
$.Child.childOf.Parent
$.Department.partOf.Organization
$.Component.assembledIn.Product

Events

// CRUD events
$.User.created
$.Order.updated
$.Product.deleted

// State transitions
$.Order.shipped
$.Payment.processed
$.Task.completed

// Notifications
$.Email.sent
$.SMS.delivered
$.Notification.read

Properties

// Identity
$.Person.hasEmail.EmailAddress
$.User.hasUsername.String
$.Entity.hasId.Identifier

// Status
$.Order.hasStatus.OrderStatus
$.User.hasRole.Role
$.Task.hasPriority.Priority

// Temporal
$.Event.startTime.DateTime
$.Subscription.expiresAt.DateTime
$.Document.modifiedAt.DateTime

Implementation Details

The $ proxy is implemented in the graphdl package:

// Simplified implementation
const handler: ProxyHandler<{ path: string }> = {
  get(target, prop) {
    if (prop === 'toString' || prop === 'valueOf') {
      return () => target.path
    }
    if (prop === 'path') {
      return target.path
    }
    const newPath = target.path ? `${target.path}.${String(prop)}` : String(prop)
    return new Proxy({ path: newPath }, handler)
  },
}

export const $ = new Proxy({ path: '$' }, handler)