Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .dockerEnvExample
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ VITE_API_URL=/
FUNCTIONS_PORT=8081
API_URL=/
OPENAI_API_KEY=sk
PB_VERSION=0.25.5
# VERSION is auto-set by the Release Please workflow
PB_VERSION=0.27.0
# VERSION is auto-set by the Release Please workflow.
32 changes: 16 additions & 16 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,40 +17,40 @@
"@chakra-ui/react": "^2.10.7",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@hookform/resolvers": "^4.1.3",
"@hookform/resolvers": "^5.0.1",
"@project/shared": "workspace:*",
"chakra-dayzed-datepicker": "^0.3.0",
"chakra-react-select": "^5.0.4",
"framer-motion": "^12.6.2",
"chakra-react-select": "^6.1.0",
"framer-motion": "^12.7.3",
"pocketbase": "^0.25.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.55.0",
"react-icons": "^5.5.0",
"react-markdown": "^9.1.0",
"react-markdown": "^10.1.0",
"react-router-dom": "^6.30.0",
"zod": "^3.24.2",
"zod": "^3.24.3",
"zod-to-ts": "^1.2.0"
},
"devDependencies": {
"@eslint/js": "^9.23.0",
"@eslint/js": "^9.24.0",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.2.0",
"@testing-library/react": "^16.3.0",
"@types/react": "^18.3.20",
"@types/react-dom": "^18.3.5",
"@vitejs/plugin-react": "^4.3.4",
"eslint": "^9.23.0",
"@types/react-dom": "^18.3.6",
"@vitejs/plugin-react": "^4.4.0",
"eslint": "^9.24.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.19",
"globals": "^15.15.0",
"happy-dom": "^15.11.7",
"globals": "^16.0.0",
"happy-dom": "^17.4.4",
"prettier": "^3.5.3",
"terser": "^5.39.0",
"typescript": "~5.8.2",
"typescript-eslint": "^8.28.0",
"vite": "^6.2.3",
"typescript": "~5.8.3",
"typescript-eslint": "^8.30.1",
"vite": "^6.3.0",
"vite-tsconfig-paths": "^5.1.4",
"vitest": "^3.0.9"
"vitest": "^3.1.1"
}
}
2 changes: 1 addition & 1 deletion dev-setup.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash

# Default PocketBase version if not set in environment
DEFAULT_PB_VERSION="0.25.5"
DEFAULT_PB_VERSION="0.27.0"
PB_VERSION=${PB_VERSION:-$DEFAULT_PB_VERSION}
PB_PATH="./pocket_base"

Expand Down
2 changes: 1 addition & 1 deletion dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ RUN yarn build
###################################################
FROM alpine:latest AS pocketbase

ARG PB_VERSION=0.25.5
ARG PB_VERSION=0.27.0
ARG TARGETARCH
ENV ACTUAL_PB_VERSION=${PB_VERSION}

Expand Down
14 changes: 7 additions & 7 deletions functions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@
},
"dependencies": {
"@project/shared": "workspace:*",
"body-parser": "^1.20.3",
"body-parser": "^2.2.0",
"cors": "^2.8.5",
"dotenv": "^16.4.7",
"express": "^4.21.2",
"openai": "^4.90.0",
"dotenv": "^16.5.0",
"express": "^5.1.0",
"openai": "^4.95.0",
"pocketbase": "^0.25.2",
"tsx": "^4.19.3",
"zod": "^3.24.2"
"zod": "^3.24.3"
},
"devDependencies": {
"@types/body-parser": "^1.19.5",
"@types/cors": "^2.8.17",
"@types/express": "^5.0.1",
"@types/node": "^22.13.14",
"@types/node": "^22.14.1",
"nodemon": "^3.1.9",
"ts-node": "^10.9.2",
"typescript": "^5.8.2"
"typescript": "^5.8.3"
}
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"name": "fullstack-pb-template",
"version": "1.1.0",
"version": "0.0.0",
"private": true,
"main": "index.js",
"workspaces": [
"./*"
],
"scripts": {
"setup": "yarn run setup:script && yarn run setup:install && yarn run setup:build",
"setup": "yarn install && yarn run setup:script && yarn run setup:install && yarn run setup:build",
"setup:script": "chmod +x ./dev-setup.sh && ./dev-setup.sh",
"setup:install": "yarn install",
"setup:build": "yarn build",
Expand Down
8 changes: 4 additions & 4 deletions shared/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@project/shared",
"version": "1.0.0",
"version": "0.0.0",
"description": "Shared zod schemas for the project",
"private": true,
"type": "module",
Expand Down Expand Up @@ -40,13 +40,13 @@
},
"license": "MIT",
"devDependencies": {
"@types/node": "^22.13.14",
"@types/node": "^22.14.1",
"nodemon": "^3.1.9",
"tsup": "^8.4.0",
"typescript": "^5.8.2"
"typescript": "^5.8.3"
},
"dependencies": {
"pocketbase": "^0.25.2",
"zod": "^3.24.2"
"zod": "^3.24.3"
}
}
87 changes: 62 additions & 25 deletions shared/src/mutator/baseMutator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
RecordService,
} from "pocketbase";

interface Defaults {
export interface MutatorOptions {
expand: string[];
filter: string[];
sort: string[];
Expand All @@ -18,14 +18,51 @@ interface Defaults {
export abstract class BaseMutator<T extends RecordModel, InputType> {
protected pb: TypedPocketBase;

protected defaults: Defaults = {
// Define a default property that subclasses will override
protected options: MutatorOptions = {
expand: [],
filter: [],
sort: [],
};

constructor(pb: TypedPocketBase) {
constructor(pb: TypedPocketBase, options?: Partial<MutatorOptions>) {
this.pb = pb;

// Initialize with default options first
this.initializeOptions();
if (options) {
this.overrideOptions(options);
}
}

private initializeOptions(): void {
this.options = this.setDefaults();
}
/**
* Initialize options with class-specific defaults
* Subclasses should override this instead of directly setting options
*/
protected setDefaults(): MutatorOptions {
return {
expand: [],
filter: [],
sort: [],
};
}

/**
* Merge provided options with current options
*/
protected overrideOptions(newOptions: Partial<MutatorOptions>): void {
if (newOptions.expand !== undefined) {
this.options.expand = newOptions.expand;
}
if (newOptions.filter !== undefined) {
this.options.filter = newOptions.filter;
}
if (newOptions.sort !== undefined) {
this.options.sort = newOptions.sort;
}
}

/**
Expand Down Expand Up @@ -66,6 +103,19 @@ export abstract class BaseMutator<T extends RecordModel, InputType> {
}
}

/**
* Create or update entity (upsert)
*/
async upsert(input: InputType & { id?: string }): Promise<T> {
if (input?.id) {
return await this.update(input.id, input as Partial<T>);
}

// Implementations should override this method if they need
// more specific upsert logic like checking for existing entities
return await this.create(input);
}

/**
* Get entity by ID
*/
Expand Down Expand Up @@ -118,19 +168,6 @@ export abstract class BaseMutator<T extends RecordModel, InputType> {
}
}

/**
* Create or update entity (upsert)
*/
async upsert(input: InputType & { id?: string }): Promise<T> {
if (input?.id) {
return await this.update(input.id, input as Partial<T>);
}

// Implementations should override this method if they need
// more specific upsert logic like checking for existing entities
return await this.create(input);
}

/**
* Delete entity by ID
*/
Expand Down Expand Up @@ -174,12 +211,12 @@ export abstract class BaseMutator<T extends RecordModel, InputType> {
*/
protected prepareExpand(expand?: string | string[]): string | undefined {
// Handle empty defaults case
if (!this.defaults.expand.length && !expand) {
if (!this.options.expand.length && !expand) {
return undefined;
}

// Convert all inputs to arrays for easy processing
let expandArray: string[] = [...this.defaults.expand];
let expandArray: string[] = [...this.options.expand];

if (expand) {
// If expand is a string, split it and add the parts
Expand All @@ -205,7 +242,7 @@ export abstract class BaseMutator<T extends RecordModel, InputType> {
}

// Join with comma and space
return uniqueExpands.join(", ");
return uniqueExpands.join(",");
}

/**
Expand All @@ -214,12 +251,12 @@ export abstract class BaseMutator<T extends RecordModel, InputType> {
*/
protected prepareFilter(filter?: string | string[]): string | undefined {
// Handle empty case
if (!this.defaults.filter.length && !filter) {
if (!this.options.filter.length && !filter) {
return undefined;
}

// Convert all inputs to arrays for easy processing
let filterArray: string[] = [...this.defaults.filter];
let filterArray: string[] = [...this.options.filter];

if (filter) {
// If filter is a string, add it as is (it might contain && already)
Expand All @@ -241,7 +278,7 @@ export abstract class BaseMutator<T extends RecordModel, InputType> {
}

// Join with AND operator
return validFilters.join(" && ");
return validFilters.join("&&");
}

/**
Expand All @@ -255,15 +292,15 @@ export abstract class BaseMutator<T extends RecordModel, InputType> {
}

// If no explicit sort but we have defaults
if (this.defaults.sort.length) {
if (this.options.sort.length) {
// Filter out empty and undefined values
const validSorts = this.defaults.sort.filter(
const validSorts = this.options.sort.filter(
(s) => s !== "" && s !== undefined,
);

// If we have valid sort items after filtering
if (validSorts.length) {
return validSorts.join(", ");
return validSorts.join(",");
}
}

Expand Down
7 changes: 3 additions & 4 deletions shared/src/mutator/projectMutator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BaseMutator } from "./baseMutator";
import { BaseMutator, MutatorOptions } from "./baseMutator";
import { ProjectInputType, ProjectType, TypedPocketBase } from "../types";
import { ProjectInputSchema } from "../schema";

Expand All @@ -8,9 +8,8 @@ import { ProjectInputSchema } from "../schema";
*/

export class ProjectMutator extends BaseMutator<ProjectType, ProjectInputType> {
constructor(pb: TypedPocketBase) {
super(pb);
this.defaults = {
protected setDefaults(): MutatorOptions {
return {
expand: [],
filter: [],
sort: ["-updated"],
Expand Down
7 changes: 3 additions & 4 deletions shared/src/mutator/userMutator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BaseMutator } from "./baseMutator";
import { BaseMutator, MutatorOptions } from "./baseMutator";
import { UserInputType, UserType, TypedPocketBase } from "../types";
import { UserInputSchema } from "../schema";

Expand All @@ -8,9 +8,8 @@ import { UserInputSchema } from "../schema";
*/

export class UserMutator extends BaseMutator<UserType, UserInputType> {
constructor(pb: TypedPocketBase) {
super(pb);
this.defaults = {
protected setDefaults(): MutatorOptions {
return {
expand: [],
filter: [],
sort: ["-updated"],
Expand Down
1 change: 0 additions & 1 deletion shared/src/schema/project.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { z } from "zod";
import { StatusEnum } from "../enums";
import {
baseSchema,
baseImageFileSchema,
inputImageFileSchema,
omitImageFilesSchema,
Expand Down
Loading
Loading