Skip to content

Commit

Permalink
fix: reactivity
Browse files Browse the repository at this point in the history
  • Loading branch information
tien committed Oct 15, 2024
1 parent 2e35cb6 commit 4cf4976
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 96 deletions.
28 changes: 0 additions & 28 deletions packages/vue/src/composables/use-async-data.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
import { lazyValuesKey } from "../keys.js";
import type { AsyncState, ReadonlyAsyncState } from "./types.js";
import { ReactiveDotError } from "@reactive-dot/core";
import type { Falsy } from "@reactive-dot/core/internal.js";
import type { Observable, Subscription } from "rxjs";
import {
computed,
inject,
type MaybeRef,
type MaybeRefOrGetter,
onWatcherCleanup,
shallowReadonly,
shallowRef,
toValue,
unref,
watchEffect,
} from "vue";

Expand Down Expand Up @@ -109,25 +103,3 @@ export function useAsyncData<T>(
) => promiseLike.then(onfulfilled, onrejected),
} as ReadonlyAsyncState<T> & PromiseLike<ReadonlyAsyncState<T, unknown, T>>;
}

/**
* @internal
*/
export function useLazyValue<T>(
key: MaybeRefOrGetter<string>,
get: MaybeRef<() => T>,
) {
const cache = inject(lazyValuesKey);

if (cache === undefined) {
throw new ReactiveDotError("No lazy values cache provided");
}

return computed(
() =>
(toValue(cache).get(toValue(key))?.value ??
toValue(cache)
.set(toValue(key), shallowRef(unref(get)()))
.get(toValue(key))!.value) as T,
);
}
8 changes: 3 additions & 5 deletions packages/vue/src/composables/use-client.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { ChainComposableOptions } from "./types.js";
import { useAsyncData, useLazyValue } from "./use-async-data.js";
import { useAsyncData } from "./use-async-data.js";
import { internal_useChainId } from "./use-chain-id.js";
import { useChainConfig } from "./use-config.js";
import { useLazyValue } from "./use-lazy-value.js";
import { getClient } from "@reactive-dot/core";
import { computed, toValue } from "vue";

Expand All @@ -24,9 +25,6 @@ export function useClientPromise(options?: ChainComposableOptions) {

return useLazyValue(
computed(() => `client-${chainId.value}`),
computed(() => {
const chainConfigValue = toValue(chainConfig);
return () => getClient(chainConfigValue);
}),
() => getClient(toValue(chainConfig)),
);
}
46 changes: 46 additions & 0 deletions packages/vue/src/composables/use-lazy-value.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { lazyValuesKey } from "../keys.js";
import { ReactiveDotError } from "@reactive-dot/core";
import {
type MaybeRefOrGetter,
type ShallowRef,
computed,
toValue,
shallowRef,
inject,
} from "vue";

/**
* @internal
*/
export function useLazyValue<T>(key: MaybeRefOrGetter<string>, get: () => T) {
return lazyValue(key, get, useLazyValuesCache());
}

/**
* @internal
*/
export function useLazyValuesCache() {
const cache = inject(lazyValuesKey);

if (cache === undefined) {
throw new ReactiveDotError("No lazy values cache provided");
}

return cache;
}

