@gftdcojp/gftd-orm
Version:
Enterprise-grade real-time data platform with ksqlDB, inspired by Supabase architecture
296 lines • 8.91 kB
JavaScript
/**
* Next.js用のReactフック(ブラウザ専用)
*/
import { useState, useEffect, useRef, useCallback } from 'react';
import { BrowserClient } from '../browser-client';
/**
* ブラウザクライアント専用のReactフック
* README.mdで言及されている機能を実装
*/
export function useBrowserClient(config, options = {}) {
const [client, setClient] = useState(null);
const [isConnected, setIsConnected] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const clientRef = useRef(null);
const connect = useCallback(async () => {
if (clientRef.current)
return;
try {
setIsLoading(true);
setError(null);
const newClient = new BrowserClient(config);
await newClient.initialize();
clientRef.current = newClient;
setClient(newClient);
setIsConnected(true);
}
catch (err) {
setError(err instanceof Error ? err : new Error('Failed to connect'));
}
finally {
setIsLoading(false);
}
}, [config]);
const disconnect = useCallback(() => {
if (clientRef.current) {
clientRef.current.disconnect();
clientRef.current = null;
setClient(null);
setIsConnected(false);
}
}, []);
const health = useCallback(async () => {
if (!clientRef.current) {
throw new Error('Client is not connected');
}
return clientRef.current.health();
}, []);
useEffect(() => {
if (options.autoConnect !== false) {
connect();
}
return () => {
disconnect();
};
}, [connect, disconnect, options.autoConnect]);
return {
client,
isConnected,
isLoading,
error,
connect,
disconnect,
health,
};
}
/**
* GFTD-ORMクライアントのReactフック (legacy)
*/
export function useGftdOrm(config, options = {}) {
const [client, setClient] = useState(null);
const [isConnected, setIsConnected] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const clientRef = useRef(null);
const connect = useCallback(async () => {
if (clientRef.current)
return;
try {
setIsLoading(true);
setError(null);
const newClient = new BrowserClient(config);
await newClient.initialize();
clientRef.current = newClient;
setClient(newClient);
setIsConnected(true);
}
catch (err) {
setError(err instanceof Error ? err : new Error('Failed to connect'));
}
finally {
setIsLoading(false);
}
}, [config]);
const disconnect = useCallback(() => {
if (clientRef.current) {
clientRef.current.disconnect();
clientRef.current = null;
setClient(null);
setIsConnected(false);
}
}, []);
const health = useCallback(async () => {
if (!clientRef.current) {
throw new Error('Client is not connected');
}
return clientRef.current.health();
}, []);
useEffect(() => {
if (options.autoConnect !== false) {
connect();
}
return () => {
disconnect();
};
}, [connect, disconnect, options.autoConnect]);
return {
client,
isConnected,
isLoading,
error,
connect,
disconnect,
health,
};
}
/**
* リアルタイムサブスクリプション用のフック
* README.mdの例に合わせて改良
*/
export function useRealtimeSubscription(client, table, event, callback) {
const callbackRef = useRef(callback);
callbackRef.current = callback;
useEffect(() => {
if (!client?.realtime)
return;
// テーブル名をベースにしたデフォルトのチャンネル名を生成
const channelName = `${table}-updates`;
const realtimeChannel = client.channel(channelName);
const handleEvent = (payload) => {
callbackRef.current(payload);
};
realtimeChannel.onTable(table, event, handleEvent);
realtimeChannel.connect();
return () => {
realtimeChannel.unsubscribe();
realtimeChannel.disconnect();
};
}, [client, table, event]);
}
/**
* カスタムチャンネルでのリアルタイムサブスクリプション用のフック
*/
export function useRealtimeSubscriptionWithChannel(client, channel, table, event, callback) {
const callbackRef = useRef(callback);
callbackRef.current = callback;
useEffect(() => {
if (!client?.realtime)
return;
const realtimeChannel = client.channel(channel);
const handleEvent = (payload) => {
callbackRef.current(payload);
};
realtimeChannel.onTable(table, event, handleEvent);
realtimeChannel.connect();
return () => {
realtimeChannel.unsubscribe();
realtimeChannel.disconnect();
};
}, [client, channel, table, event]);
}
/**
* データフェッチ用のフック
*/
export function useGftdOrmQuery(client, table, queryBuilder, dependencies = []) {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const refetch = useCallback(async () => {
if (!client)
return;
try {
setLoading(true);
setError(null);
let query = client.from(table);
if (queryBuilder) {
query = queryBuilder(query);
}
const result = await query.execute();
if (result.error) {
throw result.error;
}
setData(result.data);
}
catch (err) {
setError(err instanceof Error ? err : new Error('Query failed'));
}
finally {
setLoading(false);
}
}, [client, table, queryBuilder]);
useEffect(() => {
if (client) {
refetch();
}
}, [client, refetch, ...dependencies]);
return {
data,
loading,
error,
refetch,
};
}
/**
* データミューテーション用のフック
*/
export function useGftdOrmMutation(client, table) {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const insert = useCallback(async (data) => {
if (!client)
throw new Error('Client is not connected');
try {
setLoading(true);
setError(null);
const result = await client.from(table).insert(data);
if (result.error) {
throw result.error;
}
return result.data;
}
catch (err) {
setError(err instanceof Error ? err : new Error('Insert failed'));
throw err;
}
finally {
setLoading(false);
}
}, [client, table]);
const update = useCallback(async (data, where) => {
if (!client)
throw new Error('Client is not connected');
try {
setLoading(true);
setError(null);
let query = client.from(table);
if (where) {
query = where(query);
}
const result = await query.update(data);
if (result.error) {
throw result.error;
}
return result.data;
}
catch (err) {
setError(err instanceof Error ? err : new Error('Update failed'));
throw err;
}
finally {
setLoading(false);
}
}, [client, table]);
const remove = useCallback(async (where) => {
if (!client)
throw new Error('Client is not connected');
try {
setLoading(true);
setError(null);
let query = client.from(table);
if (where) {
query = where(query);
}
const result = await query.delete();
if (result.error) {
throw result.error;
}
return result.data;
}
catch (err) {
setError(err instanceof Error ? err : new Error('Delete failed'));
throw err;
}
finally {
setLoading(false);
}
}, [client, table]);
return {
insert,
update,
remove,
loading,
error,
};
}
//# sourceMappingURL=useGftdOrm.js.map