Skip to content

Commit

Permalink
reworked typings on data loader methods
Browse files Browse the repository at this point in the history
  • Loading branch information
aexol committed Jun 14, 2024
1 parent 9f02c2e commit 57a6667
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 49 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "i-graphql",
"version": "0.1.4",
"version": "0.1.5",
"private": false,
"license": "MIT",
"description": "GraphQL Friendly ORM for MongoDB",
Expand Down
7 changes: 2 additions & 5 deletions src/cacheFunctions.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
const STANDARD_TTL_IN_MILLISECONDS = 3000;

const dataLoaderCache: Record<
string,
{ value: any; createdAt: number; ttl: number }
> = {};
const dataLoaderCache: Record<string, { value: any; createdAt: number; ttl: number }> = {};

export const setToCache = (key: string, value: any, ttl?: number) => {
dataLoaderCache[key] = {
ttl: typeof ttl === "undefined" ? STANDARD_TTL_IN_MILLISECONDS : ttl,
ttl: typeof ttl === 'undefined' ? STANDARD_TTL_IN_MILLISECONDS : ttl,
createdAt: new Date().valueOf(),
value,
};
Expand Down
10 changes: 4 additions & 6 deletions src/db.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Db, MongoClient } from "mongodb";
import { Db, MongoClient } from 'mongodb';
let mongoConnection: { db: Db; client: MongoClient } | undefined = undefined;

