Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EdgeDB] Add Product queries | refactor service/repo layers appropriately #3332

Draft
wants to merge 3 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions src/components/product/dto/product.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
import { SetDbType } from '~/core/database';
import { SetChangeType } from '~/core/database/changes';
import { e } from '~/core/edgedb';
import { RegisterResource } from '~/core/resources';
import { LinkTo, RegisterResource } from '~/core/resources';
import { DbScriptureReferences } from '../../scripture';
import {
ScriptureRangeInput,
Expand Down Expand Up @@ -54,8 +54,8 @@ export class Product extends Producible {
static readonly Parent = () =>
import('../../engagement/dto').then((m) => m.LanguageEngagement);

readonly engagement: ID;
readonly project: ID;
readonly engagement: Secured<LinkTo<'LanguageEngagement'>>;
readonly project: Secured<LinkTo<'Project'>>;

@Field()
@DbLabel('ProductMedium')
Expand Down Expand Up @@ -269,6 +269,12 @@ declare module '../dto/producible.dto' {
}
}

export const ProductConcretes = {
DirectScriptureProduct,
DerivativeScriptureProduct,
OtherProduct,
};

declare module '~/core/resources/map' {
interface ResourceMap {
Product: typeof Product;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ export class FixNaNTotalVerseEquivalentsMigration extends BaseMigration {
.map('id')
.run();

const products = await this.productService.readManyUnsecured(
const products = await this.productService.readMany(
ids,
this.fakeAdminSession,
);

for (const p of products) {
const correctTotalVerseEquivalent = getTotalVerseEquivalents(
...p.scriptureReferences,
...p.scriptureReferences.value,
);

if (p.__typename === 'DirectScriptureProduct') {
Expand Down
230 changes: 230 additions & 0 deletions src/components/product/product.edgedb.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
import { Injectable, Type } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import { LazyGetter } from 'lazy-get-decorator';
import { ID, PublicOf, Session } from '../../common';
import { grabInstances } from '../../common/instance-maps';
import { e, RepoFor } from '../../core/edgedb';
import {
ProductConcretes as ConcreteTypes,
CreateDerivativeScriptureProduct,
CreateDirectScriptureProduct,
CreateOtherProduct,
Product,
} from './dto';
import { ProductRepository } from './product.repository';

// scriptureReferencesOverride, scriptureReferences

const baseHydrate = e.shape(e.Product, (product) => ({
...product['*'],
__typename: product.__type__.name,
project: {
id: true,
status: true,
type: true,
},
engagement: {
id: true,
status: true,
},
parent: e.tuple({
identity: product.engagement.id,
labels: e.array_agg(e.set(product.engagement.__type__.name.slice(9, null))),
properties: e.tuple({
id: product.engagement.id,
createdAt: product.engagement.createdAt,
}),
}),
pnpIndex: true,
scriptureReferences: product.scripture,
}));

const directScriptureExtraHydrate = {
totalVerses: true,
totalVerseEquivalents: true,
} as const;

const derivativeScriptureExtraHydrate = {
scripture: true,
composite: true,
totalVerses: true,
totalVerseEquivalents: true,
} as const;

const otherExtraHydrate = {
title: true,
description: true,
} as const;

const directScriptureProductHydrate = e.shape(
e.DirectScriptureProduct,
(dsp) => ({
...baseHydrate(dsp),
__typename: dsp.__type__.name,
unspecifiedScripture: {
book: true,
totalVerses: true,
},
//TODO - remove after migration
unspecifiedScripturePortion: {
book: true,
totalVerses: true,
},
...directScriptureExtraHydrate,
}),
);

const derivativeScriptureProductHydrate = e.shape(
e.DerivativeScriptureProduct,
(dsp) => ({
...baseHydrate(dsp),
__typename: dsp.__type__.name,
scriptureReferencesOverride: dsp.scriptureOverride,
produces: {
scriptureReferences: e.tuple([dsp.produces.scripture]),
createdAt: dsp.produces.createdAt,
id: dsp.produces.id,
},
...derivativeScriptureExtraHydrate,
}),
);

const otherProductHydrate = e.shape(e.OtherProduct, (op) => ({
...baseHydrate(op),
__typename: op.__type__.name,
scriptureReferencesOverride: false, //TODO - remove after migration
...otherExtraHydrate,
}));

const hydrate = e.shape(e.Product, (product) => ({
...baseHydrate(product),
...e.is(e.DirectScriptureProduct, directScriptureExtraHydrate),
...e.is(e.DerivativeScriptureProduct, derivativeScriptureExtraHydrate),
...e.is(e.OtherProduct, otherExtraHydrate),
}));

export const ConcreteRepos = {
DirectScriptureProduct: class DirectScriptureProductRepository extends RepoFor(
ConcreteTypes.DirectScriptureProduct,
{
hydrate: directScriptureProductHydrate,
omit: ['create'],
},
) {
async create(input: CreateDirectScriptureProduct) {
const engagement = e.cast(
e.LanguageEngagement,
e.uuid(input.engagementId),
);
return await this.defaults.create({
...input,
projectContext: engagement.projectContext,
});
}
},

DerivativeScriptureProduct: class DerivativeScriptureProductRepository extends RepoFor(
ConcreteTypes.DerivativeScriptureProduct,
{
hydrate: derivativeScriptureProductHydrate,
omit: ['create'],
},
) {
async create(input: CreateDerivativeScriptureProduct) {
const engagement = e.cast(
e.LanguageEngagement,
e.uuid(input.engagementId),
);
return await this.defaults.create({
...input,
projectContext: engagement.projectContext,
});
}
},

OtherProduct: class OtherProductRepository extends RepoFor(
ConcreteTypes.OtherProduct,
{
hydrate: otherProductHydrate,
omit: ['create'],
},
) {
async create(input: CreateOtherProduct) {
const engagement = e.cast(
e.LanguageEngagement,
e.uuid(input.engagementId),
);
return await this.defaults.create({
...input,
projectContext: engagement.projectContext,
});
}
},
} satisfies Record<keyof typeof ConcreteTypes, Type>;

@Injectable()
export class ProductEdgedbRepository
extends RepoFor(Product, {
hydrate,
omit: ['create'],
})
implements PublicOf<ProductRepository>
{
constructor(private readonly moduleRef: ModuleRef) {
super();
}

@LazyGetter() protected get concretes() {
return grabInstances(this.moduleRef, ConcreteRepos);
}

async createDerivative(

Check failure on line 181 in src/components/product/product.edgedb.repository.ts

View workflow job for this annotation

GitHub Actions / lint

Property 'createDerivative' in type 'ProductEdgedbRepository' is not assignable to the same property in base type 'PublicOf<ProductRepository>'.
input: CreateDerivativeScriptureProduct & {
totalVerses: number;
totalVerseEquivalents: number;
},
_session: Session,
) {
return await this.concretes.DerivativeScriptureProduct.create(input);
}

async createDirect(

Check failure on line 191 in src/components/product/product.edgedb.repository.ts

View workflow job for this annotation

GitHub Actions / lint

Property 'createDirect' in type 'ProductEdgedbRepository' is not assignable to the same property in base type 'PublicOf<ProductRepository>'.
input: CreateDirectScriptureProduct & {
totalVerses: number;
totalVerseEquivalents: number;
},
_session: Session,
) {
return await this.concretes.DirectScriptureProduct.create(input);
}

async createOther(input: CreateOtherProduct, _session: Session) {

Check failure on line 201 in src/components/product/product.edgedb.repository.ts

View workflow job for this annotation

GitHub Actions / lint

Property 'createOther' in type 'ProductEdgedbRepository' is not assignable to the same property in base type 'PublicOf<ProductRepository>'.
return await this.concretes.OtherProduct.create(input);
}

async listIdsAndScriptureRefs(engagementId: ID) {

Check failure on line 205 in src/components/product/product.edgedb.repository.ts

View workflow job for this annotation

GitHub Actions / lint

Property 'listIdsAndScriptureRefs' in type 'ProductEdgedbRepository' is not assignable to the same property in base type 'PublicOf<ProductRepository>'.
const engagement = e.cast(e.LanguageEngagement, e.uuid(engagementId));
const query = e.select(e.DirectScriptureProduct, (dsp) => ({
id: true,
pnpIndex: true,
scriptureRanges: dsp.scripture,
unspecifiedScripture: dsp.unspecifiedScripture,
filter: e.op(dsp.engagement, '=', engagement),
}));

return await this.db.run(query);
}

async listIdsWithPnpIndexes(engagementId: ID, _type?: string) {

Check failure on line 218 in src/components/product/product.edgedb.repository.ts

View workflow job for this annotation

GitHub Actions / lint

Property 'listIdsWithPnpIndexes' in type 'ProductEdgedbRepository' is not assignable to the same property in base type 'PublicOf<ProductRepository>'.
const engagement = e.cast(e.LanguageEngagement, e.uuid(engagementId));

const query = e.select(e.Product, (p) => ({
id: true,
pnpIndex: p.pnpIndex,
...e.is(e.DirectScriptureProduct, {}),
filter: e.op(p.engagement, '=', engagement),
}));

return await this.db.run(query);
}
}
Loading
Loading