Compare commits

..

2 commits

Author SHA1 Message Date
Rayan Konecny
3601b7fc0a Adds companies and rides models with sync endpoints
Introduces database schema, Prisma models, and API support for companies and rides, enabling CRUD operations and synchronization. Updates the sync flow to handle companies and rides, removes redundant user sync, and aligns naming conventions and indexing for better consistency and maintainability.

Co-authored-by: Copilot <copilot@github.com>
2026-05-03 03:51:16 -03:00
Rayan Konecny
259c2e04f7 Corrects comment typo for improved readability
Fixes a minor typo in a section comment to enhance code clarity.
No functional changes introduced.
2026-05-03 02:49:12 -03:00
19 changed files with 3819 additions and 72 deletions

View file

@ -24,9 +24,38 @@ model users {
password String
createdAt DateTime @default(now())
updatedAt DateTime
rides rides[]
tokens tokens[]
}
model companies {
id String @id
name String
cost_per_km Decimal @db.Decimal(10, 2)
notes String? @default("")
createdAt DateTime? @default(now()) @db.Timestamptz(6)
updatedAt DateTime? @default(now()) @db.Timestamptz(6)
@@index([name], map: "idx_companies_name")
}
model rides {
id String @id
user_id String
company String
km Decimal @db.Decimal(10, 2)
cost_per_km Decimal @db.Decimal(10, 2)
total Decimal @db.Decimal(10, 2)
ride_date String
synced Int? @default(0) @db.SmallInt
createdAt DateTime? @default(now()) @db.Timestamptz(6)
updatedAt DateTime? @default(now()) @db.Timestamptz(6)
users users @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
@@index([synced], map: "idx_rides_synced")
@@index([user_id], map: "idx_rides_user_id")
}
enum TokenType {
REFRESH
}

View file

@ -0,0 +1,40 @@
import { Request, Response } from 'express';
import * as syncService from '../services/sync.service.js';
export async function syncCompanies(req: Request, res: Response): Promise<void> {
try {
const parsed = syncService.syncCompaniesSchema.safeParse(req.body);
if (!parsed.success) {
res.status(400).json({ error: parsed.error.flatten() });
return;
}
const synced = await syncService.syncCompanies(parsed.data);
res.json({
success: true,
message: `${synced.length} company/companies synced`,
data: synced,
});
} catch (err: any) {
res.status(500).json({ error: err.message ?? 'Error syncing companies' });
}
}
export async function syncRides(req: Request, res: Response): Promise<void> {
try {
const parsed = syncService.syncRidesSchema.safeParse(req.body);
if (!parsed.success) {
res.status(400).json({ error: parsed.error.flatten() });
return;
}
const synced = await syncService.syncRides(parsed.data);
res.json({
success: true,
message: `${synced.length} ride(s) synced`,
data: synced,
});
} catch (err: any) {
res.status(500).json({ error: err.message ?? 'Error syncing rides' });
}
}

View file

@ -27,3 +27,13 @@ export type tokens = Prisma.tokensModel
*
*/
export type users = Prisma.usersModel
/**
* Model companies
*
*/
export type companies = Prisma.companiesModel
/**
* Model rides
*
*/
export type rides = Prisma.ridesModel

View file

@ -51,3 +51,13 @@ export type tokens = Prisma.tokensModel
*
*/
export type users = Prisma.usersModel
/**
* Model companies
*
*/
export type companies = Prisma.companiesModel
/**
* Model rides
*
*/
export type rides = Prisma.ridesModel

View file

