@tanstack/angular-db 0.1.54 → 0.1.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -43,15 +43,23 @@ function injectLiveQuery(opts) {
43
43
  throw new Error(`Invalid options provided to injectLiveQuery`);
44
44
  });
45
45
  const state = core.signal(/* @__PURE__ */ new Map());
46
- const data = core.signal([]);
46
+ const internalData = core.signal([]);
47
47
  const status = core.signal(
48
48
  collection() ? `idle` : `disabled`
49
49
  );
50
+ const data = core.computed(() => {
51
+ const currentCollection = collection();
52
+ if (!currentCollection) {
53
+ return internalData();
54
+ }
55
+ const config = currentCollection.config;
56
+ return config?.singleResult ? internalData()[0] : internalData();
57
+ });
50
58
  const syncDataFromCollection = (currentCollection) => {
51
59
  const newState = new Map(currentCollection.entries());
52
60
  const newData = Array.from(currentCollection.values());
53
61
  state.set(newState);
54
- data.set(newData);
62
+ internalData.set(newData);
55
63
  status.set(currentCollection.status);
56
64
  };
57
65
  let unsub = null;
@@ -64,7 +72,7 @@ function injectLiveQuery(opts) {
64
72
  if (!currentCollection) {
65
73
  status.set(`disabled`);
66
74
  state.set(/* @__PURE__ */ new Map());
67
- data.set([]);
75
+ internalData.set([]);
68
76
  cleanup();
69
77
  return;
70
78
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/index.ts"],"sourcesContent":["import {\n DestroyRef,\n assertInInjectionContext,\n computed,\n effect,\n inject,\n signal,\n} from '@angular/core'\nimport { BaseQueryBuilder, createLiveQueryCollection } from '@tanstack/db'\nimport type {\n ChangeMessage,\n Collection,\n CollectionStatus,\n Context,\n GetResult,\n InitialQueryBuilder,\n LiveQueryCollectionConfig,\n QueryBuilder,\n} from '@tanstack/db'\nimport type { Signal } from '@angular/core'\n\n/**\n * The result of calling `injectLiveQuery`.\n * Contains reactive signals for the query state and data.\n */\nexport interface InjectLiveQueryResult<\n TResult extends object = any,\n TKey extends string | number = string | number,\n TUtils extends Record<string, any> = {},\n> {\n /** A signal containing the complete state map of results keyed by their ID */\n state: Signal<Map<TKey, TResult>>\n /** A signal containing the results as an array */\n data: Signal<Array<TResult>>\n /** A signal containing the underlying collection instance (null for disabled queries) */\n collection: Signal<Collection<TResult, TKey, TUtils> | null>\n /** A signal containing the current status of the collection */\n status: Signal<CollectionStatus | `disabled`>\n /** A signal indicating whether the collection is currently loading */\n isLoading: Signal<boolean>\n /** A signal indicating whether the collection is ready */\n isReady: Signal<boolean>\n /** A signal indicating whether the collection is idle */\n isIdle: Signal<boolean>\n /** A signal indicating whether the collection has an error */\n isError: Signal<boolean>\n /** A signal indicating whether the collection has been cleaned up */\n isCleanedUp: Signal<boolean>\n}\n\nexport function injectLiveQuery<\n TContext extends Context,\n TParams extends any,\n>(options: {\n params: () => TParams\n query: (args: {\n params: TParams\n q: InitialQueryBuilder\n }) => QueryBuilder<TContext>\n}): InjectLiveQueryResult<GetResult<TContext>>\nexport function injectLiveQuery<\n TContext extends Context,\n TParams extends any,\n>(options: {\n params: () => TParams\n query: (args: {\n params: TParams\n q: InitialQueryBuilder\n }) => QueryBuilder<TContext> | undefined | null\n}): InjectLiveQueryResult<GetResult<TContext>>\nexport function injectLiveQuery<TContext extends Context>(\n queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext>,\n): InjectLiveQueryResult<GetResult<TContext>>\nexport function injectLiveQuery<TContext extends Context>(\n queryFn: (\n q: InitialQueryBuilder,\n ) => QueryBuilder<TContext> | undefined | null,\n): InjectLiveQueryResult<GetResult<TContext>>\nexport function injectLiveQuery<TContext extends Context>(\n config: LiveQueryCollectionConfig<TContext>,\n): InjectLiveQueryResult<GetResult<TContext>>\nexport function injectLiveQuery<\n TResult extends object,\n TKey extends string | number,\n TUtils extends Record<string, any>,\n>(\n liveQueryCollection: Collection<TResult, TKey, TUtils>,\n): InjectLiveQueryResult<TResult, TKey, TUtils>\nexport function injectLiveQuery(opts: any) {\n assertInInjectionContext(injectLiveQuery)\n const destroyRef = inject(DestroyRef)\n\n const collection = computed(() => {\n // Check if it's an existing collection\n const isExistingCollection =\n opts &&\n typeof opts === `object` &&\n typeof opts.subscribeChanges === `function` &&\n typeof opts.startSyncImmediate === `function` &&\n typeof opts.id === `string`\n\n if (isExistingCollection) {\n return opts\n }\n\n if (typeof opts === `function`) {\n // Check if query function returns null/undefined (disabled query)\n const queryBuilder = new BaseQueryBuilder() as InitialQueryBuilder\n const result = opts(queryBuilder)\n\n if (result === undefined || result === null) {\n // Disabled query - return null\n return null\n }\n\n return createLiveQueryCollection({\n query: opts,\n startSync: true,\n gcTime: 0,\n })\n }\n\n // Check if it's reactive query options\n const isReactiveQueryOptions =\n opts &&\n typeof opts === `object` &&\n typeof opts.query === `function` &&\n typeof opts.params === `function`\n\n if (isReactiveQueryOptions) {\n const { params, query } = opts\n const currentParams = params()\n\n // Check if query function returns null/undefined (disabled query)\n const queryBuilder = new BaseQueryBuilder() as InitialQueryBuilder\n const result = query({ params: currentParams, q: queryBuilder })\n\n if (result === undefined || result === null) {\n // Disabled query - return null\n return null\n }\n\n return createLiveQueryCollection({\n query: (q) => query({ params: currentParams, q }),\n startSync: true,\n gcTime: 0,\n })\n }\n\n // Handle LiveQueryCollectionConfig objects\n if (opts && typeof opts === `object` && typeof opts.query === `function`) {\n return createLiveQueryCollection(opts)\n }\n\n throw new Error(`Invalid options provided to injectLiveQuery`)\n })\n\n const state = signal(new Map<string | number, any>())\n const data = signal<Array<any>>([])\n const status = signal<CollectionStatus | `disabled`>(\n collection() ? `idle` : `disabled`,\n )\n\n const syncDataFromCollection = (\n currentCollection: Collection<any, any, any>,\n ) => {\n const newState = new Map(currentCollection.entries())\n const newData = Array.from(currentCollection.values())\n\n state.set(newState)\n data.set(newData)\n status.set(currentCollection.status)\n }\n\n let unsub: (() => void) | null = null\n const cleanup = () => {\n unsub?.()\n unsub = null\n }\n\n effect((onCleanup) => {\n const currentCollection = collection()\n\n // Handle null collection (disabled query)\n if (!currentCollection) {\n status.set(`disabled` as const)\n state.set(new Map())\n data.set([])\n cleanup()\n return\n }\n\n cleanup()\n\n // Initialize immediately with current state\n syncDataFromCollection(currentCollection)\n\n // Start sync if idle\n if (currentCollection.status === `idle`) {\n currentCollection.startSyncImmediate()\n // Update status after starting sync\n status.set(currentCollection.status)\n }\n\n // Subscribe to changes\n const subscription = currentCollection.subscribeChanges(\n (_: Array<ChangeMessage<any>>) => {\n syncDataFromCollection(currentCollection)\n },\n )\n unsub = subscription.unsubscribe.bind(subscription)\n\n // Handle ready state\n currentCollection.onFirstReady(() => {\n status.set(currentCollection.status)\n })\n\n onCleanup(cleanup)\n })\n\n destroyRef.onDestroy(cleanup)\n\n return {\n state,\n data,\n collection,\n status,\n isLoading: computed(() => status() === `loading`),\n isReady: computed(() => status() === `ready` || status() === `disabled`),\n isIdle: computed(() => status() === `idle`),\n isError: computed(() => status() === `error`),\n isCleanedUp: computed(() => status() === `cleaned-up`),\n }\n}\n"],"names":["assertInInjectionContext","inject","DestroyRef","computed","BaseQueryBuilder","createLiveQueryCollection","signal","effect"],"mappings":";;;;AAwFO,SAAS,gBAAgB,MAAW;AACzCA,OAAAA,yBAAyB,eAAe;AACxC,QAAM,aAAaC,KAAAA,OAAOC,eAAU;AAEpC,QAAM,aAAaC,KAAAA,SAAS,MAAM;AAEhC,UAAM,uBACJ,QACA,OAAO,SAAS,YAChB,OAAO,KAAK,qBAAqB,cACjC,OAAO,KAAK,uBAAuB,cACnC,OAAO,KAAK,OAAO;AAErB,QAAI,sBAAsB;AACxB,aAAO;AAAA,IACT;AAEA,QAAI,OAAO,SAAS,YAAY;AAE9B,YAAM,eAAe,IAAIC,oBAAA;AACzB,YAAM,SAAS,KAAK,YAAY;AAEhC,UAAI,WAAW,UAAa,WAAW,MAAM;AAE3C,eAAO;AAAA,MACT;AAEA,aAAOC,6BAA0B;AAAA,QAC/B,OAAO;AAAA,QACP,WAAW;AAAA,QACX,QAAQ;AAAA,MAAA,CACT;AAAA,IACH;AAGA,UAAM,yBACJ,QACA,OAAO,SAAS,YAChB,OAAO,KAAK,UAAU,cACtB,OAAO,KAAK,WAAW;AAEzB,QAAI,wBAAwB;AAC1B,YAAM,EAAE,QAAQ,MAAA,IAAU;AAC1B,YAAM,gBAAgB,OAAA;AAGtB,YAAM,eAAe,IAAID,oBAAA;AACzB,YAAM,SAAS,MAAM,EAAE,QAAQ,eAAe,GAAG,cAAc;AAE/D,UAAI,WAAW,UAAa,WAAW,MAAM;AAE3C,eAAO;AAAA,MACT;AAEA,aAAOC,6BAA0B;AAAA,QAC/B,OAAO,CAAC,MAAM,MAAM,EAAE,QAAQ,eAAe,GAAG;AAAA,QAChD,WAAW;AAAA,QACX,QAAQ;AAAA,MAAA,CACT;AAAA,IACH;AAGA,QAAI,QAAQ,OAAO,SAAS,YAAY,OAAO,KAAK,UAAU,YAAY;AACxE,aAAOA,GAAAA,0BAA0B,IAAI;AAAA,IACvC;AAEA,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D,CAAC;AAED,QAAM,QAAQC,KAAAA,OAAO,oBAAI,KAA2B;AACpD,QAAM,OAAOA,KAAAA,OAAmB,EAAE;AAClC,QAAM,SAASA,KAAAA;AAAAA,IACb,eAAe,SAAS;AAAA,EAAA;AAG1B,QAAM,yBAAyB,CAC7B,sBACG;AACH,UAAM,WAAW,IAAI,IAAI,kBAAkB,SAAS;AACpD,UAAM,UAAU,MAAM,KAAK,kBAAkB,QAAQ;AAErD,UAAM,IAAI,QAAQ;AAClB,SAAK,IAAI,OAAO;AAChB,WAAO,IAAI,kBAAkB,MAAM;AAAA,EACrC;AAEA,MAAI,QAA6B;AACjC,QAAM,UAAU,MAAM;AACpB,YAAA;AACA,YAAQ;AAAA,EACV;AAEAC,OAAAA,OAAO,CAAC,cAAc;AACpB,UAAM,oBAAoB,WAAA;AAG1B,QAAI,CAAC,mBAAmB;AACtB,aAAO,IAAI,UAAmB;AAC9B,YAAM,IAAI,oBAAI,KAAK;AACnB,WAAK,IAAI,EAAE;AACX,cAAA;AACA;AAAA,IACF;AAEA,YAAA;AAGA,2BAAuB,iBAAiB;AAGxC,QAAI,kBAAkB,WAAW,QAAQ;AACvC,wBAAkB,mBAAA;AAElB,aAAO,IAAI,kBAAkB,MAAM;AAAA,IACrC;AAGA,UAAM,eAAe,kBAAkB;AAAA,MACrC,CAAC,MAAiC;AAChC,+BAAuB,iBAAiB;AAAA,MAC1C;AAAA,IAAA;AAEF,YAAQ,aAAa,YAAY,KAAK,YAAY;AAGlD,sBAAkB,aAAa,MAAM;AACnC,aAAO,IAAI,kBAAkB,MAAM;AAAA,IACrC,CAAC;AAED,cAAU,OAAO;AAAA,EACnB,CAAC;AAED,aAAW,UAAU,OAAO;AAE5B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAWJ,KAAAA,SAAS,MAAM,OAAA,MAAa,SAAS;AAAA,IAChD,SAASA,KAAAA,SAAS,MAAM,aAAa,WAAW,OAAA,MAAa,UAAU;AAAA,IACvE,QAAQA,KAAAA,SAAS,MAAM,OAAA,MAAa,MAAM;AAAA,IAC1C,SAASA,KAAAA,SAAS,MAAM,OAAA,MAAa,OAAO;AAAA,IAC5C,aAAaA,KAAAA,SAAS,MAAM,OAAA,MAAa,YAAY;AAAA,EAAA;AAEzD;;"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/index.ts"],"sourcesContent":["import {\n DestroyRef,\n assertInInjectionContext,\n computed,\n effect,\n inject,\n signal,\n} from '@angular/core'\nimport { BaseQueryBuilder, createLiveQueryCollection } from '@tanstack/db'\nimport type {\n ChangeMessage,\n Collection,\n CollectionConfigSingleRowOption,\n CollectionStatus,\n Context,\n GetResult,\n InferResultType,\n InitialQueryBuilder,\n LiveQueryCollectionConfig,\n NonSingleResult,\n QueryBuilder,\n SingleResult,\n} from '@tanstack/db'\nimport type { Signal } from '@angular/core'\n\n/**\n * The result of calling `injectLiveQuery`.\n * Contains reactive signals for the query state and data.\n */\nexport interface InjectLiveQueryResult<TContext extends Context> {\n /** A signal containing the complete state map of results keyed by their ID */\n state: Signal<Map<string | number, GetResult<TContext>>>\n /** A signal containing the results as an array, or single result for findOne queries */\n data: Signal<InferResultType<TContext>>\n /** A signal containing the underlying collection instance (null for disabled queries) */\n collection: Signal<Collection<\n GetResult<TContext>,\n string | number,\n {}\n > | null>\n /** A signal containing the current status of the collection */\n status: Signal<CollectionStatus | `disabled`>\n /** A signal indicating whether the collection is currently loading */\n isLoading: Signal<boolean>\n /** A signal indicating whether the collection is ready */\n isReady: Signal<boolean>\n /** A signal indicating whether the collection is idle */\n isIdle: Signal<boolean>\n /** A signal indicating whether the collection has an error */\n isError: Signal<boolean>\n /** A signal indicating whether the collection has been cleaned up */\n isCleanedUp: Signal<boolean>\n}\n\nexport interface InjectLiveQueryResultWithCollection<\n TResult extends object = any,\n TKey extends string | number = string | number,\n TUtils extends Record<string, any> = {},\n> {\n state: Signal<Map<TKey, TResult>>\n data: Signal<Array<TResult>>\n collection: Signal<Collection<TResult, TKey, TUtils> | null>\n status: Signal<CollectionStatus | `disabled`>\n isLoading: Signal<boolean>\n isReady: Signal<boolean>\n isIdle: Signal<boolean>\n isError: Signal<boolean>\n isCleanedUp: Signal<boolean>\n}\n\nexport interface InjectLiveQueryResultWithSingleResultCollection<\n TResult extends object = any,\n TKey extends string | number = string | number,\n TUtils extends Record<string, any> = {},\n> {\n state: Signal<Map<TKey, TResult>>\n data: Signal<TResult | undefined>\n collection: Signal<(Collection<TResult, TKey, TUtils> & SingleResult) | null>\n status: Signal<CollectionStatus | `disabled`>\n isLoading: Signal<boolean>\n isReady: Signal<boolean>\n isIdle: Signal<boolean>\n isError: Signal<boolean>\n isCleanedUp: Signal<boolean>\n}\n\nexport function injectLiveQuery<\n TContext extends Context,\n TParams extends any,\n>(options: {\n params: () => TParams\n query: (args: {\n params: TParams\n q: InitialQueryBuilder\n }) => QueryBuilder<TContext>\n}): InjectLiveQueryResult<TContext>\nexport function injectLiveQuery<\n TContext extends Context,\n TParams extends any,\n>(options: {\n params: () => TParams\n query: (args: {\n params: TParams\n q: InitialQueryBuilder\n }) => QueryBuilder<TContext> | undefined | null\n}): InjectLiveQueryResult<TContext>\nexport function injectLiveQuery<TContext extends Context>(\n queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext>,\n): InjectLiveQueryResult<TContext>\nexport function injectLiveQuery<TContext extends Context>(\n queryFn: (\n q: InitialQueryBuilder,\n ) => QueryBuilder<TContext> | undefined | null,\n): InjectLiveQueryResult<TContext>\nexport function injectLiveQuery<TContext extends Context>(\n config: LiveQueryCollectionConfig<TContext>,\n): InjectLiveQueryResult<TContext>\n// Pre-created collection without singleResult\nexport function injectLiveQuery<\n TResult extends object,\n TKey extends string | number,\n TUtils extends Record<string, any>,\n>(\n liveQueryCollection: Collection<TResult, TKey, TUtils> & NonSingleResult,\n): InjectLiveQueryResultWithCollection<TResult, TKey, TUtils>\n// Pre-created collection with singleResult\nexport function injectLiveQuery<\n TResult extends object,\n TKey extends string | number,\n TUtils extends Record<string, any>,\n>(\n liveQueryCollection: Collection<TResult, TKey, TUtils> & SingleResult,\n): InjectLiveQueryResultWithSingleResultCollection<TResult, TKey, TUtils>\nexport function injectLiveQuery(opts: any) {\n assertInInjectionContext(injectLiveQuery)\n const destroyRef = inject(DestroyRef)\n\n const collection = computed(() => {\n // Check if it's an existing collection\n const isExistingCollection =\n opts &&\n typeof opts === `object` &&\n typeof opts.subscribeChanges === `function` &&\n typeof opts.startSyncImmediate === `function` &&\n typeof opts.id === `string`\n\n if (isExistingCollection) {\n return opts\n }\n\n if (typeof opts === `function`) {\n // Check if query function returns null/undefined (disabled query)\n const queryBuilder = new BaseQueryBuilder() as InitialQueryBuilder\n const result = opts(queryBuilder)\n\n if (result === undefined || result === null) {\n // Disabled query - return null\n return null\n }\n\n return createLiveQueryCollection({\n query: opts,\n startSync: true,\n gcTime: 0,\n })\n }\n\n // Check if it's reactive query options\n const isReactiveQueryOptions =\n opts &&\n typeof opts === `object` &&\n typeof opts.query === `function` &&\n typeof opts.params === `function`\n\n if (isReactiveQueryOptions) {\n const { params, query } = opts\n const currentParams = params()\n\n // Check if query function returns null/undefined (disabled query)\n const queryBuilder = new BaseQueryBuilder() as InitialQueryBuilder\n const result = query({ params: currentParams, q: queryBuilder })\n\n if (result === undefined || result === null) {\n // Disabled query - return null\n return null\n }\n\n return createLiveQueryCollection({\n query: (q) => query({ params: currentParams, q }),\n startSync: true,\n gcTime: 0,\n })\n }\n\n // Handle LiveQueryCollectionConfig objects\n if (opts && typeof opts === `object` && typeof opts.query === `function`) {\n return createLiveQueryCollection(opts)\n }\n\n throw new Error(`Invalid options provided to injectLiveQuery`)\n })\n\n const state = signal(new Map<string | number, any>())\n const internalData = signal<Array<any>>([])\n const status = signal<CollectionStatus | `disabled`>(\n collection() ? `idle` : `disabled`,\n )\n\n // Returns single item for singleResult collections, array otherwise\n const data = computed(() => {\n const currentCollection = collection()\n if (!currentCollection) {\n return internalData()\n }\n const config = currentCollection.config as\n | CollectionConfigSingleRowOption<any, any, any>\n | undefined\n return config?.singleResult ? internalData()[0] : internalData()\n })\n\n const syncDataFromCollection = (\n currentCollection: Collection<any, any, any>,\n ) => {\n const newState = new Map(currentCollection.entries())\n const newData = Array.from(currentCollection.values())\n\n state.set(newState)\n internalData.set(newData)\n status.set(currentCollection.status)\n }\n\n let unsub: (() => void) | null = null\n const cleanup = () => {\n unsub?.()\n unsub = null\n }\n\n effect((onCleanup) => {\n const currentCollection = collection()\n\n // Handle null collection (disabled query)\n if (!currentCollection) {\n status.set(`disabled` as const)\n state.set(new Map())\n internalData.set([])\n cleanup()\n return\n }\n\n cleanup()\n\n // Initialize immediately with current state\n syncDataFromCollection(currentCollection)\n\n // Start sync if idle\n if (currentCollection.status === `idle`) {\n currentCollection.startSyncImmediate()\n // Update status after starting sync\n status.set(currentCollection.status)\n }\n\n // Subscribe to changes\n const subscription = currentCollection.subscribeChanges(\n (_: Array<ChangeMessage<any>>) => {\n syncDataFromCollection(currentCollection)\n },\n )\n unsub = subscription.unsubscribe.bind(subscription)\n\n // Handle ready state\n currentCollection.onFirstReady(() => {\n status.set(currentCollection.status)\n })\n\n onCleanup(cleanup)\n })\n\n destroyRef.onDestroy(cleanup)\n\n return {\n state,\n data,\n collection,\n status,\n isLoading: computed(() => status() === `loading`),\n isReady: computed(() => status() === `ready` || status() === `disabled`),\n isIdle: computed(() => status() === `idle`),\n isError: computed(() => status() === `error`),\n isCleanedUp: computed(() => status() === `cleaned-up`),\n }\n}\n"],"names":["assertInInjectionContext","inject","DestroyRef","computed","BaseQueryBuilder","createLiveQueryCollection","signal","effect"],"mappings":";;;;AAqIO,SAAS,gBAAgB,MAAW;AACzCA,OAAAA,yBAAyB,eAAe;AACxC,QAAM,aAAaC,KAAAA,OAAOC,eAAU;AAEpC,QAAM,aAAaC,KAAAA,SAAS,MAAM;AAEhC,UAAM,uBACJ,QACA,OAAO,SAAS,YAChB,OAAO,KAAK,qBAAqB,cACjC,OAAO,KAAK,uBAAuB,cACnC,OAAO,KAAK,OAAO;AAErB,QAAI,sBAAsB;AACxB,aAAO;AAAA,IACT;AAEA,QAAI,OAAO,SAAS,YAAY;AAE9B,YAAM,eAAe,IAAIC,oBAAA;AACzB,YAAM,SAAS,KAAK,YAAY;AAEhC,UAAI,WAAW,UAAa,WAAW,MAAM;AAE3C,eAAO;AAAA,MACT;AAEA,aAAOC,6BAA0B;AAAA,QAC/B,OAAO;AAAA,QACP,WAAW;AAAA,QACX,QAAQ;AAAA,MAAA,CACT;AAAA,IACH;AAGA,UAAM,yBACJ,QACA,OAAO,SAAS,YAChB,OAAO,KAAK,UAAU,cACtB,OAAO,KAAK,WAAW;AAEzB,QAAI,wBAAwB;AAC1B,YAAM,EAAE,QAAQ,MAAA,IAAU;AAC1B,YAAM,gBAAgB,OAAA;AAGtB,YAAM,eAAe,IAAID,oBAAA;AACzB,YAAM,SAAS,MAAM,EAAE,QAAQ,eAAe,GAAG,cAAc;AAE/D,UAAI,WAAW,UAAa,WAAW,MAAM;AAE3C,eAAO;AAAA,MACT;AAEA,aAAOC,6BAA0B;AAAA,QAC/B,OAAO,CAAC,MAAM,MAAM,EAAE,QAAQ,eAAe,GAAG;AAAA,QAChD,WAAW;AAAA,QACX,QAAQ;AAAA,MAAA,CACT;AAAA,IACH;AAGA,QAAI,QAAQ,OAAO,SAAS,YAAY,OAAO,KAAK,UAAU,YAAY;AACxE,aAAOA,GAAAA,0BAA0B,IAAI;AAAA,IACvC;AAEA,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D,CAAC;AAED,QAAM,QAAQC,KAAAA,OAAO,oBAAI,KAA2B;AACpD,QAAM,eAAeA,KAAAA,OAAmB,EAAE;AAC1C,QAAM,SAASA,KAAAA;AAAAA,IACb,eAAe,SAAS;AAAA,EAAA;AAI1B,QAAM,OAAOH,KAAAA,SAAS,MAAM;AAC1B,UAAM,oBAAoB,WAAA;AAC1B,QAAI,CAAC,mBAAmB;AACtB,aAAO,aAAA;AAAA,IACT;AACA,UAAM,SAAS,kBAAkB;AAGjC,WAAO,QAAQ,eAAe,aAAA,EAAe,CAAC,IAAI,aAAA;AAAA,EACpD,CAAC;AAED,QAAM,yBAAyB,CAC7B,sBACG;AACH,UAAM,WAAW,IAAI,IAAI,kBAAkB,SAAS;AACpD,UAAM,UAAU,MAAM,KAAK,kBAAkB,QAAQ;AAErD,UAAM,IAAI,QAAQ;AAClB,iBAAa,IAAI,OAAO;AACxB,WAAO,IAAI,kBAAkB,MAAM;AAAA,EACrC;AAEA,MAAI,QAA6B;AACjC,QAAM,UAAU,MAAM;AACpB,YAAA;AACA,YAAQ;AAAA,EACV;AAEAI,OAAAA,OAAO,CAAC,cAAc;AACpB,UAAM,oBAAoB,WAAA;AAG1B,QAAI,CAAC,mBAAmB;AACtB,aAAO,IAAI,UAAmB;AAC9B,YAAM,IAAI,oBAAI,KAAK;AACnB,mBAAa,IAAI,EAAE;AACnB,cAAA;AACA;AAAA,IACF;AAEA,YAAA;AAGA,2BAAuB,iBAAiB;AAGxC,QAAI,kBAAkB,WAAW,QAAQ;AACvC,wBAAkB,mBAAA;AAElB,aAAO,IAAI,kBAAkB,MAAM;AAAA,IACrC;AAGA,UAAM,eAAe,kBAAkB;AAAA,MACrC,CAAC,MAAiC;AAChC,+BAAuB,iBAAiB;AAAA,MAC1C;AAAA,IAAA;AAEF,YAAQ,aAAa,YAAY,KAAK,YAAY;AAGlD,sBAAkB,aAAa,MAAM;AACnC,aAAO,IAAI,kBAAkB,MAAM;AAAA,IACrC,CAAC;AAED,cAAU,OAAO;AAAA,EACnB,CAAC;AAED,aAAW,UAAU,OAAO;AAE5B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAWJ,KAAAA,SAAS,MAAM,OAAA,MAAa,SAAS;AAAA,IAChD,SAASA,KAAAA,SAAS,MAAM,aAAa,WAAW,OAAA,MAAa,UAAU;AAAA,IACvE,QAAQA,KAAAA,SAAS,MAAM,OAAA,MAAa,MAAM;AAAA,IAC1C,SAASA,KAAAA,SAAS,MAAM,OAAA,MAAa,OAAO;AAAA,IAC5C,aAAaA,KAAAA,SAAS,MAAM,OAAA,MAAa,YAAY;AAAA,EAAA;AAEzD;;"}
@@ -1,16 +1,16 @@
1
- import { Collection, CollectionStatus, Context, GetResult, InitialQueryBuilder, LiveQueryCollectionConfig, QueryBuilder } from '@tanstack/db';
1
+ import { Collection, CollectionStatus, Context, GetResult, InferResultType, InitialQueryBuilder, LiveQueryCollectionConfig, NonSingleResult, QueryBuilder, SingleResult } from '@tanstack/db';
2
2
  import { Signal } from '@angular/core';
3
3
  /**
4
4
  * The result of calling `injectLiveQuery`.
5
5
  * Contains reactive signals for the query state and data.
6
6
  */
7
- export interface InjectLiveQueryResult<TResult extends object = any, TKey extends string | number = string | number, TUtils extends Record<string, any> = {}> {
7
+ export interface InjectLiveQueryResult<TContext extends Context> {
8
8
  /** A signal containing the complete state map of results keyed by their ID */
9
- state: Signal<Map<TKey, TResult>>;
10
- /** A signal containing the results as an array */
11
- data: Signal<Array<TResult>>;
9
+ state: Signal<Map<string | number, GetResult<TContext>>>;
10
+ /** A signal containing the results as an array, or single result for findOne queries */
11
+ data: Signal<InferResultType<TContext>>;
12
12
  /** A signal containing the underlying collection instance (null for disabled queries) */
13
- collection: Signal<Collection<TResult, TKey, TUtils> | null>;
13
+ collection: Signal<Collection<GetResult<TContext>, string | number, {}> | null>;
14
14
  /** A signal containing the current status of the collection */
15
15
  status: Signal<CollectionStatus | `disabled`>;
16
16
  /** A signal indicating whether the collection is currently loading */
@@ -24,21 +24,44 @@ export interface InjectLiveQueryResult<TResult extends object = any, TKey extend
24
24
  /** A signal indicating whether the collection has been cleaned up */
25
25
  isCleanedUp: Signal<boolean>;
26
26
  }
27
+ export interface InjectLiveQueryResultWithCollection<TResult extends object = any, TKey extends string | number = string | number, TUtils extends Record<string, any> = {}> {
28
+ state: Signal<Map<TKey, TResult>>;
29
+ data: Signal<Array<TResult>>;
30
+ collection: Signal<Collection<TResult, TKey, TUtils> | null>;
31
+ status: Signal<CollectionStatus | `disabled`>;
32
+ isLoading: Signal<boolean>;
33
+ isReady: Signal<boolean>;
34
+ isIdle: Signal<boolean>;
35
+ isError: Signal<boolean>;
36
+ isCleanedUp: Signal<boolean>;
37
+ }
38
+ export interface InjectLiveQueryResultWithSingleResultCollection<TResult extends object = any, TKey extends string | number = string | number, TUtils extends Record<string, any> = {}> {
39
+ state: Signal<Map<TKey, TResult>>;
40
+ data: Signal<TResult | undefined>;
41
+ collection: Signal<(Collection<TResult, TKey, TUtils> & SingleResult) | null>;
42
+ status: Signal<CollectionStatus | `disabled`>;
43
+ isLoading: Signal<boolean>;
44
+ isReady: Signal<boolean>;
45
+ isIdle: Signal<boolean>;
46
+ isError: Signal<boolean>;
47
+ isCleanedUp: Signal<boolean>;
48
+ }
27
49
  export declare function injectLiveQuery<TContext extends Context, TParams extends any>(options: {
28
50
  params: () => TParams;
29
51
  query: (args: {
30
52
  params: TParams;
31
53
  q: InitialQueryBuilder;
32
54
  }) => QueryBuilder<TContext>;
33
- }): InjectLiveQueryResult<GetResult<TContext>>;
55
+ }): InjectLiveQueryResult<TContext>;
34
56
  export declare function injectLiveQuery<TContext extends Context, TParams extends any>(options: {
35
57
  params: () => TParams;
36
58
  query: (args: {
37
59
  params: TParams;
38
60
  q: InitialQueryBuilder;
39
61
  }) => QueryBuilder<TContext> | undefined | null;
40
- }): InjectLiveQueryResult<GetResult<TContext>>;
41
- export declare function injectLiveQuery<TContext extends Context>(queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext>): InjectLiveQueryResult<GetResult<TContext>>;
42
- export declare function injectLiveQuery<TContext extends Context>(queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext> | undefined | null): InjectLiveQueryResult<GetResult<TContext>>;
43
- export declare function injectLiveQuery<TContext extends Context>(config: LiveQueryCollectionConfig<TContext>): InjectLiveQueryResult<GetResult<TContext>>;
44
- export declare function injectLiveQuery<TResult extends object, TKey extends string | number, TUtils extends Record<string, any>>(liveQueryCollection: Collection<TResult, TKey, TUtils>): InjectLiveQueryResult<TResult, TKey, TUtils>;
62
+ }): InjectLiveQueryResult<TContext>;
63
+ export declare function injectLiveQuery<TContext extends Context>(queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext>): InjectLiveQueryResult<TContext>;
64
+ export declare function injectLiveQuery<TContext extends Context>(queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext> | undefined | null): InjectLiveQueryResult<TContext>;
65
+ export declare function injectLiveQuery<TContext extends Context>(config: LiveQueryCollectionConfig<TContext>): InjectLiveQueryResult<TContext>;
66
+ export declare function injectLiveQuery<TResult extends object, TKey extends string | number, TUtils extends Record<string, any>>(liveQueryCollection: Collection<TResult, TKey, TUtils> & NonSingleResult): InjectLiveQueryResultWithCollection<TResult, TKey, TUtils>;
67
+ export declare function injectLiveQuery<TResult extends object, TKey extends string | number, TUtils extends Record<string, any>>(liveQueryCollection: Collection<TResult, TKey, TUtils> & SingleResult): InjectLiveQueryResultWithSingleResultCollection<TResult, TKey, TUtils>;
@@ -1,16 +1,16 @@
1
- import { Collection, CollectionStatus, Context, GetResult, InitialQueryBuilder, LiveQueryCollectionConfig, QueryBuilder } from '@tanstack/db';
1
+ import { Collection, CollectionStatus, Context, GetResult, InferResultType, InitialQueryBuilder, LiveQueryCollectionConfig, NonSingleResult, QueryBuilder, SingleResult } from '@tanstack/db';
2
2
  import { Signal } from '@angular/core';
3
3
  /**
4
4
  * The result of calling `injectLiveQuery`.
5
5
  * Contains reactive signals for the query state and data.
6
6
  */
7
- export interface InjectLiveQueryResult<TResult extends object = any, TKey extends string | number = string | number, TUtils extends Record<string, any> = {}> {
7
+ export interface InjectLiveQueryResult<TContext extends Context> {
8
8
  /** A signal containing the complete state map of results keyed by their ID */
9
- state: Signal<Map<TKey, TResult>>;
10
- /** A signal containing the results as an array */
11
- data: Signal<Array<TResult>>;
9
+ state: Signal<Map<string | number, GetResult<TContext>>>;
10
+ /** A signal containing the results as an array, or single result for findOne queries */
11
+ data: Signal<InferResultType<TContext>>;
12
12
  /** A signal containing the underlying collection instance (null for disabled queries) */
13
- collection: Signal<Collection<TResult, TKey, TUtils> | null>;
13
+ collection: Signal<Collection<GetResult<TContext>, string | number, {}> | null>;
14
14
  /** A signal containing the current status of the collection */
15
15
  status: Signal<CollectionStatus | `disabled`>;
16
16
  /** A signal indicating whether the collection is currently loading */
@@ -24,21 +24,44 @@ export interface InjectLiveQueryResult<TResult extends object = any, TKey extend
24
24
  /** A signal indicating whether the collection has been cleaned up */
25
25
  isCleanedUp: Signal<boolean>;
26
26
  }
27
+ export interface InjectLiveQueryResultWithCollection<TResult extends object = any, TKey extends string | number = string | number, TUtils extends Record<string, any> = {}> {
28
+ state: Signal<Map<TKey, TResult>>;
29
+ data: Signal<Array<TResult>>;
30
+ collection: Signal<Collection<TResult, TKey, TUtils> | null>;
31
+ status: Signal<CollectionStatus | `disabled`>;
32
+ isLoading: Signal<boolean>;
33
+ isReady: Signal<boolean>;
34
+ isIdle: Signal<boolean>;
35
+ isError: Signal<boolean>;
36
+ isCleanedUp: Signal<boolean>;
37
+ }
38
+ export interface InjectLiveQueryResultWithSingleResultCollection<TResult extends object = any, TKey extends string | number = string | number, TUtils extends Record<string, any> = {}> {
39
+ state: Signal<Map<TKey, TResult>>;
40
+ data: Signal<TResult | undefined>;
41
+ collection: Signal<(Collection<TResult, TKey, TUtils> & SingleResult) | null>;
42
+ status: Signal<CollectionStatus | `disabled`>;
43
+ isLoading: Signal<boolean>;
44
+ isReady: Signal<boolean>;
45
+ isIdle: Signal<boolean>;
46
+ isError: Signal<boolean>;
47
+ isCleanedUp: Signal<boolean>;
48
+ }
27
49
  export declare function injectLiveQuery<TContext extends Context, TParams extends any>(options: {
28
50
  params: () => TParams;
29
51
  query: (args: {
30
52
  params: TParams;
31
53
  q: InitialQueryBuilder;
32
54
  }) => QueryBuilder<TContext>;
33
- }): InjectLiveQueryResult<GetResult<TContext>>;
55
+ }): InjectLiveQueryResult<TContext>;
34
56
  export declare function injectLiveQuery<TContext extends Context, TParams extends any>(options: {
35
57
  params: () => TParams;
36
58
  query: (args: {
37
59
  params: TParams;
38
60
  q: InitialQueryBuilder;
39
61
  }) => QueryBuilder<TContext> | undefined | null;
40
- }): InjectLiveQueryResult<GetResult<TContext>>;
41
- export declare function injectLiveQuery<TContext extends Context>(queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext>): InjectLiveQueryResult<GetResult<TContext>>;
42
- export declare function injectLiveQuery<TContext extends Context>(queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext> | undefined | null): InjectLiveQueryResult<GetResult<TContext>>;
43
- export declare function injectLiveQuery<TContext extends Context>(config: LiveQueryCollectionConfig<TContext>): InjectLiveQueryResult<GetResult<TContext>>;
44
- export declare function injectLiveQuery<TResult extends object, TKey extends string | number, TUtils extends Record<string, any>>(liveQueryCollection: Collection<TResult, TKey, TUtils>): InjectLiveQueryResult<TResult, TKey, TUtils>;
62
+ }): InjectLiveQueryResult<TContext>;
63
+ export declare function injectLiveQuery<TContext extends Context>(queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext>): InjectLiveQueryResult<TContext>;
64
+ export declare function injectLiveQuery<TContext extends Context>(queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext> | undefined | null): InjectLiveQueryResult<TContext>;
65
+ export declare function injectLiveQuery<TContext extends Context>(config: LiveQueryCollectionConfig<TContext>): InjectLiveQueryResult<TContext>;
66
+ export declare function injectLiveQuery<TResult extends object, TKey extends string | number, TUtils extends Record<string, any>>(liveQueryCollection: Collection<TResult, TKey, TUtils> & NonSingleResult): InjectLiveQueryResultWithCollection<TResult, TKey, TUtils>;
67
+ export declare function injectLiveQuery<TResult extends object, TKey extends string | number, TUtils extends Record<string, any>>(liveQueryCollection: Collection<TResult, TKey, TUtils> & SingleResult): InjectLiveQueryResultWithSingleResultCollection<TResult, TKey, TUtils>;
package/dist/esm/index.js CHANGED
@@ -41,15 +41,23 @@ function injectLiveQuery(opts) {
41
41
  throw new Error(`Invalid options provided to injectLiveQuery`);
42
42
  });