export const mc = async (afterConnection?: (database: Db) => void) => {
Expand All @@ -7,18 +7,16 @@ export const mc = async (afterConnection?: (database: Db) => void) => {
}
const mongoURL = process.env.MONGO_URL;
if (!mongoURL) {
throw new Error("Please provide MONGO_URL environment variable");
throw new Error('Please provide MONGO_URL environment variable');
}
const client = new MongoClient(mongoURL, {
ignoreUndefined: true,
});
const c = await client.connect();
const db = c.db();
const dbName = db.databaseName;
if (!dbName || dbName === "test") {
throw new Error(
"Provide database name inside MONGO_URL to work with iGraphQL. 'test' is also not accepted"
);
if (!dbName || dbName === 'test') {
throw new Error("Provide database name inside MONGO_URL to work with iGraphQL. 'test' is also not accepted");
}
mongoConnection = {
client,
Expand Down
60 changes: 23 additions & 37 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getFromCache, setToCache } from "@/cacheFunctions";
import { mc } from "@/db";
import { Db, WithId, OptionalUnlessRequiredId } from "mongodb";
import { getFromCache, setToCache } from '@/cacheFunctions';
import { mc } from '@/db';
import { Db, WithId, OptionalUnlessRequiredId } from 'mongodb';
type AutoCreateFields = {
[x: string]: () => any;
};
Expand All @@ -9,12 +9,9 @@ type SharedKeys<AutoTypes, MTypes> = {
[P in keyof AutoTypes]: P extends keyof MTypes ? P : never;
}[keyof AutoTypes];

export const iGraphQL = async <
IGraphQL extends Record<string, any>,
CreateFields extends AutoCreateFields = {}
>(
export const iGraphQL = async <IGraphQL extends Record<string, any>, CreateFields extends AutoCreateFields = {}>(
autoFields: CreateFields,
afterConnection?: (database: Db) => void
afterConnection?: (database: Db) => void,
) => {
const { db } = await mc(afterConnection);
return <T extends keyof IGraphQL>(
Expand All @@ -24,16 +21,15 @@ export const iGraphQL = async <
ttl?: number;
//setting this allows to use list responses project the individual object cache.
listPrimaryKey?: string;
}
},
) => {
type O = IGraphQL[T];
const collection = db.collection<O>(k);
type CurrentCollection = typeof collection;
const create = (params: OptionalUnlessRequiredId<O>) => {
return collection.insertOne(params);
};
const createWithAutoFields = <Z extends SharedKeys<CreateFields, O>>(
...keys: Array<Z>
) => {
const createWithAutoFields = <Z extends SharedKeys<CreateFields, O>>(...keys: Array<Z>) => {
const createdFields = keys.reduce<{
[P in keyof CreateFields]?: ReturnType<CreateFields[P]>;
}>((a, b) => {
Expand All @@ -51,12 +47,12 @@ export const iGraphQL = async <
const related = async <
K extends keyof O,
NewCollection extends keyof IGraphQL,
NewCollectionKey extends keyof IGraphQL[NewCollection]
NewCollectionKey extends keyof IGraphQL[NewCollection],
>(
objects: O[],
k: K,
relatedCollection: NewCollection,
nK: NewCollectionKey
nK: NewCollectionKey,
) => {
type RelatedO = IGraphQL[NewCollection];
return db
Expand All @@ -71,12 +67,12 @@ export const iGraphQL = async <
const composeRelated = async <
K extends keyof O,
NewCollection extends keyof IGraphQL,
NewCollectionKey extends keyof IGraphQL[NewCollection]
NewCollectionKey extends keyof IGraphQL[NewCollection],
>(
objects: O[],
k: K,
relatedCollection: NewCollection,
nK: NewCollectionKey
nK: NewCollectionKey,
) => {
const relatedObjects = await related(objects, k, relatedCollection, nK);
return objects.map((o) => {
Expand All @@ -85,32 +81,23 @@ export const iGraphQL = async <
return {
...o,
[k]: value.map((valueInArray: unknown) => {
if (
typeof valueInArray === "string" ||
typeof valueInArray === "number"
) {
if (typeof valueInArray === 'string' || typeof valueInArray === 'number') {
return relatedObjects.find((ro) => {
const relatedObjectKey = ro[nK as keyof typeof ro];
if (
typeof relatedObjectKey === "string" ||
typeof relatedObjectKey === "number"
) {
if (typeof relatedObjectKey === 'string' || typeof relatedObjectKey === 'number') {
return relatedObjectKey === valueInArray;
}
});
}
}),
};
}
if (typeof value === "string" || typeof value === "number") {
if (typeof value === 'string' || typeof value === 'number') {
return {
...o,
[k]: relatedObjects.find((ro) => {
const relatedObjectKey = ro[nK as keyof typeof ro];
if (
typeof relatedObjectKey === "string" ||
typeof relatedObjectKey === "number"
) {
if (typeof relatedObjectKey === 'string' || typeof relatedObjectKey === 'number') {
return relatedObjectKey === value;
}
}),
Expand All @@ -124,15 +111,15 @@ export const iGraphQL = async <

//method to get one object by Id using data loader cache
const oneById = async (
...params: Parameters<typeof collection["findOne"]>
) => {
...params: Parameters<CurrentCollection['findOne']>
): Promise<WithId<O> | null | undefined> => {
// if we have the list primary key we need to check the cache only by using this key
if (cache?.listPrimaryKey) {
let fetchingFromCacheAllowed = true;
const valueFromCache = getFromCache(
JSON.stringify({
[cache.listPrimaryKey]: params[0][cache.listPrimaryKey],
})
}),
);
if (valueFromCache) {
Object.entries(params[0]).forEach(([entryKey, entryValue]) => {
Expand All @@ -155,8 +142,9 @@ export const iGraphQL = async <
}
};

type CurrentCollectionFindType = CurrentCollection['find'];
//method to get list of objects - working with inner cache. Calls toArray at the end so you don't have to.
const list = async (...params: Parameters<typeof collection["find"]>) => {
const list = async (...params: Parameters<CurrentCollectionFindType>): Promise<WithId<O>[]> => {
const paramKey = JSON.stringify(params[0]);
const valueFromCache = getFromCache(paramKey);
if (valueFromCache) return valueFromCache;
Expand All @@ -170,7 +158,7 @@ export const iGraphQL = async <
[cache.listPrimaryKey]: individual[cache.listPrimaryKey],
}),
individual,
cache.ttl
cache.ttl,
);
}
}
Expand All @@ -191,9 +179,7 @@ export const iGraphQL = async <
};

type ToMongoString<T> = T extends object ? string : T;
type ToMongo<T> = T extends Array<infer R>
? ToMongoString<R>[]
: ToMongoString<T>;
type ToMongo<T> = T extends Array<infer R> ? ToMongoString<R>[] : ToMongoString<T>;
type Nullify<T> = T extends undefined ? undefined | null : T;
type NullifyObject<T> = {
[P in keyof T]: Nullify<T[P]>;
Expand Down

0 comments on commit 57a6667

Please sign in to comment.