Skip to content

Commit a87c5e3

Browse files
chore: wip
1 parent cb7638f commit a87c5e3

File tree

7 files changed

+70
-139
lines changed

7 files changed

+70
-139
lines changed

storage/framework/core/commerce/src/customers/fetch.ts

Lines changed: 21 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -22,77 +22,61 @@ export interface PaginatedCustomers {
2222
}
2323
}
2424

25-
export interface CustomerStats {
26-
total: number
27-
active: number
28-
inactive: number
29-
topSpenders: Partial<CustomersTable>[]
30-
recentCustomers: Partial<CustomersTable>[]
31-
}
32-
3325
/**
34-
* Fetch all customers from the database
26+
* Fetch a customer by ID
3527
*/
36-
export async function fetchAll(): Promise<CustomersTable[]> {
28+
export async function fetchById(id: number): Promise<CustomersTable | undefined> {
3729
return await db
3830
.selectFrom('customers')
31+
.where('id', '=', id)
3932
.selectAll()
40-
.execute()
33+
.executeTakeFirst()
4134
}
4235

4336
/**
44-
* Fetch customers with pagination, sorting, and filtering options
37+
* Fetch customers with simple pagination, sorting, and basic search
38+
* A minimal implementation that works well while planning for Algolia/Meilisearch
4539
*/
4640
export async function fetchPaginated(options: FetchCustomersOptions = {}): Promise<PaginatedCustomers> {
4741
// Set default values
4842
const page = options.page || 1
4943
const limit = options.limit || 10
50-
const offset = (page - 1) * limit
5144
const sortBy = options.sortBy || 'created_at'
5245
const sortOrder = options.sortOrder || 'desc'
5346

5447
// Start building the query
5548
let query = db.selectFrom('customers')
5649
let countQuery = db.selectFrom('customers')
5750

58-
// Apply search filter if provided
59-
if (options.search) {
60-
const searchTerm = `%${options.search}%`
61-
const searchFilter = eb => eb.or([
62-
eb('name', 'like', searchTerm),
63-
eb('email', 'like', searchTerm),
64-
eb('phone', 'like', searchTerm),
65-
])
66-
67-
query = query.where(searchFilter)
68-
countQuery = countQuery.where(searchFilter)
51+
// Simple name search if provided
52+
if (options.search && options.search.trim()) {
53+
const searchTerm = `%${options.search.trim()}%`
54+
query = query.where('name', 'like', searchTerm)
55+
countQuery = countQuery.where('name', 'like', searchTerm)
6956
}
7057

71-
// Apply status filter if provided and not 'all'
58+
// Basic status filter
7259
if (options.status && options.status !== 'all') {
7360
query = query.where('status', '=', options.status)
7461
countQuery = countQuery.where('status', '=', options.status)
7562
}
7663

77-
// Get total count for pagination
64+
// Get total count
7865
const countResult = await countQuery
7966
.select(eb => eb.fn.count('id').as('total'))
8067
.executeTakeFirst()
8168

8269
const total = Number(countResult?.total || 0)
8370

84-
// Apply sorting
85-
// Note: Ensure the column is valid to prevent SQL injection
86-
const validColumns = ['name', 'email', 'orders', 'totalSpent', 'lastOrder', 'status', 'created_at', 'updated_at']
87-
const validSortBy = validColumns.includes(sortBy) ? sortBy : 'created_at'
88-
89-
query = query.orderBy(validSortBy, sortOrder)
71+
// Basic sorting
72+
query = query.orderBy(sortBy, sortOrder)
9073

91-
// Apply pagination
92-
query = query.limit(limit).offset(offset)
93-
94-
// Execute the query
95-
const customers = await query.selectAll().execute()
74+
// Basic pagination
75+
const customers = await query
76+
.selectAll()
77+
.limit(limit)
78+
.offset((page - 1) * limit)
79+
.execute()
9680

9781
// Calculate pagination info
9882
const totalPages = Math.ceil(total / limit)
@@ -109,58 +93,3 @@ export async function fetchPaginated(options: FetchCustomersOptions = {}): Promi
10993
},
11094
}
11195
}
112-
113-
/**
114-
* Fetch a customer by ID
115-
*/
116-
export async function fetchById(id: number): Promise<CustomersTable | undefined> {
117-
return await db
118-
.selectFrom('customers')
119-
.where('id', '=', id)
120-
.selectAll()
121-
.executeTakeFirst()
122-
}
123-
124-
/**
125-
* Get customer statistics
126-
*/
127-
export async function fetchStats(): Promise<CustomerStats> {
128-
const totalCustomers = await db
129-
.selectFrom('customers')
130-
.select(eb => eb.fn.count('id').as('count'))
131-
.executeTakeFirst()
132-
133-
const activeCustomers = await db
134-
.selectFrom('customers')
135-
.where('status', '=', 'Active')
136-
.select(eb => eb.fn.count('id').as('count'))
137-
.executeTakeFirst()
138-
139-
const inactiveCustomers = await db
140-
.selectFrom('customers')
141-
.where('status', '=', 'Inactive')
142-
.select(eb => eb.fn.count('id').as('count'))
143-
.executeTakeFirst()
144-
145-
const topSpenders = await db
146-
.selectFrom('customers')
147-
.select(['id', 'name', 'email', 'total_spent'])
148-
.orderBy('total_spent', 'desc')
149-
.limit(5)
150-
.execute()
151-
152-
const recentCustomers = await db
153-
.selectFrom('customers')
154-
.select(['id', 'name', 'email', 'created_at'])
155-
.orderBy('created_at', 'desc')
156-
.limit(5)
157-
.execute()
158-
159-
return {
160-
total: Number(totalCustomers?.count || 0),
161-
active: Number(activeCustomers?.count || 0),
162-
inactive: Number(inactiveCustomers?.count || 0),
163-
topSpenders,
164-
recentCustomers,
165-
}
166-
}
Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,6 @@
1-
// Export types
2-
// Export fetch functionality
31
export {
4-
type CustomerStats,
5-
fetchAll,
62
fetchById,
73
type FetchCustomersOptions,
84
fetchPaginated,
9-
fetchStats,
105
type PaginatedCustomers,
116
} from './fetch'
12-
13-
// Future exports will go here
14-
// export * from './store'
15-
// export * from './update'
16-
// export * from './delete'