43
43
  const state = signal(/* @__PURE__ */ new Map());
44
- const data = signal([]);
44
+ const internalData = signal([]);
45
45
  const status = signal(
46
46
  collection() ? `idle` : `disabled`
47
47
  );
48
+ const data = computed(() => {
49
+ const currentCollection = collection();
50
+ if (!currentCollection) {
51
+ return internalData();
52
+ }
53
+ const config = currentCollection.config;
54
+ return config?.singleResult ? internalData()[0] : internalData();
55
+ });
48
56
  const syncDataFromCollection = (currentCollection) => {
49
57
  const newState = new Map(currentCollection.entries());
50
58
  const newData = Array.from(currentCollection.values());
51
59
  state.set(newState);
52
- data.set(newData);
60
+ internalData.set(newData);
53
61
  status.set(currentCollection.status);
54
62
  };
55
63
  let unsub = null;
@@ -62,7 +70,7 @@ function injectLiveQuery(opts) {
62
70
  if (!currentCollection) {
63
71
  status.set(`disabled`);
64
72
  state.set(/* @__PURE__ */ new Map());
65
- data.set([]);
73
+ internalData.set([]);
66
74
  cleanup();
67
75
  return;
68
76
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/index.ts"],"sourcesContent":["import {\n DestroyRef,\n assertInInjectionContext,\n computed,\n effect,\n inject,\n signal,\n} from '@angular/core'\nimport { BaseQueryBuilder, createLiveQueryCollection } from '@tanstack/db'\nimport type {\n ChangeMessage,\n Collection,\n CollectionStatus,\n Context,\n GetResult,\n InitialQueryBuilder,\n LiveQueryCollectionConfig,\n QueryBuilder,\n} from '@tanstack/db'\nimport type { Signal } from '@angular/core'\n\n/**\n * The result of calling `injectLiveQuery`.\n * Contains reactive signals for the query state and data.\n */\nexport interface InjectLiveQueryResult<\n TResult extends object = any,\n TKey extends string | number = string | number,\n TUtils extends Record<string, any> = {},\n> {\n /** A signal containing the complete state map of results keyed by their ID */\n state: Signal<Map<TKey, TResult>>\n /** A signal containing the results as an array */\n data: Signal<Array<TResult>>\n /** A signal containing the underlying collection instance (null for disabled queries) */\n collection: Signal<Collection<TResult, TKey, TUtils> | null>\n /** A signal containing the current status of the collection */\n status: Signal<CollectionStatus | `disabled`>\n /** A signal indicating whether the collection is currently loading */\n isLoading: Signal<boolean>\n /** A signal indicating whether the collection is ready */\n isReady: Signal<boolean>\n /** A signal indicating whether the collection is idle */\n isIdle: Signal<boolean>\n /** A signal indicating whether the collection has an error */\n isError: Signal<boolean>\n /** A signal indicating whether the collection has been cleaned up */\n isCleanedUp: Signal<boolean>\n}\n\nexport function injectLiveQuery<\n TContext extends Context,\n TParams extends any,\n>(options: {\n params: () => TParams\n query: (args: {\n params: TParams\n q: InitialQueryBuilder\n }) => QueryBuilder<TContext>\n}): InjectLiveQueryResult<GetResult<TContext>>\nexport function injectLiveQuery<\n TContext extends Context,\n TParams extends any,\n>(options: {\n params: () => TParams\n query: (args: {\n params: TParams\n q: InitialQueryBuilder\n }) => QueryBuilder<TContext> | undefined | null\n}): InjectLiveQueryResult<GetResult<TContext>>\nexport function injectLiveQuery<TContext extends Context>(\n queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext>,\n): InjectLiveQueryResult<GetResult<TContext>>\nexport function injectLiveQuery<TContext extends Context>(\n queryFn: (\n q: InitialQueryBuilder,\n ) => QueryBuilder<TContext> | undefined | null,\n): InjectLiveQueryResult<GetResult<TContext>>\nexport function injectLiveQuery<TContext extends Context>(\n config: LiveQueryCollectionConfig<TContext>,\n): InjectLiveQueryResult<GetResult<TContext>>\nexport function injectLiveQuery<\n TResult extends object,\n TKey extends string | number,\n TUtils extends Record<string, any>,\n>(\n liveQueryCollection: Collection<TResult, TKey, TUtils>,\n): InjectLiveQueryResult<TResult, TKey, TUtils>\nexport function injectLiveQuery(opts: any) {\n assertInInjectionContext(injectLiveQuery)\n const destroyRef = inject(DestroyRef)\n\n const collection = computed(() => {\n // Check if it's an existing collection\n const isExistingCollection =\n opts &&\n typeof opts === `object` &&\n typeof opts.subscribeChanges === `function` &&\n typeof opts.startSyncImmediate === `function` &&\n typeof opts.id === `string`\n\n if (isExistingCollection) {\n return opts\n }\n\n if (typeof opts === `function`) {\n // Check if query function returns null/undefined (disabled query)\n const queryBuilder = new BaseQueryBuilder() as InitialQueryBuilder\n const result = opts(queryBuilder)\n\n if (result === undefined || result === null) {\n // Disabled query - return null\n return null\n }\n\n return createLiveQueryCollection({\n query: opts,\n startSync: true,\n gcTime: 0,\n })\n }\n\n // Check if it's reactive query options\n const isReactiveQueryOptions =\n opts &&\n typeof opts === `object` &&\n typeof opts.query === `function` &&\n typeof opts.params === `function`\n\n if (isReactiveQueryOptions) {\n const { params, query } = opts\n const currentParams = params()\n\n // Check if query function returns null/undefined (disabled query)\n const queryBuilder = new BaseQueryBuilder() as InitialQueryBuilder\n const result = query({ params: currentParams, q: queryBuilder })\n\n if (result === undefined || result === null) {\n // Disabled query - return null\n return null\n }\n\n return createLiveQueryCollection({\n query: (q) => query({ params: currentParams, q }),\n startSync: true,\n gcTime: 0,\n })\n }\n\n // Handle LiveQueryCollectionConfig objects\n if (opts && typeof opts === `object` && typeof opts.query === `function`) {\n return createLiveQueryCollection(opts)\n }\n\n throw new Error(`Invalid options provided to injectLiveQuery`)\n })\n\n const state = signal(new Map<string | number, any>())\n const data = signal<Array<any>>([])\n const status = signal<CollectionStatus | `disabled`>(\n collection() ? `idle` : `disabled`,\n )\n\n const syncDataFromCollection = (\n currentCollection: Collection<any, any, any>,\n ) => {\n const newState = new Map(currentCollection.entries())\n const newData = Array.from(currentCollection.values())\n\n state.set(newState)\n data.set(newData)\n status.set(currentCollection.status)\n }\n\n let unsub: (() => void) | null = null\n const cleanup = () => {\n unsub?.()\n unsub = null\n }\n\n effect((onCleanup) => {\n const currentCollection = collection()\n\n // Handle null collection (disabled query)\n if (!currentCollection) {\n status.set(`disabled` as const)\n state.set(new Map())\n data.set([])\n cleanup()\n return\n }\n\n cleanup()\n\n // Initialize immediately with current state\n syncDataFromCollection(currentCollection)\n\n // Start sync if idle\n if (currentCollection.status === `idle`) {\n currentCollection.startSyncImmediate()\n // Update status after starting sync\n status.set(currentCollection.status)\n }\n\n // Subscribe to changes\n const subscription = currentCollection.subscribeChanges(\n (_: Array<ChangeMessage<any>>) => {\n syncDataFromCollection(currentCollection)\n },\n )\n unsub = subscription.unsubscribe.bind(subscription)\n\n // Handle ready state\n currentCollection.onFirstReady(() => {\n status.set(currentCollection.status)\n })\n\n onCleanup(cleanup)\n })\n\n destroyRef.onDestroy(cleanup)\n\n return {\n state,\n data,\n collection,\n status,\n isLoading: computed(() => status() === `loading`),\n isReady: computed(() => status() === `ready` || status() === `disabled`),\n isIdle: computed(() => status() === `idle`),\n isError: computed(() => status() === `error`),\n isCleanedUp: computed(() => status() === `cleaned-up`),\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/index.ts"],"sourcesContent":["import {\n DestroyRef,\n assertInInjectionContext,\n computed,\n effect,\n inject,\n signal,\n} from '@angular/core'\nimport { BaseQueryBuilder, createLiveQueryCollection } from '@tanstack/db'\nimport type {\n ChangeMessage,\n Collection,\n CollectionConfigSingleRowOption,\n CollectionStatus,\n Context,\n GetResult,\n InferResultType,\n InitialQueryBuilder,\n LiveQueryCollectionConfig,\n NonSingleResult,\n QueryBuilder,\n SingleResult,\n} from '@tanstack/db'\nimport type { Signal } from '@angular/core'\n\n/**\n * The result of calling `injectLiveQuery`.\n * Contains reactive signals for the query state and data.\n */\nexport interface InjectLiveQueryResult<TContext extends Context> {\n /** A signal containing the complete state map of results keyed by their ID */\n state: Signal<Map<string | number, GetResult<TContext>>>\n /** A signal containing the results as an array, or single result for findOne queries */\n data: Signal<InferResultType<TContext>>\n /** A signal containing the underlying collection instance (null for disabled queries) */\n collection: Signal<Collection<\n GetResult<TContext>,\n string | number,\n {}\n > | null>\n /** A signal containing the current status of the collection */\n status: Signal<CollectionStatus | `disabled`>\n /** A signal indicating whether the collection is currently loading */\n isLoading: Signal<boolean>\n /** A signal indicating whether the collection is ready */\n isReady: Signal<boolean>\n /** A signal indicating whether the collection is idle */\n isIdle: Signal<boolean>\n /** A signal indicating whether the collection has an error */\n isError: Signal<boolean>\n /** A signal indicating whether the collection has been cleaned up */\n isCleanedUp: Signal<boolean>\n}\n\nexport interface InjectLiveQueryResultWithCollection<\n TResult extends object = any,\n TKey extends string | number = string | number,\n TUtils extends Record<string, any> = {},\n> {\n state: Signal<Map<TKey, TResult>>\n data: Signal<Array<TResult>>\n collection: Signal<Collection<TResult, TKey, TUtils> | null>\n status: Signal<CollectionStatus | `disabled`>\n isLoading: Signal<boolean>\n isReady: Signal<boolean>\n isIdle: Signal<boolean>\n isError: Signal<boolean>\n isCleanedUp: Signal<boolean>\n}\n\nexport interface InjectLiveQueryResultWithSingleResultCollection<\n TResult extends object = any,\n TKey extends string | number = string | number,\n TUtils extends Record<string, any> = {},\n> {\n state: Signal<Map<TKey, TResult>>\n data: Signal<TResult | undefined>\n collection: Signal<(Collection<TResult, TKey, TUtils> & SingleResult) | null>\n status: Signal<CollectionStatus | `disabled`>\n isLoading: Signal<boolean>\n isReady: Signal<boolean>\n isIdle: Signal<boolean>\n isError: Signal<boolean>\n isCleanedUp: Signal<boolean>\n}\n\nexport function injectLiveQuery<\n TContext extends Context,\n TParams extends any,\n>(options: {\n params: () => TParams\n query: (args: {\n params: TParams\n q: InitialQueryBuilder\n }) => QueryBuilder<TContext>\n}): InjectLiveQueryResult<TContext>\nexport function injectLiveQuery<\n TContext extends Context,\n TParams extends any,\n>(options: {\n params: () => TParams\n query: (args: {\n params: TParams\n q: InitialQueryBuilder\n }) => QueryBuilder<TContext> | undefined | null\n}): InjectLiveQueryResult<TContext>\nexport function injectLiveQuery<TContext extends Context>(\n queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext>,\n): InjectLiveQueryResult<TContext>\nexport function injectLiveQuery<TContext extends Context>(\n queryFn: (\n q: InitialQueryBuilder,\n ) => QueryBuilder<TContext> | undefined | null,\n): InjectLiveQueryResult<TContext>\nexport function injectLiveQuery<TContext extends Context>(\n config: LiveQueryCollectionConfig<TContext>,\n): InjectLiveQueryResult<TContext>\n// Pre-created collection without singleResult\nexport function injectLiveQuery<\n TResult extends object,\n TKey extends string | number,\n TUtils extends Record<string, any>,\n>(\n liveQueryCollection: Collection<TResult, TKey, TUtils> & NonSingleResult,\n): InjectLiveQueryResultWithCollection<TResult, TKey, TUtils>\n// Pre-created collection with singleResult\nexport function injectLiveQuery<\n TResult extends object,\n TKey extends string | number,\n TUtils extends Record<string, any>,\n>(\n liveQueryCollection: Collection<TResult, TKey, TUtils> & SingleResult,\n): InjectLiveQueryResultWithSingleResultCollection<TResult, TKey, TUtils>\nexport function injectLiveQuery(opts: any) {\n assertInInjectionContext(injectLiveQuery)\n const destroyRef = inject(DestroyRef)\n\n const collection = computed(() => {\n // Check if it's an existing collection\n const isExistingCollection =\n opts &&\n typeof opts === `object` &&\n typeof opts.subscribeChanges === `function` &&\n typeof opts.startSyncImmediate === `function` &&\n typeof opts.id === `string`\n\n if (isExistingCollection) {\n return opts\n }\n\n if (typeof opts === `function`) {\n // Check if query function returns null/undefined (disabled query)\n const queryBuilder = new BaseQueryBuilder() as InitialQueryBuilder\n const result = opts(queryBuilder)\n\n if (result === undefined || result === null) {\n // Disabled query - return null\n return null\n }\n\n return createLiveQueryCollection({\n query: opts,\n startSync: true,\n gcTime: 0,\n })\n }\n\n // Check if it's reactive query options\n const isReactiveQueryOptions =\n opts &&\n typeof opts === `object` &&\n typeof opts.query === `function` &&\n typeof opts.params === `function`\n\n if (isReactiveQueryOptions) {\n const { params, query } = opts\n const currentParams = params()\n\n // Check if query function returns null/undefined (disabled query)\n const queryBuilder = new BaseQueryBuilder() as InitialQueryBuilder\n const result = query({ params: currentParams, q: queryBuilder })\n\n if (result === undefined || result === null) {\n // Disabled query - return null\n return null\n }\n\n return createLiveQueryCollection({\n query: (q) => query({ params: currentParams, q }),\n startSync: true,\n gcTime: 0,\n })\n }\n\n // Handle LiveQueryCollectionConfig objects\n if (opts && typeof opts === `object` && typeof opts.query === `function`) {\n return createLiveQueryCollection(opts)\n }\n\n throw new Error(`Invalid options provided to injectLiveQuery`)\n })\n\n const state = signal(new Map<string | number, any>())\n const internalData = signal<Array<any>>([])\n const status = signal<CollectionStatus | `disabled`>(\n collection() ? `idle` : `disabled`,\n )\n\n // Returns single item for singleResult collections, array otherwise\n const data = computed(() => {\n const currentCollection = collection()\n if (!currentCollection) {\n return internalData()\n }\n const config = currentCollection.config as\n | CollectionConfigSingleRowOption<any, any, any>\n | undefined\n return config?.singleResult ? internalData()[0] : internalData()\n })\n\n const syncDataFromCollection = (\n currentCollection: Collection<any, any, any>,\n ) => {\n const newState = new Map(currentCollection.entries())\n const newData = Array.from(currentCollection.values())\n\n state.set(newState)\n internalData.set(newData)\n status.set(currentCollection.status)\n }\n\n let unsub: (() => void) | null = null\n const cleanup = () => {\n unsub?.()\n unsub = null\n }\n\n effect((onCleanup) => {\n const currentCollection = collection()\n\n // Handle null collection (disabled query)\n if (!currentCollection) {\n status.set(`disabled` as const)\n state.set(new Map())\n internalData.set([])\n cleanup()\n return\n }\n\n cleanup()\n\n // Initialize immediately with current state\n syncDataFromCollection(currentCollection)\n\n // Start sync if idle\n if (currentCollection.status === `idle`) {\n currentCollection.startSyncImmediate()\n // Update status after starting sync\n status.set(currentCollection.status)\n }\n\n // Subscribe to changes\n const subscription = currentCollection.subscribeChanges(\n (_: Array<ChangeMessage<any>>) => {\n syncDataFromCollection(currentCollection)\n },\n )\n unsub = subscription.unsubscribe.bind(subscription)\n\n // Handle ready state\n currentCollection.onFirstReady(() => {\n status.set(currentCollection.status)\n })\n\n onCleanup(cleanup)\n })\n\n destroyRef.onDestroy(cleanup)\n\n return {\n state,\n data,\n collection,\n status,\n isLoading: computed(() => status() === `loading`),\n isReady: computed(() => status() === `ready` || status() === `disabled`),\n isIdle: computed(() => status() === `idle`),\n isError: computed(() => status() === `error`),\n isCleanedUp: computed(() => status() === `cleaned-up`),\n }\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/angular-db",
3
- "version": "0.1.54",
3
+ "version": "0.1.55",
4
4
  "description": "Angular integration for @tanstack/db",
5
5
  "author": "Ethan McDaniel",
6
6
  "license": "MIT",
@@ -38,7 +38,7 @@
38
38
  "src"
39
39
  ],
40
40
  "dependencies": {
41
- "@tanstack/db": "0.5.28"
41
+ "@tanstack/db": "0.5.29"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "@angular/core": ">=16.0.0",
package/src/index.ts CHANGED
@@ -10,12 +10,16 @@ import { BaseQueryBuilder, createLiveQueryCollection } from '@tanstack/db'
10
10
  import type {
11
11
  ChangeMessage,
12
12
  Collection,
13
+ CollectionConfigSingleRowOption,
13
14
  CollectionStatus,
14
15
  Context,
15
16
  GetResult,
17
+ InferResultType,
16
18
  InitialQueryBuilder,
17
19
  LiveQueryCollectionConfig,
20
+ NonSingleResult,
18
21
  QueryBuilder,
22
+ SingleResult,
19
23
  } from '@tanstack/db'
20
24
  import type { Signal } from '@angular/core'
21
25
 
@@ -23,17 +27,17 @@ import type { Signal } from '@angular/core'
23
27
  * The result of calling `injectLiveQuery`.
24
28
  * Contains reactive signals for the query state and data.
25
29
  */
26
- export interface InjectLiveQueryResult<
27
- TResult extends object = any,
28
- TKey extends string | number = string | number,
29
- TUtils extends Record<string, any> = {},
30
- > {
30
+ export interface InjectLiveQueryResult<TContext extends Context> {
31
31
  /** A signal containing the complete state map of results keyed by their ID */
32
- state: Signal<Map<TKey, TResult>>
33
- /** A signal containing the results as an array */
34
- data: Signal<Array<TResult>>
32
+ state: Signal<Map<string | number, GetResult<TContext>>>
33
+ /** A signal containing the results as an array, or single result for findOne queries */
34
+ data: Signal<InferResultType<TContext>>
35
35
  /** A signal containing the underlying collection instance (null for disabled queries) */
36
- collection: Signal<Collection<TResult, TKey, TUtils> | null>
36
+ collection: Signal<Collection<
37
+ GetResult<TContext>,
38
+ string | number,
39
+ {}
40
+ > | null>
37
41
  /** A signal containing the current status of the collection */
38
42
  status: Signal<CollectionStatus | `disabled`>
39
43
  /** A signal indicating whether the collection is currently loading */
@@ -48,6 +52,38 @@ export interface InjectLiveQueryResult<
48
52
  isCleanedUp: Signal<boolean>
49
53
  }
50
54
 
55
+ export interface InjectLiveQueryResultWithCollection<
56
+ TResult extends object = any,
57
+ TKey extends string | number = string | number,
58
+ TUtils extends Record<string, any> = {},
59
+ > {
60
+ state: Signal<Map<TKey, TResult>>
61
+ data: Signal<Array<TResult>>
62
+ collection: Signal<Collection<TResult, TKey, TUtils> | null>
63
+ status: Signal<CollectionStatus | `disabled`>
64
+ isLoading: Signal<boolean>
65
+ isReady: Signal<boolean>
66
+ isIdle: Signal<boolean>
67
+ isError: Signal<boolean>
68
+ isCleanedUp: Signal<boolean>
69
+ }
70
+
71
+ export interface InjectLiveQueryResultWithSingleResultCollection<
72
+ TResult extends object = any,
73
+ TKey extends string | number = string | number,
74
+ TUtils extends Record<string, any> = {},
75
+ > {
76
+ state: Signal<Map<TKey, TResult>>
77
+ data: Signal<TResult | undefined>
78
+ collection: Signal<(Collection<TResult, TKey, TUtils> & SingleResult) | null>
79
+ status: Signal<CollectionStatus | `disabled`>
80
+ isLoading: Signal<boolean>
81
+ isReady: Signal<boolean>
82
+ isIdle: Signal<boolean>
83
+ isError: Signal<boolean>
84
+ isCleanedUp: Signal<boolean>
85
+ }
86
+
51
87
  export function injectLiveQuery<
52
88
  TContext extends Context,
53
89
  TParams extends any,
@@ -57,7 +93,7 @@ export function injectLiveQuery<
57
93
  params: TParams
58
94
  q: InitialQueryBuilder
59
95
  }) => QueryBuilder<TContext>
60
- }): InjectLiveQueryResult<GetResult<TContext>>
96
+ }): InjectLiveQueryResult<TContext>
61
97
  export function injectLiveQuery<
