Type System
Sentro automatically generates TypeScript types from your database schema, providing compile-time safety for all database operations.
Auto-Generated Types File
When you run connector.start(), it introspects your database and generates a dbmanager-types.ts file with complete type definitions.
File Location
./dbmanager-types.tsGenerated Types
TableName
Union type of all table names in your database:
export type TableName =
| "users"
| "posts"
| "comments"
| "orders"
// ... all your tablesColumnsByTable
Column names for each table:
export type ColumnsByTable = {
users: "id" | "email" | "name" | "created_at" | "updated_at";
posts: "id" | "title" | "content" | "userId" | "created_at";
comments: "id" | "text" | "postId" | "userId" | "created_at";
// ...
}Row Types
Complete row type for each table with all columns and their types:
export type Row_Users = {
id: number;
email: string;
name: string;
age: number | null;
isActive: boolean;
role: "admin" | "user";
created_at: string;
updated_at: string;
}
export type Row = {
users: Row_Users;
posts: Row_Posts;
comments: Row_Comments;
// ...
}Insert Types
Types for inserting new records (excludes auto-generated fields):
export type Insert_Users = {
email: string;
name: string;
age?: number | null;
isActive?: boolean;
role?: "admin" | "user";
}
export type Insert = {
users: Insert_Users;
posts: Insert_Posts;
// ...
}Update Types
Types for updating records (all fields optional):
export type Update_Users = {
where: {
id: number;
} | {
email: string;
};
patch: {
email?: string;
name?: string;
age?: number | null;
isActive?: boolean;
role?: "admin" | "user";
};
}
export type Update = {
users: Update_Users;
posts: Update_Posts;
// ...
}Delete Types
Types for deleting records:
export type Delete_Users = {
where: {
id: number;
} | {
email: string;
};
single: boolean;
}
export type Delete = {
users: Delete_Users;
// ...
}Primary Key Types
Primary key column name for each table:
export type PK = {
users: "id";
posts: "id";
comments: "id";
// ...
}Relations
Foreign key relationships for each table:
export type Relations_Posts = {
user: Row_Users;
}
export type Relations_Comments = {
post: Row_Posts;
user: Row_Users;
}
export type Relations = {
users: Relations_Users;
posts: Relations_Posts;
comments: Relations_Comments;
// ...
}Global Namespace
Types are also exported in a global namespace for easy access:
declare global {
namespace DBManagerSchema {
type TableName = /* ... */;
// Get list response type
type ListBy<TN extends TableName> = {
rows: RowBy<TN>[];
total: number;
}
// Get row type by table name
type RowBy<TN extends TableName> = Row[TN];
// Get insert type by table name
type InsertBy<TN extends TableName> = Insert[TN];
// Get update type by table name
type UpdateBy<TN extends TableName> = Update[TN];
// Get delete type by table name
type DeleteBy<TN extends TableName> = Delete[TN];
// Get primary key column name
type PKBy<TN extends TableName> = PK[TN];
// Get relations
type RelationsBy<TN extends TableName> = Relations[TN];
}
}Using Generated Types
In Customizers
import { ModelCustomizer } from "@sentrodb/connector-node/dist/inc/customizers/modelCustomizer";
connector.customize(() => {
const c = new ModelCustomizer("users");
c.onBefore("CREATE", (payload: DBManagerSchema.InsertBy<"users">, ctx) => {
// payload is typed as Insert_Users
payload.email = payload.email.toLowerCase();
payload.isActive = true;
return payload;
});
c.onAfter("READ", (result: DBManagerSchema.ListBy<"users">, ctx) => {
// result.rows is typed as Row_Users[]
result.rows.forEach(user => {
console.log(user.email); // Type-safe access
});
return result;
});
return c;
});In Actions
connector.customize(() => {
const c = new ModelCustomizer("users");
c.addAction({
type: "detail",
id: "send-email",
label: "Send Email",
callback: async (
request,
record: DBManagerSchema.RowBy<"users">,
db
) => {
// record is typed as Row_Users
console.log(record.email); // Type-safe
// Send email...
return { success: true };
}
});
return c;
});In Database Operations
// Insert with type safety
const newUser: DBManagerSchema.InsertBy<"users"> = {
email: "user@example.com",
name: "John Doe",
isActive: true
};
await db.insert({
table: "users",
data: newUser
});
// Update with type safety
const updateData: DBManagerSchema.UpdateBy<"users"> = {
where: { id: 1 },
patch: { name: "Jane Doe" }
};
await db.update({
table: "users",
...updateData
});
// Read with type safety
const result = await db.get({
table: "users",
where: { isActive: true }
});
const users: DBManagerSchema.RowBy<"users">[] = result.rows;Enum Types
Database enums are automatically converted to TypeScript union types:
// If you have an enum column in your database:
// CREATE TYPE user_role AS ENUM ('admin', 'user', 'moderator');
// Generated type:
export type Row_Users = {
id: number;
email: string;
role: "admin" | "user" | "moderator"; // Enum as union type
// ...
}Nullable Fields
Nullable database columns are typed as optional or union with null:
export type Row_Users = {
id: number;
email: string;
age: number | null; // Nullable column
bio: string | null; // Nullable column
// ...
}
export type Insert_Users = {
email: string;
age?: number | null; // Optional in insert
bio?: string | null; // Optional in insert
}JSON Columns
JSON columns are typed as any or Record<string, any>:
export type Row_Users = {
id: number;
metadata: Record<string, any>; // JSON column
settings: any; // JSONB column
}Type Helpers
Extract Single Row Type
type User = DBManagerSchema.RowBy<"users">;
const user: User = {
id: 1,
email: "user@example.com",
name: "John Doe",
// ...
};Extract Insert Type
type CreateUser = DBManagerSchema.InsertBy<"users">;
const newUser: CreateUser = {
email: "user@example.com",
name: "John Doe"
};Extract Column Names
type UserColumns = ColumnsByTable["users"];
// "id" | "email" | "name" | "created_at" | ...
const column: UserColumns = "email"; // Type-safeRegenerating Types
Types are automatically regenerated when you call connector.start(). If you modify your database schema, restart your application to regenerate the types.
// After database schema changes
await connector.start(); // Regenerates dbmanager-types.tsTypeScript Configuration
Make sure your tsconfig.json includes the generated types:
{
"compilerOptions": {
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
},
"include": [
"src/**/*",
"dbmanager-types.ts" // Include generated types
]
}Best Practices
- Always use the generated types for type safety
- Regenerate types after schema changes
- Use type helpers for cleaner code
- Leverage TypeScript's IntelliSense for better DX
- Don't manually modify generated types
- Commit the types file to version control
- Use strict TypeScript configuration