Skip to content

Commit

Permalink
feat(service): introduce image fetching service
Browse files Browse the repository at this point in the history
Refactors the SupabaseCachingService to get all hypercert columns except
for the image. Renamed the getMetadata method to getMetadataWithoutImage
to make this explicit.

Introduces MetadataImageService for fetching the image when the field is
selected in a metadata query.
  • Loading branch information
bitbeckers committed Feb 11, 2025
1 parent 028f072 commit 12038fc
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 16 deletions.
5 changes: 3 additions & 2 deletions src/graphql/schemas/resolvers/baseTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,14 @@ export function createBaseResolver<T extends ClassType>(
readonly supabaseCachingService = container.resolve(SupabaseCachingService);
readonly supabaseDataService = container.resolve(SupabaseDataService);

getMetadata(args: GetMetadataArgs, single: boolean = false) {
getMetadataWithoutImage(args: GetMetadataArgs, single: boolean = false) {
console.debug(
`[${entityFieldName}Resolver::getMetadata] Fetching metadata`,
);

try {
const queries = this.supabaseCachingService.getMetadata(args);
const queries =
this.supabaseCachingService.getMetadataWithoutImage(args);
if (single) {
return queries.data.executeTakeFirst();
}
Expand Down
2 changes: 1 addition & 1 deletion src/graphql/schemas/resolvers/fractionResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class FractionResolver extends FractionBaseResolver {
return;
}

return await this.getMetadata(
return await this.getMetadataWithoutImage(
{
where: { hypercerts: { id: { eq: fraction.claims_id } } },
},
Expand Down
2 changes: 1 addition & 1 deletion src/graphql/schemas/resolvers/hyperboardResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class HyperboardResolver extends HyperboardBaseResolver {
}).then((res) => res.data),
]);

const metadata = await this.getMetadata({
const metadata = await this.getMetadataWithoutImage({
where: { hypercerts: { hypercert_id: { in: hypercertIds } } },
})
.then((res) => res.data)
Expand Down
2 changes: 1 addition & 1 deletion src/graphql/schemas/resolvers/hypercertResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class HypercertResolver extends HypercertBaseResolver {
return;
}

return await this.getMetadata(
return await this.getMetadataWithoutImage(
{ where: { uri: { eq: hypercert.uri } } },
true,
);
Expand Down
29 changes: 27 additions & 2 deletions src/graphql/schemas/resolvers/metadataResolver.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,43 @@
import { Args, ObjectType, Query, Resolver } from "type-graphql";
import {
Args,
FieldResolver,
ObjectType,
Query,
Resolver,
Root,
} from "type-graphql";
import { inject, singleton } from "tsyringe";
import { Metadata } from "../typeDefs/metadataTypeDefs.js";
import { GetMetadataArgs } from "../args/metadataArgs.js";
import { createBaseResolver, DataResponse } from "./baseTypes.js";
import { MetadataImageService } from "../../../services/MetadataImageService.js";

@ObjectType()
export class GetMetadataResponse extends DataResponse(Metadata) {}

const MetadataBaseResolver = createBaseResolver("metadata");

@singleton()
@Resolver(() => Metadata)
class MetadataResolver extends MetadataBaseResolver {
constructor(
@inject(MetadataImageService) private imageService: MetadataImageService,
) {
super();
}

@Query(() => GetMetadataResponse)
async metadata(@Args() args: GetMetadataArgs) {
return await this.getMetadata(args);
return await this.getMetadataWithoutImage(args);
}

@FieldResolver(() => String, {
nullable: true,
description: "Base64 encoded representation of the image of the hypercert",
})
async image(@Root() metadata: Metadata) {
if (!metadata.uri) return null;
return await this.imageService.getImageByUri(metadata.uri);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/graphql/schemas/resolvers/orderResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class OrderResolver extends OrderBaseResolver {
true,
);

const metadata = await this.getMetadata(
const metadata = await this.getMetadataWithoutImage(
{
where: {
hypercerts: {
Expand Down
2 changes: 1 addition & 1 deletion src/graphql/schemas/resolvers/salesResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class SalesResolver extends SalesBaseResolver {
return null;
}

const metadata = await this.getMetadata(
const metadata = await this.getMetadataWithoutImage(
{
where: {
hypercerts: {
Expand Down
5 changes: 0 additions & 5 deletions src/graphql/schemas/typeDefs/metadataTypeDefs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@ class Metadata extends BasicTypeDef {
name?: string;
@Field({ nullable: true, description: "Description of the hypercert" })
description?: string;
@Field({
nullable: true,
description: "Base64 encoded representation of the image of the hypercert",
})
image?: string;
@Field({ nullable: true, description: "URI of the hypercert metadata" })
uri?: string;
@Field({
Expand Down
30 changes: 30 additions & 0 deletions src/services/MetadataImageService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { singleton } from "tsyringe";
import { kyselyCaching } from "../client/kysely.js";
import { CachingDatabase } from "../types/kyselySupabaseCaching.js";
import { BaseSupabaseService } from "./BaseSupabaseService.js";

@singleton()
export class MetadataImageService extends BaseSupabaseService<CachingDatabase> {
constructor() {
super(kyselyCaching);
}

// TODO: remove these when we more refactor the services to improve typing and performance
getDataQuery() {
throw new Error("Method not implemented - not needed for image service");
}

getCountQuery() {
throw new Error("Method not implemented - not needed for image service");
}

async getImageByUri(uri: string): Promise<string | null> {
const result = await this.db
.selectFrom("metadata")
.select(["image"])
.where("uri", "=", uri)
.executeTakeFirst();

return result?.image ?? null;
}
}
39 changes: 37 additions & 2 deletions src/services/SupabaseCachingService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export class SupabaseCachingService extends BaseSupabaseService<CachingDatabase>
};
}

getMetadata(args: GetMetadataArgs) {
getMetadataWithoutImage(args: GetMetadataArgs) {
return {
data: this.handleGetData("metadata", args),
count: this.handleGetCount("metadata", args),
Expand Down Expand Up @@ -138,9 +138,44 @@ export class SupabaseCachingService extends BaseSupabaseService<CachingDatabase>
case "fractions_view":
return this.db.selectFrom("fractions_view").selectAll();
case "metadata":
// Skip the image column
// 1. id
// 2. name
// 3. description
// 4. image
// 5. external_url
// 6. work_scope
// 7. work_timeframe_from
// 8. work_timeframe_to
// 9. impact_scope
// 10. impact_timeframe_from
// 11. impact_timeframe_to
// 12. contributors
// 13. rights
// 14. uri
// 15. properties
// 16. allow_list_uri
// 17. parsed
return this.db
.selectFrom("metadata")
.selectAll("metadata")
.select([
"id",
"name",
"description",
"external_url",
"work_scope",
"work_timeframe_from",
"work_timeframe_to",
"impact_scope",
"impact_timeframe_from",
"impact_timeframe_to",
"contributors",
"rights",
"uri",
"properties",
"allow_list_uri",
"parsed",
])
.$if(args.where?.hypercerts, (qb) =>
qb.innerJoin("claims", "claims.uri", "metadata.uri"),
);
Expand Down

0 comments on commit 12038fc

Please sign in to comment.