@ -89,6 +89,123 @@ export type DateTimeWithAggregatesFilter<$PrismaModel = never> = {
_max?: Prisma.NestedDateTimeFilter<$PrismaModel>
}
export type DecimalFilter<$PrismaModel = never> = {
equals?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
in?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel>
notIn?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel>
lt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
lte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
not?: Prisma.NestedDecimalFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string
}
export type StringNullableFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
mode?: Prisma.QueryMode
not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null
}
export type DateTimeNullableFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
not?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> | Date | string | null
}
export type SortOrderInput = {
sort: Prisma.SortOrder
nulls?: Prisma.NullsOrder
}
export type DecimalWithAggregatesFilter<$PrismaModel = never> = {
equals?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
in?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel>
notIn?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel>
lt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
lte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
not?: Prisma.NestedDecimalWithAggregatesFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string
_count?: Prisma.NestedIntFilter<$PrismaModel>
_avg?: Prisma.NestedDecimalFilter<$PrismaModel>
_sum?: Prisma.NestedDecimalFilter<$PrismaModel>
_min?: Prisma.NestedDecimalFilter<$PrismaModel>
_max?: Prisma.NestedDecimalFilter<$PrismaModel>
}
export type StringNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
mode?: Prisma.QueryMode
not?: Prisma.NestedStringNullableWithAggregatesFilter<$PrismaModel> | string | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedStringNullableFilter<$PrismaModel>
_max?: Prisma.NestedStringNullableFilter<$PrismaModel>
}
export type DateTimeNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
not?: Prisma.NestedDateTimeNullableWithAggregatesFilter<$PrismaModel> | Date | string | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
_max?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
}
export type IntNullableFilter<$PrismaModel = never> = {
equals?: number | Prisma.IntFieldRefInput<$PrismaModel> | null
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
not?: Prisma.NestedIntNullableFilter<$PrismaModel> | number | null
}
export type IntNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: number | Prisma.IntFieldRefInput<$PrismaModel> | null
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
not?: Prisma.NestedIntNullableWithAggregatesFilter<$PrismaModel> | number | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_avg?: Prisma.NestedFloatNullableFilter<$PrismaModel>
_sum?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedIntNullableFilter<$PrismaModel>
_max?: Prisma.NestedIntNullableFilter<$PrismaModel>
}
export type NestedStringFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
@ -173,4 +290,125 @@ export type NestedDateTimeWithAggregatesFilter<$PrismaModel = never> = {
_max?: Prisma.NestedDateTimeFilter<$PrismaModel>
}
export type NestedDecimalFilter<$PrismaModel = never> = {
equals?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
in?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel>
notIn?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel>
lt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
lte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
not?: Prisma.NestedDecimalFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string
}
export type NestedStringNullableFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null
}
export type NestedDateTimeNullableFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
not?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> | Date | string | null
}
export type NestedDecimalWithAggregatesFilter<$PrismaModel = never> = {
equals?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
in?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel>
notIn?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel>
lt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
lte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
not?: Prisma.NestedDecimalWithAggregatesFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string
_count?: Prisma.NestedIntFilter<$PrismaModel>
_avg?: Prisma.NestedDecimalFilter<$PrismaModel>
_sum?: Prisma.NestedDecimalFilter<$PrismaModel>
_min?: Prisma.NestedDecimalFilter<$PrismaModel>
_max?: Prisma.NestedDecimalFilter<$PrismaModel>
}
export type NestedStringNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
not?: Prisma.NestedStringNullableWithAggregatesFilter<$PrismaModel> | string | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedStringNullableFilter<$PrismaModel>
_max?: Prisma.NestedStringNullableFilter<$PrismaModel>
}
export type NestedIntNullableFilter<$PrismaModel = never> = {
equals?: number | Prisma.IntFieldRefInput<$PrismaModel> | null
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
not?: Prisma.NestedIntNullableFilter<$PrismaModel> | number | null
}
export type NestedDateTimeNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
not?: Prisma.NestedDateTimeNullableWithAggregatesFilter<$PrismaModel> | Date | string | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
_max?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
}
export type NestedIntNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: number | Prisma.IntFieldRefInput<$PrismaModel> | null
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
not?: Prisma.NestedIntNullableWithAggregatesFilter<$PrismaModel> | number | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_avg?: Prisma.NestedFloatNullableFilter<$PrismaModel>
_sum?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedIntNullableFilter<$PrismaModel>
_max?: Prisma.NestedIntNullableFilter<$PrismaModel>
}
export type NestedFloatNullableFilter<$PrismaModel = never> = {
equals?: number | Prisma.FloatFieldRefInput<$PrismaModel> | null
in?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel> | null
notIn?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel> | null
lt?: number | Prisma.FloatFieldRefInput<$PrismaModel>
lte?: number | Prisma.FloatFieldRefInput<$PrismaModel>
gt?: number | Prisma.FloatFieldRefInput<$PrismaModel>
gte?: number | Prisma.FloatFieldRefInput<$PrismaModel>
not?: Prisma.NestedFloatNullableFilter<$PrismaModel> | number | null
}

File diff suppressed because one or more lines are too long

View file

