-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generic data model and Supabase data service #125
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,13 @@ | ||||||||||||||||||||
// GenericModel class | ||||||||||||||||||||
export default abstract class GenericModel { | ||||||||||||||||||||
// Abstract property for table name | ||||||||||||||||||||
static TABLE_NAME: string; | ||||||||||||||||||||
|
||||||||||||||||||||
static DATABASE_MAP: Object; | ||||||||||||||||||||
|
||||||||||||||||||||
// Abstract method for parsing JSON | ||||||||||||||||||||
static parseJson(json: any): GenericModel { | ||||||||||||||||||||
throw new Error("parseJson method not implemented."); | ||||||||||||||||||||
return json | ||||||||||||||||||||
} | ||||||||||||||||||||
Comment on lines
+8
to
+12
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Improve type safety and implementation of parseJson. Several issues need to be addressed:
- static parseJson(json: any): GenericModel {
- throw new Error("parseJson method not implemented.");
- return json
- }
+ abstract static parseJson<T extends GenericModel>(
+ json: Record<string, unknown>
+ ): T; This change:
📝 Committable suggestion
Suggested change
🧰 Tools🪛 Biome (1.9.4)[error] 11-11: This code is unreachable ... because this statement will throw an exception beforehand (lint/correctness/noUnreachable) 🪛 eslint (1.23.1)[error] 9-9: Unexpected any. Specify a different type. (@typescript-eslint/no-explicit-any) |
||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,36 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
import GenericModel from "./GenericModel" | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
export default class User extends GenericModel { | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
static TABLE_NAME = "members" | ||||||||||||||||||||||||||||||||||||||||||||||||||
static DATABASE_MAP: Object = { | ||||||||||||||||||||||||||||||||||||||||||||||||||
id: "uuid", | ||||||||||||||||||||||||||||||||||||||||||||||||||
username: "username", | ||||||||||||||||||||||||||||||||||||||||||||||||||
email: "fk_email", | ||||||||||||||||||||||||||||||||||||||||||||||||||
identity: "fk_identity", | ||||||||||||||||||||||||||||||||||||||||||||||||||
avatar: "avatar", | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+5
to
+12
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Improve type safety and complete database mappings
Apply this diff to improve type safety and add missing mappings: - static DATABASE_MAP: Object = {
+ static DATABASE_MAP: Record<string, string> = {
id: "uuid",
username: "username",
email: "fk_email",
identity: "fk_identity",
avatar: "avatar",
+ phone: "phone",
+ profileBackground: "profile_background",
+ joinedAt: "joined_at",
+ department: "department",
+ grade: "grade",
+ bio: "bio"
}
🧰 Tools🪛 Biome (1.9.4)[error] 6-6: Don't use 'Object' as a type. Prefer explicitly define the object shape. This type means "any non-nullable value", which is slightly better than 'unknown', but it's still a broad type. (lint/complexity/noBannedTypes) 🪛 eslint (1.23.1)[error] 6-6: Don't use
(@typescript-eslint/ban-types) |
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
public id: String = "" | ||||||||||||||||||||||||||||||||||||||||||||||||||
public username: String = "" | ||||||||||||||||||||||||||||||||||||||||||||||||||
public email: String = "" | ||||||||||||||||||||||||||||||||||||||||||||||||||
public phone: String = "" | ||||||||||||||||||||||||||||||||||||||||||||||||||
public avatar: String = "" | ||||||||||||||||||||||||||||||||||||||||||||||||||
public profileBackground: String = "" | ||||||||||||||||||||||||||||||||||||||||||||||||||
public joinedAt: Date = new Date() | ||||||||||||||||||||||||||||||||||||||||||||||||||
public identity: String = "" | ||||||||||||||||||||||||||||||||||||||||||||||||||
public department: String = "" | ||||||||||||||||||||||||||||||||||||||||||||||||||
public grade: String = "" | ||||||||||||||||||||||||||||||||||||||||||||||||||
public bio: String = "" | ||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+14
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Use lowercase primitive types Replace uppercase Apply this diff to fix the type declarations: - public id: String = ""
- public username: String = ""
- public email: String = ""
- public phone: String = ""
- public avatar: String = ""
- public profileBackground: String = ""
+ public id: string = ""
+ public username: string = ""
+ public email: string = ""
+ public phone: string = ""
+ public avatar: string = ""
+ public profileBackground: string = ""
public joinedAt: Date = new Date()
- public identity: String = ""
- public department: String = ""
- public grade: String = ""
- public bio: String = ""
+ public identity: string = ""
+ public department: string = ""
+ public grade: string = ""
+ public bio: string = "" 📝 Committable suggestion
Suggested change
🧰 Tools🪛 Biome (1.9.4)[error] 14-14: Don't use 'String' as a type. Use lowercase primitives for consistency. (lint/complexity/noBannedTypes) [error] 15-15: Don't use 'String' as a type. Use lowercase primitives for consistency. (lint/complexity/noBannedTypes) [error] 16-16: Don't use 'String' as a type. Use lowercase primitives for consistency. (lint/complexity/noBannedTypes) [error] 17-17: Don't use 'String' as a type. Use lowercase primitives for consistency. (lint/complexity/noBannedTypes) [error] 18-18: Don't use 'String' as a type. Use lowercase primitives for consistency. (lint/complexity/noBannedTypes) [error] 19-19: Don't use 'String' as a type. Use lowercase primitives for consistency. (lint/complexity/noBannedTypes) [error] 21-21: Don't use 'String' as a type. Use lowercase primitives for consistency. (lint/complexity/noBannedTypes) [error] 22-22: Don't use 'String' as a type. Use lowercase primitives for consistency. (lint/complexity/noBannedTypes) [error] 23-23: Don't use 'String' as a type. Use lowercase primitives for consistency. (lint/complexity/noBannedTypes) [error] 24-24: Don't use 'String' as a type. Use lowercase primitives for consistency. (lint/complexity/noBannedTypes) 🪛 eslint (1.23.1)[error] 14-14: Don't use (@typescript-eslint/ban-types) [error] 15-15: Don't use (@typescript-eslint/ban-types) [error] 16-16: Don't use (@typescript-eslint/ban-types) [error] 17-17: Don't use (@typescript-eslint/ban-types) [error] 18-18: Don't use (@typescript-eslint/ban-types) [error] 19-19: Don't use (@typescript-eslint/ban-types) [error] 21-21: Don't use (@typescript-eslint/ban-types) [error] 22-22: Don't use (@typescript-eslint/ban-types) [error] 23-23: Don't use (@typescript-eslint/ban-types) [error] 24-24: Don't use (@typescript-eslint/ban-types) |
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
static parseJson(json: any) : User { | ||||||||||||||||||||||||||||||||||||||||||||||||||
const user = new User() | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
for (const [userProperty, jsonField] of Object.entries(this.DATABASE_MAP)) | ||||||||||||||||||||||||||||||||||||||||||||||||||
if (json[jsonField] !== undefined) | ||||||||||||||||||||||||||||||||||||||||||||||||||
(user as any)[userProperty] = json[jsonField]; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
return user | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+27
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Improve type safety and error handling in parseJson
Consider applying this improvement: - static parseJson(json: any) : User {
+ static parseJson(json: Record<string, unknown>) : User {
const user = new User()
- for (const [userProperty, jsonField] of Object.entries(this.DATABASE_MAP))
+ for (const [userProperty, jsonField] of Object.entries(User.DATABASE_MAP)) {
if (json[jsonField] !== undefined)
- (user as any)[userProperty] = json[jsonField];
+ (user as Record<string, unknown>)[userProperty] = json[jsonField];
+ }
+
+ // Validate required fields
+ if (!user.id || !user.email) {
+ throw new Error('Missing required fields: id and email are mandatory');
+ }
return user
} 📝 Committable suggestion
Suggested change
🧰 Tools🪛 Biome (1.9.4)[error] 30-30: Using this in a static context can be confusing. this refers to the class. (lint/complexity/noThisInStatic) 🪛 eslint (1.23.1)[error] 27-27: Unexpected any. Specify a different type. (@typescript-eslint/no-explicit-any) [error] 32-32: Unexpected any. Specify a different type. (@typescript-eslint/no-explicit-any) |
||||||||||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { createFileRoute } from '@tanstack/react-router' | ||
// import { VStack } from '../../components' | ||
|
||
// const homeItems = [ | ||
// { title: "test", description: "Hello world." }, | ||
// { title: "test", description: "Hello world." }, | ||
// { title: "test", description: "Hello world." }, | ||
// { title: "test", description: "Hello world." }, | ||
// { title: "test", description: "Hello world." }, | ||
// { title: "test", description: "Hello world." }, | ||
// { title: "test", description: "Hello world." }, | ||
// { title: "test", description: "Hello world." }, | ||
// { title: "test", description: "Hello world." }, | ||
// { title: "test", description: "Hello world." }, | ||
// { title: "test", description: "Hello world." }, | ||
// ] | ||
|
||
// User.fetchSingle().then(user => { | ||
// console.log(user) | ||
// }) | ||
|
||
// const supabaseService = new SupabaseService() | ||
// SupabaseService.fetchSingle(User, "c7e80cb0-7d3d-411f-9983-5e3addf62980", { email: "ncuapp@test.com" }).then( | ||
// response => { | ||
// console.log(response) | ||
// } | ||
// ) | ||
|
||
// SupabaseService.fetchMultiple(User).then( | ||
// response => { | ||
// console.log(response) | ||
// } | ||
// ) | ||
|
||
// async function fetch() { | ||
// const { data } = await supabase.from('members').select('*') | ||
// console.log(data) | ||
// } | ||
// fetch() | ||
|
||
export const Route = createFileRoute('/home/')({ | ||
|
||
component: () => <div> | ||
<section className='h-[200px] mb-[40px] bg-yellow-50 relative border-b-[5px] border-gray-600'> | ||
|
||
<div className='flex flex-col absolute left-[10px] bottom-[5px]'> | ||
<h1 className='font-bold text-4xl text-black'>這裡最多七個字</h1> | ||
<h2 className='font-bold text-black'>中文系 二年級</h2> | ||
</div> | ||
|
||
{/* <div className=' | ||
w-[125px] h-[125px] | ||
absolute right-[15px] bottom-[-25px] | ||
border-[4px] border-gray-600 rounded-full bg-gray-500 | ||
'></div> */} | ||
|
||
<div className="avatar absolute right-[15px] bottom-[-25px]"> | ||
<div className="ring-gray-300 w-[125px] rounded-full ring"> | ||
<img src="https://img.daisyui.com/images/stock/photo-1534528741775-53994a69daeb.webp" /> | ||
</div> | ||
</div> | ||
|
||
<span className=' | ||
absolute top-[20px] right-[15px] | ||
text-black font-bold text-xs | ||
'> | ||
變更個人檔案 | ||
</span> | ||
</section> | ||
</div >, | ||
}) |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,84 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import GenericModel from "../models/GenericModel"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { supabase } from "../utils/supabase"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Supabase service for quickly accessing data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export default class SupabaseService { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/* Fetch a single object | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* Parameters | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* ---------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* modelClass: class | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* The target model class | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* targetID: str | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* The target record ID | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* criteria: Dictionary | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* Extra search criteria, please follow the DATABASE_MAPPING of the target model | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* Returns | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* ------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* The target object (of the target model type). Null if record is not found. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public static async fetchSingle<T extends GenericModel>( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
modelClass: new() => T, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
targetID: String, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
criteria?: Partial<Record<string, any>>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
): Promise<T | null> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+23
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Fix TypeScript type declarations. The method signature has some type-related issues:
public static async fetchSingle<T extends GenericModel>(
modelClass: new() => T,
- targetID: String,
- criteria?: Partial<Record<string, any>>,
+ targetID: string,
+ criteria?: Partial<Record<keyof T, unknown>>,
): Promise<T | null> { 📝 Committable suggestion
Suggested change
🧰 Tools🪛 Biome (1.9.4)[error] 25-25: Don't use 'String' as a type. Use lowercase primitives for consistency. (lint/complexity/noBannedTypes) 🪛 eslint (1.23.1)[error] 25-25: Don't use (@typescript-eslint/ban-types) [error] 26-26: Unexpected any. Specify a different type. (@typescript-eslint/no-explicit-any) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const model = (modelClass as any) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const tableName = model.TABLE_NAME | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
var query = supabase.from(tableName) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.select('*') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.eq("uuid", targetID) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for (const key in criteria) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (model.DATABASE_MAP[key]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
query = query.eq(model.DATABASE_MAP[key], criteria[key]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const data = await query; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+31
to
+39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Improve query construction and error handling. Several improvements can be made to the query construction:
- var query = supabase.from(tableName)
+ const query = supabase.from(tableName)
.select('*')
.eq("uuid", targetID)
for (const key in criteria)
if (model.DATABASE_MAP[key])
query = query.eq(model.DATABASE_MAP[key], criteria[key])
- const data = await query;
+ const { data, error } = await query;
+ if (error) {
+ throw new Error(`Failed to fetch ${tableName}: ${error.message}`);
+ }
🧰 Tools🪛 eslint (1.23.1)[error] 31-33: Unexpected var, use let or const instead. (no-var) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!data.data || data.data.length == 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return null | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const record = data.data[0] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return model.parseJson(record) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/* Fetch an array of objects | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* Parameters | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* ---------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* modelClass: class | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* The target model class | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* Returns | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* ------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* Array of objects (of the target model type). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* Returns empty array if no records can be found. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public static async fetchMultiple<T extends GenericModel>( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
modelClass: new() => T, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
): Promise<Array<T>> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const model = (modelClass as any) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const tableName = model.TABLE_NAME | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const data = await supabase.from(tableName) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.select('*') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const records = data.data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const results: Array<T> = [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
records?.forEach(record => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const user = model.parseJson(record) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
results.push(user) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return results | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+64
to
+83
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add pagination and improve error handling. The current implementation has several potential issues:
public static async fetchMultiple<T extends GenericModel>(
modelClass: new() => T,
+ limit: number = 100,
+ offset: number = 0
): Promise<Array<T>> {
const model = (modelClass as any)
const tableName = model.TABLE_NAME
- const data = await supabase.from(tableName)
- .select('*')
+ const { data, error } = await supabase.from(tableName)
+ .select('*')
+ .range(offset, offset + limit - 1)
+ if (error) {
+ throw new Error(`Failed to fetch ${tableName}: ${error.message}`);
+ }
const records = data.data
const results: Array<T> = []
records?.forEach(record => {
- const user = model.parseJson(record)
- results.push(user)
+ const item = model.parseJson(record)
+ results.push(item)
})
return results
} 📝 Committable suggestion
Suggested change
🧰 Tools🪛 eslint (1.23.1)[error] 67-67: Unexpected any. Specify a different type. (@typescript-eslint/no-explicit-any) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Improve type safety of DATABASE_MAP.
The
Object
type is too broad and unsafe. Consider using a more specific type that properly represents the database field mappings.Also, consider making these properties abstract to enforce implementation:
📝 Committable suggestion
🧰 Tools
🪛 Biome (1.9.4)
[error] 6-6: Don't use 'Object' as a type.
Prefer explicitly define the object shape. This type means "any non-nullable value", which is slightly better than 'unknown', but it's still a broad type.
(lint/complexity/noBannedTypes)
🪛 eslint (1.23.1)
[error] 6-6: Don't use
Object
as a type. TheObject
type actually means "any non-nullish value", so it is marginally better thanunknown
.object
instead.unknown
instead.NonNullable<unknown>
instead.(@typescript-eslint/ban-types)