62
98
  TContext extends Context,
63
99
  TParams extends any,
@@ -67,25 +103,34 @@ export function injectLiveQuery<
67
103
  params: TParams
68
104
  q: InitialQueryBuilder
69
105
  }) => QueryBuilder<TContext> | undefined | null
70
- }): InjectLiveQueryResult<GetResult<TContext>>
106
+ }): InjectLiveQueryResult<TContext>
71
107
  export function injectLiveQuery<TContext extends Context>(
72
108
  queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext>,
73
- ): InjectLiveQueryResult<GetResult<TContext>>
109
+ ): InjectLiveQueryResult<TContext>
74
110
  export function injectLiveQuery<TContext extends Context>(
75
111
  queryFn: (
76
112
  q: InitialQueryBuilder,
77
113
  ) => QueryBuilder<TContext> | undefined | null,
78
- ): InjectLiveQueryResult<GetResult<TContext>>
114
+ ): InjectLiveQueryResult<TContext>
79
115
  export function injectLiveQuery<TContext extends Context>(
80
116
  config: LiveQueryCollectionConfig<TContext>,
81
- ): InjectLiveQueryResult<GetResult<TContext>>
117
+ ): InjectLiveQueryResult<TContext>
118
+ // Pre-created collection without singleResult
119
+ export function injectLiveQuery<
120
+ TResult extends object,
121
+ TKey extends string | number,
122
+ TUtils extends Record<string, any>,
123
+ >(
124
+ liveQueryCollection: Collection<TResult, TKey, TUtils> & NonSingleResult,
125
+ ): InjectLiveQueryResultWithCollection<TResult, TKey, TUtils>
126
+ // Pre-created collection with singleResult
82
127
  export function injectLiveQuery<
