orm (WIP)

This commit is contained in:
Jean Jacques Avril 2025-01-01 14:17:30 +00:00
parent bdd4042cef
commit ceab3db8b4
No known key found for this signature in database
13 changed files with 13552 additions and 29 deletions

View File

@ -46,11 +46,16 @@ RUN echo "set -g theme_nerd_fonts yes" >> ~/.config/fish/config.fish \
# Installiere Deno
ENV DENO_INSTALL=/deno
RUN mkdir -p /deno \
RUN mkdir -p ${DENO_INSTALL} \
&& curl -fsSL https://deno.land/x/install/install.sh | sh \
&& chown -R vscode /deno
ENV PATH=${DENO_INSTALL}/bin:/usr/local/go/bin:${PATH} \
# Installiere Bun
ENV BUN_INSTALL=/bun
RUN mkdir -p ${BUN_INSTALL} \
&& curl -fsSL https://bun.sh/install | bash
ENV PATH=${BUN_INSTALL}/bin:${DENO_INSTALL}/bin:/usr/local/go/bin:${PATH} \
DENO_DIR=${DENO_INSTALL}/.cache/deno
RUN groupadd -r docker && usermod -aG docker $USERNAME
@ -58,7 +63,7 @@ RUN groupadd -r docker && usermod -aG docker $USERNAME
WORKDIR /workspace
# Zusätzliche Pakete installieren
RUN apt-get update && apt-get install -y protobuf-compiler
RUN apt-get update && apt-get install -y protobuf-compiler netcat
# Ports für React und Dart Services
EXPOSE 3000 8080 4000

View File

@ -22,16 +22,17 @@
],
"features": {
//"docker-in-docker": "latest",
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {}
//"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {}
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
},
"runArgs": ["--add-host=host.docker.internal:host-gateway"],
//"runArgs": ["--add-host=host.docker.internal:host-gateway"],
"postCreateCommand": "./.devcontainer/setup.sh",
"remoteUser": "vscode",
"updateRemoteUserUID": true,
//"workspaceMount": "",
//"workspaceFolder": "/workspaces",
"mounts": [
"type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock",
//"type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock",
"source=${localEnv:HOME}${localEnv:USERPROFILE}/.ssh,target=/home/vscode/.ssh-host,type=bind,consistency=cached"
//"source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached"
]

View File

@ -18,6 +18,7 @@ if [ -d "backend-dart" ]; then
(
cd backend-dart
dart pub get
bun install
) &
else
echo "backend-dart directory not found, skipping..."

View File

