Skip to content

Commit

Permalink
Add proper ORM and postgres support (#3978)
Browse files Browse the repository at this point in the history
* Add postgresql support

* Fixes

* Fix perfs
  • Loading branch information
charlesBochet authored Feb 14, 2024
1 parent 94ad0e3 commit 4613f64
Show file tree
Hide file tree
Showing 24 changed files with 2,143 additions and 344 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@hello-pangea/dnd": "^16.2.0",
"@hookform/resolvers": "^3.1.1",
"@jsdevtools/rehype-toc": "^3.0.2",
"@libsql/client": "^0.4.3",
"@mdx-js/react": "^3.0.0",
"@nestjs/apollo": "^11.0.5",
"@nestjs/axios": "^3.0.1",
Expand Down Expand Up @@ -76,6 +77,7 @@
"deep-equal": "^2.2.2",
"docusaurus-node-polyfills": "^1.0.0",
"dotenv-cli": "^7.2.1",
"drizzle-orm": "^0.29.3",
"esbuild-plugin-svgr": "^2.1.0",
"file-type": "16.5.4",
"framer-motion": "^10.12.17",
Expand Down Expand Up @@ -238,6 +240,7 @@
"cross-var": "^1.1.0",
"danger": "^11.3.0",
"dotenv-cli": "^7.2.1",
"drizzle-kit": "^0.20.14",
"eslint": "^8.53.0",
"eslint-config-next": "14.0.4",
"eslint-config-prettier": "^9.1.0",
Expand Down
3 changes: 3 additions & 0 deletions packages/twenty-website/.env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
BASE_URL=http://localhost:3000
GITHUB_TOKEN=your_github_token
DATABASE_DRIVER=sqlite # or pg
DATABASE_PG_URL=postgres://website:website@localhost:5432/website # only if using postgres

7 changes: 6 additions & 1 deletion packages/twenty-website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
"lint": "next lint",
"database:generate:pg": "drizzle-kit generate:pg --config=src/database/postgres/drizzle-posgres.config.ts",
"database:generate:sqlite": "drizzle-kit generate:sqlite --config=src/database/sqlite/drizzle-sqlite.config.ts"
},
"dependencies": {
"postgres": "^3.4.3"
}
}
13 changes: 5 additions & 8 deletions packages/twenty-website/src/app/components/AvatarGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import styled from '@emotion/styled';
import Link from 'next/link';

export interface User {
login: string;
id: string;
avatarUrl: string;
}

