Skip to content

Commit

Permalink
feat(backend/shared): save onboarding quiz answers to DB bb-167 (#227)
Browse files Browse the repository at this point in the history
* feat(backend): add  onboarding_answers_to_users table bb-167

* feat(backend): add  onboarding answer entity bb-167

* feat(backend): add  onboarding answer model bb-167

* feat(backend): add onboarding repository bb-167

* feat(backend): add onboarding controller bb-167

* feat(backend): add onboarding servise bb-167

* feat(backend): add question to answer model bb-167

* feat(backend): add onboarding question model bb-167

* feat(shared): add req/resp onboarding answer types bb-167

* feat(shared): add common quiz  error extention bb-167

* feat(shared): add onboarding answers to user model bb-167

* refactor(backend): createUserAnswers repository bb-167

* refactor(backend): createUserAnswers in servise and controller bb-167

* feat(backend): add onboarding_answers_to_users to DB schema bb-167

* fix(backend): swagger for onboarding answer bb-167

* feat(backend): add findAnswersByIds to repo bb-167

* refactor(shared): remove unnecessary bb-167

* refactor(shared): rename onboardingError bb-167

* fix(backend): relation in user model bb-167

* refactor(backend): add findAnswersByIds and OnboardingAnswerResponseDto to service bb-167

* feat(shared): add validation to onboarding answers bb-167

* feat(shared): add OnboardingAnswerRequestBody bb-167

* feat(backend): create all methods for onboarding repository bb-167

* feat(backend): create all methods for onboarding service bb-167

* feat(backend): add userId to onboarding entity bb-167

* fix(backend): db schema bb-167

* fix(backend): add bracrs bb-167

* refactor(backend): imports, add braces bb-167

* refactor(backend): imports, add braces bb-167

* refactor(shared): rename OnboardingAnswerRequestBody bb-167

* refactor(shared/backend): move question length validation to service bb-167

* feat(backend): add onboarding answers length validation bb-167

* refactor(backend): use .count in countQuestions bb-167
  • Loading branch information
yulyaolshanska authored Aug 30, 2024
1 parent c5e20b4 commit 6779d9d
Show file tree
Hide file tree
Showing 40 changed files with 798 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { type Knex } from "knex";

const TableName = {
ONBOARDING_ANSWERS: "onboarding_answers",
ONBOARDING_ANSWERS_TO_USERS: "onboarding_answers_to_users",
USERS: "users",
} as const;

const ColumnName = {
ANSWER_ID: "answer_id",
CREATED_AT: "created_at",
ID: "id",
UPDATED_AT: "updated_at",
USER_ID: "user_id",
} as const;

const DELETE_STRATEGY = "CASCADE";

function up(knex: Knex): Promise<void> {
return knex.schema.createTable(
TableName.ONBOARDING_ANSWERS_TO_USERS,
(table) => {
table.increments(ColumnName.ID).primary();
table
.integer(ColumnName.USER_ID)
.notNullable()
.references(ColumnName.ID)
.inTable(TableName.USERS)
.onDelete(DELETE_STRATEGY);
table
.integer(ColumnName.ANSWER_ID)
.notNullable()
.references(ColumnName.ID)
.inTable(TableName.ONBOARDING_ANSWERS)
.onDelete(DELETE_STRATEGY);
table.timestamp(ColumnName.CREATED_AT).defaultTo(knex.fn.now());
table.timestamp(ColumnName.UPDATED_AT).defaultTo(knex.fn.now());
table.unique([ColumnName.USER_ID, ColumnName.ANSWER_ID]);
},
);
}

function down(knex: Knex): Promise<void> {
return knex.schema.dropTableIfExists(TableName.ONBOARDING_ANSWERS_TO_USERS);
}

export { down, up };
3 changes: 3 additions & 0 deletions apps/backend/src/libs/enums/relation-name.enum.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
const RelationName = {
ONBOARDING_ANSWERS: "answers",
ONBOARDING_QUESTION: "question",
USER_DETAILS: "userDetails",
USERS: "users",
} as const;

export { RelationName };
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type APIHandlerOptions<
body: T["body"];
params: T["params"];
query: T["query"];
user?: T["user"];
user: T["user"];
};

export { type APIHandlerOptions };
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
const DatabaseTableName = {
CATEGORIES: "categories",
MIGRATIONS: "migrations",
ONBOARDING_ANSWERS: "onboarding_answers",
ONBOARDING_ANSWERS_TO_USERS: "onboarding_answers_to_users",
ONBOARDING_QUESTIONS: "onboarding_questions",
USER_DETAILS: "user_details",
USERS: "users",
} as const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { config } from "~/libs/modules/config/config.js";
import { database } from "~/libs/modules/database/database.js";
import { logger } from "~/libs/modules/logger/logger.js";
import { authController } from "~/modules/auth/auth.js";
import { onboardingController } from "~/modules/onboarding/onboarding.js";
import { userController } from "~/modules/users/users.js";

import { BaseServerApplication } from "./base-server-application.js";
Expand All @@ -12,6 +13,7 @@ const apiV1 = new BaseServerApplicationApi(
config,
...authController.routes,
...userController.routes,
...onboardingController.routes,
);
const serverApplication = new BaseServerApplication({
apis: [apiV1],
Expand Down
4 changes: 2 additions & 2 deletions apps/backend/src/libs/types/repository.type.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
type Repository<T = unknown> = {
create(payload: unknown): Promise<T>;
delete(): Promise<boolean>;
delete(id: number): Promise<boolean>;
find(id: number): Promise<T>;
findAll(): Promise<T[]>;
update(): Promise<T>;
update(id: number, payload: unknown): Promise<T>;
};

export { type Repository };
4 changes: 2 additions & 2 deletions apps/backend/src/libs/types/service.type.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
type Service<T = unknown> = {
create(payload: unknown): Promise<T>;
delete(): Promise<boolean>;
delete(id: number): Promise<boolean>;
find(id: number): Promise<T>;
findAll(): Promise<{
items: T[];
}>;
update(): Promise<T>;
update(id: number, payload: unknown): Promise<T>;
};

export { type Service };
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const DEFAULT_COUNT_VALUE = 0;
const FIRST_ELEMENT_INDEX = 0;

export { DEFAULT_COUNT_VALUE, FIRST_ELEMENT_INDEX };
1 change: 1 addition & 0 deletions apps/backend/src/modules/onboarding/libs/enums/enums.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { OnboardingApiPath } from "shared";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { OnboardingError } from "shared";
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type CountResult = {
count?: string;
};

export { type CountResult };
7 changes: 7 additions & 0 deletions apps/backend/src/modules/onboarding/libs/types/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export { type CountResult } from "./count-result.type.js";
export {
type OnboardingAnswerDto,
type OnboardingAnswerRequestBodyDto,
type OnboardingAnswerRequestDto,
type OnboardingAnswerResponseDto,
} from "shared";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { onboardingAnswersValidationSchema } from "shared";
113 changes: 113 additions & 0 deletions apps/backend/src/modules/onboarding/onboarding-answer.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { type Entity } from "~/libs/types/types.js";

class OnboardingAnswerEntity implements Entity {
private createdAt: string;

private id: null | number;

private label: string;

private questionId: number;

private updatedAt: string;

private userId: null | number;

private constructor({
createdAt,
id,
label,
questionId,
updatedAt,
userId,
}: {
createdAt: string;
id: null | number;
label: string;
questionId: number;
updatedAt: string;
userId: null | number;
}) {
this.createdAt = createdAt;
this.id = id;
this.label = label;
this.questionId = questionId;
this.updatedAt = updatedAt;
this.userId = userId;
}

public static initialize({
createdAt,
id,
label,
questionId,
updatedAt,
userId,
}: {
createdAt: string;
id: number;
label: string;
questionId: number;
updatedAt: string;
userId: number;
}): OnboardingAnswerEntity {
return new OnboardingAnswerEntity({
createdAt,
id,
label,
questionId,
updatedAt,
userId,
});
}

public static initializeNew({
label,
questionId,
}: {
label: string;
questionId: number;
}): OnboardingAnswerEntity {
return new OnboardingAnswerEntity({
createdAt: "",
id: null,
label,
questionId,
updatedAt: "",
userId: null,
});
}

public toNewObject(): {
createdAt: string;
label: string;
questionId: number;
updatedAt: string;
} {
return {
createdAt: this.createdAt,
label: this.label,
questionId: this.questionId,
updatedAt: this.updatedAt,
};
}
public toObject(): {
createdAt: string;
id: number;
label: string;
questionId: number;
updatedAt: string;
userId: number;
} {
return {
createdAt: this.createdAt,
id: this.id as number,
label: this.label,
questionId: this.questionId,
updatedAt: this.updatedAt,
userId: this.userId as number,
};
}
}

export { OnboardingAnswerEntity };
50 changes: 50 additions & 0 deletions apps/backend/src/modules/onboarding/onboarding-answer.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { Model, type RelationMappings } from "objection";

import {
AbstractModel,
DatabaseTableName,
} from "~/libs/modules/database/database.js";

import { UserModel } from "../users/users.js";
import { OnboardingQuestionModel } from "./onboarding-question.model.js";

class OnboardingAnswerModel extends AbstractModel {
public label!: string;

public questionId!: number;

public userId!: number;

public users!: UserModel[];

static get relationMappings(): RelationMappings {
return {
question: {
join: {
from: `${DatabaseTableName.ONBOARDING_ANSWERS}.questionId`,
to: `${DatabaseTableName.ONBOARDING_QUESTIONS}.id`,
},
modelClass: OnboardingQuestionModel,
relation: Model.BelongsToOneRelation,
},
users: {
join: {
from: `${DatabaseTableName.ONBOARDING_ANSWERS}.id`,
through: {
from: `${DatabaseTableName.ONBOARDING_ANSWERS_TO_USERS}.answerId`,
to: `${DatabaseTableName.ONBOARDING_ANSWERS_TO_USERS}.userId`,
},
to: `${DatabaseTableName.USERS}.id`,
},
modelClass: UserModel,
relation: Model.ManyToManyRelation,
},
};
}

public static override get tableName(): string {
return DatabaseTableName.ONBOARDING_ANSWERS;
}
}

export { OnboardingAnswerModel };
33 changes: 33 additions & 0 deletions apps/backend/src/modules/onboarding/onboarding-question.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Model, type RelationMappings } from "objection";

import {
AbstractModel,
DatabaseTableName,
} from "~/libs/modules/database/database.js";

import { OnboardingAnswerModel } from "./onboarding-answer.model.js";

class OnboardingQuestionModel extends AbstractModel {
public answers!: OnboardingAnswerModel[];

public label!: string;

static get relationMappings(): RelationMappings {
return {
answers: {
join: {
from: `${DatabaseTableName.ONBOARDING_QUESTIONS}.id`,
to: `${DatabaseTableName.ONBOARDING_ANSWERS}.questionId`,
},
modelClass: OnboardingAnswerModel,
relation: Model.HasManyRelation,
},
};
}

public static override get tableName(): string {
return DatabaseTableName.ONBOARDING_QUESTIONS;
}
}

export { OnboardingQuestionModel };
Loading

0 comments on commit 6779d9d

Please sign in to comment.