83
128
  TResult extends object,
84
129
  TKey extends string | number,
85
130
  TUtils extends Record<string, any>,
86
131
  >(
87
- liveQueryCollection: Collection<TResult, TKey, TUtils>,
88
- ): InjectLiveQueryResult<TResult, TKey, TUtils>
132
+ liveQueryCollection: Collection<TResult, TKey, TUtils> & SingleResult,
133
+ ): InjectLiveQueryResultWithSingleResultCollection<TResult, TKey, TUtils>
89
134
  export function injectLiveQuery(opts: any) {
90
135
  assertInInjectionContext(injectLiveQuery)
91
136
  const destroyRef = inject(DestroyRef)
@@ -156,11 +201,23 @@ export function injectLiveQuery(opts: any) {
156
201
  })
157
202
 
158
203
  const state = signal(new Map<string | number, any>())
159
- const data = signal<Array<any>>([])
204
+ const internalData = signal<Array<any>>([])
160
205
  const status = signal<CollectionStatus | `disabled`>(
161
206
  collection() ? `idle` : `disabled`,
162
207
  )
163
208
 
209
+ // Returns single item for singleResult collections, array otherwise
210
+ const data = computed(() => {
211
+ const currentCollection = collection()
212
+ if (!currentCollection) {
213
+ return internalData()
214
+ }
215
+ const config = currentCollection.config as
216
+ | CollectionConfigSingleRowOption<any, any, any>
217
+ | undefined
218
+ return config?.singleResult ? internalData()[0] : internalData()
219
+ })
220
+
164
221
  const syncDataFromCollection = (
165
222
  currentCollection: Collection<any, any, any>,
166
223
  ) => {
@@ -168,7 +225,7 @@ export function injectLiveQuery(opts: any) {
168
225
  const newData = Array.from(currentCollection.values())
169
226
 
170
227
  state.set(newState)
171
- data.set(newData)
228
+ internalData.set(newData)
172
229
  status.set(currentCollection.status)
173
230
  }
174
231
 
@@ -185,7 +242,7 @@ export function injectLiveQuery(opts: any) {
185
242
  if (!currentCollection) {
186
243
  status.set(`disabled` as const)
187
244
  state.set(new Map())
188
- data.set([])
245
+ internalData.set([])
189
246
  cleanup()
190
247
  return
191
248
  }