# @pol-studios/db

> Database layer for React applications with Supabase and PowerSync support

A comprehensive database abstraction layer supporting both Supabase (V2 hooks) and PowerSync (V3 hooks) for offline-first applications. Provides React Query integration, realtime subscriptions, mutation hooks, and storage utilities.

## Installation

```bash
pnpm add @pol-studios/db
```

## Peer Dependencies

```bash
# Required
pnpm add react @supabase/supabase-js @tanstack/react-query @pol-studios/db/auth @pol-studios/hooks

# Optional (for React Native / offline-first)
pnpm add @powersync/react-native @react-native-community/netinfo react-native
```

## Quick Start

```tsx
import { SupabaseProvider, useDbQuery, useDbInsert, useDbUpdate, useDbDelete } from "@pol-studios/db";

// Wrap your app with the provider
function App() {
  return (
    <SupabaseProvider url={SUPABASE_URL} anonKey={SUPABASE_ANON_KEY}>
      <QueryClientProvider client={queryClient}>
        <MyApp />
      </QueryClientProvider>
    </SupabaseProvider>
  );
}

// Query data
function ProjectList() {
  const { data, isLoading } = useDbQuery("projects", {
    select: "*",
    order: { column: "created_at", ascending: false },
  });

  if (isLoading) return <Loading />;
  return <List items={data} />;
}

// Mutations
function CreateProject() {
  const insert = useDbInsert("projects");
  const update = useDbUpdate("projects");
  const remove = useDbDelete("projects");

  const handleCreate = () => {
    insert.mutate({ name: "New Project", status: "active" });
  };

  const handleUpdate = (id, data) => {
    update.mutate({ id, ...data });
  };

  const handleDelete = (id) => {
    remove.mutate({ id });
  };
}
```

## Subpath Exports

| Path | Description |
|------|-------------|
| `@pol-studios/db` | All exports combined |
| `@pol-studios/db/client` | Supabase client utilities |
| `@pol-studios/db/core` | Core types and configuration |
| `@pol-studios/db/query` | Query system utilities |
| `@pol-studios/db/mutation` | Mutation hooks (batch operations) |
| `@pol-studios/db/realtime` | Realtime subscription utilities |
| `@pol-studios/db/parser` | Query parser utilities |
| `@pol-studios/db/hooks` | V3 hooks (PowerSync) |
| `@pol-studios/db/types` | TypeScript type definitions |
| `@pol-studios/db/gen` | Generated entity configurations |

## API Reference

### V2 Hooks (Supabase-based)

```tsx
import {
  // Query hooks
  useDbQuery,
  useDbInfiniteQuery,
  useDbAdvanceQuery,
  useDbPartialQuery,
  useDbRealtimeQuery,

  // Mutation hooks
  useDbInsert,
  useDbUpdate,
  useDbDelete,
  useDbUpsert,
  useDbMultiUpsert,
  useDbMultiDelete,

  // Batch mutations
  useBatchUpsert,
  useBatchDelete,
} from "@pol-studios/db";

// Basic query
const { data } = useDbQuery("projects", {
  select: "id, name, status",
  filter: { status: "active" },
  order: { column: "name" },
  limit: 10,
});

// Infinite scroll query
const { data, fetchNextPage, hasNextPage } = useDbInfiniteQuery("projects", {
  select: "*",
  pageSize: 20,
});

// Advanced query with joins
const { data } = useDbAdvanceQuery("projects", {
  select: "*, tasks(*), owner:profiles(*)",
  filter: { archived: false },
});

// Realtime query (auto-updates on changes)
const { data } = useDbRealtimeQuery("projects", {
  select: "*",
  filter: { team_id: teamId },
});

// Insert with automatic cache invalidation
const { mutate: insert } = useDbInsert("projects");
insert({ name: "New Project" });

// Update
const { mutate: update } = useDbUpdate("projects");
update({ id: projectId, name: "Updated Name" });

// Upsert
const { mutate: upsert } = useDbUpsert("projects");
upsert({ id: projectId, name: "Name" }); // Insert or update

// Batch operations
const { mutate: batchUpsert } = useBatchUpsert("projects");
batchUpsert(projectsArray);
```

### V3 Hooks (PowerSync / Offline-first)

```tsx
import {
  // V3 Query hooks
  useDbQueryV3,
  useDbQueryById,
  useDbInfiniteQueryV3,
  useDbCountV3,
  useAdvanceQuery,

  // V3 Mutation hooks
  useDbInsertV3,
  useDbUpdateV3,
  useDbDeleteV3,
  useDbUpsertV3,

  // Sync utilities
  useSyncStatus,
  useSyncControl,
  useOnlineStatus,
  useDataLayer,
} from "@pol-studios/db";

// V3 queries work offline with PowerSync
const { data } = useDbQueryV3("projects", {
  where: { status: "active" },
  orderBy: { created_at: "desc" },
});

// Get single item by ID
const { data: project } = useDbQueryById("projects", projectId);

// Count query
const { data: count } = useDbCountV3("projects", {
  where: { status: "active" },
});

// Sync status
const { isSyncing, lastSyncTime, pendingChanges } = useSyncStatus();

// Control sync
const { startSync, stopSync, forceSync } = useSyncControl();

// Online status
const isOnline = useOnlineStatus();
```

### Supabase Client

```tsx
import {
  useSupabase,
  SupabaseProvider,
  createNewSupabaseClient,
  typedSupabase,
  onSupabaseInitialized,
  setDefaultOptions,
} from "@pol-studios/db";

// Get typed Supabase client
const supabase = useSupabase();

// Direct client creation
const client = createNewSupabaseClient(url, key);

// Typed client for specific database schema
const typed = typedSupabase(client);

// Initialize callback
onSupabaseInitialized((client) => {
  console.log("Supabase ready");
});
```

### Realtime Subscriptions

```tsx
import { useDbRealtime, useLiveChangesIndicator, useLiveChangeTracking } from "@pol-studios/db";

// Subscribe to table changes
useDbRealtime("projects", {
  event: "INSERT",
  filter: `team_id=eq.${teamId}`,
  callback: (payload) => {
    console.log("New project:", payload.new);
  },
});

// Track live changes indicator
const { hasChanges, changeCount } = useLiveChangesIndicator("projects");

// Track specific changes
const { changes, clearChanges } = useLiveChangeTracking("projects", projectId);
```

### Storage

```tsx
import {
  useStorageUrl,
  useStoragePath,
  useStorageUpload,
  useStorageUploadWithEntity,
  useDbUpload,
} from "@pol-studios/db";

// Get public URL for storage path
const url = useStorageUrl("avatars", "user-123.png");

// Generate storage path
const path = useStoragePath("documents", { entityId, fileName });

// Upload file
const { upload, isUploading, progress } = useStorageUpload("documents");
await upload(file);

// Upload with entity association
const { upload } = useStorageUploadWithEntity("attachments", {
  entityType: "project",
  entityId: projectId,
});
```

### Utility Hooks

```tsx
import {
  useAI,
  useReceiptAI,
  useServerAvailability,
  useSearchQuery,
  useAutosaveState,
  useBackgroundTask,
  useToastError,
  useLatestOperationLog,
  useConsent,
  useAccountDeletion,
  useUserStatus,
  useDataExport,
} from "@pol-studios/db";

// AI integration
const { generate, isLoading } = useAI();

// Receipt AI processing
const { processReceipt } = useReceiptAI();

// Server availability check
const isAvailable = useServerAvailability();

// Search with debounce
const { results, search } = useSearchQuery("projects", { debounce: 300 });

// Autosave state
const [value, setValue, { isDirty, isSaving }] = useAutosaveState(initial, saveFn);

// Background task
const { run, isRunning, progress } = useBackgroundTask(asyncFn);

// Error toast integration
const showError = useToastError();
```

### Edge Functions

```tsx
import { useSupabaseFunction } from "@pol-studios/db";

// Call Supabase Edge Functions
const { invoke, isLoading, data, error } = useSupabaseFunction("process-data");
await invoke({ input: "value" });
```

### Data Layer Provider (V3)

```tsx
import { DataLayerProvider, useDataLayer } from "@pol-studios/db";

// Wrap app for offline-first support
<DataLayerProvider config={dataLayerConfig}>
  <App />
</DataLayerProvider>

// Access data layer
const { adapter, isReady, syncStatus } = useDataLayer();
```

## TypeScript Types

```tsx
import type {
  // Database types
  DatabaseTypes,
  TableNames,
  PublicTableNames,
  SchemaNames,
  SchemaTableNames,

  // Query types
  QueryOptions,
  QueryResult,
  QuerySingleResult,
  WhereClause,
  WhereOperators,
  OrderBy,

  // Mutation types
  MutationResult,
  MutationHookResult,
  DeleteMutationResult,
  ExtractRow,
  ExtractInsert,
  ExtractUpdate,

  // V3 types
  DataLayerConfig,
  DataAdapter,
  SyncStatus,
  SyncMode,
  SyncScope,
  SyncControl,
  ConnectionConfig,

  // Strategy types
  SupabaseStrategy,
  PowerSyncStrategy,
  HybridStrategy,
  CachedStrategy,
  AutoStrategy,
  TableStrategy,

  // Schema types
  DatabaseSchema,
  TableSchema,
  ColumnInfo,
  ColumnType,
  RelationshipInfo,
  RelationshipType,

  // Supabase types
  TypedSupabaseClient,
  SupabaseDatabaseTypes,
  UserSessionId,
} from "@pol-studios/db";
```

## Network Utilities

```tsx
import {
  getOnlineStatus,
  getOnlineStatusSync,
  initializeNetworkMonitoring,
  subscribeToNetworkChanges,
  isReactNative,
} from "@pol-studios/db";

// Check online status
const isOnline = await getOnlineStatus();
const isOnlineSync = getOnlineStatusSync();

// Initialize network monitoring
initializeNetworkMonitoring();

// Subscribe to network changes
const unsubscribe = subscribeToNetworkChanges((isOnline) => {
  console.log("Network:", isOnline ? "online" : "offline");
});
```

## Related Packages

- [@pol-studios/db/auth](../auth) - Authentication (required peer dependency)
- [@pol-studios/hooks](../hooks) - React hooks (required peer dependency)
- [@pol-studios/utils](../utils) - Utility functions
- [@pol-studios/features](../features) - Feature modules (uses db)

## License

UNLICENSED
