Skip to content

Commit fb4e715

Browse files
committed
add query method w caching
1 parent 7113523 commit fb4e715

2 files changed

Lines changed: 36 additions & 7 deletions

File tree

src/cache.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,11 @@ export interface CachedMethods<DType> {
4848
args?: FindArgs
4949
) => Promise<(DType | undefined)[]>;
5050
deleteFromCacheById: (id: string) => Promise<void>;
51+
dataLoader?: DataLoader<string, DType, string>;
52+
primeCache: (item: DType, ttl?: number) => void;
5153
}
5254

53-
export const createCachingMethods = <DType>({
55+
export const createCachingMethods = <DType extends { id: string }>({
5456
container,
5557
cache,
5658
options,
@@ -64,10 +66,9 @@ export const createCachingMethods = <DType>({
6466
// id,
6567
// }));
6668
// const response = await container.items.bulk(operations);
69+
const idList = ids.map((id) => `'${id}'`).join(",");
6770
const querySpec = {
68-
query: `select * from c where c.id in (${ids
69-
.map((id) => `'${id}'`)
70-
.join(",")})`,
71+
query: `select * from c where c.id in (${idList})`,
7172
// query: "select * from c where c.id in (@ids)",
7273
// parameters: [{ name: "@ids", value: ids }],
7374
};
@@ -115,6 +116,19 @@ export const createCachingMethods = <DType>({
115116
loader.clear(id);
116117
await cache.delete(cachePrefix + id);
117118
},
119+
/**
120+
* Loads an item into DataLoader and optionally the cache (if TTL is specified)
121+
* Use this when running a query outside of the findOneById/findManyByIds methos
122+
* that automatically and transparently do this
123+
*/
124+
primeCache: (doc: DType, ttl?: number) => {
125+
const key = doc.id;
126+
loader.prime(key, doc);
127+
if (ttl) {
128+
cache.set(key, EJSON.stringify(doc), { ttl });
129+
}
130+
},
131+
dataLoader: loader,
118132
};
119133

120134
return methods;

src/datasource.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { DataSource } from "apollo-datasource";
22
import { ApolloError } from "apollo-server-errors";
33
import { InMemoryLRUCache, KeyValueCache } from "apollo-server-caching";
4-
import { Container } from "@azure/cosmos";
4+
import { Container, SqlQuerySpec } from "@azure/cosmos";
55
import { Logger } from "./helpers";
66

77
import { isCosmosDbContainer } from "./helpers";
8-
import { createCachingMethods, CachedMethods } from "./cache";
8+
import { createCachingMethods, CachedMethods, FindArgs } from "./cache";
9+
import DataLoader from "dataloader";
910

1011
export interface CosmosDataSourceOptions {
1112
logger?: Logger;
@@ -15,7 +16,7 @@ const placeholderHandler = () => {
1516
throw new Error("DataSource not initialized");
1617
};
1718

18-
export class CosmosDataSource<TData, TContext = any>
19+
export class CosmosDataSource<TData extends { id: string }, TContext = any>
1920
extends DataSource<TContext>
2021
implements CachedMethods<TData> {
2122
container: Container;
@@ -26,6 +27,20 @@ export class CosmosDataSource<TData, TContext = any>
2627
findOneById: CachedMethods<TData>["findOneById"] = placeholderHandler;
2728
findManyByIds: CachedMethods<TData>["findManyByIds"] = placeholderHandler;
2829
deleteFromCacheById: CachedMethods<TData>["deleteFromCacheById"] = placeholderHandler;
30+
dataLoader: CachedMethods<TData>["dataLoader"];
31+
primeCache: CachedMethods<TData>["primeCache"] = placeholderHandler;
32+
33+
// base SQL operations aren't cached so directly declared here
34+
async findManyByQuery(query: SqlQuerySpec | string, { ttl }: FindArgs) {
35+
const results = await this.container.items.query<TData>(query).fetchAll();
36+
// prime these into the dataloader and maybe the cache
37+
if (this.dataLoader && results.resources) {
38+
results.resources.forEach((r) => {
39+
this.primeCache(r, ttl);
40+
});
41+
}
42+
return results.resources;
43+
}
2944

3045
constructor(container: Container, options: CosmosDataSourceOptions = {}) {
3146
super();

0 commit comments

Comments
 (0)