storage/framework/core/commerce/src/customers/update.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,25 @@ import { db } from '@stacksjs/database'
1414
*/
1515
export async function update(id: number, request: CustomerRequestType): Promise<CustomerType | undefined> {
1616
try {
17-
// Create the update data object by picking only defined properties from the request
18-
const updateData: CustomerUpdate = Object.entries(request)
19-
.filter(([_, value]) => value !== undefined)
20-
.reduce((obj, [key, value]) => {
21-
obj[key] = value
22-
return obj
23-
}, {} as CustomerUpdate)
17+
// Create a single update data object directly from the request
18+
const updateData: CustomerUpdate = {
19+
name: request.get('name'),
20+
email: request.get('email'),
21+
phone: request.get('phone'),
22+
orders: request.get<number>('orders'),
23+
total_spent: request.get<number>('totalSpent'),
24+
last_order: request.get('lastOrder'),
25+
status: request.get('status'),
26+
avatar: request.get('avatar'),
27+
user_id: request.get<number>('user_id'),
28+
}
29+
30+
// Remove undefined values
31+
Object.keys(updateData).forEach((key) => {
32+
if (updateData[key as keyof CustomerUpdate] === undefined) {
33+
delete updateData[key as keyof CustomerUpdate]
34+
}
35+
})
2436

2537
// Skip update if no fields are provided
2638
if (Object.keys(updateData).length === 0) {

storage/framework/core/orm/src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,7 @@ export async function writeModelRequest(): Promise<void> {
707707
}
708708
}
709709

710-
fieldStringType += ` get<T>(key: T): string | undefined`
710+
fieldStringType += ` get<T>(key: string): T | undefined`
711711

712712
const otherModelRelations = await fetchOtherModelRelations(modelName)
713713

storage/framework/server-auto-imports.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,4 +244,4 @@
244244
"transactionRequest": true,
245245
"userRequest": true
246246
}
247-
}
247+
}

0 commit comments

Comments
 (0)