mirror of
https://github.com/twentyhq/twenty.git
synced 2024-09-11 23:37:21 +03:00
Add proper ORM and postgres support (#3978)
* Add postgresql support * Fixes * Fix perfs
This commit is contained in:
parent
94ad0e33ec
commit
4613f64910
@ -22,6 +22,7 @@
|
|||||||
"@hello-pangea/dnd": "^16.2.0",
|
"@hello-pangea/dnd": "^16.2.0",
|
||||||
"@hookform/resolvers": "^3.1.1",
|
"@hookform/resolvers": "^3.1.1",
|
||||||
"@jsdevtools/rehype-toc": "^3.0.2",
|
"@jsdevtools/rehype-toc": "^3.0.2",
|
||||||
|
"@libsql/client": "^0.4.3",
|
||||||
"@mdx-js/react": "^3.0.0",
|
"@mdx-js/react": "^3.0.0",
|
||||||
"@nestjs/apollo": "^11.0.5",
|
"@nestjs/apollo": "^11.0.5",
|
||||||
"@nestjs/axios": "^3.0.1",
|
"@nestjs/axios": "^3.0.1",
|
||||||
@ -76,6 +77,7 @@
|
|||||||
"deep-equal": "^2.2.2",
|
"deep-equal": "^2.2.2",
|
||||||
"docusaurus-node-polyfills": "^1.0.0",
|
"docusaurus-node-polyfills": "^1.0.0",
|
||||||
"dotenv-cli": "^7.2.1",
|
"dotenv-cli": "^7.2.1",
|
||||||
|
"drizzle-orm": "^0.29.3",
|
||||||
"esbuild-plugin-svgr": "^2.1.0",
|
"esbuild-plugin-svgr": "^2.1.0",
|
||||||
"file-type": "16.5.4",
|
"file-type": "16.5.4",
|
||||||
"framer-motion": "^10.12.17",
|
"framer-motion": "^10.12.17",
|
||||||
@ -238,6 +240,7 @@
|
|||||||
"cross-var": "^1.1.0",
|
"cross-var": "^1.1.0",
|
||||||
"danger": "^11.3.0",
|
"danger": "^11.3.0",
|
||||||
"dotenv-cli": "^7.2.1",
|
"dotenv-cli": "^7.2.1",
|
||||||
|
"drizzle-kit": "^0.20.14",
|
||||||
"eslint": "^8.53.0",
|
"eslint": "^8.53.0",
|
||||||
"eslint-config-next": "14.0.4",
|
"eslint-config-next": "14.0.4",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
|
@ -1,2 +1,5 @@
|
|||||||
BASE_URL=http://localhost:3000
|
BASE_URL=http://localhost:3000
|
||||||
GITHUB_TOKEN=your_github_token
|
GITHUB_TOKEN=your_github_token
|
||||||
|
DATABASE_DRIVER=sqlite # or pg
|
||||||
|
DATABASE_PG_URL=postgres://website:website@localhost:5432/website # only if using postgres
|
||||||
|
|
||||||
|
@ -7,6 +7,11 @@
|
|||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import styled from '@emotion/styled';
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
export interface User {
|
export interface User {
|
||||||
login: string;
|
id: string;
|
||||||
avatarUrl: string;
|
avatarUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,13 +66,10 @@ const AvatarGrid = ({ users }: { users: User[] }) => {
|
|||||||
return (
|
return (
|
||||||
<AvatarGridContainer>
|
<AvatarGridContainer>
|
||||||
{users.map((user) => (
|
{users.map((user) => (
|
||||||
<Link
|
<Link href={`/developers/contributors/${user.id}`} key={`l_${user.id}`}>
|
||||||
href={`/developers/contributors/${user.login}`}
|
<AvatarItem key={user.id}>
|
||||||
key={`l_${user.login}`}
|
<img src={user.avatarUrl} alt={user.id} />
|
||||||
>
|
<span className="username">{user.id}</span>
|
||||||
<AvatarItem key={user.login}>
|
|
||||||
<img src={user.avatarUrl} alt={user.login} />
|
|
||||||
<span className="username">{user.login}</span>
|
|
||||||
</AvatarItem>
|
</AvatarItem>
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
|
@ -10,6 +10,9 @@ export const ActivityLog = ({
|
|||||||
}: {
|
}: {
|
||||||
data: { value: number; day: string }[];
|
data: { value: number; day: string }[];
|
||||||
}) => {
|
}) => {
|
||||||
|
if (!data.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<CardContainer>
|
<CardContainer>
|
||||||
<Title>Activity</Title>
|
<Title>Activity</Title>
|
||||||
|
@ -90,10 +90,12 @@ export const ProfileCard = ({
|
|||||||
<StyledGithubIcon size="M" color="rgba(0,0,0,1)" />
|
<StyledGithubIcon size="M" color="rgba(0,0,0,1)" />
|
||||||
</a>
|
</a>
|
||||||
</h3>
|
</h3>
|
||||||
<p className="duration">
|
{firstContributionAt && (
|
||||||
Contributing since{' '}
|
<p className="duration">
|
||||||
{format(new Date(firstContributionAt), 'MMMM yyyy')}
|
Contributing since{' '}
|
||||||
</p>
|
{format(new Date(firstContributionAt), 'MMMM yyyy')}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</Details>
|
</Details>
|
||||||
</ProfileContainer>
|
</ProfileContainer>
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import Database from 'better-sqlite3';
|
|
||||||
import { Metadata } from 'next';
|
import { Metadata } from 'next';
|
||||||
|
|
||||||
import { Background } from '@/app/components/oss-friends/Background';
|
import { Background } from '@/app/components/oss-friends/Background';
|
||||||
@ -9,12 +8,8 @@ import { ProfileCard } from '@/app/developers/contributors/[slug]/components/Pro
|
|||||||
import { ProfileInfo } from '@/app/developers/contributors/[slug]/components/ProfileInfo';
|
import { ProfileInfo } from '@/app/developers/contributors/[slug]/components/ProfileInfo';
|
||||||
import { PullRequests } from '@/app/developers/contributors/[slug]/components/PullRequests';
|
import { PullRequests } from '@/app/developers/contributors/[slug]/components/PullRequests';
|
||||||
import { ThankYou } from '@/app/developers/contributors/[slug]/components/ThankYou';
|
import { ThankYou } from '@/app/developers/contributors/[slug]/components/ThankYou';
|
||||||
|
import { findAll } from '@/database/database';
|
||||||
interface Contributor {
|
import { pullRequestModel, userModel } from '@/database/model';
|
||||||
login: string;
|
|
||||||
avatarUrl: string;
|
|
||||||
pullRequestCount: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function generateMetadata({
|
export function generateMetadata({
|
||||||
params,
|
params,
|
||||||
@ -27,134 +22,109 @@ export function generateMetadata({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default async function ({ params }: { params: { slug: string } }) {
|
export default async function ({ params }: { params: { slug: string } }) {
|
||||||
const db = new Database('db.sqlite', { readonly: true });
|
const contributors = await findAll(userModel);
|
||||||
|
|
||||||
const contributor = db
|
const contributor = contributors.find(
|
||||||
.prepare(
|
(contributor) => contributor.id === params.slug,
|
||||||
`
|
);
|
||||||
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 pullRequestActivity = db
|
if (!contributor) {
|
||||||
.prepare(
|
return;
|
||||||
`
|
}
|
||||||
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 }[];
|
|
||||||
|
|
||||||
// Latest PRs.
|
const pullRequests = await findAll(pullRequestModel);
|
||||||
const pullRequestList = db
|
const mergedPullRequests = pullRequests
|
||||||
.prepare(
|
.filter((pr) => pr.mergedAt !== null)
|
||||||
`
|
.filter(
|
||||||
SELECT
|
(pr) =>
|
||||||
id,
|
![
|
||||||
title,
|
'dependabot',
|
||||||
body,
|
'cyborch',
|
||||||
url,
|
'emilienchvt',
|
||||||
createdAt,
|
'Samox',
|
||||||
updatedAt,
|
'charlesBochet',
|
||||||
closedAt,
|
'gitstart-app',
|
||||||
mergedAt,
|
'thaisguigon',
|
||||||
authorId
|
'lucasbordeau',
|
||||||
FROM
|
'magrinj',
|
||||||
pullRequests
|
'Weiko',
|
||||||
WHERE
|
'gitstart-twenty',
|
||||||
authorId = (SELECT id FROM users WHERE login = :user_id)
|
'bosiraphael',
|
||||||
ORDER BY
|
'martmull',
|
||||||
DATE(createdAt) DESC
|
'FelixMalfait',
|
||||||
LIMIT
|
'thomtrp',
|
||||||
10
|
'Bonapara',
|
||||||
`,
|
'nimraahmed',
|
||||||
)
|
].includes(pr.authorId),
|
||||||
.all({ user_id: params.slug }) as {
|
);
|
||||||
title: string;
|
|
||||||
createdAt: string;
|
|
||||||
url: string;
|
|
||||||
id: string;
|
|
||||||
mergedAt: string | null;
|
|
||||||
authorId: string;
|
|
||||||
}[];
|
|
||||||
|
|
||||||
const mergedPullRequests = db
|
const contributorPullRequests = pullRequests.filter(
|
||||||
.prepare(
|
(pr) => pr.authorId === contributor.id,
|
||||||
`
|
);
|
||||||
SELECT * FROM (
|
const mergedContributorPullRequests = contributorPullRequests.filter(
|
||||||
SELECT
|
(pr) => pr.mergedAt !== null,
|
||||||
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;
|
|
||||||
}[];
|
|
||||||
|
|
||||||
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<Background />
|
<Background />
|
||||||
<ContentContainer>
|
<ContentContainer>
|
||||||
<Breadcrumb active={contributor.login} />
|
<Breadcrumb active={contributor.id} />
|
||||||
<ProfileCard
|
<ProfileCard
|
||||||
username={contributor.login}
|
username={contributor.id}
|
||||||
avatarUrl={contributor.avatarUrl}
|
avatarUrl={contributor.avatarUrl}
|
||||||
firstContributionAt={pullRequestActivity[0].day}
|
firstContributionAt={pullRequestActivityArray[0]?.day}
|
||||||
/>
|
/>
|
||||||
<ProfileInfo
|
<ProfileInfo
|
||||||
mergedPRsCount={mergedPullRequests[0].merged_count}
|
mergedPRsCount={mergedContributorPullRequests.length}
|
||||||
rank={(100 - Number(mergedPullRequests[0].rank_percentage)).toFixed(
|
rank={Math.ceil(Number(contributorRank)).toFixed(0)}
|
||||||
0,
|
activeDays={pullRequestActivityArray.length}
|
||||||
)}
|
/>
|
||||||
activeDays={pullRequestActivity.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} />
|
<ThankYou authorId={contributor.login} />
|
||||||
</ContentContainer>
|
</ContentContainer>
|
||||||
</>
|
</>
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
import Database from 'better-sqlite3';
|
|
||||||
|
|
||||||
export async function GET(
|
|
||||||
request: Request,
|
|
||||||
{ params }: { params: { slug: string } },
|
|
||||||
) {
|
|
||||||
const db = new Database('db.sqlite', { readonly: true });
|
|
||||||
|
|
||||||
if (
|
|
||||||
params.slug !== 'users' &&
|
|
||||||
params.slug !== 'labels' &&
|
|
||||||
params.slug !== 'pullRequests' &&
|
|
||||||
params.slug !== 'issues'
|
|
||||||
) {
|
|
||||||
return Response.json({ error: 'Invalid table name' }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const rows = db.prepare('SELECT * FROM ' + params.slug).all();
|
|
||||||
|
|
||||||
db.close();
|
|
||||||
|
|
||||||
return Response.json(rows);
|
|
||||||
}
|
|
@ -1,7 +1,14 @@
|
|||||||
import { graphql } from '@octokit/graphql';
|
import { graphql } from '@octokit/graphql';
|
||||||
import Database from 'better-sqlite3';
|
|
||||||
|
|
||||||
const db = new Database('db.sqlite', { verbose: console.log });
|
import { insertMany, migrate } from '@/database/database';
|
||||||
|
import {
|
||||||
|
issueLabelModel,
|
||||||
|
issueModel,
|
||||||
|
labelModel,
|
||||||
|
pullRequestLabelModel,
|
||||||
|
pullRequestModel,
|
||||||
|
userModel,
|
||||||
|
} from '@/database/model';
|
||||||
|
|
||||||
interface LabelNode {
|
interface LabelNode {
|
||||||
id: string;
|
id: string;
|
||||||
@ -188,176 +195,132 @@ async function fetchAssignableUsers(): Promise<Set<string>> {
|
|||||||
return new Set(repository.assignableUsers.nodes.map((user) => user.login));
|
return new Set(repository.assignableUsers.nodes.map((user) => user.login));
|
||||||
}
|
}
|
||||||
|
|
||||||
const initDb = () => {
|
|
||||||
db.prepare(
|
|
||||||
`
|
|
||||||
CREATE TABLE IF NOT EXISTS pullRequests (
|
|
||||||
id TEXT PRIMARY KEY,
|
|
||||||
title TEXT,
|
|
||||||
body TEXT,
|
|
||||||
url TEXT,
|
|
||||||
createdAt TEXT,
|
|
||||||
updatedAt TEXT,
|
|
||||||
closedAt TEXT,
|
|
||||||
mergedAt TEXT,
|
|
||||||
authorId TEXT,
|
|
||||||
FOREIGN KEY (authorId) REFERENCES users(id)
|
|
||||||
);
|
|
||||||
`,
|
|
||||||
).run();
|
|
||||||
|
|
||||||
db.prepare(
|
|
||||||
`
|
|
||||||
CREATE TABLE IF NOT EXISTS issues (
|
|
||||||
id TEXT PRIMARY KEY,
|
|
||||||
title TEXT,
|
|
||||||
body TEXT,
|
|
||||||
url TEXT,
|
|
||||||
createdAt TEXT,
|
|
||||||
updatedAt TEXT,
|
|
||||||
closedAt TEXT,
|
|
||||||
authorId TEXT,
|
|
||||||
FOREIGN KEY (authorId) REFERENCES users(id)
|
|
||||||
);
|
|
||||||
`,
|
|
||||||
).run();
|
|
||||||
|
|
||||||
db.prepare(
|
|
||||||
`
|
|
||||||
CREATE TABLE IF NOT EXISTS users (
|
|
||||||
id TEXT PRIMARY KEY,
|
|
||||||
login TEXT,
|
|
||||||
avatarUrl TEXT,
|
|
||||||
url TEXT,
|
|
||||||
isEmployee BOOLEAN
|
|
||||||
);
|
|
||||||
`,
|
|
||||||
).run();
|
|
||||||
|
|
||||||
db.prepare(
|
|
||||||
`
|
|
||||||
CREATE TABLE IF NOT EXISTS labels (
|
|
||||||
id TEXT PRIMARY KEY,
|
|
||||||
name TEXT,
|
|
||||||
color TEXT,
|
|
||||||
description TEXT
|
|
||||||
);
|
|
||||||
`,
|
|
||||||
).run();
|
|
||||||
|
|
||||||
db.prepare(
|
|
||||||
`
|
|
||||||
CREATE TABLE IF NOT EXISTS pullRequestLabels (
|
|
||||||
pullRequestId TEXT,
|
|
||||||
labelId TEXT,
|
|
||||||
FOREIGN KEY (pullRequestId) REFERENCES pullRequests(id),
|
|
||||||
FOREIGN KEY (labelId) REFERENCES labels(id)
|
|
||||||
);
|
|
||||||
`,
|
|
||||||
).run();
|
|
||||||
|
|
||||||
db.prepare(
|
|
||||||
`
|
|
||||||
CREATE TABLE IF NOT EXISTS issueLabels (
|
|
||||||
issueId TEXT,
|
|
||||||
labelId TEXT,
|
|
||||||
FOREIGN KEY (issueId) REFERENCES issues(id),
|
|
||||||
FOREIGN KEY (labelId) REFERENCES labels(id)
|
|
||||||
);
|
|
||||||
`,
|
|
||||||
).run();
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
initDb();
|
await migrate();
|
||||||
|
|
||||||
// TODO if we ever hit API Rate Limiting
|
// TODO if we ever hit API Rate Limiting
|
||||||
const lastPRCursor = null;
|
const lastPRCursor = null;
|
||||||
const lastIssueCursor = null;
|
const lastIssueCursor = null;
|
||||||
|
|
||||||
const assignableUsers = await fetchAssignableUsers();
|
const assignableUsers = await fetchAssignableUsers();
|
||||||
const prs = (await fetchData(lastPRCursor)) as Array<PullRequestNode>;
|
const fetchedPRs = (await fetchData(lastPRCursor)) as Array<PullRequestNode>;
|
||||||
const issues = (await fetchData(lastIssueCursor, true)) as Array<IssueNode>;
|
const fetchedIssues = (await fetchData(
|
||||||
|
lastIssueCursor,
|
||||||
|
true,
|
||||||
|
)) as Array<IssueNode>;
|
||||||
|
|
||||||
const insertPR = db.prepare(
|
for (const pr of fetchedPRs) {
|
||||||
'INSERT INTO pullRequests (id, title, body, url, createdAt, updatedAt, closedAt, mergedAt, authorId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO NOTHING',
|
|
||||||
);
|
|
||||||
const insertIssue = db.prepare(
|
|
||||||
'INSERT INTO issues (id, title, body, url, createdAt, updatedAt, closedAt, authorId) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO NOTHING',
|
|
||||||
);
|
|
||||||
const insertUser = db.prepare(
|
|
||||||
'INSERT INTO users (id, login, avatarUrl, url, isEmployee) VALUES (?, ?, ?, ?, ?) ON CONFLICT(id) DO NOTHING',
|
|
||||||
);
|
|
||||||
const insertLabel = db.prepare(
|
|
||||||
'INSERT INTO labels (id, name, color, description) VALUES (?, ?, ?, ?) ON CONFLICT(id) DO NOTHING',
|
|
||||||
);
|
|
||||||
const insertPullRequestLabel = db.prepare(
|
|
||||||
'INSERT INTO pullRequestLabels (pullRequestId, labelId) VALUES (?, ?)',
|
|
||||||
);
|
|
||||||
const insertIssueLabel = db.prepare(
|
|
||||||
'INSERT INTO issueLabels (issueId, labelId) VALUES (?, ?)',
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const pr of prs) {
|
|
||||||
console.log(pr);
|
|
||||||
if (pr.author == null) {
|
if (pr.author == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
insertUser.run(
|
await insertMany(
|
||||||
pr.author.resourcePath,
|
userModel,
|
||||||
pr.author.login,
|
[
|
||||||
pr.author.avatarUrl,
|
{
|
||||||
pr.author.url,
|
id: pr.author.login,
|
||||||
assignableUsers.has(pr.author.login) ? 1 : 0,
|
avatarUrl: pr.author.avatarUrl,
|
||||||
|
url: pr.author.url,
|
||||||
|
isEmployee: assignableUsers.has(pr.author.login) ? '1' : '0',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{ onConflictKey: 'id' },
|
||||||
);
|
);
|
||||||
insertPR.run(
|
|
||||||
pr.id,
|
await insertMany(
|
||||||
pr.title,
|
pullRequestModel,
|
||||||
pr.body,
|
[
|
||||||
pr.url,
|
{
|
||||||
pr.createdAt,
|
id: pr.id,
|
||||||
pr.updatedAt,
|
title: pr.title,
|
||||||
pr.closedAt,
|
body: pr.body,
|
||||||
pr.mergedAt,
|
url: pr.url,
|
||||||
pr.author.resourcePath,
|
createdAt: pr.createdAt,
|
||||||
|
updatedAt: pr.updatedAt,
|
||||||
|
closedAt: pr.closedAt,
|
||||||
|
mergedAt: pr.mergedAt,
|
||||||
|
authorId: pr.author.login,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{ onConflictKey: 'id' },
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const label of pr.labels.nodes) {
|
for (const label of pr.labels.nodes) {
|
||||||
insertLabel.run(label.id, label.name, label.color, label.description);
|
await insertMany(
|
||||||
insertPullRequestLabel.run(pr.id, label.id);
|
labelModel,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: label.id,
|
||||||
|
name: label.name,
|
||||||
|
color: label.color,
|
||||||
|
description: label.description,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{ onConflictKey: 'id' },
|
||||||
|
);
|
||||||
|
await insertMany(pullRequestLabelModel, [
|
||||||
|
{
|
||||||
|
pullRequestId: pr.id,
|
||||||
|
labelId: label.id,
|
||||||
|
},
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const issue of issues) {
|
for (const issue of fetchedIssues) {
|
||||||
if (issue.author == null) {
|
if (issue.author == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
insertUser.run(
|
await insertMany(
|
||||||
issue.author.resourcePath,
|
userModel,
|
||||||
issue.author.login,
|
[
|
||||||
issue.author.avatarUrl,
|
{
|
||||||
issue.author.url,
|
id: issue.author.login,
|
||||||
assignableUsers.has(issue.author.login) ? 1 : 0,
|
avatarUrl: issue.author.avatarUrl,
|
||||||
|
url: issue.author.url,
|
||||||
|
isEmployee: assignableUsers.has(issue.author.login) ? '1' : '0',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{ onConflictKey: 'id' },
|
||||||
);
|
);
|
||||||
|
|
||||||
insertIssue.run(
|
await insertMany(
|
||||||
issue.id,
|
issueModel,
|
||||||
issue.title,
|
[
|
||||||
issue.body,
|
{
|
||||||
issue.url,
|
id: issue.id,
|
||||||
issue.createdAt,
|
title: issue.title,
|
||||||
issue.updatedAt,
|
body: issue.body,
|
||||||
issue.closedAt,
|
url: issue.url,
|
||||||
issue.author.resourcePath,
|
createdAt: issue.createdAt,
|
||||||
|
updatedAt: issue.updatedAt,
|
||||||
|
closedAt: issue.closedAt,
|
||||||
|
authorId: issue.author.login,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{ onConflictKey: 'id' },
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const label of issue.labels.nodes) {
|
for (const label of issue.labels.nodes) {
|
||||||
insertLabel.run(label.id, label.name, label.color, label.description);
|
await insertMany(
|
||||||
insertIssueLabel.run(issue.id, label.id);
|
labelModel,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: label.id,
|
||||||
|
name: label.name,
|
||||||
|
color: label.color,
|
||||||
|
description: label.description,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{ onConflictKey: 'id' },
|
||||||
|
);
|
||||||
|
await insertMany(issueLabelModel, [
|
||||||
|
{
|
||||||
|
pullRequestId: issue.id,
|
||||||
|
labelId: label.id,
|
||||||
|
},
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
db.close();
|
|
||||||
|
|
||||||
return new Response('Data synced', { status: 200 });
|
return new Response('Data synced', { status: 200 });
|
||||||
}
|
}
|
||||||
|
@ -1,41 +1,44 @@
|
|||||||
import Database from 'better-sqlite3';
|
|
||||||
|
|
||||||
import AvatarGrid from '@/app/components/AvatarGrid';
|
import AvatarGrid from '@/app/components/AvatarGrid';
|
||||||
import { Header } from '@/app/components/developers/contributors/Header';
|
import { Header } from '@/app/components/developers/contributors/Header';
|
||||||
import { Background } from '@/app/components/oss-friends/Background';
|
import { Background } from '@/app/components/oss-friends/Background';
|
||||||
import { ContentContainer } from '@/app/components/oss-friends/ContentContainer';
|
import { ContentContainer } from '@/app/components/oss-friends/ContentContainer';
|
||||||
|
import { findAll } from '@/database/database';
|
||||||
|
import { pullRequestModel, userModel } from '@/database/model';
|
||||||
|
|
||||||
interface Contributor {
|
interface Contributor {
|
||||||
login: string;
|
id: string;
|
||||||
avatarUrl: string;
|
avatarUrl: string;
|
||||||
pullRequestCount: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Contributors = async () => {
|
const Contributors = async () => {
|
||||||
const db = new Database('db.sqlite', { readonly: true });
|
const contributors = await findAll(userModel);
|
||||||
|
const pullRequests = await findAll(pullRequestModel);
|
||||||
|
|
||||||
const contributors = db
|
const pullRequestByAuthor = pullRequests.reduce((acc, pr) => {
|
||||||
.prepare(
|
acc[pr.authorId] = acc[pr.authorId] ? acc[pr.authorId] + 1 : 1;
|
||||||
`SELECT
|
return acc;
|
||||||
u.login,
|
}, {});
|
||||||
u.avatarUrl,
|
|
||||||
COUNT(pr.id) AS pullRequestCount
|
const fitlerContributors = contributors
|
||||||
FROM
|
.filter((contributor) => contributor.isEmployee === '0')
|
||||||
users u
|
.filter(
|
||||||
JOIN
|
(contributor) =>
|
||||||
pullRequests pr ON u.id = pr.authorId
|
![
|
||||||
WHERE
|
'dependabot',
|
||||||
u.isEmployee = FALSE
|
'cyborch',
|
||||||
AND u.login NOT IN ('dependabot', 'cyborch', 'emilienchvt', 'Samox')
|
'emilienchvt',
|
||||||
GROUP BY
|
'Samox',
|
||||||
u.id
|
'nimraahmed',
|
||||||
ORDER BY
|
'gitstart-app',
|
||||||
pullRequestCount DESC;
|
].includes(contributor.id),
|
||||||
`,
|
|
||||||
)
|
)
|
||||||
.all() as Contributor[];
|
.map((contributor) => {
|
||||||
|
contributor.pullRequestCount = pullRequestByAuthor[contributor.id] || 0;
|
||||||
|
|
||||||
db.close();
|
return contributor;
|
||||||
|
})
|
||||||
|
.sort((a, b) => b.pullRequestCount - a.pullRequestCount)
|
||||||
|
.filter((contributor) => contributor.pullRequestCount > 0);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -43,7 +46,7 @@ const Contributors = async () => {
|
|||||||
<ContentContainer>
|
<ContentContainer>
|
||||||
<Header />
|
<Header />
|
||||||
<div>
|
<div>
|
||||||
<AvatarGrid users={contributors} />
|
<AvatarGrid users={fitlerContributors as Contributor[]} />
|
||||||
</div>
|
</div>
|
||||||
</ContentContainer>
|
</ContentContainer>
|
||||||
</>
|
</>
|
||||||
|
70
packages/twenty-website/src/database/database.ts
Normal file
70
packages/twenty-website/src/database/database.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import { createClient } from '@libsql/client';
|
||||||
|
import { drizzle as sqliteDrizzle } from 'drizzle-orm/libsql';
|
||||||
|
import { migrate as sqliteMigrate } from 'drizzle-orm/libsql/migrator';
|
||||||
|
import { drizzle as pgDrizzle } from 'drizzle-orm/postgres-js';
|
||||||
|
import { migrate as postgresMigrate } from 'drizzle-orm/postgres-js/migrator';
|
||||||
|
import { SQLiteTableWithColumns } from 'drizzle-orm/sqlite-core';
|
||||||
|
import postgres from 'postgres';
|
||||||
|
|
||||||
|
import 'dotenv/config';
|
||||||
|
|
||||||
|
// Todo: Deprecate SQLite once prototyping is complete, this is making things impossible to type properly
|
||||||
|
const databaseDriver = process.env.DATABASE_DRIVER;
|
||||||
|
|
||||||
|
const sqliteClient = createClient({
|
||||||
|
url: 'file:twenty-website.sqlite',
|
||||||
|
});
|
||||||
|
const pgClient = postgres(`${process.env.DATABASE_PG_URL}`);
|
||||||
|
const sqliteDb = sqliteDrizzle(sqliteClient, { logger: true });
|
||||||
|
const pgDb = pgDrizzle(pgClient, { logger: true });
|
||||||
|
|
||||||
|
const isSqliteDriver = databaseDriver === 'sqlite';
|
||||||
|
|
||||||
|
const migrate = async () => {
|
||||||
|
if (isSqliteDriver) {
|
||||||
|
await sqliteMigrate(sqliteDb, {
|
||||||
|
migrationsFolder: './src/database/sqlite/migrations',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await postgresMigrate(pgDb, {
|
||||||
|
migrationsFolder: './src/database/postgres/migrations',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const findAll = (model: SQLiteTableWithColumns<any>) => {
|
||||||
|
return isSqliteDriver
|
||||||
|
? sqliteDb.select().from(model).all()
|
||||||
|
: pgDb.select().from(model).execute();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Todo: rework typing
|
||||||
|
const insertMany = async (
|
||||||
|
model: SQLiteTableWithColumns<any>,
|
||||||
|
data: any,
|
||||||
|
options?: { onConflictKey?: string },
|
||||||
|
) => {
|
||||||
|
if (isSqliteDriver) {
|
||||||
|
const query = sqliteDb.insert(model).values(data);
|
||||||
|
if (options?.onConflictKey) {
|
||||||
|
return query
|
||||||
|
.onConflictDoNothing({
|
||||||
|
target: [model[options.onConflictKey]],
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
return query.execute();
|
||||||
|
}
|
||||||
|
const query = pgDb.insert(model).values(data);
|
||||||
|
if (options?.onConflictKey) {
|
||||||
|
return query
|
||||||
|
.onConflictDoNothing({
|
||||||
|
target: [model[options.onConflictKey]],
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
return query.execute();
|
||||||
|
};
|
||||||
|
|
||||||
|
export { findAll, insertMany, migrate };
|
47
packages/twenty-website/src/database/model.ts
Normal file
47
packages/twenty-website/src/database/model.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import {
|
||||||
|
pgIssueLabels,
|
||||||
|
pgIssues,
|
||||||
|
pgLabels,
|
||||||
|
pgPullRequestLabels,
|
||||||
|
pgPullRequests,
|
||||||
|
pgUsers,
|
||||||
|
} from '@/database/postgres/schema-postgres';
|
||||||
|
import {
|
||||||
|
sqlLiteIssueLabels,
|
||||||
|
sqlLiteIssues,
|
||||||
|
sqlLiteLabels,
|
||||||
|
sqlLitePullRequestLabels,
|
||||||
|
sqlLitePullRequests,
|
||||||
|
sqlLiteUsers,
|
||||||
|
} from '@/database/sqlite/schema-sqlite';
|
||||||
|
|
||||||
|
const databaseDriver = process.env.DATABASE_DRIVER;
|
||||||
|
const isSqliteDriver = databaseDriver === 'sqlite';
|
||||||
|
|
||||||
|
export const userModel = isSqliteDriver ? sqlLiteUsers : pgUsers;
|
||||||
|
export const pullRequestModel = isSqliteDriver
|
||||||
|
? sqlLitePullRequests
|
||||||
|
: pgPullRequests;
|
||||||
|
export const issueModel = isSqliteDriver ? sqlLiteIssues : pgIssues;
|
||||||
|
export const labelModel = isSqliteDriver ? sqlLiteLabels : pgLabels;
|
||||||
|
export const pullRequestLabelModel = isSqliteDriver
|
||||||
|
? sqlLitePullRequestLabels
|
||||||
|
: pgPullRequestLabels;
|
||||||
|
export const issueLabelModel = isSqliteDriver
|
||||||
|
? sqlLiteIssueLabels
|
||||||
|
: pgIssueLabels;
|
||||||
|
|
||||||
|
export type User = typeof sqlLiteUsers.$inferSelect;
|
||||||
|
export type PullRequest = typeof sqlLitePullRequests.$inferSelect;
|
||||||
|
export type Issue = typeof sqlLiteIssues.$inferSelect;
|
||||||
|
export type Label = typeof sqlLiteLabels.$inferSelect;
|
||||||
|
export type PullRequestLabel = typeof sqlLitePullRequestLabels.$inferSelect;
|
||||||
|
export type IssueLabel = typeof sqlLiteIssueLabels.$inferSelect;
|
||||||
|
|
||||||
|
export type UserInsert = typeof sqlLiteUsers.$inferInsert;
|
||||||
|
export type PullRequestInsert = typeof sqlLitePullRequests.$inferInsert;
|
||||||
|
export type IssueInsert = typeof sqlLiteIssues.$inferInsert;
|
||||||
|
export type LabelInsert = typeof sqlLiteLabels.$inferInsert;
|
||||||
|
export type PullRequestLabelInsert =
|
||||||
|
typeof sqlLitePullRequestLabels.$inferInsert;
|
||||||
|
export type IssueLabelInsert = typeof sqlLiteIssueLabels.$inferInsert;
|
@ -0,0 +1,14 @@
|
|||||||
|
import { Config } from 'drizzle-kit';
|
||||||
|
|
||||||
|
import 'dotenv/config';
|
||||||
|
|
||||||
|
const pgConfig = {
|
||||||
|
schema: './src/database/postgres/schema-postgres.ts',
|
||||||
|
out: './src/database/postgres/migrations',
|
||||||
|
driver: 'pg',
|
||||||
|
dbCredentials: {
|
||||||
|
connectionString: process.env.DATABASE_PG_URL ?? '',
|
||||||
|
},
|
||||||
|
} satisfies Config;
|
||||||
|
|
||||||
|
export default pgConfig;
|
@ -0,0 +1,84 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS "issueLabels" (
|
||||||
|
"issueId" text,
|
||||||
|
"labelId" text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE IF NOT EXISTS "issues" (
|
||||||
|
"id" text PRIMARY KEY NOT NULL,
|
||||||
|
"externalId" text,
|
||||||
|
"title" text,
|
||||||
|
"body" text,
|
||||||
|
"url" text,
|
||||||
|
"createdAt" text,
|
||||||
|
"updatedAt" text,
|
||||||
|
"closedAt" text,
|
||||||
|
"authorId" text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE IF NOT EXISTS "labels" (
|
||||||
|
"id" text PRIMARY KEY NOT NULL,
|
||||||
|
"externalId" text,
|
||||||
|
"name" text,
|
||||||
|
"color" text,
|
||||||
|
"description" text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE IF NOT EXISTS "pullRequestLabels" (
|
||||||
|
"pullRequestExternalId" text,
|
||||||
|
"labelId" text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE IF NOT EXISTS "pullRequests" (
|
||||||
|
"id" text PRIMARY KEY NOT NULL,
|
||||||
|
"title" text,
|
||||||
|
"body" text,
|
||||||
|
"url" text,
|
||||||
|
"createdAt" text,
|
||||||
|
"updatedAt" text,
|
||||||
|
"closedAt" text,
|
||||||
|
"mergedAt" text,
|
||||||
|
"authorId" text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE IF NOT EXISTS "users" (
|
||||||
|
"id" text PRIMARY KEY NOT NULL,
|
||||||
|
"avatarUrl" text,
|
||||||
|
"url" text,
|
||||||
|
"isEmployee" text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
DO $$ BEGIN
|
||||||
|
ALTER TABLE "issueLabels" ADD CONSTRAINT "issueLabels_issueId_issues_id_fk" FOREIGN KEY ("issueId") REFERENCES "issues"("id") ON DELETE no action ON UPDATE no action;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
||||||
|
--> statement-breakpoint
|
||||||
|
DO $$ BEGIN
|
||||||
|
ALTER TABLE "issueLabels" ADD CONSTRAINT "issueLabels_labelId_labels_id_fk" FOREIGN KEY ("labelId") REFERENCES "labels"("id") ON DELETE no action ON UPDATE no action;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
||||||
|
--> statement-breakpoint
|
||||||
|
DO $$ BEGIN
|
||||||
|
ALTER TABLE "issues" ADD CONSTRAINT "issues_authorId_users_id_fk" FOREIGN KEY ("authorId") REFERENCES "users"("id") ON DELETE no action ON UPDATE no action;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
||||||
|
--> statement-breakpoint
|
||||||
|
DO $$ BEGIN
|
||||||
|
ALTER TABLE "pullRequestLabels" ADD CONSTRAINT "pullRequestLabels_pullRequestExternalId_pullRequests_id_fk" FOREIGN KEY ("pullRequestExternalId") REFERENCES "pullRequests"("id") ON DELETE no action ON UPDATE no action;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
||||||
|
--> statement-breakpoint
|
||||||
|
DO $$ BEGIN
|
||||||
|
ALTER TABLE "pullRequestLabels" ADD CONSTRAINT "pullRequestLabels_labelId_labels_id_fk" FOREIGN KEY ("labelId") REFERENCES "labels"("id") ON DELETE no action ON UPDATE no action;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
||||||
|
--> statement-breakpoint
|
||||||
|
DO $$ BEGIN
|
||||||
|
ALTER TABLE "pullRequests" ADD CONSTRAINT "pullRequests_authorId_users_id_fk" FOREIGN KEY ("authorId") REFERENCES "users"("id") ON DELETE no action ON UPDATE no action;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
@ -0,0 +1,343 @@
|
|||||||
|
{
|
||||||
|
"id": "a7895a79-44a3-4fad-b750-f89d8c04d85c",
|
||||||
|
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||||
|
"version": "5",
|
||||||
|
"dialect": "pg",
|
||||||
|
"tables": {
|
||||||
|
"issueLabels": {
|
||||||
|
"name": "issueLabels",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"issueId": {
|
||||||
|
"name": "issueId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"labelId": {
|
||||||
|
"name": "labelId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"issueLabels_issueId_issues_id_fk": {
|
||||||
|
"name": "issueLabels_issueId_issues_id_fk",
|
||||||
|
"tableFrom": "issueLabels",
|
||||||
|
"tableTo": "issues",
|
||||||
|
"columnsFrom": [
|
||||||
|
"issueId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"issueLabels_labelId_labels_id_fk": {
|
||||||
|
"name": "issueLabels_labelId_labels_id_fk",
|
||||||
|
"tableFrom": "issueLabels",
|
||||||
|
"tableTo": "labels",
|
||||||
|
"columnsFrom": [
|
||||||
|
"labelId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"issues": {
|
||||||
|
"name": "issues",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"externalId": {
|
||||||
|
"name": "externalId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"name": "title",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"name": "body",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"name": "url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"name": "createdAt",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"name": "updatedAt",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"closedAt": {
|
||||||
|
"name": "closedAt",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"authorId": {
|
||||||
|
"name": "authorId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"issues_authorId_users_id_fk": {
|
||||||
|
"name": "issues_authorId_users_id_fk",
|
||||||
|
"tableFrom": "issues",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"authorId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"name": "labels",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"externalId": {
|
||||||
|
"name": "externalId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"color": {
|
||||||
|
"name": "color",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"name": "description",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"pullRequestLabels": {
|
||||||
|
"name": "pullRequestLabels",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"pullRequestExternalId": {
|
||||||
|
"name": "pullRequestExternalId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"labelId": {
|
||||||
|
"name": "labelId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"pullRequestLabels_pullRequestExternalId_pullRequests_id_fk": {
|
||||||
|
"name": "pullRequestLabels_pullRequestExternalId_pullRequests_id_fk",
|
||||||
|
"tableFrom": "pullRequestLabels",
|
||||||
|
"tableTo": "pullRequests",
|
||||||
|
"columnsFrom": [
|
||||||
|
"pullRequestExternalId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"pullRequestLabels_labelId_labels_id_fk": {
|
||||||
|
"name": "pullRequestLabels_labelId_labels_id_fk",
|
||||||
|
"tableFrom": "pullRequestLabels",
|
||||||
|
"tableTo": "labels",
|
||||||
|
"columnsFrom": [
|
||||||
|
"labelId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"pullRequests": {
|
||||||
|
"name": "pullRequests",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"name": "title",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"name": "body",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"name": "url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"name": "createdAt",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"name": "updatedAt",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"closedAt": {
|
||||||
|
"name": "closedAt",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"mergedAt": {
|
||||||
|
"name": "mergedAt",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"authorId": {
|
||||||
|
"name": "authorId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"pullRequests_authorId_users_id_fk": {
|
||||||
|
"name": "pullRequests_authorId_users_id_fk",
|
||||||
|
"tableFrom": "pullRequests",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"authorId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"name": "users",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"avatarUrl": {
|
||||||
|
"name": "avatarUrl",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"name": "url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"isEmployee": {
|
||||||
|
"name": "isEmployee",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {},
|
||||||
|
"schemas": {},
|
||||||
|
"_meta": {
|
||||||
|
"columns": {},
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"version": "5",
|
||||||
|
"dialect": "pg",
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"idx": 0,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1707921820164,
|
||||||
|
"tag": "0000_absent_giant_man",
|
||||||
|
"breakpoints": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
import { pgTable, text } from 'drizzle-orm/pg-core';
|
||||||
|
|
||||||
|
export const pgUsers = pgTable('users', {
|
||||||
|
id: text('id').primaryKey(),
|
||||||
|
avatarUrl: text('avatarUrl'),
|
||||||
|
url: text('url'),
|
||||||
|
isEmployee: text('isEmployee'),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const pgPullRequests = pgTable('pullRequests', {
|
||||||
|
id: text('id').primaryKey(),
|
||||||
|
name: text('title'),
|
||||||
|
body: text('body'),
|
||||||
|
url: text('url'),
|
||||||
|
createdAt: text('createdAt'),
|
||||||
|
updatedAt: text('updatedAt'),
|
||||||
|
closedAt: text('closedAt'),
|
||||||
|
mergedAt: text('mergedAt'),
|
||||||
|
authorId: text('authorId').references(() => pgUsers.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const pgIssues = pgTable('issues', {
|
||||||
|
id: text('id').primaryKey(),
|
||||||
|
externalId: text('externalId'),
|
||||||
|
title: text('title'),
|
||||||
|
body: text('body'),
|
||||||
|
url: text('url'),
|
||||||
|
createdAt: text('createdAt'),
|
||||||
|
updatedAt: text('updatedAt'),
|
||||||
|
closedAt: text('closedAt'),
|
||||||
|
authorId: text('authorId').references(() => pgUsers.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const pgLabels = pgTable('labels', {
|
||||||
|
id: text('id').primaryKey(),
|
||||||
|
externalId: text('externalId'),
|
||||||
|
name: text('name'),
|
||||||
|
color: text('color'),
|
||||||
|
description: text('description'),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const pgPullRequestLabels = pgTable('pullRequestLabels', {
|
||||||
|
pullRequestId: text('pullRequestExternalId').references(
|
||||||
|
() => pgPullRequests.id,
|
||||||
|
),
|
||||||
|
labelId: text('labelId').references(() => pgLabels.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const pgIssueLabels = pgTable('issueLabels', {
|
||||||
|
issueId: text('issueId').references(() => pgIssues.id),
|
||||||
|
labelId: text('labelId').references(() => pgLabels.id),
|
||||||
|
});
|
@ -0,0 +1,14 @@
|
|||||||
|
import { Config } from 'drizzle-kit';
|
||||||
|
|
||||||
|
import 'dotenv/config';
|
||||||
|
|
||||||
|
const sqliteConfig = {
|
||||||
|
schema: './src/database/sqlite/schema-sqlite.ts',
|
||||||
|
out: './src/database/sqlite/migrations',
|
||||||
|
driver: 'libsql',
|
||||||
|
dbCredentials: {
|
||||||
|
url: 'twenty-website.sqlite',
|
||||||
|
},
|
||||||
|
} satisfies Config;
|
||||||
|
|
||||||
|
export default sqliteConfig;
|
@ -0,0 +1,54 @@
|
|||||||
|
CREATE TABLE `issueLabels` (
|
||||||
|
`issueId` text,
|
||||||
|
`labelId` text,
|
||||||
|
FOREIGN KEY (`issueId`) REFERENCES `issues`(`id`) ON UPDATE no action ON DELETE no action,
|
||||||
|
FOREIGN KEY (`labelId`) REFERENCES `labels`(`id`) ON UPDATE no action ON DELETE no action
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE `issues` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`externalId` text,
|
||||||
|
`title` text,
|
||||||
|
`body` text,
|
||||||
|
`url` text,
|
||||||
|
`createdAt` text,
|
||||||
|
`updatedAt` text,
|
||||||
|
`closedAt` text,
|
||||||
|
`authorId` text,
|
||||||
|
FOREIGN KEY (`authorId`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE `labels` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`externalId` text,
|
||||||
|
`name` text,
|
||||||
|
`color` text,
|
||||||
|
`description` text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE `pullRequestLabels` (
|
||||||
|
`pullRequestExternalId` text,
|
||||||
|
`labelId` text,
|
||||||
|
FOREIGN KEY (`pullRequestExternalId`) REFERENCES `pullRequests`(`id`) ON UPDATE no action ON DELETE no action,
|
||||||
|
FOREIGN KEY (`labelId`) REFERENCES `labels`(`id`) ON UPDATE no action ON DELETE no action
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE `pullRequests` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`title` text,
|
||||||
|
`body` text,
|
||||||
|
`url` text,
|
||||||
|
`createdAt` text,
|
||||||
|
`updatedAt` text,
|
||||||
|
`closedAt` text,
|
||||||
|
`mergedAt` text,
|
||||||
|
`authorId` text,
|
||||||
|
FOREIGN KEY (`authorId`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE `users` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`avatarUrl` text,
|
||||||
|
`url` text,
|
||||||
|
`isEmployee` text
|
||||||
|
);
|
@ -0,0 +1,367 @@
|
|||||||
|
{
|
||||||
|
"version": "5",
|
||||||
|
"dialect": "sqlite",
|
||||||
|
"id": "033cd768-53b9-4c60-99ee-be070ea7abd6",
|
||||||
|
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||||
|
"tables": {
|
||||||
|
"issueLabels": {
|
||||||
|
"name": "issueLabels",
|
||||||
|
"columns": {
|
||||||
|
"issueId": {
|
||||||
|
"name": "issueId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"labelId": {
|
||||||
|
"name": "labelId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"issueLabels_issueId_issues_id_fk": {
|
||||||
|
"name": "issueLabels_issueId_issues_id_fk",
|
||||||
|
"tableFrom": "issueLabels",
|
||||||
|
"tableTo": "issues",
|
||||||
|
"columnsFrom": [
|
||||||
|
"issueId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"issueLabels_labelId_labels_id_fk": {
|
||||||
|
"name": "issueLabels_labelId_labels_id_fk",
|
||||||
|
"tableFrom": "issueLabels",
|
||||||
|
"tableTo": "labels",
|
||||||
|
"columnsFrom": [
|
||||||
|
"labelId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"issues": {
|
||||||
|
"name": "issues",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"externalId": {
|
||||||
|
"name": "externalId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"name": "title",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"name": "body",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"name": "url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"name": "createdAt",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"name": "updatedAt",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"closedAt": {
|
||||||
|
"name": "closedAt",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"authorId": {
|
||||||
|
"name": "authorId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"issues_authorId_users_id_fk": {
|
||||||
|
"name": "issues_authorId_users_id_fk",
|
||||||
|
"tableFrom": "issues",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"authorId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"name": "labels",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"externalId": {
|
||||||
|
"name": "externalId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"color": {
|
||||||
|
"name": "color",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"name": "description",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"pullRequestLabels": {
|
||||||
|
"name": "pullRequestLabels",
|
||||||
|
"columns": {
|
||||||
|
"pullRequestExternalId": {
|
||||||
|
"name": "pullRequestExternalId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"labelId": {
|
||||||
|
"name": "labelId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"pullRequestLabels_pullRequestExternalId_pullRequests_id_fk": {
|
||||||
|
"name": "pullRequestLabels_pullRequestExternalId_pullRequests_id_fk",
|
||||||
|
"tableFrom": "pullRequestLabels",
|
||||||
|
"tableTo": "pullRequests",
|
||||||
|
"columnsFrom": [
|
||||||
|
"pullRequestExternalId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"pullRequestLabels_labelId_labels_id_fk": {
|
||||||
|
"name": "pullRequestLabels_labelId_labels_id_fk",
|
||||||
|
"tableFrom": "pullRequestLabels",
|
||||||
|
"tableTo": "labels",
|
||||||
|
"columnsFrom": [
|
||||||
|
"labelId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"pullRequests": {
|
||||||
|
"name": "pullRequests",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"name": "title",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"name": "body",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"name": "url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"name": "createdAt",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"name": "updatedAt",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"closedAt": {
|
||||||
|
"name": "closedAt",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"mergedAt": {
|
||||||
|
"name": "mergedAt",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"authorId": {
|
||||||
|
"name": "authorId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"pullRequests_authorId_users_id_fk": {
|
||||||
|
"name": "pullRequests_authorId_users_id_fk",
|
||||||
|
"tableFrom": "pullRequests",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"authorId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"name": "users",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"avatarUrl": {
|
||||||
|
"name": "avatarUrl",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"name": "url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"isEmployee": {
|
||||||
|
"name": "isEmployee",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {},
|
||||||
|
"_meta": {
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {},
|
||||||
|
"columns": {}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"version": "5",
|
||||||
|
"dialect": "sqlite",
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"idx": 0,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1707920913359,
|
||||||
|
"tag": "0000_small_karma",
|
||||||
|
"breakpoints": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
52
packages/twenty-website/src/database/sqlite/schema-sqlite.ts
Normal file
52
packages/twenty-website/src/database/sqlite/schema-sqlite.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
||||||
|
|
||||||
|
export const sqlLiteUsers = sqliteTable('users', {
|
||||||
|
id: text('id').primaryKey(),
|
||||||
|
avatarUrl: text('avatarUrl'),
|
||||||
|
url: text('url'),
|
||||||
|
isEmployee: text('isEmployee'),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const sqlLitePullRequests = sqliteTable('pullRequests', {
|
||||||
|
id: text('id').primaryKey(),
|
||||||
|
name: text('title'),
|
||||||
|
body: text('body'),
|
||||||
|
url: text('url'),
|
||||||
|
createdAt: text('createdAt'),
|
||||||
|
updatedAt: text('updatedAt'),
|
||||||
|
closedAt: text('closedAt'),
|
||||||
|
mergedAt: text('mergedAt'),
|
||||||
|
authorId: text('authorId').references(() => sqlLiteUsers.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const sqlLiteIssues = sqliteTable('issues', {
|
||||||
|
id: text('id').primaryKey(),
|
||||||
|
externalId: text('externalId'),
|
||||||
|
title: text('title'),
|
||||||
|
body: text('body'),
|
||||||
|
url: text('url'),
|
||||||
|
createdAt: text('createdAt'),
|
||||||
|
updatedAt: text('updatedAt'),
|
||||||
|
closedAt: text('closedAt'),
|
||||||
|
authorId: text('authorId').references(() => sqlLiteUsers.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const sqlLiteLabels = sqliteTable('labels', {
|
||||||
|
id: text('id').primaryKey(),
|
||||||
|
externalId: text('externalId'),
|
||||||
|
name: text('name'),
|
||||||
|
color: text('color'),
|
||||||
|
description: text('description'),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const sqlLitePullRequestLabels = sqliteTable('pullRequestLabels', {
|
||||||
|
pullRequestId: text('pullRequestExternalId').references(
|
||||||
|
() => sqlLitePullRequests.id,
|
||||||
|
),
|
||||||
|
labelId: text('labelId').references(() => sqlLiteLabels.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const sqlLiteIssueLabels = sqliteTable('issueLabels', {
|
||||||
|
issueId: text('issueId').references(() => sqlLiteIssues.id),
|
||||||
|
labelId: text('labelId').references(() => sqlLiteLabels.id),
|
||||||
|
});
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es2020",
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
Loading…
Reference in New Issue
Block a user