@ -385,7 +385,9 @@ type FieldRefInputType<Model, FieldType> = Model extends never ? never : FieldRe
export const ModelName = {
tokens: 'tokens',
users: 'users'
users: 'users',
companies: 'companies',
rides: 'rides'
} as const
export type ModelName = (typeof ModelName)[keyof typeof ModelName]
@ -401,7 +403,7 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
omit: GlobalOmitOptions
}
meta: {
modelProps: "tokens" | "users"
modelProps: "tokens" | "users" | "companies" | "rides"
txIsolationLevel: TransactionIsolationLevel
}
model: {
@ -553,6 +555,154 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
}
}
}
companies: {
payload: Prisma.$companiesPayload<ExtArgs>
fields: Prisma.companiesFieldRefs
operations: {
findUnique: {
args: Prisma.companiesFindUniqueArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$companiesPayload> | null
}
findUniqueOrThrow: {
args: Prisma.companiesFindUniqueOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$companiesPayload>
}
findFirst: {
args: Prisma.companiesFindFirstArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$companiesPayload> | null
}
findFirstOrThrow: {
args: Prisma.companiesFindFirstOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$companiesPayload>
}
findMany: {
args: Prisma.companiesFindManyArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$companiesPayload>[]
}
create: {
args: Prisma.companiesCreateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$companiesPayload>
}
createMany: {
args: Prisma.companiesCreateManyArgs<ExtArgs>
result: BatchPayload
}
createManyAndReturn: {
args: Prisma.companiesCreateManyAndReturnArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$companiesPayload>[]
}
delete: {
args: Prisma.companiesDeleteArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$companiesPayload>
}
update: {
args: Prisma.companiesUpdateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$companiesPayload>
}
deleteMany: {
args: Prisma.companiesDeleteManyArgs<ExtArgs>
result: BatchPayload
}
updateMany: {
args: Prisma.companiesUpdateManyArgs<ExtArgs>
result: BatchPayload
}
updateManyAndReturn: {
args: Prisma.companiesUpdateManyAndReturnArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$companiesPayload>[]
}
upsert: {
args: Prisma.companiesUpsertArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$companiesPayload>
}
aggregate: {
args: Prisma.CompaniesAggregateArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.AggregateCompanies>
}
groupBy: {
args: Prisma.companiesGroupByArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.CompaniesGroupByOutputType>[]
}
count: {
args: Prisma.companiesCountArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.CompaniesCountAggregateOutputType> | number
}
}
}
rides: {
payload: Prisma.$ridesPayload<ExtArgs>
fields: Prisma.ridesFieldRefs
operations: {
findUnique: {
args: Prisma.ridesFindUniqueArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ridesPayload> | null
}
findUniqueOrThrow: {
args: Prisma.ridesFindUniqueOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ridesPayload>
}
findFirst: {
args: Prisma.ridesFindFirstArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ridesPayload> | null
}
findFirstOrThrow: {
args: Prisma.ridesFindFirstOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ridesPayload>
}
findMany: {
args: Prisma.ridesFindManyArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ridesPayload>[]
}
create: {
args: Prisma.ridesCreateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ridesPayload>
}
createMany: {
args: Prisma.ridesCreateManyArgs<ExtArgs>
result: BatchPayload
}
createManyAndReturn: {
args: Prisma.ridesCreateManyAndReturnArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ridesPayload>[]
}
delete: {
args: Prisma.ridesDeleteArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ridesPayload>
}
update: {
args: Prisma.ridesUpdateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ridesPayload>
}
deleteMany: {
args: Prisma.ridesDeleteManyArgs<ExtArgs>
result: BatchPayload
}
updateMany: {
args: Prisma.ridesUpdateManyArgs<ExtArgs>
result: BatchPayload
}
updateManyAndReturn: {
args: Prisma.ridesUpdateManyAndReturnArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ridesPayload>[]
}
upsert: {
args: Prisma.ridesUpsertArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ridesPayload>
}
aggregate: {
args: Prisma.RidesAggregateArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.AggregateRides>
}
groupBy: {
args: Prisma.ridesGroupByArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.RidesGroupByOutputType>[]
}
count: {
args: Prisma.ridesCountArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.RidesCountAggregateOutputType> | number
}
}
}
}
} & {
other: {
@ -616,6 +766,34 @@ export const UsersScalarFieldEnum = {
export type UsersScalarFieldEnum = (typeof UsersScalarFieldEnum)[keyof typeof UsersScalarFieldEnum]
export const CompaniesScalarFieldEnum = {
id: 'id',
name: 'name',
cost_per_km: 'cost_per_km',
notes: 'notes',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
} as const
export type CompaniesScalarFieldEnum = (typeof CompaniesScalarFieldEnum)[keyof typeof CompaniesScalarFieldEnum]
export const RidesScalarFieldEnum = {
id: 'id',
user_id: 'user_id',
company: 'company',
km: 'km',
cost_per_km: 'cost_per_km',
total: 'total',
ride_date: 'ride_date',
synced: 'synced',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
} as const
export type RidesScalarFieldEnum = (typeof RidesScalarFieldEnum)[keyof typeof RidesScalarFieldEnum]
export const SortOrder = {
asc: 'asc',
desc: 'desc'
@ -632,6 +810,14 @@ export const QueryMode = {
export type QueryMode = (typeof QueryMode)[keyof typeof QueryMode]
export const NullsOrder = {
first: 'first',
last: 'last'
} as const
export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder]
/**
* Field references
@ -680,6 +866,20 @@ export type ListDateTimeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaM
/**
* Reference to a field of type 'Decimal'
*/
export type DecimalFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Decimal'>
/**
* Reference to a field of type 'Decimal[]'
*/
export type ListDecimalFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Decimal[]'>
/**
* Reference to a field of type 'Int'
*/
@ -693,6 +893,20 @@ export type IntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'In
export type ListIntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Int[]'>
/**
* Reference to a field of type 'Float'
*/
export type FloatFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Float'>
/**
* Reference to a field of type 'Float[]'
*/
export type ListFloatFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Float[]'>
/**
* Batch Payload for updateMany & deleteMany & createMany
*/
@ -805,6 +1019,8 @@ export type PrismaClientOptions = ({
export type GlobalOmitConfig = {
tokens?: Prisma.tokensOmit
users?: Prisma.usersOmit
companies?: Prisma.companiesOmit
rides?: Prisma.ridesOmit
}
/* Types for Logging */

View file

@ -52,7 +52,9 @@ export const AnyNull = runtime.AnyNull
export const ModelName = {
tokens: 'tokens',
users: 'users'
users: 'users',
companies: 'companies',
rides: 'rides'
} as const
export type ModelName = (typeof ModelName)[keyof typeof ModelName]
@ -95,6 +97,34 @@ export const UsersScalarFieldEnum = {
export type UsersScalarFieldEnum = (typeof UsersScalarFieldEnum)[keyof typeof UsersScalarFieldEnum]
export const CompaniesScalarFieldEnum = {
id: 'id',
name: 'name',
cost_per_km: 'cost_per_km',
notes: 'notes',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
} as const
export type CompaniesScalarFieldEnum = (typeof CompaniesScalarFieldEnum)[keyof typeof CompaniesScalarFieldEnum]
export const RidesScalarFieldEnum = {
id: 'id',
user_id: 'user_id',
company: 'company',
km: 'km',
cost_per_km: 'cost_per_km',
total: 'total',
ride_date: 'ride_date',
synced: 'synced',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
} as const
export type RidesScalarFieldEnum = (typeof RidesScalarFieldEnum)[keyof typeof RidesScalarFieldEnum]
export const SortOrder = {
asc: 'asc',
desc: 'desc'
@ -110,3 +140,11 @@ export const QueryMode = {
export type QueryMode = (typeof QueryMode)[keyof typeof QueryMode]
export const NullsOrder = {
first: 'first',
last: 'last'
} as const
export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder]

View file

@ -10,4 +10,6 @@
*/
export type * from './models/tokens.js'
export type * from './models/users.js'
export type * from './models/companies.js'
export type * from './models/rides.js'
export type * from './commonInputTypes.js'

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -190,6 +190,7 @@ export type usersWhereInput = {
password?: Prisma.StringFilter<"users"> | string
createdAt?: Prisma.DateTimeFilter<"users"> | Date | string
updatedAt?: Prisma.DateTimeFilter<"users"> | Date | string
rides?: Prisma.RidesListRelationFilter
tokens?: Prisma.TokensListRelationFilter
}
@ -200,6 +201,7 @@ export type usersOrderByWithRelationInput = {
password?: Prisma.SortOrder
createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder
rides?: Prisma.ridesOrderByRelationAggregateInput
tokens?: Prisma.tokensOrderByRelationAggregateInput
}
@ -213,6 +215,7 @@ export type usersWhereUniqueInput = Prisma.AtLeast<{
password?: Prisma.StringFilter<"users"> | string
createdAt?: Prisma.DateTimeFilter<"users"> | Date | string
updatedAt?: Prisma.DateTimeFilter<"users"> | Date | string
rides?: Prisma.RidesListRelationFilter
tokens?: Prisma.TokensListRelationFilter
}, "id" | "email">
@ -247,6 +250,7 @@ export type usersCreateInput = {
password: string
createdAt?: Date | string
updatedAt: Date | string
rides?: Prisma.ridesCreateNestedManyWithoutUsersInput
tokens?: Prisma.tokensCreateNestedManyWithoutUsersInput
}
@ -257,6 +261,7 @@ export type usersUncheckedCreateInput = {
password: string
createdAt?: Date | string
updatedAt: Date | string
rides?: Prisma.ridesUncheckedCreateNestedManyWithoutUsersInput
tokens?: Prisma.tokensUncheckedCreateNestedManyWithoutUsersInput
}
@ -267,6 +272,7 @@ export type usersUpdateInput = {
password?: Prisma.StringFieldUpdateOperationsInput | string
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
rides?: Prisma.ridesUpdateManyWithoutUsersNestedInput
tokens?: Prisma.tokensUpdateManyWithoutUsersNestedInput
}
@ -277,6 +283,7 @@ export type usersUncheckedUpdateInput = {
password?: Prisma.StringFieldUpdateOperationsInput | string
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
rides?: Prisma.ridesUncheckedUpdateManyWithoutUsersNestedInput
tokens?: Prisma.tokensUncheckedUpdateManyWithoutUsersNestedInput
}
@ -353,6 +360,20 @@ export type usersUpdateOneRequiredWithoutTokensNestedInput = {
update?: Prisma.XOR<Prisma.XOR<Prisma.usersUpdateToOneWithWhereWithoutTokensInput, Prisma.usersUpdateWithoutTokensInput>, Prisma.usersUncheckedUpdateWithoutTokensInput>
}
export type usersCreateNestedOneWithoutRidesInput = {
create?: Prisma.XOR<Prisma.usersCreateWithoutRidesInput, Prisma.usersUncheckedCreateWithoutRidesInput>
connectOrCreate?: Prisma.usersCreateOrConnectWithoutRidesInput
connect?: Prisma.usersWhereUniqueInput
}
export type usersUpdateOneRequiredWithoutRidesNestedInput = {
create?: Prisma.XOR<Prisma.usersCreateWithoutRidesInput, Prisma.usersUncheckedCreateWithoutRidesInput>
connectOrCreate?: Prisma.usersCreateOrConnectWithoutRidesInput
upsert?: Prisma.usersUpsertWithoutRidesInput
connect?: Prisma.usersWhereUniqueInput
update?: Prisma.XOR<Prisma.XOR<Prisma.usersUpdateToOneWithWhereWithoutRidesInput, Prisma.usersUpdateWithoutRidesInput>, Prisma.usersUncheckedUpdateWithoutRidesInput>
}
export type usersCreateWithoutTokensInput = {
id: string
name: string
@ -360,6 +381,7 @@ export type usersCreateWithoutTokensInput = {
password: string
createdAt?: Date | string
updatedAt: Date | string
rides?: Prisma.ridesCreateNestedManyWithoutUsersInput
}
export type usersUncheckedCreateWithoutTokensInput = {
@ -369,6 +391,7 @@ export type usersUncheckedCreateWithoutTokensInput = {
password: string
createdAt?: Date | string
updatedAt: Date | string
rides?: Prisma.ridesUncheckedCreateNestedManyWithoutUsersInput
}
export type usersCreateOrConnectWithoutTokensInput = {
@ -394,6 +417,7 @@ export type usersUpdateWithoutTokensInput = {
password?: Prisma.StringFieldUpdateOperationsInput | string
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
rides?: Prisma.ridesUpdateManyWithoutUsersNestedInput
}
export type usersUncheckedUpdateWithoutTokensInput = {
@ -403,6 +427,63 @@ export type usersUncheckedUpdateWithoutTokensInput = {
password?: Prisma.StringFieldUpdateOperationsInput | string
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
rides?: Prisma.ridesUncheckedUpdateManyWithoutUsersNestedInput
}
export type usersCreateWithoutRidesInput = {
id: string
name: string
email: string
password: string
createdAt?: Date | string
updatedAt: Date | string
tokens?: Prisma.tokensCreateNestedManyWithoutUsersInput
}
export type usersUncheckedCreateWithoutRidesInput = {
id: string
name: string
email: string
password: string
createdAt?: Date | string
updatedAt: Date | string
tokens?: Prisma.tokensUncheckedCreateNestedManyWithoutUsersInput
}
export type usersCreateOrConnectWithoutRidesInput = {
where: Prisma.usersWhereUniqueInput
create: Prisma.XOR<Prisma.usersCreateWithoutRidesInput, Prisma.usersUncheckedCreateWithoutRidesInput>
}
export type usersUpsertWithoutRidesInput = {
update: Prisma.XOR<Prisma.usersUpdateWithoutRidesInput, Prisma.usersUncheckedUpdateWithoutRidesInput>
create: Prisma.XOR<Prisma.usersCreateWithoutRidesInput, Prisma.usersUncheckedCreateWithoutRidesInput>
where?: Prisma.usersWhereInput
}
export type usersUpdateToOneWithWhereWithoutRidesInput = {
where?: Prisma.usersWhereInput
data: Prisma.XOR<Prisma.usersUpdateWithoutRidesInput, Prisma.usersUncheckedUpdateWithoutRidesInput>
}
export type usersUpdateWithoutRidesInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
tokens?: Prisma.tokensUpdateManyWithoutUsersNestedInput
}
export type usersUncheckedUpdateWithoutRidesInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string
email?: Prisma.StringFieldUpdateOperationsInput | string
password?: Prisma.StringFieldUpdateOperationsInput | string
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
tokens?: Prisma.tokensUncheckedUpdateManyWithoutUsersNestedInput
}
@ -411,10 +492,12 @@ export type usersUncheckedUpdateWithoutTokensInput = {
*/
export type UsersCountOutputType = {
rides: number
tokens: number
}
export type UsersCountOutputTypeSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
rides?: boolean | UsersCountOutputTypeCountRidesArgs
tokens?: boolean | UsersCountOutputTypeCountTokensArgs
}
@ -428,6 +511,13 @@ export type UsersCountOutputTypeDefaultArgs<ExtArgs extends runtime.Types.Extens
select?: Prisma.UsersCountOutputTypeSelect<ExtArgs> | null
}
/**
* UsersCountOutputType without action
*/
export type UsersCountOutputTypeCountRidesArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
where?: Prisma.ridesWhereInput
}
/**
* UsersCountOutputType without action
*/
@ -443,6 +533,7 @@ export type usersSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs =
password?: boolean
createdAt?: boolean
updatedAt?: boolean
rides?: boolean | Prisma.users$ridesArgs<ExtArgs>
tokens?: boolean | Prisma.users$tokensArgs<ExtArgs>
_count?: boolean | Prisma.UsersCountOutputTypeDefaultArgs<ExtArgs>
}, ExtArgs["result"]["users"]>
@ -476,6 +567,7 @@ export type usersSelectScalar = {
export type usersOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "name" | "email" | "password" | "createdAt" | "updatedAt", ExtArgs["result"]["users"]>
export type usersInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
rides?: boolean | Prisma.users$ridesArgs<ExtArgs>
tokens?: boolean | Prisma.users$tokensArgs<ExtArgs>
_count?: boolean | Prisma.UsersCountOutputTypeDefaultArgs<ExtArgs>
}
@ -485,6 +577,7 @@ export type usersIncludeUpdateManyAndReturn<ExtArgs extends runtime.Types.Extens
export type $usersPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
name: "users"
objects: {
rides: Prisma.$ridesPayload<ExtArgs>[]
tokens: Prisma.$tokensPayload<ExtArgs>[]
}
scalars: runtime.Types.Extensions.GetPayloadResult<{
@ -888,6 +981,7 @@ readonly fields: usersFieldRefs;
*/
export interface Prisma__usersClient<T, Null = never, ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs, GlobalOmitOptions = {}> extends Prisma.PrismaPromise<T> {
readonly [Symbol.toStringTag]: "PrismaPromise"
rides<T extends Prisma.users$ridesArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.users$ridesArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$ridesPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
tokens<T extends Prisma.users$tokensArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.users$tokensArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$tokensPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
@ -1316,6 +1410,30 @@ export type usersDeleteManyArgs<ExtArgs extends runtime.Types.Extensions.Interna
limit?: number
}
/**
* users.rides
*/
export type users$ridesArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
/**
* Select specific fields to fetch from the rides
*/
select?: Prisma.ridesSelect<ExtArgs> | null
/**
* Omit specific fields from the rides
*/
omit?: Prisma.ridesOmit<ExtArgs> | null
/**
* Choose, which related nodes to fetch as well
*/
include?: Prisma.ridesInclude<ExtArgs> | null
where?: Prisma.ridesWhereInput
orderBy?: Prisma.ridesOrderByWithRelationInput | Prisma.ridesOrderByWithRelationInput[]
cursor?: Prisma.ridesWhereUniqueInput
take?: number
skip?: number
distinct?: Prisma.RidesScalarFieldEnum | Prisma.RidesScalarFieldEnum[]
}
/**
* users.tokens
*/

View file

@ -0,0 +1,50 @@
import prisma from '../lib/prisma.js';
export async function findCompanyById(id: string) {
return prisma.companies.findUnique({ where: { id } });
}
export async function createCompany(data: {
id: string;
name: string;
cost_per_km: any;
notes?: string;
}) {
return prisma.companies.create({ data });
}
export async function updateCompany(
id: string,
data: Partial<{
name: string;
cost_per_km: any;
notes: string;
}>
) {
return prisma.companies.update({ where: { id }, data });
}
export async function deleteCompany(id: string) {
return prisma.companies.delete({ where: { id } });
}
export async function listCompanies() {
return prisma.companies.findMany();
}
export async function upsertCompany(data: {
id: string;
name: string;
cost_per_km: any;
notes?: string;
}) {
return prisma.companies.upsert({
where: { id: data.id },
update: {
name: data.name,
cost_per_km: data.cost_per_km,
notes: data.notes,
},
create: data,
});
}

View file

@ -0,0 +1,82 @@
import prisma from '../lib/prisma.js';
export async function findRideById(id: string) {
return prisma.rides.findUnique({ where: { id } });
}
export async function createRide(data: {
id: string;
user_id: string;
company: string;
km: any;
cost_per_km: any;
total: any;
ride_date: string;
synced?: number;
}) {
return prisma.rides.create({ data });
}
export async function updateRide(
id: string,
data: Partial<{
user_id: string;
company: string;
km: any;
cost_per_km: any;
total: any;
ride_date: string;
synced: number;
}>
) {
return prisma.rides.update({ where: { id }, data });
}
export async function deleteRide(id: string) {
return prisma.rides.delete({ where: { id } });
}
export async function listRidesByUserId(user_id: string) {
return prisma.rides.findMany({ where: { user_id } });
}
export async function listRidesNotSynced(user_id: string) {
return prisma.rides.findMany({
where: {
user_id,
synced: 0,
},
});
}
export async function markRideAsSynced(id: string) {
return prisma.rides.update({
where: { id },
data: { synced: 1 },
});
}
export async function upsertRide(data: {
id: string;
user_id: string;
company: string;
km: any;
cost_per_km: any;
total: any;
ride_date: string;
synced?: number;
}) {
return prisma.rides.upsert({
where: { id: data.id },
update: {
user_id: data.user_id,
company: data.company,
km: data.km,
cost_per_km: data.cost_per_km,
total: data.total,
ride_date: data.ride_date,
synced: data.synced,
},
create: data,
});
}

View file

@ -0,0 +1,9 @@
import { Router } from 'express';
import * as syncController from '../controllers/sync.controller.js';
const router = Router();
router.post('/companies', syncController.syncCompanies);
router.post('/rides', syncController.syncRides);
export default router;

View file

@ -2,6 +2,7 @@ import express from 'express';
import cors from 'cors';
import authRoutes from './routes/auth.routes.js';
import usersRoutes from './routes/users.routes.js';
import syncRoutes from './routes/sync.routes.js';
const app = express();
const port = process.env.PORT ? Number(process.env.PORT) : 4000;
@ -11,6 +12,7 @@ app.use(express.json());
app.use('/auth', authRoutes);
app.use('/users', usersRoutes);
app.use('/sync', syncRoutes);
app.listen(port, '0.0.0.0', () => {
console.log(`Server is running on port ${port}`);

View file

@ -0,0 +1,66 @@
import { z } from 'zod';
import * as companiesRepo from '../repositories/companies.repository.js';
import * as ridesRepo from '../repositories/rides.repository.js';
// Validation schemas
export const syncCompaniesSchema = z.object({
companies: z.array(
z.object({
id: z.string(),
name: z.string(),
cost_per_km: z.number().or(z.string()),
notes: z.string().optional(),
})
),
});
export const syncRidesSchema = z.object({
rides: z.array(
z.object({
id: z.string(),
user_id: z.string(),
company: z.string(),
km: z.number().or(z.string()),
cost_per_km: z.number().or(z.string()),
total: z.number().or(z.string()),
ride_date: z.string(),
synced: z.number().optional(),
})
),
});
export async function syncCompanies(
input: z.infer<typeof syncCompaniesSchema>
) {
const synced = [];
for (const company of input.companies) {
const result = await companiesRepo.upsertCompany({
id: company.id,
name: company.name,
cost_per_km: company.cost_per_km,
notes: company.notes,
});
synced.push(result);
}
return synced;
}
export async function syncRides(
input: z.infer<typeof syncRidesSchema>
) {
const synced = [];
for (const ride of input.rides) {
const result = await ridesRepo.upsertRide({
id: ride.id,
user_id: ride.user_id,
company: ride.company,
km: ride.km,
cost_per_km: ride.cost_per_km,
total: ride.total,
ride_date: ride.ride_date,
synced: ride.synced,
});
synced.push(result);
}
return synced;
}

View file

@ -1,36 +1,51 @@
-- ============================================================
-- TopTran — Script de criação das tabelas no PostgreSQL
-- TopTran — PostgreSQL table creation script
-- ============================================================
-- NOTE: The "users" table already exists with the schema below.
-- Do NOT run the commented block if it already exists.
-- ============================================================
CREATE TABLE IF NOT EXISTS empresas (
id TEXT PRIMARY KEY,
nome TEXT NOT NULL,
custo_por_km NUMERIC(10,2) NOT NULL,
observacoes TEXT DEFAULT '',
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- [EXISTING TABLE — DO NOT RECREATE]
-- CREATE TABLE IF NOT EXISTS users (
-- id TEXT PRIMARY KEY,
-- name TEXT NOT NULL,
-- email TEXT NOT NULL UNIQUE,
-- password TEXT NOT NULL,
-- "createdAt" TIMESTAMPTZ DEFAULT NOW(),
-- "updatedAt" TIMESTAMPTZ DEFAULT NOW()
-- );
CREATE TABLE IF NOT EXISTS usuarios (
-- ============================================================
-- Companies
-- ============================================================
CREATE TABLE IF NOT EXISTS companies (
id TEXT PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
token TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
cost_per_km NUMERIC(10,2) NOT NULL,
notes TEXT DEFAULT '',
"createdAt" TIMESTAMPTZ DEFAULT NOW(),
"updatedAt" TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS corridas (
-- ============================================================
-- Rides
-- ============================================================
CREATE TABLE IF NOT EXISTS rides (
id TEXT PRIMARY KEY,
usuario_id TEXT NOT NULL REFERENCES usuarios(id) ON DELETE CASCADE,
empresa TEXT NOT NULL,
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
company TEXT NOT NULL,
km NUMERIC(10,2) NOT NULL,
custo_por_km NUMERIC(10,2) NOT NULL,
cost_per_km NUMERIC(10,2) NOT NULL,
total NUMERIC(10,2) NOT NULL,
data TEXT NOT NULL,
sincronizado SMALLINT DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW()
ride_date TEXT NOT NULL,
synced SMALLINT DEFAULT 0,
"createdAt" TIMESTAMPTZ DEFAULT NOW(),
"updatedAt" TIMESTAMPTZ DEFAULT NOW()
);
-- Índices para performance
CREATE INDEX IF NOT EXISTS idx_corridas_usuario_id ON corridas(usuario_id);
CREATE INDEX IF NOT EXISTS idx_corridas_sincronizado ON corridas(sincronizado);
CREATE INDEX IF NOT EXISTS idx_usuarios_email ON usuarios(email);
-- ============================================================
-- Indexes
-- ============================================================
CREATE INDEX IF NOT EXISTS idx_rides_user_id ON rides(user_id);
CREATE INDEX IF NOT EXISTS idx_rides_synced ON rides(synced);
CREATE INDEX IF NOT EXISTS idx_companies_name ON companies(name);

View file

@ -4,7 +4,6 @@ import {
marcarCorridaComoSincronizada,
obterCorridasNaoSincronizadas,
obterEmpresas,
obterUsuario,
} from "@/services/db";
import { api } from "@/server/api";
import { router } from "expo-router";
@ -37,13 +36,6 @@ const INITIAL_ITEMS: SyncItem[] = [
status: "pending",
detail: "",
},
{
key: "usuarios",
label: "Usuários",
description: "Dados do usuário autenticado",
status: "pending",
detail: "",
},
{
key: "corridas",
label: "Corridas",
@ -75,14 +67,14 @@ export default function SincronizarPage() {
setDone(false);
setItems(INITIAL_ITEMS);
// ── Empresas ────────────────────────────────────────────
// ── Companies ────────────────────────────────────────────
update("empresas", { status: "syncing" });
try {
const empresas = await obterEmpresas();
await api.post("/sync/empresas", { empresas });
const companies = await obterEmpresas();
await api.post("/sync/companies", { companies });
update("empresas", {
status: "success",
detail: `${empresas.length} registro${empresas.length !== 1 ? "s" : ""} enviado${empresas.length !== 1 ? "s" : ""}`,
detail: `${companies.length} registro${companies.length !== 1 ? "s" : ""} enviado${companies.length !== 1 ? "s" : ""}`,
});
} catch (e: any) {
update("empresas", {
@ -91,37 +83,20 @@ export default function SincronizarPage() {
});
}
// ── Usuários ─────────────────────────────────────────────
update("usuarios", { status: "syncing" });
try {
const usuario = await obterUsuario(user.id);
if (usuario) {
await api.post("/sync/usuarios", { usuarios: [usuario] });
update("usuarios", { status: "success", detail: "1 registro enviado" });
} else {
update("usuarios", { status: "error", detail: "Usuário não encontrado" });
}
} catch (e: any) {
update("usuarios", {
status: "error",
detail: e?.response?.data?.error ?? e?.message ?? "Falha na conexão",
});
}
// ── Corridas ─────────────────────────────────────────────
// ── Rides ─────────────────────────────────────────────────
update("corridas", { status: "syncing" });
try {
const corridas = await obterCorridasNaoSincronizadas(user.id);
if (corridas.length === 0) {
const rides = await obterCorridasNaoSincronizadas(user.id);
if (rides.length === 0) {
update("corridas", { status: "success", detail: "Nenhuma corrida pendente" });
} else {
await api.post("/sync/corridas", { corridas });
for (const c of corridas) {
await marcarCorridaComoSincronizada(c.id);
await api.post("/sync/rides", { rides });
for (const ride of rides) {
await marcarCorridaComoSincronizada(ride.id);
}
update("corridas", {
status: "success",
detail: `${corridas.length} corrida${corridas.length !== 1 ? "s" : ""} enviada${corridas.length !== 1 ? "s" : ""}`,
detail: `${rides.length} corrida${rides.length !== 1 ? "s" : ""} enviada${rides.length !== 1 ? "s" : ""}`,
});
}
} catch (e: any) {