/**
* @internal
*/
export function lazyValue<T>(
key: MaybeRefOrGetter<string>,
get: () => T,
cache: MaybeRefOrGetter<Map<string, ShallowRef<unknown>>>,
) {
return computed(
() =>
(toValue(cache).get(toValue(key))?.value ??
toValue(cache).set(toValue(key), shallowRef(get())).get(toValue(key))!
.value) as T,
);
}
93 changes: 41 additions & 52 deletions packages/vue/src/composables/use-query.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { ChainComposableOptions, ReadonlyAsyncState } from "./types.js";
import { useAsyncData, useLazyValue } from "./use-async-data.js";
import { useAsyncData } from "./use-async-data.js";
import { lazyValue, useLazyValuesCache } from "./use-lazy-value.js";
import { useTypedApiPromise } from "./use-typed-api.js";
import {
type ChainId,
Expand All @@ -18,60 +19,54 @@ import type {
QueryInstruction,
} from "@reactive-dot/core/internal.js";
import { stringify } from "@reactive-dot/utils/internal.js";
import type { ChainDefinition, TypedApi } from "polkadot-api";
import { from, type Observable } from "rxjs";
import { switchMap } from "rxjs/operators";
import {
computed,
type MaybeRef,
type MaybeRefOrGetter,
onWatcherCleanup,
type Ref,
type ShallowRef,
toValue,
unref,
type UnwrapRef,
watchEffect,
} from "vue";

export function useLazyLoadQuery<
TQuery extends MaybeRef<
| ((
builder: Query<[], TDescriptor>,
) => Query<QueryInstruction<TDescriptor>[], TDescriptor> | Falsy)
| Falsy
>,
TQuery extends (
builder: Query<[], TDescriptor>,
) => Query<QueryInstruction<TDescriptor>[], TDescriptor> | Falsy,
TDescriptor extends TChainId extends void
? CommonDescriptor
: Chains[TChainId],
TChainId extends ChainId,
>(builder: TQuery, options?: ChainComposableOptions<TChainId>) {
const responses = computed(() => {
const builderValue = unref(builder);

if (!builderValue) {
return;
}
const typedApiPromise = useTypedApiPromise(options);
const cache = useLazyValuesCache();

const query = builderValue(new Query([]));
const responses = computed(() => {
const query = builder(new Query([]));

if (!query) {
return;
}

if (query.instructions.length === 0) {
if (query.instructions.length === 1) {
return useAsyncData(
useQueryInstructionFuture(query.instructions.at(0)!, options),
queryInstruction(query.instructions.at(0)!, typedApiPromise, cache),
);
}

return query.instructions
.flatMap((instruction) => {
if (!("multi" in instruction)) {
return useQueryInstructionFuture(instruction, options);
return queryInstruction(instruction, typedApiPromise, cache);
}

return (instruction.args as unknown[]).map((args) => {
const { multi, ...rest } = instruction;
return useQueryInstructionFuture({ ...rest, args }, options);
return queryInstruction({ ...rest, args }, typedApiPromise, cache);
});
})
.map(useAsyncData);
Expand All @@ -89,12 +84,12 @@ export function useLazyLoadQuery<
const state = {
data: computed(() =>
!Array.isArray(responses.value)
? responses.value?.data
? responses.value?.data.value
: responses.value.map((response) => response.data),
),
error: computed(() => {
if (!Array.isArray(responses.value)) {
return responses.value?.error;
return responses.value?.error.value;
}

const errorResponses = responses.value.filter(
Expand All @@ -113,7 +108,7 @@ export function useLazyLoadQuery<
}),
status: computed(() => {
if (!Array.isArray(responses.value)) {
return responses.value?.status;
return responses.value?.status.value;
}

if (
Expand Down Expand Up @@ -199,7 +194,7 @@ export function useLazyLoadQuery<
} as unknown as Return;
}

function useQueryInstructionFuture(
function queryInstruction(
instruction: MaybeRefOrGetter<
Exclude<
QueryInstruction,
Expand All @@ -208,36 +203,30 @@ function useQueryInstructionFuture(
{}>
>
>,
options?: ChainComposableOptions,
typedApiPromise: MaybeRefOrGetter<Promise<TypedApi<ChainDefinition>>>,
cache: MaybeRefOrGetter<Map<string, ShallowRef<unknown>>>,
) {
const typedApiPromise = useTypedApiPromise(options);

return useLazyValue(
return lazyValue(
computed(() => `query/${stringify(toValue(instruction))}`),
computed(() => {
const instructionValue = toValue(instruction);
const preflightResult = preflight(instructionValue);
const typedApiPromiseValue = toValue(typedApiPromise);

return () => {
switch (preflightResult) {
case "promise":
return typedApiPromiseValue.then(
() => {
switch (preflight(toValue(instruction))) {
case "promise":
return toValue(typedApiPromise).then(
(typedApi) =>
executeQuery(typedApi, toValue(instruction)) as Promise<unknown>,
);
case "observable":
return from(toValue(typedApiPromise)).pipe(
switchMap(
(typedApi) =>
executeQuery(typedApi, instructionValue) as Promise<unknown>,
);
case "observable":
return from(typedApiPromiseValue).pipe(
switchMap(
(typedApi) =>
executeQuery(
typedApi,
instructionValue,
) as Observable<unknown>,
),
);
}
};
}),
executeQuery(
typedApi,
toValue(instruction),
) as Observable<unknown>,
),
);
}
},
cache,
);
}
20 changes: 9 additions & 11 deletions packages/vue/src/composables/use-typed-api.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import type { ChainComposableOptions } from "./types.js";
import { useAsyncData, useLazyValue } from "./use-async-data.js";
import { useAsyncData } from "./use-async-data.js";
import { internal_useChainId } from "./use-chain-id.js";
import { useClientPromise } from "./use-client.js";
import { useChainConfig } from "./use-config.js";
import { useLazyValue } from "./use-lazy-value.js";
import type { ChainId, Chains } from "@reactive-dot/core";
import type { TypedApi } from "polkadot-api";
import { computed } from "vue";
Expand Down Expand Up @@ -31,15 +32,12 @@ export function useTypedApiPromise<TChainId extends ChainId>(

return useLazyValue(
computed(() => `typed-api-${chainId.value}`),
computed(() => {
const clientPromiseValue = clientPromise.value;
return () =>
clientPromiseValue.then(
(client) =>
client.getTypedApi(chainConfig.value.descriptor) as TypedApi<
Chains[TChainId]
>,
);
}),
() =>
clientPromise.value.then(
(client) =>
client.getTypedApi(chainConfig.value.descriptor) as TypedApi<
Chains[TChainId]
>,
),
);
}

0 comments on commit 4cf4976

Please sign in to comment.