@ -63,7 +63,7 @@ structured into well-defined layers with separation of concerns.
- PNPM: npm install -g pnpm
### Run Software
# Run Software
You can start developing and hacking by starting the dev container. Besides that
you can also install the dev environment on your host system. Make sure versions
@ -90,6 +90,27 @@ go run cmd/actatempus/main.go # Backend on port 8080
cd backend-dart
dart run bin/backend_dart.dart # Backend on port 8080
```
## Databse
To simplify things, we chose to use prisma as orm. This enables us to use the same database definition for go and dart. Therefore also error prone manually written sql queries can be avoided.
In order to deploy the database schema you need to run
```bash
bunx prisma db push
```
The prisma cli can be initialized with the following command:
```bash
bunx prisma
```
More: https://www.prisma.io/docs/orm/tools/prisma-cli
### Bun Studio
After deployment, data can be accessed via a webui:
```bash
bunx prisma studio
```
# Known Issues

BIN
backend-dart/bun.lockb Executable file

Binary file not shown.

View File

@ -0,0 +1,2 @@
#!/bin/sh
bun prisma generate

View File

@ -0,0 +1,5 @@
{
"dependencies": {
"prisma": "^6.1.0"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,531 @@
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'model.dart' as _i1;
import 'prisma.dart' as _i2;
class Task {
const Task({
this.id,
this.name,
this.description,
this.projectId,
this.createdAt,
this.updatedAt,
this.project,
});
factory Task.fromJson(Map json) => Task(
id: json['id'],
name: json['name'],
description: json['description'],
projectId: json['projectId'],
createdAt: switch (json['createdAt']) {
DateTime value => value,
String value => DateTime.parse(value),
_ => json['createdAt']
},
updatedAt: switch (json['updatedAt']) {
DateTime value => value,
String value => DateTime.parse(value),
_ => json['updatedAt']
},
project: json['project'] is Map
? _i1.Project.fromJson(json['project'])
: null,
);
final String? id;
final String? name;
final String? description;
final String? projectId;
final DateTime? createdAt;
final DateTime? updatedAt;
final _i1.Project? project;
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'description': description,
'projectId': projectId,
'createdAt': createdAt?.toIso8601String(),
'updatedAt': updatedAt?.toIso8601String(),
'project': project?.toJson(),
};
}
class TimeEntry {
const TimeEntry({
this.id,
this.startTime,
this.endTime,
this.description,
this.userId,
this.projectId,
this.createdAt,
this.updatedAt,
this.user,
this.project,
});
factory TimeEntry.fromJson(Map json) => TimeEntry(
id: json['id'],
startTime: switch (json['startTime']) {
DateTime value => value,
String value => DateTime.parse(value),
_ => json['startTime']
},
endTime: switch (json['endTime']) {
DateTime value => value,
String value => DateTime.parse(value),
_ => json['endTime']
},
description: json['description'],
userId: json['userId'],
projectId: json['projectId'],
createdAt: switch (json['createdAt']) {
DateTime value => value,
String value => DateTime.parse(value),
_ => json['createdAt']
},
updatedAt: switch (json['updatedAt']) {
DateTime value => value,
String value => DateTime.parse(value),
_ => json['updatedAt']
},
user: json['user'] is Map ? _i1.User.fromJson(json['user']) : null,
project: json['project'] is Map
? _i1.Project.fromJson(json['project'])
: null,
);
final String? id;
final DateTime? startTime;
final DateTime? endTime;
final String? description;
final String? userId;
final String? projectId;
final DateTime? createdAt;
final DateTime? updatedAt;
final _i1.User? user;
final _i1.Project? project;
Map<String, dynamic> toJson() => {
'id': id,
'startTime': startTime?.toIso8601String(),
'endTime': endTime?.toIso8601String(),
'description': description,
'userId': userId,
'projectId': projectId,
'createdAt': createdAt?.toIso8601String(),
'updatedAt': updatedAt?.toIso8601String(),
'user': user?.toJson(),
'project': project?.toJson(),
};
}
class Project {
const Project({
this.id,
this.name,
this.description,
this.clientId,
this.userId,
this.createdAt,
this.updatedAt,
this.tasks,
this.timeEntries,
this.user,
this.$count,
});
factory Project.fromJson(Map json) => Project(
id: json['id'],
name: json['name'],
description: json['description'],
clientId: json['clientId'],
userId: json['userId'],
createdAt: switch (json['createdAt']) {
DateTime value => value,
String value => DateTime.parse(value),
_ => json['createdAt']
},
updatedAt: switch (json['updatedAt']) {
DateTime value => value,
String value => DateTime.parse(value),
_ => json['updatedAt']
},
tasks: (json['tasks'] as Iterable?)
?.map((json) => _i1.Task.fromJson(json)),
timeEntries: (json['timeEntries'] as Iterable?)
?.map((json) => _i1.TimeEntry.fromJson(json)),
user: json['user'] is Map ? _i1.User.fromJson(json['user']) : null,
$count: json['_count'] is Map
? _i2.ProjectCountOutputType.fromJson(json['_count'])
: null,
);
final String? id;
final String? name;
final String? description;
final String? clientId;
final String? userId;
final DateTime? createdAt;
final DateTime? updatedAt;
final Iterable<_i1.Task>? tasks;
final Iterable<_i1.TimeEntry>? timeEntries;
final _i1.User? user;
final _i2.ProjectCountOutputType? $count;
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'description': description,
'clientId': clientId,
'userId': userId,
'createdAt': createdAt?.toIso8601String(),
'updatedAt': updatedAt?.toIso8601String(),
'tasks': tasks?.map((e) => e.toJson()),
'timeEntries': timeEntries?.map((e) => e.toJson()),
'user': user?.toJson(),
'_count': $count?.toJson(),
};
}
class User {
const User({
this.id,
this.name,
this.email,
this.password,
this.createdAt,
this.updatedAt,
this.projects,
this.timeEntries,
this.$count,
});
factory User.fromJson(Map json) => User(
id: json['id'],
name: json['name'],
email: json['email'],
password: json['password'],
createdAt: switch (json['createdAt']) {
DateTime value => value,
String value => DateTime.parse(value),
_ => json['createdAt']
},
updatedAt: switch (json['updatedAt']) {
DateTime value => value,
String value => DateTime.parse(value),
_ => json['updatedAt']
},
projects: (json['projects'] as Iterable?)
?.map((json) => _i1.Project.fromJson(json)),
timeEntries: (json['timeEntries'] as Iterable?)
?.map((json) => _i1.TimeEntry.fromJson(json)),
$count: json['_count'] is Map
? _i2.UserCountOutputType.fromJson(json['_count'])
: null,
);
final String? id;
final String? name;
final String? email;
final String? password;
final DateTime? createdAt;
final DateTime? updatedAt;
final Iterable<_i1.Project>? projects;
final Iterable<_i1.TimeEntry>? timeEntries;
final _i2.UserCountOutputType? $count;
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'email': email,
'password': password,
'createdAt': createdAt?.toIso8601String(),
'updatedAt': updatedAt?.toIso8601String(),
'projects': projects?.map((e) => e.toJson()),
'timeEntries': timeEntries?.map((e) => e.toJson()),
'_count': $count?.toJson(),
};
}
class CreateManyUserAndReturnOutputType {
const CreateManyUserAndReturnOutputType({
this.id,
this.name,
this.email,
this.password,
this.createdAt,
this.updatedAt,
});
factory CreateManyUserAndReturnOutputType.fromJson(Map json) =>
CreateManyUserAndReturnOutputType(
id: json['id'],
name: json['name'],
email: json['email'],
password: json['password'],
createdAt: switch (json['createdAt']) {
DateTime value => value,
String value => DateTime.parse(value),
_ => json['createdAt']
},
updatedAt: switch (json['updatedAt']) {
DateTime value => value,
String value => DateTime.parse(value),
_ => json['updatedAt']
},
);
final String? id;
final String? name;
final String? email;
final String? password;
final DateTime? createdAt;
final DateTime? updatedAt;
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'email': email,
'password': password,
'createdAt': createdAt?.toIso8601String(),
'updatedAt': updatedAt?.toIso8601String(),
};
}
class CreateManyProjectAndReturnOutputType {
const CreateManyProjectAndReturnOutputType({
this.id,
this.name,
this.description,
this.clientId,
this.userId,
this.createdAt,
this.updatedAt,
this.user,
});
factory CreateManyProjectAndReturnOutputType.fromJson(Map json) =>
CreateManyProjectAndReturnOutputType(
id: json['id'],
name: json['name'],
description: json['description'],
clientId: json['clientId'],
userId: json['userId'],
createdAt: switch (json['createdAt']) {
DateTime value => value,
String value => DateTime.parse(value),
_ => json['createdAt']
},
updatedAt: switch (json['updatedAt']) {
DateTime value => value,
String value => DateTime.parse(value),
_ => json['updatedAt']
},
user: json['user'] is Map ? _i1.User.fromJson(json['user']) : null,
);
final String? id;
final String? name;
final String? description;
final String? clientId;
final String? userId;
final DateTime? createdAt;
final DateTime? updatedAt;
final _i1.User? user;
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'description': description,
'clientId': clientId,
'userId': userId,
'createdAt': createdAt?.toIso8601String(),
'updatedAt': updatedAt?.toIso8601String(),
'user': user?.toJson(),
};
}
class CreateManyTimeEntryAndReturnOutputType {
const CreateManyTimeEntryAndReturnOutputType({
this.id,
this.startTime,
this.endTime,
this.description,
this.userId,
this.projectId,
this.createdAt,
this.updatedAt,
this.user,
this.project,
});
factory CreateManyTimeEntryAndReturnOutputType.fromJson(Map json) =>
CreateManyTimeEntryAndReturnOutputType(
id: json['id'],
startTime: switch (json['startTime']) {
DateTime value => value,
String value => DateTime.parse(value),
_ => json['startTime']
},
endTime: switch (json['endTime']) {
DateTime value => value,
String value => DateTime.parse(value),
_ => json['endTime']
},
description: json['description'],
userId: json['userId'],
projectId: json['projectId'],
createdAt: switch (json['createdAt']) {
DateTime value => value,
String value => DateTime.parse(value),
_ => json['createdAt']
},
updatedAt: switch (json['updatedAt']) {
DateTime value => value,
String value => DateTime.parse(value),
_ => json['updatedAt']
},
user: json['user'] is Map ? _i1.User.fromJson(json['user']) : null,
project: json['project'] is Map
? _i1.Project.fromJson(json['project'])
: null,
);
final String? id;
final DateTime? startTime;
final DateTime? endTime;
final String? description;
final String? userId;
final String? projectId;
final DateTime? createdAt;
final DateTime? updatedAt;
final _i1.User? user;
final _i1.Project? project;
Map<String, dynamic> toJson() => {
'id': id,
'startTime': startTime?.toIso8601String(),
'endTime': endTime?.toIso8601String(),
'description': description,
'userId': userId,
'projectId': projectId,
'createdAt': createdAt?.toIso8601String(),
'updatedAt': updatedAt?.toIso8601String(),
'user': user?.toJson(),
'project': project?.toJson(),
};
}
class CreateManyTaskAndReturnOutputType {
const CreateManyTaskAndReturnOutputType({
this.id,
this.name,
this.description,
this.projectId,
this.createdAt,
this.updatedAt,
this.project,
});
factory CreateManyTaskAndReturnOutputType.fromJson(Map json) =>
CreateManyTaskAndReturnOutputType(
id: json['id'],
name: json['name'],
description: json['description'],
projectId: json['projectId'],
createdAt: switch (json['createdAt']) {
DateTime value => value,
String value => DateTime.parse(value),
_ => json['createdAt']
},
updatedAt: switch (json['updatedAt']) {
DateTime value => value,
String value => DateTime.parse(value),
_ => json['updatedAt']
},
project: json['project'] is Map
? _i1.Project.fromJson(json['project'])
: null,
);
final String? id;
final String? name;
final String? description;
final String? projectId;
final DateTime? createdAt;
final DateTime? updatedAt;
final _i1.Project? project;
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'description': description,
'projectId': projectId,
'createdAt': createdAt?.toIso8601String(),
'updatedAt': updatedAt?.toIso8601String(),
'project': project?.toJson(),
};
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,60 @@
generator dartClient {
provider = "dart run orm"
output = "lib/infrastructure/persistence/db"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// User Model
model User {
id String @id @default(uuid())
name String
email String @unique
password String
projects Project[] // Beziehung zu Projekten
timeEntries TimeEntry[] // Beziehung zu Zeiteinträgen
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// Project Model
model Project {
id String @id @default(uuid())
name String
description String?
clientId String?
tasks Task[] // Beziehung zu Aufgaben
timeEntries TimeEntry[] // Beziehung zu Zeiteinträgen
user User @relation(fields: [userId], references: [id])
userId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// TimeEntry Model
model TimeEntry {
id String @id @default(uuid())
startTime DateTime
endTime DateTime
description String?
user User @relation(fields: [userId], references: [id])
userId String
project Project @relation(fields: [projectId], references: [id])
projectId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// Task Model (optional)
model Task {
id String @id @default(uuid())
name String
description String?
project Project @relation(fields: [projectId], references: [id])
projectId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

View File

@ -11,29 +11,29 @@ services:
volumes:
- postgres_data:/var/lib/postgresql/data
pgadmin:
image: dpage/pgadmin4:latest
container_name: pgadmin
environment:
PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL:-admin@admin.com}
PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD:-admin}
#PGADMIN_CONFIG_SERVER_MODE: 'False'
ports:
- "5050:80"
#pgadmin:
# image: dpage/pgadmin4:latest
# container_name: pgadmin
# environment:
# PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL:-admin@admin.com}
# PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD:-admin}
# #PGADMIN_CONFIG_SERVER_MODE: 'False'
# ports:
# - "5050:80"
redis:
image: redis/redis-stack:latest
#image: redis:latest
container_name: redis-server
ports:
- "${REDIS_PORT:-6379}:6379"
- "8001:8001" # RedisInsight WebUI
#environment:
# - REDIS_ARGS=--requirepass ${REDIS_PASSWORD:-password}
volumes:
- redis_data:/data
- ./_common/docker/redis.conf:/usr/local/etc/redis/redis.conf
#command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
#redis:
# image: redis/redis-stack:latest
# #image: redis:latest
# container_name: redis-server
# ports:
# - "${REDIS_PORT:-6379}:6379"
# - "8001:8001" # RedisInsight WebUI
# #environment:
# # - REDIS_ARGS=--requirepass ${REDIS_PASSWORD:-password}
# volumes:
# - redis_data:/data
# - ./_common/docker/redis.conf:/usr/local/etc/redis/redis.conf
# #command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
volumes:
postgres_data: