Merge pull request #1 from webbeetechnologies/develop

Develop
This commit is contained in:
Umar Adilov 2026-02-13 15:34:21 +03:00 committed by GitHub
commit 1c33189fca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 90 additions and 330 deletions

View File

@ -65,7 +65,7 @@ import type { TaylorDatabase } from "./types.js";
export const queryBuilder = createQueryBuilder<TaylorDatabase>({
baseUrl: process.env.TAYLORDB_BASE_URL!,
baseId: process.env.TAYLORDB_SERVER_ID!,
apiKey: process.env.TAYLORDB_API_TOKEN!,
apiKey: "",
});
// ============================================================================

View File

@ -174,7 +174,6 @@ This template is designed to deploy to TaylorDB's platform using the included `t
**Environment Variables Required:**
- `TAYLORDB_BASE_URL`
- `TAYLORDB_API_TOKEN`
- `TAYLORDB_SERVER_ID`
---

View File

@ -1,5 +1,6 @@
import express from "express";
import cors from "cors";
import cookieParser from "cookie-parser";
import * as trpcExpress from "@trpc/server/adapters/express";
import { appRouter } from "./router.js";
import { createContext } from "./trpc.js";
@ -7,6 +8,9 @@ import { createContext } from "./trpc.js";
const app = express();
const PORT = process.env.PORT || 3001;
// Parse cookies
app.use(cookieParser());
// Enable CORS for frontend (adjust origin in production)
app.use(
cors({

View File

@ -14,13 +14,15 @@
"start": "node dist/index.js"
},
"dependencies": {
"@taylordb/query-builder": "^0.10.3",
"@taylordb/query-builder": "^0.11.4",
"@trpc/server": "^11.8.1",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"express": "^5.2.1",
"zod": "^4.3.5"
},
"devDependencies": {
"@types/cookie-parser": "^1.4.10",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.6",
"@types/node": "^24.10.1",

View File

@ -6,6 +6,39 @@ import { router, publicProcedure } from "../trpc";
*
* Another example sub-router showing a different domain.
* Demonstrates relationships (author references users).
*
* Example using TaylorDB queryBuilder (available via ctx.queryBuilder):
*
* // Query all posts
* const posts = await ctx.queryBuilder.from("posts").select("*");
*
* // Query with filters
* const publishedPosts = await ctx.queryBuilder
* .from("posts")
* .where({ published: true })
* .select("*");
*
* // Create a new post
* const newPost = await ctx.queryBuilder
* .from("posts")
* .insert({
* title: "My Title",
* content: "My Content",
* authorId: 1,
* published: false
* });
*
* // Update a post
* const updatedPost = await ctx.queryBuilder
* .from("posts")
* .where({ id: 1 })
* .update({ published: true });
*
* // Delete a post
* await ctx.queryBuilder
* .from("posts")
* .where({ id: 1 })
* .delete();
*/
// In-memory store for demonstration
@ -36,9 +69,9 @@ export const postsRouter = router({
published: z.boolean().optional(),
authorId: z.number().optional(),
})
.optional()
.optional(),
)
.query(({ input }) => {
.query(({ input, ctx }) => {
let result = posts;
if (input?.published !== undefined) {
@ -88,7 +121,7 @@ export const postsRouter = router({
title: z.string().min(1).max(200).optional(),
content: z.string().min(1).optional(),
published: z.boolean().optional(),
})
}),
)
.mutation(({ input }) => {
const post = posts.find((p) => p.id === input.id);

View File

@ -1,319 +0,0 @@
import { createQueryBuilder } from "@taylordb/query-builder";
import type { TaylorDatabase } from "./types.js";
/**
* TaylorDB Query Builder Instance
*
* This is the main query builder instance configured with your TaylorDB credentials.
* Use this to perform all database operations in a type-safe manner.
*/
export const queryBuilder = createQueryBuilder<TaylorDatabase>({
baseUrl: process.env.TAYLORDB_BASE_URL!,
baseId: process.env.TAYLORDB_SERVER_ID!,
apiKey: process.env.TAYLORDB_API_TOKEN!,
});
/**
* ============================================================================
* Example Query Functions
* ============================================================================
*
* Below are example patterns for common database operations.
* Replace these with your own functions based on your actual schema.
*
* For comprehensive examples, see: /docs/TAYLORDB_QUERY_REFERENCE.md
*/
// ============================================================================
// READ Operations (Queries)
// ============================================================================
/**
* Example: Get all records from a table
*
* @example
* export async function getAllUsers() {
* return await queryBuilder
* .selectFrom("users")
* .select(["id", "name", "email", "createdAt"])
* .orderBy("createdAt", "desc")
* .execute();
* }
*/
/**
* Example: Get a single record by ID
*
* @example
* export async function getUserById(id: number) {
* return await queryBuilder
* .selectFrom("users")
* .where("id", "=", id)
* .executeTakeFirst();
* }
*/
/**
* Example: Get records with filtering
*
* @example
* export async function getActiveUsers() {
* return await queryBuilder
* .selectFrom("users")
* .where("status", "=", "active")
* .orderBy("name", "asc")
* .execute();
* }
*/
/**
* Example: Get records with date range filtering
*
* @example
* export async function getRecordsInDateRange(startDate: string, endDate: string) {
* return await queryBuilder
* .selectFrom("records")
* .where("date", ">=", ["exactDay", startDate])
* .where("date", "<=", ["exactDay", endDate])
* .orderBy("date", "asc")
* .execute();
* }
*/
// ============================================================================
// CREATE Operations (Insert)
// ============================================================================
/**
* Example: Insert a new record
*
* @example
* export async function createUser(data: { name: string; email: string }) {
* return await queryBuilder
* .insertInto("users")
* .values({
* name: data.name,
* email: data.email,
* status: "active",
* })
* .executeTakeFirst();
* }
*/
/**
* Example: Insert with single-select field
*
* Note: Single-select fields must be wrapped in an array
*
* @example
* export async function createTask(data: { title: string; priority: "low" | "medium" | "high" }) {
* return await queryBuilder
* .insertInto("tasks")
* .values({
* title: data.title,
* priority: [data.priority], // Wrap in array for single-select
* })
* .executeTakeFirst();
* }
*/
/**
* Example: Insert with computed fields
*
* @example
* export async function createOrder(data: { quantity: number; pricePerUnit: number }) {
* const totalPrice = data.quantity * data.pricePerUnit;
*
* return await queryBuilder
* .insertInto("orders")
* .values({
* quantity: data.quantity,
* pricePerUnit: data.pricePerUnit,
* totalPrice: totalPrice,
* })
* .executeTakeFirst();
* }
*/
// ============================================================================
// UPDATE Operations
// ============================================================================
/**
* Example: Update a record
*
* @example
* export async function updateUser(id: number, data: { name?: string; email?: string }) {
* return await queryBuilder
* .update("users")
* .set(data)
* .where("id", "=", id)
* .execute();
* }
*/
/**
* Example: Update with conditional recalculation
*
* @example
* export async function updateOrder(id: number, data: { quantity?: number; pricePerUnit?: number }) {
* // Fetch current record to compute total
* const currentOrder = await queryBuilder
* .selectFrom("orders")
* .select(["quantity", "pricePerUnit"])
* .where("id", "=", id)
* .executeTakeFirst();
*
* if (!currentOrder) {
* throw new Error("Order not found");
* }
*
* const newQuantity = data.quantity ?? currentOrder.quantity ?? 0;
* const newPrice = data.pricePerUnit ?? currentOrder.pricePerUnit ?? 0;
* const totalPrice = newQuantity * newPrice;
*
* return await queryBuilder
* .update("orders")
* .set({
* ...data,
* totalPrice,
* })
* .where("id", "=", id)
* .execute();
* }
*/
// ============================================================================
// DELETE Operations
// ============================================================================
/**
* Example: Delete a single record
*
* @example
* export async function deleteUser(id: number) {
* return await queryBuilder
* .deleteFrom("users")
* .where("id", "=", id)
* .execute();
* }
*/
/**
* Example: Delete multiple records by IDs
*
* @example
* export async function deleteUsers(ids: number[]) {
* return await queryBuilder
* .deleteFrom("users")
* .where("id", "hasAnyOf", ids)
* .execute();
* }
*/
/**
* Example: Delete with condition
*
* @example
* export async function deleteInactiveUsers() {
* return await queryBuilder
* .deleteFrom("users")
* .where("status", "=", "inactive")
* .execute();
* }
*/
// ============================================================================
// AGGREGATION Operations (Manual)
// ============================================================================
/**
* Example: Calculate statistics
*
* @example
* export async function getUserStats() {
* const users = await queryBuilder
* .selectFrom("users")
* .select(["age"])
* .execute();
*
* if (users.length === 0) {
* return { count: 0, average: null, min: null, max: null };
* }
*
* const ages = users.map(u => u.age).filter((a): a is number => a !== undefined);
*
* return {
* count: ages.length,
* average: ages.reduce((a, b) => a + b, 0) / ages.length,
* min: Math.min(...ages),
* max: Math.max(...ages),
* };
* }
*/
/**
* Example: Sum totals for a date
*
* @example
* export async function getTotalSalesForDate(date: string) {
* const sales = await queryBuilder
* .selectFrom("sales")
* .select(["amount", "quantity"])
* .where("date", "=", ["exactDay", date])
* .execute();
*
* return {
* totalAmount: sales.reduce((sum, s) => sum + (s.amount ?? 0), 0),
* totalQuantity: sales.reduce((sum, s) => sum + (s.quantity ?? 0), 0),
* };
* }
*/
/**
* ============================================================================
* Query Builder Quick Reference
* ============================================================================
*
* SELECT:
* - .selectFrom("tableName")
* - .select(["field1", "field2"])
* - .execute() // Returns array
* - .executeTakeFirst() // Returns single record or undefined
*
* WHERE:
* - .where("field", "=", value)
* - .where("field", ">", value)
* - .where("field", "hasAnyOf", [value1, value2])
* - .where("date", ">=", ["exactDay", "2024-01-01"])
*
* ORDER BY:
* - .orderBy("field", "asc")
* - .orderBy("field", "desc")
*
* INSERT:
* - .insertInto("tableName")
* - .values({ field1: value1, field2: value2 })
* - .executeTakeFirst()
*
* UPDATE:
* - .update("tableName")
* - .set({ field1: value1 })
* - .where("id", "=", id)
* - .execute()
*
* DELETE:
* - .deleteFrom("tableName")
* - .where("id", "=", id)
* - .execute()
*
* Field Types:
* - Text: string
* - Number: number
* - Date: ["exactDay", "YYYY-MM-DD"]
* - Single Select: ["option"]
* - Multi Select: ["opt1", "opt2"]
* - Boolean: true/false
*
* For comprehensive examples, see: /docs/TAYLORDB_QUERY_REFERENCE.md
*/

View File

@ -1,15 +1,30 @@
import { createQueryBuilder } from "@taylordb/query-builder";
import { initTRPC } from "@trpc/server";
import type { CreateExpressContextOptions } from "@trpc/server/adapters/express";
import { TaylorDatabase } from "./taylordb/types";
/**
* Create context for each tRPC request
* This is where you can add user session, database clients, etc.
*/
export const createContext = ({ req, res }: CreateExpressContextOptions) => {
// Extract app_access_token from cookies
const appAccessToken = req.cookies?.app_access_token;
if (!appAccessToken) {
throw new Error("Unauthorized: app_access_token cookie is required");
}
const queryBuilder = createQueryBuilder<TaylorDatabase>({
baseUrl: process.env.TAYLORDB_BASE_URL!,
baseId: process.env.TAYLORDB_SERVER_ID!,
apiKey: appAccessToken,
});
return {
req,
res,
// Add any shared context here (e.g., database client, user session)
queryBuilder,
};
};

View File

@ -29,7 +29,7 @@ import type { TaylorDatabase } from "./types.js";
export const queryBuilder = createQueryBuilder<TaylorDatabase>({
baseUrl: process.env.TAYLORDB_BASE_URL!,
baseId: process.env.TAYLORDB_SERVER_ID!,
apiKey: process.env.TAYLORDB_API_TOKEN!,
apiKey: "",
});
```

View File

@ -144,6 +144,9 @@ importers:
'@trpc/server':
specifier: ^11.8.1
version: 11.8.1(typescript@5.9.3)
cookie-parser:
specifier: ^1.4.7
version: 1.4.7
cors:
specifier: ^2.8.5
version: 2.8.5
@ -154,6 +157,9 @@ importers:
specifier: ^4.3.5
version: 4.3.5
devDependencies:
'@types/cookie-parser':
specifier: ^1.4.10
version: 1.4.10(@types/express@5.0.6)
'@types/cors':
specifier: ^2.8.19
version: 2.8.19
@ -1315,6 +1321,11 @@ packages:
'@types/connect@3.4.38':
resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
'@types/cookie-parser@1.4.10':
resolution: {integrity: sha512-B4xqkqfZ8Wek+rCOeRxsjMS9OgvzebEzzLYw7NHYuvzb7IdxOkI0ZHGgeEBX4PUM7QGVvNSK60T3OvWj3YfBRg==}
peerDependencies:
'@types/express': '*'
'@types/cors@2.8.19':
resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==}
@ -1569,6 +1580,13 @@ packages:
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
cookie-parser@1.4.7:
resolution: {integrity: sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==}
engines: {node: '>= 0.8.0'}
cookie-signature@1.0.6:
resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
cookie-signature@1.2.2:
resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==}
engines: {node: '>=6.6.0'}
@ -3638,6 +3656,10 @@ snapshots:
dependencies:
'@types/node': 24.10.1
'@types/cookie-parser@1.4.10(@types/express@5.0.6)':
dependencies:
'@types/express': 5.0.6
'@types/cors@2.8.19':
dependencies:
'@types/node': 24.10.1
@ -3942,6 +3964,13 @@ snapshots:
convert-source-map@2.0.0: {}
cookie-parser@1.4.7:
dependencies:
cookie: 0.7.2
cookie-signature: 1.0.6
cookie-signature@1.0.6: {}
cookie-signature@1.2.2: {}
cookie@0.7.2: {}

View File

@ -21,7 +21,6 @@ services:
env:
vars:
TAYLORDB_BASE_URL: vars.TAYLORDB_INTERNAL_BASE_URL
TAYLORDB_API_TOKEN: secrets.TAYLORDB_API_TOKEN
TAYLORDB_SERVER_ID: vars.TAYLORDB_SERVER_ID
FRONTEND_URL: routing.client.url
@ -31,7 +30,6 @@ services:
env:
vars:
TAYLORDB_BASE_URL: vars.TAYLORDB_INTERNAL_BASE_URL
TAYLORDB_API_TOKEN: secrets.TAYLORDB_API_TOKEN
TAYLORDB_SERVER_ID: vars.TAYLORDB_SERVER_ID
FRONTEND_URL: routing.client.url
@ -41,7 +39,6 @@ services:
env:
vars:
TAYLORDB_BASE_URL: vars.TAYLORDB_INTERNAL_BASE_URL
TAYLORDB_API_TOKEN: secrets.TAYLORDB_API_TOKEN
TAYLORDB_SERVER_ID: vars.TAYLORDB_SERVER_ID
FRONTEND_URL: routing.client.url