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

feat(graphql): add Character & Person & Subject relations #677

Merged
merged 12 commits into from
Sep 21, 2024
8 changes: 4 additions & 4 deletions bin/fix-date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
return;
}

start = fields.at(-1)?.subject_id ?? start;
start = fields.at(-1)?.subjectID ?? start;

Check warning on line 29 in bin/fix-date.ts

View check run for this annotation

Codecov / codecov/patch

bin/fix-date.ts#L29

Added line #L29 was not covered by tests

for (const s of fields) {
const subject = await SubjectRepo.findOne({ where: { id: s.subject_id, subjectBan: 0 } });
const subject = await SubjectRepo.findOne({ where: { id: s.subjectID, subjectBan: 0 } });

Check warning on line 32 in bin/fix-date.ts

View check run for this annotation

Codecov / codecov/patch

bin/fix-date.ts#L32

Added line #L32 was not covered by tests
if (!subject) {
continue;
}
Expand All @@ -50,11 +50,11 @@
continue;
}

console.log(s.subject_id, date);
console.log(s.subjectID, date);

Check warning on line 53 in bin/fix-date.ts

View check run for this annotation

Codecov / codecov/patch

bin/fix-date.ts#L53

Added line #L53 was not covered by tests

await SubjectFieldsRepo.update(
{
subject_id: s.subject_id,
subjectID: s.subjectID,

Check warning on line 57 in bin/fix-date.ts

View check run for this annotation

Codecov / codecov/patch

bin/fix-date.ts#L57

Added line #L57 was not covered by tests
},
{
year: date.year,
Expand Down
40 changes: 40 additions & 0 deletions lib/graphql/schema.gen.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,25 @@ type Character {
lock: Int!
name: String!
nsfw: Boolean!
persons(limit: Int! = 10, offset: Int! = 0): [CharacterRelatedPerson!]
redirect: Int!
role: Int!
subjects(limit: Int! = 10, offset: Int! = 0): [CharacterRelatedSubject!]
summary: String!
}

type CharacterRelatedPerson {
person: Person!
subject: Subject!
summary: String!
}

type CharacterRelatedSubject {
order: Int!
subject: Subject!
type: Int!
}

type Episode {
airdate: String!
comment: Int!
Expand Down Expand Up @@ -56,6 +70,7 @@ type InfoboxValue {

type Person {
career: [String!]!
characters(limit: Int! = 10, offset: Int! = 0): [PersonRelatedCharacter!]
collects: Int!
comment: Int!
id: Int!
Expand All @@ -66,10 +81,22 @@ type Person {
name: String!
nsfw: Boolean!
redirect: Int!
subjects(limit: Int! = 10, offset: Int! = 0): [PersonRelatedSubject!]
summary: String!
type: Int!
}

type PersonRelatedCharacter {
character: Character!
subject: Subject!
summary: String!
}

type PersonRelatedSubject {
position: Int!
subject: Subject!
}

type Query {
character(id: Int!): Character!
me: User
Expand All @@ -79,6 +106,7 @@ type Query {

type Subject {
airtime: SubjectAirtime!
characters(limit: Int! = 10, offset: Int! = 0): [SubjectRelatedCharacter!]
collection: SubjectCollection!
episodes(
limit: Int! = 30
Expand All @@ -95,6 +123,7 @@ type Subject {
name: String!
name_cn: String!
nsfw: Boolean!
persons(limit: Int! = 10, offset: Int! = 0): [SubjectRelatedPerson!]
platform: SubjectPlatform!
rating: SubjectRating!
redirect: Int!
Expand Down Expand Up @@ -144,6 +173,17 @@ type SubjectRating {
total: Int!
}

type SubjectRelatedCharacter {
character: Character!
order: Int!
type: Int!
}

type SubjectRelatedPerson {
person: Person!
position: Int!
}

type SubjectRelation {
order: Int!
relation: Int!
Expand Down
90 changes: 87 additions & 3 deletions lib/graphql/types/character.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,37 @@
import { extendType, intArg, nonNull, objectType } from 'nexus';

import type { Context } from '@app/lib/graphql/context.ts';
import type * as entity from '@app/lib/orm/entity/index.ts';
import { CharacterRepo } from '@app/lib/orm/index.ts';
import * as entity from '@app/lib/orm/entity/index.ts';
import { CastRepo, CharacterRepo, CharacterSubjectsRepo } from '@app/lib/orm/index.ts';
import { personImages } from '@app/lib/response.ts';

import { Images, InfoboxItem } from './common.ts';
import { convertPerson } from './person.ts';
import { convertSubject } from './subject.ts';

const CharacterRelatedSubject = objectType({
name: 'CharacterRelatedSubject',
definition(t) {
t.nonNull.field('subject', {
type: 'Subject',
});
t.nonNull.int('type');
t.nonNull.int('order');
},
});

const CharacterRelatedPerson = objectType({
name: 'CharacterRelatedPerson',
definition(t) {
t.nonNull.field('person', {
type: 'Person',
});
t.nonNull.field('subject', {
type: 'Subject',
});
t.nonNull.string('summary');
},
});

const Character = objectType({
name: 'Character',
Expand All @@ -24,10 +50,68 @@
t.nonNull.int('lock');
t.nonNull.int('redirect');
t.nonNull.boolean('nsfw');
t.list.nonNull.field('subjects', {
type: CharacterRelatedSubject,
args: {
limit: nonNull(intArg({ default: 10 })),
offset: nonNull(intArg({ default: 0 })),
},
async resolve(
parent: { id: number },
{ limit, offset }: { limit: number; offset: number },
{ auth: { allowNsfw } }: Context,
) {
let query = CharacterSubjectsRepo.createQueryBuilder('r')
.innerJoinAndMapOne('r.subject', entity.Subject, 's', 's.id = r.subjectID')
.innerJoinAndMapOne('s.fields', entity.SubjectFields, 'f', 'f.subjectID = s.id')
.where('r.characterID = :id', { id: parent.id });
if (!allowNsfw) {
query = query.andWhere('s.subjectNsfw = :allowNsfw', { allowNsfw });
}
const relations = await query
.orderBy('r.type', 'ASC')
.orderBy('r.order', 'ASC')
.skip(offset)
.take(limit)
.getMany();
return relations.map((r) => ({
subject: convertSubject(r.subject),
type: r.type,
order: r.order,
}));
},
});
t.list.nonNull.field('persons', {
type: CharacterRelatedPerson,
args: {
limit: nonNull(intArg({ default: 10 })),
offset: nonNull(intArg({ default: 0 })),
},
async resolve(
parent: { id: number },
{ limit, offset }: { limit: number; offset: number },
{ auth: { allowNsfw } }: Context,
) {
const query = CastRepo.createQueryBuilder('r')
.innerJoinAndMapOne('r.person', entity.Person, 'p', 'p.id = r.personID')
.innerJoinAndMapOne('r.subject', entity.Subject, 's', 's.id = r.subjectID')
.innerJoinAndMapOne('s.fields', entity.SubjectFields, 'f', 'f.subjectID = s.id')
.where('r.characterID = :id', { id: parent.id });
if (!allowNsfw) {
query.andWhere('s.subjectNsfw = :allowNsfw', { allowNsfw });
}
const relations = await query.skip(offset).take(limit).getMany();
return relations.map((r) => ({
person: convertPerson(r.person),
subject: convertSubject(r.subject),
summary: r.summary,
}));
},

Check warning on line 109 in lib/graphql/types/character.ts

View check run for this annotation

Codecov / codecov/patch

lib/graphql/types/character.ts#L91-L109

Added lines #L91 - L109 were not covered by tests
});
},
});

function convertCharacter(character: entity.Character) {
export function convertCharacter(character: entity.Character) {
let wiki: Wiki = {
type: '',
data: [],
Expand Down
87 changes: 84 additions & 3 deletions lib/graphql/types/person.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,36 @@
import { extendType, intArg, nonNull, objectType } from 'nexus';

import type { Context } from '@app/lib/graphql/context.ts';
import type * as entity from '@app/lib/orm/entity/index.ts';
import { PersonRepo } from '@app/lib/orm/index.ts';
import * as entity from '@app/lib/orm/entity/index.ts';
import { CastRepo, PersonRepo, PersonSubjectsRepo } from '@app/lib/orm/index.ts';
import { personImages } from '@app/lib/response.ts';

import { convertCharacter } from './character.ts';
import { Images, InfoboxItem } from './common.ts';
import { convertSubject } from './subject.ts';

const PersonRelatedSubject = objectType({
name: 'PersonRelatedSubject',
definition(t) {
t.nonNull.field('subject', {
type: 'Subject',
});
t.nonNull.int('position');
},
});

const PersonRelatedCharacter = objectType({
name: 'PersonRelatedCharacter',
definition(t) {
t.nonNull.field('character', {
type: 'Character',
});
t.nonNull.field('subject', {
type: 'Subject',
});
t.nonNull.string('summary');
},
});

const Person = objectType({
name: 'Person',
Expand All @@ -25,6 +50,62 @@
t.nonNull.int('lock');
t.nonNull.int('redirect');
t.nonNull.boolean('nsfw');
t.list.nonNull.field('subjects', {
type: PersonRelatedSubject,
args: {
limit: nonNull(intArg({ default: 10 })),
offset: nonNull(intArg({ default: 0 })),
},
async resolve(
parent: { id: number },
{ limit, offset }: { limit: number; offset: number },
{ auth: { allowNsfw } }: Context,
) {
let query = PersonSubjectsRepo.createQueryBuilder('r')
.innerJoinAndMapOne('r.subject', entity.Subject, 's', 's.id = r.subjectID')
.innerJoinAndMapOne('s.fields', entity.SubjectFields, 'f', 'f.subjectID = s.id')
.where('r.personID = :id', { id: parent.id });
if (!allowNsfw) {
query = query.andWhere('s.subjectNsfw = :allowNsfw', { allowNsfw });
}
const relations = await query
.orderBy('r.position', 'ASC')
.skip(offset)
.take(limit)
.getMany();
return relations.map((r) => ({
subject: convertSubject(r.subject),
position: r.position,
}));
},
});
t.list.nonNull.field('characters', {
type: PersonRelatedCharacter,
args: {
limit: nonNull(intArg({ default: 10 })),
offset: nonNull(intArg({ default: 0 })),
},
async resolve(
parent: { id: number },
{ limit, offset }: { limit: number; offset: number },
{ auth: { allowNsfw } }: Context,
) {
const query = CastRepo.createQueryBuilder('r')
.innerJoinAndMapOne('r.character', entity.Character, 'c', 'c.id = r.characterID')
.innerJoinAndMapOne('r.subject', entity.Subject, 's', 's.id = r.subjectID')
.innerJoinAndMapOne('s.fields', entity.SubjectFields, 'f', 'f.subjectID = s.id')
.where('r.personID = :id', { id: parent.id });
if (!allowNsfw) {
query.andWhere('s.subjectNsfw = :allowNsfw', { allowNsfw });
}
const relations = await query.skip(offset).take(limit).getMany();
return relations.map((r) => ({
character: convertCharacter(r.character),
subject: convertSubject(r.subject),
summary: r.summary,
}));
},

Check warning on line 107 in lib/graphql/types/person.ts

View check run for this annotation

Codecov / codecov/patch

lib/graphql/types/person.ts#L89-L107

Added lines #L89 - L107 were not covered by tests
});
},
});

Expand Down Expand Up @@ -54,7 +135,7 @@
return result;
}

function convertPerson(person: entity.Person) {
export function convertPerson(person: entity.Person) {
let wiki: Wiki = {
type: '',
data: [],
Expand Down
Loading