Expand Down Expand Up @@ -66,13 +66,10 @@ const AvatarGrid = ({ users }: { users: User[] }) => {
return (
<AvatarGridContainer>
{users.map((user) => (
<Link
href={`/developers/contributors/${user.login}`}
key={`l_${user.login}`}
>
<AvatarItem key={user.login}>
<img src={user.avatarUrl} alt={user.login} />
<span className="username">{user.login}</span>
<Link href={`/developers/contributors/${user.id}`} key={`l_${user.id}`}>
<AvatarItem key={user.id}>
<img src={user.avatarUrl} alt={user.id} />
<span className="username">{user.id}</span>
</AvatarItem>
</Link>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ export const ActivityLog = ({
}: {
data: { value: number; day: string }[];
}) => {
if (!data.length) {
return null;
}
return (
<CardContainer>
<Title>Activity</Title>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,12 @@ export const ProfileCard = ({
<StyledGithubIcon size="M" color="rgba(0,0,0,1)" />
</a>
</h3>
<p className="duration">
Contributing since{' '}
{format(new Date(firstContributionAt), 'MMMM yyyy')}
</p>
{firstContributionAt && (
<p className="duration">
Contributing since{' '}
{format(new Date(firstContributionAt), 'MMMM yyyy')}
</p>
)}
</Details>
</ProfileContainer>
);
Expand Down
210 changes: 90 additions & 120 deletions packages/twenty-website/src/app/developers/contributors/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import Database from 'better-sqlite3';
import { Metadata } from 'next';

import { Background } from '@/app/components/oss-friends/Background';
Expand All @@ -9,12 +8,8 @@ import { ProfileCard } from '@/app/developers/contributors/[slug]/components/Pro
import { ProfileInfo } from '@/app/developers/contributors/[slug]/components/ProfileInfo';
import { PullRequests } from '@/app/developers/contributors/[slug]/components/PullRequests';
import { ThankYou } from '@/app/developers/contributors/[slug]/components/ThankYou';

interface Contributor {
login: string;
avatarUrl: string;
pullRequestCount: number;
}
import { findAll } from '@/database/database';
import { pullRequestModel, userModel } from '@/database/model';

export function generateMetadata({
params,
Expand All @@ -27,134 +22,109 @@ export function generateMetadata({
}

export default async function ({ params }: { params: { slug: string } }) {
const db = new Database('db.sqlite', { readonly: true });
const contributors = await findAll(userModel);

const contributor = db
.prepare(
`
SELECT
u.login,
u.avatarUrl,
(SELECT COUNT(*) FROM pullRequests WHERE authorId = u.id) AS pullRequestCount,
(SELECT COUNT(*) FROM issues WHERE authorId = u.id) AS issuesCount
FROM
users u
WHERE
u.login = :user_id
`,
)
.get({ user_id: params.slug }) as Contributor;
const contributor = contributors.find(
(contributor) => contributor.id === params.slug,
);

const pullRequestActivity = db
.prepare(
`
SELECT
COUNT(*) as value,
DATE(createdAt) as day
FROM
pullRequests
WHERE
authorId = (SELECT id FROM users WHERE login = :user_id)
GROUP BY
DATE(createdAt)
ORDER BY
DATE(createdAt)
`,
)
.all({ user_id: params.slug }) as { value: number; day: string }[];
if (!contributor) {
return;
}

// Latest PRs.
const pullRequestList = db
.prepare(
`
SELECT
id,
title,
body,
url,
createdAt,
updatedAt,
closedAt,
mergedAt,
authorId
FROM
pullRequests
WHERE
authorId = (SELECT id FROM users WHERE login = :user_id)
ORDER BY
DATE(createdAt) DESC
LIMIT
10
`,
)
.all({ user_id: params.slug }) as {
title: string;
createdAt: string;
url: string;
id: string;
mergedAt: string | null;
authorId: string;
}[];
const pullRequests = await findAll(pullRequestModel);
const mergedPullRequests = pullRequests
.filter((pr) => pr.mergedAt !== null)
.filter(
(pr) =>
![
'dependabot',
'cyborch',
'emilienchvt',
'Samox',
'charlesBochet',
'gitstart-app',
'thaisguigon',
'lucasbordeau',
'magrinj',
'Weiko',
'gitstart-twenty',
'bosiraphael',
'martmull',
'FelixMalfait',
'thomtrp',
'Bonapara',
'nimraahmed',
].includes(pr.authorId),
);

const mergedPullRequests = db
.prepare(
`
SELECT * FROM (
SELECT
merged_pr_counts.*,
(RANK() OVER(ORDER BY merged_count) - 1) / CAST( total_authors as float) * 100 as rank_percentage
FROM
(
SELECT
authorId,
COUNT(*) FILTER (WHERE mergedAt IS NOT NULL) as merged_count
FROM
pullRequests pr
JOIN
users u ON pr.authorId = u.id
WHERE
u.isEmployee = FALSE
GROUP BY
authorId
) AS merged_pr_counts
CROSS JOIN
(
SELECT COUNT(DISTINCT authorId) as total_authors
FROM pullRequests pr
JOIN
users u ON pr.authorId = u.id
WHERE
u.isEmployee = FALSE
) AS author_counts
) WHERE authorId = (SELECT id FROM users WHERE login = :user_id)
`,
)
.all({ user_id: params.slug }) as {
merged_count: number;
rank_percentage: number;
}[];
const contributorPullRequests = pullRequests.filter(
(pr) => pr.authorId === contributor.id,
);
const mergedContributorPullRequests = contributorPullRequests.filter(
(pr) => pr.mergedAt !== null,
);

db.close();
const mergedContributorPullRequestsByContributor = mergedPullRequests.reduce(
(acc, pr) => {
acc[pr.authorId] = (acc[pr.authorId] || 0) + 1;
return acc;
},
{},
);

const mergedContributorPullRequestsByContributorArray = Object.entries(
mergedContributorPullRequestsByContributor,
)
.map(([authorId, value]) => ({ authorId, value }))
.sort((a, b) => b.value - a.value);

const contributorRank =
((mergedContributorPullRequestsByContributorArray.findIndex(
(contributor) => contributor.authorId === params.slug,
) +
1) /
contributors.length) *
100;

const pullRequestActivity = contributorPullRequests.reduce((acc, pr) => {
const date = new Date(pr.createdAt).toISOString().split('T')[0];
acc[date] = (acc[date] || 0) + 1;
return acc;
}, []);

const pullRequestActivityArray = Object.entries(pullRequestActivity)
.map(([day, value]) => ({ day, value }))
.sort((a, b) => new Date(a.day).getTime() - new Date(b.day).getTime());

return (
<>
<Background />
<ContentContainer>
<Breadcrumb active={contributor.login} />
<Breadcrumb active={contributor.id} />
<ProfileCard
username={contributor.login}
username={contributor.id}
avatarUrl={contributor.avatarUrl}
firstContributionAt={pullRequestActivity[0].day}
firstContributionAt={pullRequestActivityArray[0]?.day}
/>
<ProfileInfo
mergedPRsCount={mergedPullRequests[0].merged_count}
rank={(100 - Number(mergedPullRequests[0].rank_percentage)).toFixed(
0,
)}
activeDays={pullRequestActivity.length}
mergedPRsCount={mergedContributorPullRequests.length}
rank={Math.ceil(Number(contributorRank)).toFixed(0)}
activeDays={pullRequestActivityArray.length}
/>
<ActivityLog data={pullRequestActivityArray} />
<PullRequests
list={
contributorPullRequests.slice(0, 9) as {
id: string;
title: string;
url: string;
createdAt: string;
mergedAt: string | null;
authorId: string;
}[]
}
/>
<ActivityLog data={pullRequestActivity} />
<PullRequests list={pullRequestList} />
<ThankYou authorId={contributor.login} />
</ContentContainer>
</>
Expand Down

This file was deleted.

Loading

0 comments on commit 4613f64

Please sign in to comment.